#include <sys/queue.h>
+#include "super.h"
+
EXTERN struct inode {
u16_t i_mode; /* file type, protection, etc. */
u16_t i_nlinks; /* how many links to this file */
#define ISEEK 1 /* i_seek = ISEEK if last op was SEEK */
#define IN_MARKCLEAN(i) i->i_dirt = IN_CLEAN
-#define IN_MARKDIRTY(i) i->i_dirt = IN_DIRTY
+#define IN_MARKDIRTY(i) do { if(i->i_sp->s_rd_only) { printf("%s:%d: dirty inode on rofs ", __FILE__, __LINE__); util_stacktrace(); } else { i->i_dirt = IN_DIRTY; } } while(0)
#define IN_ISCLEAN(i) i->i_dirt == IN_CLEAN
#define IN_ISDIRTY(i) i->i_dirt == IN_DIRTY
return(r);
}
+ if(rip->i_sp->s_rd_only) {
+ r = EROFS;
+ } else if(fs_m_in.m_type == REQ_UNLINK) {
/* Now test if the call is allowed, separately for unlink() and rmdir(). */
- if(fs_m_in.m_type == REQ_UNLINK) {
/* Only the su may unlink directories, but the su can unlink any
* dir.*/
if( (rip->i_mode & I_TYPE) == I_DIRECTORY) r = EPERM;
if( (rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
return(EINVAL);
- start = fs_m_in.REQ_TRC_START_LO;
- end = fs_m_in.REQ_TRC_END_LO;
+ if(rip->i_sp->s_rd_only) {
+ r = EROFS;
+ } else {
+ start = fs_m_in.REQ_TRC_START_LO;
+ end = fs_m_in.REQ_TRC_END_LO;
- if (end == 0)
+ if (end == 0)
r = truncate_inode(rip, start);
- else
+ else
r = freesp_inode(rip, start, end);
-
+ }
+
return(r);
}
rdwt_err = OK; /* set to EIO if disk error occurs */
+ /* If this is file i/o, check we can write */
if (rw_flag == WRITING && !block_spec) {
+ if(rip->i_sp->s_rd_only)
+ return EROFS;
+
/* Check in advance to see if file will grow too big. */
if (position > (off_t) (rip->i_sp->s_max_size - nrbytes))
return(EFBIG);
*/
if(position > f_size) clear_zone(rip, f_size, 0);
}
+
+ /* If this is block i/o, check we can write */
+ if(block_spec && rw_flag == WRITING &&
+ (dev_t) rip->i_zone[0] == superblock.s_dev && superblock.s_rd_only)
+ return EROFS;
cum_io = 0;
/* Split the transfer into chunks that don't span two blocks. */
if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
if (rdwt_err == END_OF_FILE) r = OK;
- if (r == OK) {
+ /* even on a ROFS, writing to a device node on it is fine,
+ * just don't update the inode stats for it. And dito for reading.
+ */
+ if (r == OK && !rip->i_sp->s_rd_only) {
if (rw_flag == READING) rip->i_update |= ATIME;
if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
IN_MARKDIRTY(rip); /* inode is thus now dirty */
u64_t position;
unsigned int off, cum_io, chunk, block_size;
size_t nrbytes;
+ dev_t target_dev;
/* Pseudo inode for rw_chunk */
struct inode rip;
r = OK;
+
+ target_dev = (dev_t) fs_m_in.REQ_DEV2;
/* Get the values from the request message */
rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING);
(unsigned long) fs_m_in.REQ_SEEK_POS_HI);
nrbytes = (size_t) fs_m_in.REQ_NBYTES;
- block_size = get_block_size( (dev_t) fs_m_in.REQ_DEV2);
+ block_size = get_block_size(target_dev);
+
+ /* Don't block-write to a RO-mounted filesystem. */
+ if(superblock.s_dev == target_dev && superblock.s_rd_only)
+ return EROFS;
- rip.i_zone[0] = (zone_t) fs_m_in.REQ_DEV2;
+ rip.i_zone[0] = (zone_t) target_dev;
rip.i_mode = I_BLOCK_SPECIAL;
rip.i_size = 0;
else {
fs_m_out.RES_NBYTES = userbuf_off;
fs_m_out.RES_SEEK_POS_LO = new_pos;
- rip->i_update |= ATIME;
- IN_MARKDIRTY(rip);
+ if(!rip->i_sp->s_rd_only) {
+ rip->i_update |= ATIME;
+ IN_MARKDIRTY(rip);
+ }
r = OK;
}