readonly: Initial pieces for read-only mounts
authorAlan Cox <alan@linux.intel.com>
Fri, 20 Feb 2015 20:45:25 +0000 (20:45 +0000)
committerAlan Cox <alan@linux.intel.com>
Fri, 20 Feb 2015 20:45:25 +0000 (20:45 +0000)
Kernel/filesys.c
Kernel/include/kernel.h
Kernel/syscall_fs2.c

index 490c969..dc95386 100644 (file)
@@ -187,6 +187,7 @@ inoptr i_open(uint16_t dev, uint16_t ino)
 {
     struct dinode *buf;
     inoptr nindex, j;
+    struct mount *m;
     bool isnew = false;
 
     if(!validdev(dev))
@@ -201,9 +202,11 @@ inoptr i_open(uint16_t dev, uint16_t ino)
         }
     }
 
+    m = fs_tab_get(dev);
+
     /* Maybe make this DEBUG only eventually - the fs_tab_get cost
        is higher than ideal */
-    if(ino < ROOTINODE || ino >= (fs_tab_get(dev)->m_fs->s_isize - 2) * 8) {
+    if(ino < ROOTINODE || ino >= (m->m_fs->s_isize - 2) * 8) {
         kputs("i_open: bad inode number\n");
         return NULLINODE;
     }
@@ -232,7 +235,7 @@ inoptr i_open(uint16_t dev, uint16_t ino)
     nindex->c_dev = dev;
     nindex->c_num = ino;
     nindex->c_magic = CMAGIC;
-
+    nindex->c_flags = (m->m_flags & MS_RDONLY) ? CRDONLY : 0;
 found:
     if(isnew) {
         if(nindex->c_node.i_nlink || nindex->c_node.i_mode & F_MASK)
@@ -265,6 +268,10 @@ bool ch_link(inoptr wd, char *oldname, char *newname, inoptr nindex)
     struct direct curentry;
     int i;
 
+    if (wd->c_flags & CRDONLY) {
+        udata.u_error = EROFS;
+        return false;
+    }
     if(!(getperm(wd) & OTH_WR))
     {
         udata.u_error = EPERM;
@@ -394,6 +401,11 @@ inoptr newfile(inoptr pino, char *name)
     uint8_t j;
 
     /* First see if parent is writeable */
+    if (pino->c_flags & CRDONLY) {
+        udata.u_error = EROFS;
+        goto nogood;
+    }
+
     if(!(getperm(pino) & OTH_WR))
         goto nogood;
 
@@ -468,6 +480,7 @@ uint16_t i_alloc(uint16_t devno)
 {
     staticfast fsptr dev;
     staticfast blkno_t blk;
+    staticfast struct mount *m;
     struct dinode *buf;
     staticfast uint16_t j;
     uint16_t k;
@@ -475,6 +488,7 @@ uint16_t i_alloc(uint16_t devno)
 
     if(baddev(dev = getdev(devno)))
         goto corrupt;
+    m = fs_tab_get(devno);
 
 tryagain:
     if(dev->s_ninode) {
@@ -800,11 +814,15 @@ uint16_t devnum(inoptr ino)
 /* F_trunc frees all the blocks associated with the file, if it
  * is a disk file.
  */
-void f_trunc(inoptr ino)
+int f_trunc(inoptr ino)
 {
     uint16_t dev;
     int8_t j;
 
+    if (ino->c_flags & CRDONLY) {
+        udata.u_error = EROFS;
+        return -1;
+    }
     dev = ino->c_dev;
 
     /* First deallocate the double indirect blocks */
@@ -821,6 +839,7 @@ void f_trunc(inoptr ino)
 
     ino->c_flags |= CDIRTY;
     ino->c_node.i_size = 0;
+    return 0;
 }
 
 
@@ -1015,6 +1034,9 @@ uint8_t getperm(inoptr ino)
 */
 void setftime(inoptr ino, uint8_t flag)
 {
+    if (ino->c_flags & CRDONLY)
+        return;
+
     ino->c_flags |= CDIRTY;
 
     if(flag & A_TIME)
index a5f623f..a87240a 100644 (file)
@@ -191,6 +191,7 @@ typedef struct cinode { // note: exists in memory *and* on disk
     uint8_t    c_refs;            /* In-core reference count */
     uint8_t    c_flags;           
 #define CDIRTY         0x80    /* Modified flag. */
+#define CRDONLY                0x40    /* On a read only file system */
 #define CFLOCK         0x0F    /* flock bits */
 #define CFLEX          0x0F    /* locked exclusive */
 #define CFMAX          0x0E    /* highest shared lock count permitted */
@@ -672,7 +673,7 @@ extern void i_ref(inoptr ino);
 extern void i_deref(inoptr ino);
 extern void wr_inode(inoptr ino);
 extern bool isdevice(inoptr ino);
-extern void f_trunc(inoptr ino);
+extern int f_trunc(inoptr ino);
 extern void freeblk(uint16_t dev, blkno_t blk, uint8_t level);
 extern blkno_t bmap(inoptr ip, blkno_t bn, int rwflg);
 extern void validblk(uint16_t dev, blkno_t num);
index b96656f..23ea036 100644 (file)
@@ -186,6 +186,10 @@ static arg_t chmod_op(inoptr ino)
 {
        if (ino->c_node.i_uid != udata.u_euid && esuper())
                return (-1);
+       if (ino->c_flags & CRDONLY) {
+               udata.u_error = EROFS;
+               return -1;
+       }
 
        ino->c_node.i_mode =
            (mode & MODE_MASK) | (ino->c_node.i_mode & F_MASK);
@@ -242,6 +246,10 @@ static int chown_op(inoptr ino)
 {
        if (ino->c_node.i_uid != udata.u_euid && esuper())
                return (-1);
+       if (ino->c_flags & CRDONLY) {
+               udata.u_error = EROFS;
+               return -1;
+       }
        ino->c_node.i_uid = owner;
        ino->c_node.i_gid = group;
        setftime(ino, C_TIME);
@@ -308,6 +316,10 @@ arg_t _utime(void)
 
        if (!(ino = n_open(file, NULLINOPTR)))
                return (-1);
+       if (ino->c_flags & CRDONLY) {
+               udata.u_error = EROFS;
+               goto out2;
+       }
        /* Special case in the Unix API - NULL means now */
        if (buf) {
                if (ino->c_node.i_uid != udata.u_euid && esuper())
@@ -363,6 +375,10 @@ arg_t _acct(void)
                         udata.u_error = EINVAL;
                         return -1;
                 }
+               if (ino->c_flags & CRDONLY) {
+                       udata.u_error = EROFS;
+                       return -1;
+               }
                acct_fh = udata.u_files[fd];
                ++of_tab[acct_fh].o_refs;
         }
@@ -473,11 +489,17 @@ arg_t _open(void)
        perm = getperm(ino);
        if ((r && !(perm & OTH_RD)) || (w && !(perm & OTH_WR))) {
                udata.u_error = EPERM;
-               goto cantopen;
+               goto idrop;
        }
-       if (getmode(ino) == F_DIR && w) {
-               udata.u_error = EISDIR;
-               goto cantopen;
+       if (w) {
+               if (getmode(ino) == F_DIR ) {
+                       udata.u_error = EISDIR;
+                       goto idrop;
+               }
+               if (ino->c_flags & CRDONLY) {
+                       udata.u_error = EROFS;
+                       goto idrop;
+               }
        }
        itmp = ino;
        /* d_open may block and thus ino may become invalid as may
@@ -485,12 +507,13 @@ arg_t _open(void)
        if (isdevice(ino)
            && d_open((int) ino->c_node.i_addr[0], flag) != 0) {
                udata.u_error = ENXIO;
-               goto cantopen;
+               goto idrop;
        }
        /* get the static pointer back */
        ino = itmp;
        if (trunc && getmode(ino) == F_REG) {
-               f_trunc(ino);
+               if (f_trunc(ino))
+                       goto idrop;
                for (j = 0; j < OFTSIZE; ++j)
                        /* Arguably should fix at read/write */
                        if (of_tab[j].o_inode == ino)