nfsd: silence lockdep warning
[safe/jmp/linux-2.6] / fs / jffs2 / dir.c
index da6034d..6f60cc9 100644 (file)
@@ -1,19 +1,16 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright © 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.90 2005/11/07 11:14:39 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/crc32.h>
 #include <linux/jffs2.h>
@@ -35,18 +32,19 @@ static int jffs2_mkdir (struct inode *,struct dentry *,int);
 static int jffs2_rmdir (struct inode *,struct dentry *);
 static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
 static int jffs2_rename (struct inode *, struct dentry *,
-                        struct inode *, struct dentry *);
+                        struct inode *, struct dentry *);
 
 const struct file_operations jffs2_dir_operations =
 {
        .read =         generic_read_dir,
        .readdir =      jffs2_readdir,
-       .ioctl =        jffs2_ioctl,
-       .fsync =        jffs2_fsync
+       .unlocked_ioctl=jffs2_ioctl,
+       .fsync =        jffs2_fsync,
+       .llseek =       generic_file_llseek,
 };
 
 
-struct inode_operations jffs2_dir_inode_operations =
+const struct inode_operations jffs2_dir_inode_operations =
 {
        .create =       jffs2_create,
        .lookup =       jffs2_lookup,
@@ -89,7 +87,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
        dir_f = JFFS2_INODE_INFO(dir_i);
        c = JFFS2_SB_INFO(dir_i->i_sb);
 
-       down(&dir_f->sem);
+       mutex_lock(&dir_f->sem);
 
        /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
        for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) {
@@ -102,18 +100,16 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
        }
        if (fd)
                ino = fd->ino;
-       up(&dir_f->sem);
+       mutex_unlock(&dir_f->sem);
        if (ino) {
-               inode = iget(dir_i->i_sb, ino);
-               if (!inode) {
+               inode = jffs2_iget(dir_i->i_sb, ino);
+               if (IS_ERR(inode)) {
                        printk(KERN_WARNING "iget() failed for ino #%u\n", ino);
-                       return (ERR_PTR(-EIO));
+                       return ERR_CAST(inode);
                }
        }
 
-       d_add(target, inode);
-
-       return NULL;
+       return d_splice_alias(inode, target);
 }
 
 /***********************************************************************/
@@ -149,7 +145,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
        }
 
        curofs=1;
-       down(&f->sem);
+       mutex_lock(&f->sem);
        for (fd = f->dents; fd; fd = fd->next) {
 
                curofs++;
@@ -169,7 +165,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        break;
                offset++;
        }
-       up(&f->sem);
+       mutex_unlock(&f->sem);
  out:
        filp->f_pos = offset;
        return 0;
@@ -211,16 +207,15 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
        f = JFFS2_INODE_INFO(inode);
        dir_f = JFFS2_INODE_INFO(dir_i);
 
+       /* jffs2_do_create() will want to lock it, _after_ reserving
+          space and taking c-alloc_sem. If we keep it locked here,
+          lockdep gets unhappy (although it's a false positive;
+          nothing else will be looking at this inode yet so there's
+          no chance of AB-BA deadlock involving its f->sem). */
+       mutex_unlock(&f->sem);
+
        ret = jffs2_do_create(c, dir_f, f, ri,
                              dentry->d_name.name, dentry->d_name.len);
-
-       if (ret)
-               goto fail;
-
-       ret = jffs2_init_security(inode, dir_i);
-       if (ret)
-               goto fail;
-       ret = jffs2_init_acl(inode, dir_i);
        if (ret)
                goto fail;
 
@@ -230,7 +225,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
        d_instantiate(dentry, inode);
 
        D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
-                 inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
+                 inode->i_ino, inode->i_mode, inode->i_nlink,
+                 f->inocache->pino_nlink, inode->i_mapping->nrpages));
        return 0;
 
  fail:
@@ -254,7 +250,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
        ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
                              dentry->d_name.len, dead_f, now);
        if (dead_f->inocache)
-               dentry->d_inode->i_nlink = dead_f->inocache->nlink;
+               dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink;
        if (!ret)
                dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
        return ret;
