Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / fs / jfs / namei.c
index 295268ad231b5ec1f26c78cb43489d434122c907..41c20477126237384bcf4421a0a6ae42765adbe7 100644 (file)
@@ -4,16 +4,16 @@
  *
  *   This program is free software;  you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or 
+ *   the Free Software Foundation; either version 2 of the License, or
  *   (at your option) any later version.
- * 
+ *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  *   the GNU General Public License for more details.
  *
  *   You should have received a copy of the GNU General Public License
- *   along with this program;  if not, write to the Free Software 
+ *   along with this program;  if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
@@ -41,7 +41,7 @@ static s64 commitZeroLink(tid_t, struct inode *);
 /*
  * NAME:       free_ea_wmap(inode)
  *
- * FUNCTION:   free uncommitted extended attributes from working map 
+ * FUNCTION:   free uncommitted extended attributes from working map
  *
  */
 static inline void free_ea_wmap(struct inode *inode)
@@ -62,7 +62,7 @@ static inline void free_ea_wmap(struct inode *inode)
  * FUNCTION:   create a regular file in the parent directory <dip>
  *             with name = <from dentry> and mode = <mode>
  *
- * PARAMETER:  dip     - parent directory vnode
+ * PARAMETER:  dip     - parent directory vnode
  *             dentry  - dentry of new file
  *             mode    - create mode (rwxrwxrwx).
  *             nd- nd struct
@@ -97,15 +97,15 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
         * begin the transaction before we search the directory.
         */
        ip = ialloc(dip, mode);
