]> err.no Git - linux-2.6/blobdiff - fs/jffs2/fs.c
[PATCH] VFS: Permit filesystem to perform statfs with a known root dentry
[linux-2.6] / fs / jffs2 / fs.c
index b0b96d7272d8d4b21b3e9912bfd32a780dc4a47d..2900ec3ec3afb79614a5479179880d0682dddf20 100644 (file)
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/capability.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -32,15 +33,15 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
        struct jffs2_raw_inode *ri;
-       unsigned short dev;
+       union jffs2_device_node dev;
        unsigned char *mdata = NULL;
        int mdatalen = 0;
        unsigned int ivalid;
-       uint32_t phys_ofs, alloclen;
+       uint32_t alloclen;
        int ret;
        D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
        ret = inode_change_ok(inode, iattr);
-       if (ret) 
+       if (ret)
                return ret;
 
        /* Special cases - we don't want more than one data node
@@ -50,20 +51,24 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
           it out again with the appropriate data attached */
        if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
                /* For these, we don't actually need to read the old node */
-               dev = old_encode_dev(inode->i_rdev);
+               mdatalen = jffs2_encode_dev(&dev, inode->i_rdev);
                mdata = (char *)&dev;
-               mdatalen = sizeof(dev);
                D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
        } else if (S_ISLNK(inode->i_mode)) {
+               down(&f->sem);
                mdatalen = f->metadata->size;
                mdata = kmalloc(f->metadata->size, GFP_USER);
-               if (!mdata)
+               if (!mdata) {
+                       up(&f->sem);
                        return -ENOMEM;
+               }
                ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
                if (ret) {
+                       up(&f->sem);
                        kfree(mdata);
                        return ret;
                }
+               up(&f->sem);
                D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
        }
 
@@ -73,9 +78,9 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
                        kfree(mdata);
                return -ENOMEM;
        }
-               
-       ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen,
-                               ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
+
+       ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &alloclen,
+                                 ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
        if (ret) {
                jffs2_free_raw_inode(ri);
                if (S_ISLNK(inode->i_mode & S_IFMT))
@@ -84,7 +89,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        }
        down(&f->sem);
        ivalid = iattr->ia_valid;
-       
+
        ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
        ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
@@ -100,7 +105,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
                if (iattr->ia_mode & S_ISGID &&
                    !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
                        ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
-               else 
+               else
                        ri->mode = cpu_to_jemode(iattr->ia_mode);
        else
                ri->mode = cpu_to_jemode(inode->i_mode);
@@ -126,10 +131,10 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        else
                ri->data_crc = cpu_to_je32(0);
 
-       new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL);
+       new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, ALLOC_NORMAL);
        if (S_ISLNK(inode->i_mode))
                kfree(mdata);
-       
+
        if (IS_ERR(new_metadata)) {
                jffs2_complete_reservation(c);
                jffs2_free_raw_inode(ri);
@@ -167,7 +172,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        jffs2_complete_reservation(c);
 
        /* We have to do the vmtruncate() without f->sem held, since
-          some pages may be locked and waiting for it in readpage(). 
+          some pages may be locked and waiting for it in readpage().
           We are protected from a simultaneous write() extending i_size
           back past iattr->ia_size, because do_truncate() holds the
           generic inode semaphore. */
@@ -179,12 +184,17 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
 
 int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
 {
-       return jffs2_do_setattr(dentry->d_inode, iattr);
+       int rc;
+
+       rc = jffs2_do_setattr(dentry->d_inode, iattr);
+       if (!rc && (iattr->ia_valid & ATTR_MODE))
+               rc = jffs2_acl_chmod(dentry->d_inode);
+       return rc;
 }
 
-int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
+int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
+       struct jffs2_sb_info *c = JFFS2_SB_INFO(dentry->d_sb);
        unsigned long avail;
 
        buf->f_type = JFFS2_SUPER_MAGIC;
@@ -210,14 +220,15 @@ int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
 
 void jffs2_clear_inode (struct inode *inode)
 {
-       /* We can forget about this inode for now - drop all 
+       /* We can forget about this inode for now - drop all
         *  the nodelists associated with it, etc.
         */
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-       
+
        D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+       jffs2_xattr_delete_inode(c, f->inocache);
        jffs2_do_clear_inode(c, f);
 }
 
@@ -226,6 +237,8 @@ void jffs2_read_inode (struct inode *inode)
        struct jffs2_inode_info *f;
        struct jffs2_sb_info *c;
        struct jffs2_raw_inode latest_node;
+       union jffs2_device_node jdev;
+       dev_t rdev = 0;
        int ret;
 
        D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
@@ -234,7 +247,8 @@ void jffs2_read_inode (struct inode *inode)
        c = JFFS2_SB_INFO(inode->i_sb);
 
        jffs2_init_inode_info(f);
-       
+       down(&f->sem);
+
        ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
 
        if (ret) {
@@ -254,14 +268,13 @@ void jffs2_read_inode (struct inode *inode)
 
        inode->i_blksize = PAGE_SIZE;
        inode->i_blocks = (inode->i_size + 511) >> 9;
-       
+
        switch (inode->i_mode & S_IFMT) {
-               jint16_t rdev;
 
        case S_IFLNK:
                inode->i_op = &jffs2_symlink_inode_operations;
                break;
-               
+
        case S_IFDIR:
        {
                struct jffs2_full_dirent *fd;
@@ -290,21 +303,32 @@ void jffs2_read_inode (struct inode *inode)
        case S_IFBLK:
        case S_IFCHR:
                /* Read the device numbers from the media */
+               if (f->metadata->size != sizeof(jdev.old) &&
+                   f->metadata->size != sizeof(jdev.new)) {
+                       printk(KERN_NOTICE "Device node has strange size %d\n", f->metadata->size);
+                       up(&f->sem);
+                       jffs2_do_clear_inode(c, f);
+                       make_bad_inode(inode);
+                       return;
+               }
                D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
-               if (jffs2_read_dnode(c, f, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
+               if (jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size) < 0) {
                        /* Eep */
                        printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
                        up(&f->sem);
                        jffs2_do_clear_inode(c, f);
                        make_bad_inode(inode);
                        return;
-               }                       
+               }
+               if (f->metadata->size == sizeof(jdev.old))
+                       rdev = old_decode_dev(je16_to_cpu(jdev.old));
+               else
+                       rdev = new_decode_dev(je32_to_cpu(jdev.new));
 
        case S_IFSOCK:
        case S_IFIFO:
                inode->i_op = &jffs2_file_inode_operations;
-               init_special_inode(inode, inode->i_mode,
-                                  old_decode_dev((je16_to_cpu(rdev))));
+               init_special_inode(inode, inode->i_mode, rdev);
                break;
 
        default:
@@ -354,11 +378,11 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
                down(&c->alloc_sem);
                jffs2_flush_wbuf_pad(c);
                up(&c->alloc_sem);
-       }       
+       }
 
        if (!(*flags & MS_RDONLY))
                jffs2_start_garbage_collect_thread(c);
-       
+
        *flags |= MS_NOATIME;
 
        return 0;
@@ -392,14 +416,15 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
        D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
 
        c = JFFS2_SB_INFO(sb);
-       
+
        inode = new_inode(sb);
-       
+
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
        f = JFFS2_INODE_INFO(inode);
        jffs2_init_inode_info(f);
+       down(&f->sem);
 
        memset(ri, 0, sizeof(*ri));
        /* Set OS-specific defaults for new inodes */
@@ -458,14 +483,14 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
 #endif
 
        c->flash_size = c->mtd->size;
-       c->sector_size = c->mtd->erasesize; 
+       c->sector_size = c->mtd->erasesize;
        blocks = c->flash_size / c->sector_size;
 
        /*
         * Size alignment check
         */
        if ((c->sector_size * blocks) != c->flash_size) {
-               c->flash_size = c->sector_size * blocks;                
+               c->flash_size = c->sector_size * blocks;
                printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n",
                        c->flash_size / 1024);
        }
@@ -489,6 +514,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
        }
        memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
 