@@ -286,9 +282,9 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
        ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
 
        if (!ret) {
-               down(&f->sem);
-               old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
-               up(&f->sem);
+               mutex_lock(&f->sem);
+               old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink;
+               mutex_unlock(&f->sem);
                d_instantiate(dentry, old_dentry->d_inode);
                dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
                atomic_inc(&old_dentry->d_inode->i_count);
@@ -314,7 +310,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        /* FIXME: If you care. We'd need to use frags for the target
           if it grows much more than this */
        if (targetlen > 254)
-               return -EINVAL;
+               return -ENAMETOOLONG;
 
        ri = jffs2_alloc_raw_inode();
 
@@ -362,7 +358,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
 
        if (IS_ERR(fn)) {
                /* Eeek. Wave bye bye */
-               up(&f->sem);
+               mutex_unlock(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
                return PTR_ERR(fn);
@@ -372,7 +368,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        f->target = kmalloc(targetlen + 1, GFP_KERNEL);
        if (!f->target) {
                printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
-               up(&f->sem);
+               mutex_unlock(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
                return -ENOMEM;
@@ -385,7 +381,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
           obsoleted by the first data write
        */
        f->metadata = fn;
-       up(&f->sem);
+       mutex_unlock(&f->sem);
 
        jffs2_complete_reservation(c);
 
@@ -394,7 +390,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                jffs2_clear_inode(inode);
                return ret;
        }
-       ret = jffs2_init_acl(inode, dir_i);
+       ret = jffs2_init_acl_post(inode);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
@@ -417,7 +413,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        }
 
        dir_f = JFFS2_INODE_INFO(dir_i);
-       down(&dir_f->sem);
+       mutex_lock(&dir_f->sem);
 
        rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
@@ -440,7 +436,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                   as if it were the final unlink() */
                jffs2_complete_reservation(c);
                jffs2_free_raw_dirent(rd);
-               up(&dir_f->sem);
+               mutex_unlock(&dir_f->sem);
                jffs2_clear_inode(inode);
                return PTR_ERR(fd);
        }
@@ -453,7 +449,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
           one if necessary. */
        jffs2_add_fd_to_list(c, fd, &dir_f->dents);
 
-       up(&dir_f->sem);
+       mutex_unlock(&dir_f->sem);
        jffs2_complete_reservation(c);
 
        d_instantiate(dentry, inode);
@@ -504,11 +500,14 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
 
        inode->i_op = &jffs2_dir_inode_operations;
        inode->i_fop = &jffs2_dir_operations;
-       /* Directories get nlink 2 at start */
-       inode->i_nlink = 2;
 
        f = JFFS2_INODE_INFO(inode);
 
+       /* Directories get nlink 2 at start */
+       inode->i_nlink = 2;
+       /* but ic->pino_nlink is the parent ino# */
+       f->inocache->pino_nlink = dir_i->i_ino;
+
        ri->data_crc = cpu_to_je32(0);
        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 
@@ -518,7 +517,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
 
        if (IS_ERR(fn)) {
                /* Eeek. Wave bye bye */
-               up(&f->sem);
+               mutex_unlock(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
                return PTR_ERR(fn);
@@ -527,7 +526,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
           obsoleted by the first data write
        */
        f->metadata = fn;
-       up(&f->sem);
+       mutex_unlock(&f->sem);
 
        jffs2_complete_reservation(c);
 
@@ -536,7 +535,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
                jffs2_clear_inode(inode);
                return ret;
        }
-       ret = jffs2_init_acl(inode, dir_i);
+       ret = jffs2_init_acl_post(inode);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
@@ -559,7 +558,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
        }
 
        dir_f = JFFS2_INODE_INFO(dir_i);
-       down(&dir_f->sem);
+       mutex_lock(&dir_f->sem);
 
        rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
@@ -582,7 +581,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
                   as if it were the final unlink() */
                jffs2_complete_reservation(c);
                jffs2_free_raw_dirent(rd);
-               up(&dir_f->sem);
+               mutex_unlock(&dir_f->sem);
                jffs2_clear_inode(inode);
                return PTR_ERR(fd);
        }
@@ -596,7 +595,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
           one if necessary. */
        jffs2_add_fd_to_list(c, fd, &dir_f->dents);
 
-       up(&dir_f->sem);
+       mutex_unlock(&dir_f->sem);
        jffs2_complete_reservation(c);
 
        d_instantiate(dentry, inode);
@@ -605,17 +604,25 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
 
 static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
 {
+       struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
+       struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
        struct jffs2_full_dirent *fd;
        int ret;
+       uint32_t now = get_seconds();
 
        for (fd = f->dents ; fd; fd = fd->next) {
                if (fd->ino)
                        return -ENOTEMPTY;
        }
-       ret = jffs2_unlink(dir_i, dentry);
-       if (!ret)
+
+       ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
+                             dentry->d_name.len, f, now);
+       if (!ret) {
+               dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
+               clear_nlink(dentry->d_inode);
                drop_nlink(dir_i);
+       }
        return ret;
 }
 