-       if (ip == NULL) {
-               rc = -ENOSPC;
+       if (IS_ERR(ip)) {
+               rc = PTR_ERR(ip);
                goto out2;
        }
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        rc = jfs_init_acl(tid, ip, dip);
        if (rc)
@@ -190,7 +190,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
  * FUNCTION:   create a child directory in the parent directory <dip>
  *             with name = <from dentry> and mode = <mode>
  *
- * PARAMETER:  dip     - parent directory vnode
+ * PARAMETER:  dip     - parent directory vnode
  *             dentry  - dentry of child directory
  *             mode    - create mode (rwxrwxrwx).
  *
@@ -231,15 +231,15 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
         * begin the transaction before we search the directory.
         */
        ip = ialloc(dip, S_IFDIR | mode);
-       if (ip == NULL) {
-               rc = -ENOSPC;
+       if (IS_ERR(ip)) {
+               rc = PTR_ERR(ip);
                goto out2;
        }
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        rc = jfs_init_acl(tid, ip, dip);
        if (rc)
@@ -292,7 +292,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
        mark_inode_dirty(ip);
 
        /* update parent directory inode */
-       dip->i_nlink++;         /* for '..' from child directory */
+       inc_nlink(dip);         /* for '..' from child directory */
        dip->i_ctime = dip->i_mtime = CURRENT_TIME;
        mark_inode_dirty(dip);
 
@@ -324,7 +324,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
  *
  * FUNCTION:   remove a link to child directory
  *
- * PARAMETER:  dip     - parent inode
+ * PARAMETER:  dip     - parent inode
  *             dentry  - child directory dentry
  *
  * RETURN:     -EINVAL - if name is . or ..
@@ -332,10 +332,10 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
  *             errors from subroutines
  *
  * note:
- * if other threads have the directory open when the last link 
- * is removed, the "." and ".." entries, if present, are removed before 
- * rmdir() returns and no new entries may be created in the directory, 
- * but the directory is not removed until the last reference to 
+ * if other threads have the directory open when the last link
+ * is removed, the "." and ".." entries, if present, are removed before
+ * rmdir() returns and no new entries may be created in the directory,
+ * but the directory is not removed until the last reference to
  * the directory is released (cf.unlink() of regular file).
  */
 static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
@@ -365,8 +365,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        iplist[0] = dip;
        iplist[1] = ip;
@@ -393,9 +393,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
        /* update parent directory's link count corresponding
         * to ".." entry of the target directory deleted
         */
-       dip->i_nlink--;
        dip->i_ctime = dip->i_mtime = CURRENT_TIME;
-       mark_inode_dirty(dip);
+       inode_dec_link_count(dip);
 
        /*
         * OS/2 could have created EA and/or ACL
@@ -415,7 +414,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
        JFS_IP(ip)->acl.flag = 0;
 
        /* mark the target directory as deleted */
-       ip->i_nlink = 0;
+       clear_nlink(ip);
        mark_inode_dirty(ip);
 
        rc = txCommit(tid, 2, &iplist[0], 0);
@@ -447,11 +446,11 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
 /*
  * NAME:       jfs_unlink(dip, dentry)
  *
- * FUNCTION:   remove a link to object <vp> named by <name> 
+ * FUNCTION:   remove a link to object <vp> named by <name>
  *             from parent directory <dvp>
  *
- * PARAMETER:  dip     - inode of parent directory
- *             dentry  - dentry of object to be removed
+ * PARAMETER:  dip     - inode of parent directory
+ *             dentry  - dentry of object to be removed
  *
  * RETURN:     errors from subroutines
  *
@@ -484,12 +483,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
        if ((rc = get_UCSname(&dname, dentry)))
                goto out;
 
-       IWRITE_LOCK(ip);
+       IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        iplist[0] = dip;
        iplist[1] = ip;
@@ -515,8 +514,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
        mark_inode_dirty(dip);
 
        /* update target's inode */
-       ip->i_nlink--;
-       mark_inode_dirty(ip);
+       inode_dec_link_count(ip);
 
        /*
         *      commit zero link count object
@@ -600,7 +598,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
  *
  * FUNCTION:    for non-directory, called by jfs_remove(),
  *             truncate a regular file, directory or symbolic
- *             link to zero length. return 0 if type is not 
+ *             link to zero length. return 0 if type is not
  *             one of these.
  *
  *             if the file is currently associated with a VM segment
@@ -610,7 +608,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
  *             map by ctrunc1.
  *             if there is no VM segment on entry, the resources are
  *             freed in both work and permanent map.
- *             (? for temporary file - memory object is cached even 
+ *             (? for temporary file - memory object is cached even
  *             after no reference:
  *             reference count > 0 -   )
  *
@@ -664,7 +662,7 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip)
 
        /*
         * free xtree/data (truncate to zero length):
-        * free xtree/data pages from cache if COMMIT_PWMAP, 
+        * free xtree/data pages from cache if COMMIT_PWMAP,
         * free xtree/data blocks from persistent block map, and
         * free xtree/data blocks from working block map if COMMIT_PWMAP;
         */
@@ -679,7 +677,7 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip)
  * NAME:       jfs_free_zero_link()
  *
  * FUNCTION:    for non-directory, called by iClose(),
- *             free resources of a file from cache and WORKING map 
+ *             free resources of a file from cache and WORKING map
  *             for a file previously committed with zero link count
  *             while associated with a pager object,
  *
@@ -764,7 +762,7 @@ void jfs_free_zero_link(struct inode *ip)
  * FUNCTION:   create a link to <vp> by the name = <name>
  *             in the parent directory <dvp>
  *
- * PARAMETER:  vp      - target object
+ * PARAMETER:  vp      - target object
  *             dvp     - parent directory of new link
  *             name    - name of new link to target object
  *             crp     - credential
@@ -804,8 +802,8 @@ static int jfs_link(struct dentry *old_dentry,
 
        tid = txBegin(ip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dir)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        /*
         * scan parent directory for entry/freespace
@@ -824,7 +822,7 @@ static int jfs_link(struct dentry *old_dentry,
                goto free_dname;
 
        /* update object inode */
-       ip->i_nlink++;          /* for new link */
+       inc_nlink(ip);          /* for new link */
        ip->i_ctime = CURRENT_TIME;
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(dir);
@@ -835,7 +833,7 @@ static int jfs_link(struct dentry *old_dentry,
        rc = txCommit(tid, 2, &iplist[0], 0);
 
        if (rc) {
-               ip->i_nlink--;
+               ip->i_nlink--; /* never instantiated */
                iput(ip);
        } else
                d_instantiate(dentry, ip);
@@ -860,8 +858,8 @@ static int jfs_link(struct dentry *old_dentry,
  *                     in directory <dip>
  *
  * PARAMETER:  dip         - parent directory vnode
- *                     dentry  - dentry of symbolic link
- *                     name    - the path name of the existing object 
+ *                     dentry  - dentry of symbolic link
+ *                     name    - the path name of the existing object
  *                                   that will be the source of the link
  *
  * RETURN:     errors from subroutines
@@ -908,15 +906,15 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
         * (iAlloc() returns new, locked inode)
         */
        ip = ialloc(dip, S_IFLNK | 0777);
-       if (ip == NULL) {
-               rc = -ENOSPC;
+       if (IS_ERR(ip)) {
+               rc = PTR_ERR(ip);
                goto out2;
        }
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        rc = jfs_init_security(tid, ip, dip);
        if (rc)
@@ -928,7 +926,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
        tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
 
        /* fix symlink access permission
-        * (dir_create() ANDs in the u.u_cmask, 
+        * (dir_create() ANDs in the u.u_cmask,
         * but symlinks really need to be 777 access)
         */
        ip->i_mode |= 0777;
@@ -969,7 +967,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                ip->i_mapping->a_ops = &jfs_aops;
 
                /*
-                * even though the data of symlink object (source 
+                * even though the data of symlink object (source
                 * path name) is treated as non-journaled user data,
                 * it is read/written thru buffer cache for performance.
                 */
@@ -980,7 +978,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                xlen = xsize >> JFS_SBI(sb)->l2bsize;
                if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
                        txAbort(tid, 0);
-                       rc = -ENOSPC;
                        goto out3;
                }
                extent = xaddr;
@@ -1130,7 +1127,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto out3;
                }
        } else if (new_ip) {
-               IWRITE_LOCK(new_ip);
+               IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
                /* Init inode for quota operations. */
                DQUOT_INIT(new_ip);
        }
@@ -1140,13 +1137,21 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         */
        tid = txBegin(new_dir->i_sb, 0);
 
-       mutex_lock(&JFS_IP(new_dir)->commit_mutex);
-       mutex_lock(&JFS_IP(old_ip)->commit_mutex);
+       /*
+        * How do we know the locking is safe from deadlocks?
+        * The vfs does the hard part for us.  Any time we are taking nested
+        * commit_mutexes, the vfs already has i_mutex held on the parent.
+        * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
+        */
+       mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
        if (old_dir != new_dir)
-               mutex_lock(&JFS_IP(old_dir)->commit_mutex);
+               mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
+                                 COMMIT_MUTEX_SECOND_PARENT);
 
        if (new_ip) {
-               mutex_lock(&JFS_IP(new_ip)->commit_mutex);
+               mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
+                                 COMMIT_MUTEX_VICTIM);
                /*
                 * Change existing directory entry to new inode number
                 */
@@ -1155,9 +1160,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                              old_ip->i_ino, JFS_RENAME);
                if (rc)
                        goto out4;