+       jffs2_init_xattr_subsystem(c);
+
        if ((ret = jffs2_do_mount_fs(c)))
                goto out_inohash;
 
@@ -523,6 +550,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
        else
                kfree(c->blocks);
  out_inohash:
+       jffs2_clear_xattr_subsystem(c);
        kfree(c->inocache_list);
  out_wbuf:
        jffs2_flash_cleanup(c);
@@ -543,16 +571,16 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
        struct jffs2_inode_cache *ic;
        if (!nlink) {
                /* The inode has zero nlink but its nodes weren't yet marked
-                  obsolete. This has to be because we're still waiting for 
+                  obsolete. This has to be because we're still waiting for
                   the final (close() and) iput() to happen.
 
-                  There's a possibility that the final iput() could have 
+                  There's a possibility that the final iput() could have
                   happened while we were contemplating. In order to ensure
                   that we don't cause a new read_inode() (which would fail)
                   for the inode in question, we use ilookup() in this case
                   instead of iget().
 
-                  The nlink can't _become_ zero at this point because we're 
+                  The nlink can't _become_ zero at this point because we're
                   holding the alloc_sem, and jffs2_do_unlink() would also
                   need that while decrementing nlink on any inode.
                */
@@ -599,19 +627,19 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
        return JFFS2_INODE_INFO(inode);
 }
 
-unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
-                                  struct jffs2_inode_info *f, 
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
+                                  struct jffs2_inode_info *f,
                                   unsigned long offset,
                                   unsigned long *priv)
 {
        struct inode *inode = OFNI_EDONI_2SFFJ(f);
        struct page *pg;
 
-       pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, 
+       pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT,
                             (void *)jffs2_do_readpage_unlock, inode);
        if (IS_ERR(pg))
                return (void *)pg;
-       
+
        *priv = (unsigned long)pg;
        return kmap(pg);
 }
@@ -628,7 +656,7 @@ void jffs2_gc_release_page(struct jffs2_sb_info *c,
 
 static int jffs2_flash_setup(struct jffs2_sb_info *c) {
        int ret = 0;
-       
+
        if (jffs2_cleanmarker_oob(c)) {
                /* NAND flash... do setup accordingly */
                ret = jffs2_nand_flash_setup(c);
@@ -636,13 +664,6 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
                        return ret;
        }
 
-       /* add setups for other bizarre flashes here... */
-       if (jffs2_nor_ecc(c)) {
-               ret = jffs2_nor_ecc_flash_setup(c);
-               if (ret)
-                       return ret;
-       }
-       
        /* and Dataflash */
        if (jffs2_dataflash(c)) {
                ret = jffs2_dataflash_setup(c);
@@ -666,11 +687,6 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
                jffs2_nand_flash_cleanup(c);
        }
 
-       /* add cleanups for other bizarre flashes here... */
-       if (jffs2_nor_ecc(c)) {
-               jffs2_nor_ecc_flash_cleanup(c);
-       }
-       
        /* and DataFlash */
        if (jffs2_dataflash(c)) {
                jffs2_dataflash_cleanup(c);