@@ -684,7 +691,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
 
        if (IS_ERR(fn)) {
                /* Eeek. Wave bye bye */
-               up(&f->sem);
+               mutex_unlock(&f->sem);
                jffs2_complete_reservation(c);
                jffs2_clear_inode(inode);
                return PTR_ERR(fn);
@@ -693,7 +700,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
           obsoleted by the first data write
        */
        f->metadata = fn;
-       up(&f->sem);
+       mutex_unlock(&f->sem);
 
        jffs2_complete_reservation(c);
 
@@ -702,7 +709,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
                jffs2_clear_inode(inode);
                return ret;
        }
-       ret = jffs2_init_acl(inode, dir_i);
+       ret = jffs2_init_acl_post(inode);
        if (ret) {
                jffs2_clear_inode(inode);
                return ret;
@@ -725,7 +732,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
        }
 
        dir_f = JFFS2_INODE_INFO(dir_i);
-       down(&dir_f->sem);
+       mutex_lock(&dir_f->sem);
 
        rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
@@ -751,7 +758,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
                   as if it were the final unlink() */
                jffs2_complete_reservation(c);
                jffs2_free_raw_dirent(rd);
-               up(&dir_f->sem);
+               mutex_unlock(&dir_f->sem);
                jffs2_clear_inode(inode);
                return PTR_ERR(fd);
        }
@@ -764,7 +771,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
           one if necessary. */
        jffs2_add_fd_to_list(c, fd, &dir_f->dents);
 
-       up(&dir_f->sem);
+       mutex_unlock(&dir_f->sem);
        jffs2_complete_reservation(c);
 
        d_instantiate(dentry, inode);
@@ -773,7 +780,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
 }
 
 static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
-                        struct inode *new_dir_i, struct dentry *new_dentry)
+                        struct inode *new_dir_i, struct dentry *new_dentry)
 {
        int ret;
        struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
@@ -791,14 +798,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                if (S_ISDIR(new_dentry->d_inode->i_mode)) {
                        struct jffs2_full_dirent *fd;
 
-                       down(&victim_f->sem);
+                       mutex_lock(&victim_f->sem);
                        for (fd = victim_f->dents; fd; fd = fd->next) {
                                if (fd->ino) {
-                                       up(&victim_f->sem);
+                                       mutex_unlock(&victim_f->sem);
                                        return -ENOTEMPTY;
                                }
                        }
-                       up(&victim_f->sem);
+                       mutex_unlock(&victim_f->sem);
                }
        }
 
@@ -827,9 +834,12 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                /* Don't oops if the victim was a dirent pointing to an
                   inode which didn't exist. */
                if (victim_f->inocache) {
-                       down(&victim_f->sem);
-                       victim_f->inocache->nlink--;
-                       up(&victim_f->sem);
+                       mutex_lock(&victim_f->sem);
+                       if (S_ISDIR(new_dentry->d_inode->i_mode))
+                               victim_f->inocache->pino_nlink = 0;
+                       else
+                               victim_f->inocache->pino_nlink--;
+                       mutex_unlock(&victim_f->sem);
                }
        }
 
@@ -847,11 +857,11 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
        if (ret) {
                /* Oh shit. We really ought to make a single node which can do both atomically */
                struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
-               down(&f->sem);
+               mutex_lock(&f->sem);
                inc_nlink(old_dentry->d_inode);
-               if (f->inocache)
-                       f->inocache->nlink++;
-               up(&f->sem);
+               if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode))
+                       f->inocache->pino_nlink++;
+               mutex_unlock(&f->sem);
 
                printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
                /* Might as well let the VFS know */