From 9a664b498484ff0b36060958877418c6274be18d Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Thu, 22 Dec 2011 01:29:27 +0100 Subject: [PATCH] mfs: restore readonly mounting . use dirty marking hooks to check and warn when inodes/bufs are marked dirty on a readonly mounted fs . add readonly mount checks to restore readonly mounting Signed-off-by: Ben Gras --- servers/mfs/clean.h | 2 +- servers/mfs/inode.h | 4 +++- servers/mfs/link.c | 18 ++++++++++++------ servers/mfs/path.c | 3 +++ servers/mfs/protect.c | 5 +++++ servers/mfs/read.c | 31 ++++++++++++++++++++++++++----- 6 files changed, 50 insertions(+), 13 deletions(-) diff --git a/servers/mfs/clean.h b/servers/mfs/clean.h index 6f740a198..626c7acec 100644 --- a/servers/mfs/clean.h +++ b/servers/mfs/clean.h @@ -2,7 +2,7 @@ #ifndef _MFS_CLEAN_H #define _MFS_CLEAN_H 1 -#define MARKDIRTY(b) ((b)->b_dirt = BP_DIRTY) +#define MARKDIRTY(b) do { if(superblock.s_dev == (b)->b_dev && superblock.s_rd_only) { printf("%s:%d: dirty block on rofs! ", __FILE__, __LINE__); util_stacktrace(); } else { (b)->b_dirt = BP_DIRTY; } } while(0) #define MARKCLEAN(b) ((b)->b_dirt = BP_CLEAN) #define ISDIRTY(b) ((b)->b_dirt == BP_DIRTY) diff --git a/servers/mfs/inode.h b/servers/mfs/inode.h index ea2038eee..112defb61 100644 --- a/servers/mfs/inode.h +++ b/servers/mfs/inode.h @@ -16,6 +16,8 @@ #include +#include "super.h" + EXTERN struct inode { u16_t i_mode; /* file type, protection, etc. */ u16_t i_nlinks; /* how many links to this file */ @@ -63,7 +65,7 @@ EXTERN unsigned int inode_cache_miss; #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 diff --git a/servers/mfs/link.c b/servers/mfs/link.c index a872b865b..49854634e 100644 --- a/servers/mfs/link.c +++ b/servers/mfs/link.c @@ -148,8 +148,10 @@ PUBLIC int fs_unlink() 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; @@ -496,14 +498,18 @@ PUBLIC int fs_ftrunc(void) 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); } diff --git a/servers/mfs/path.c b/servers/mfs/path.c index 804cde6a6..efab7a333 100644 --- a/servers/mfs/path.c +++ b/servers/mfs/path.c @@ -494,6 +494,9 @@ int check_permissions; /* check permissions when flag is !IS_EMPTY */ if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) { return(ENOTDIR); } + + if((flag == DELETE || flag == ENTER) && ldir_ptr->i_sp->s_rd_only) + return EROFS; r = OK; diff --git a/servers/mfs/protect.c b/servers/mfs/protect.c index b2d92c078..7e46ae318 100644 --- a/servers/mfs/protect.c +++ b/servers/mfs/protect.c @@ -21,6 +21,11 @@ PUBLIC int fs_chmod() /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); + + if(rip->i_sp->s_rd_only) { + put_inode(rip); + return EROFS; + } /* Now make the change. Clear setgid bit if file is not in caller's grp */ rip->i_mode = (rip->i_mode & ~ALL_MODES) | (mode & ALL_MODES); diff --git a/servers/mfs/read.c b/servers/mfs/read.c index b89ae25a9..6ec47b272 100644 --- a/servers/mfs/read.c +++ b/servers/mfs/read.c @@ -62,7 +62,11 @@ PUBLIC int fs_readwrite(void) 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); @@ -73,6 +77,11 @@ PUBLIC int fs_readwrite(void) */ 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. */ @@ -114,7 +123,10 @@ PUBLIC int fs_readwrite(void) 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 */ @@ -136,11 +148,14 @@ PUBLIC int fs_breadwrite(void) 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); @@ -149,9 +164,13 @@ PUBLIC int fs_breadwrite(void) (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; @@ -642,8 +661,10 @@ PUBLIC int fs_getdents(void) 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; } -- 2.44.0