-               new_ip->i_nlink--;
+               drop_nlink(new_ip);
                if (S_ISDIR(new_ip->i_mode)) {
-                       new_ip->i_nlink--;
+                       drop_nlink(new_ip);
                        if (new_ip->i_nlink) {
                                mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
                                if (old_dir != new_dir)
@@ -1178,7 +1183,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        /* free block resources */
                        if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
                                txAbort(tid, 1);        /* Marks FS Dirty */
-                               rc = new_size;          
+                               rc = new_size;
                                goto out4;
                        }
                        tblk = tid_to_tblock(tid);
@@ -1208,7 +1213,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto out4;
                }
                if (S_ISDIR(old_ip->i_mode))
-                       new_dir->i_nlink++;
+                       inc_nlink(new_dir);
        }
        /*
         * Remove old directory entry
@@ -1223,7 +1228,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                goto out4;
        }
        if (S_ISDIR(old_ip->i_mode)) {
-               old_dir->i_nlink--;
+               drop_nlink(old_dir);
                if (old_dir != new_dir) {
                        /*
                         * Change inode number of parent for moved directory
@@ -1294,7 +1299,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_size = xtTruncate_pmap(tid, new_ip, new_size);
                if (new_size < 0) {
                        txAbort(tid, 1);
-                       rc = new_size;          
+                       rc = new_size;
                } else
                        rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
                txEnd(tid);
@@ -1352,16 +1357,16 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
                goto out;
 
        ip = ialloc(dir, mode);
-       if (ip == NULL) {
-               rc = -ENOSPC;
+       if (IS_ERR(ip)) {
+               rc = PTR_ERR(ip);
                goto out1;
        }
        jfs_ip = JFS_IP(ip);
 
        tid = txBegin(dir->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dir)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        rc = jfs_init_acl(tid, ip, dir);
        if (rc)
@@ -1498,7 +1503,7 @@ struct dentry *jfs_get_parent(struct dentry *dentry)
        return parent;
 }
 
-struct inode_operations jfs_dir_inode_operations = {
+const struct inode_operations jfs_dir_inode_operations = {
        .create         = jfs_create,
        .lookup         = jfs_lookup,
        .link           = jfs_link,