[GFS2] Pass the correct value to kunmap_atomic
[pandora-kernel.git] / fs / ocfs2 / namei.c
index f6b77ff..259155f 100644 (file)
@@ -56,6 +56,7 @@
 #include "journal.h"
 #include "namei.h"
 #include "suballoc.h"
+#include "super.h"
 #include "symlink.h"
 #include "sysfile.h"
 #include "uptodate.h"
@@ -161,8 +162,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
                goto bail;
        }
 
-       mlog(0, "find name %.*s in directory %"MLFu64"\n", dentry->d_name.len,
-            dentry->d_name.name, OCFS2_I(dir)->ip_blkno);
+       mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len,
+            dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno);
 
        status = ocfs2_meta_lock(dir, NULL, NULL, 0);
        if (status < 0) {
@@ -178,9 +179,10 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
        if (status < 0)
                goto bail_add;
 
-       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno);
+       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
        if (IS_ERR(inode)) {
-               mlog(ML_ERROR, "Unable to create inode %"MLFu64"\n", blkno);
+               mlog(ML_ERROR, "Unable to create inode %llu\n",
+                    (unsigned long long)blkno);
                ret = ERR_PTR(-EACCES);
                goto bail_unlock;
        }
@@ -197,10 +199,32 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
        spin_unlock(&oi->ip_lock);
 
 bail_add:
-
        dentry->d_op = &ocfs2_dentry_ops;
        ret = d_splice_alias(inode, dentry);
 
+       if (inode) {
+               /*
+                * If d_splice_alias() finds a DCACHE_DISCONNECTED
+                * dentry, it will d_move() it on top of ourse. The
+                * return value will indicate this however, so in
+                * those cases, we switch them around for the locking
+                * code.
+                *
+                * NOTE: This dentry already has ->d_op set from
+                * ocfs2_get_parent() and ocfs2_get_dentry()
+                */
+               if (ret)
+                       dentry = ret;
+
+               status = ocfs2_dentry_attach_lock(dentry, inode,
+                                                 OCFS2_I(dir)->ip_blkno);
+               if (status) {
+                       mlog_errno(status);
+                       ret = ERR_PTR(status);
+                       goto bail_unlock;
+               }
+       }
+
 bail_unlock:
        /* Don't drop the cluster lock until *after* the d_add --
         * unlink on another node will message us to remove that
@@ -309,13 +333,6 @@ static int ocfs2_mknod(struct inode *dir,
        /* get our super block */
        osb = OCFS2_SB(dir->i_sb);
 
-       if (S_ISDIR(mode) && (dir->i_nlink >= OCFS2_LINK_MAX)) {
-               mlog(ML_ERROR, "inode %"MLFu64" has i_nlink of %u\n",
-                    OCFS2_I(dir)->ip_blkno, dir->i_nlink);
-               status = -EMLINK;
-               goto leave;
-       }
-
        handle = ocfs2_alloc_handle(osb);
        if (handle == NULL) {
                status = -ENOMEM;
@@ -330,6 +347,11 @@ static int ocfs2_mknod(struct inode *dir,
                goto leave;
        }
 
+       if (S_ISDIR(mode) && (dir->i_nlink >= OCFS2_LINK_MAX)) {
+               status = -EMLINK;
+               goto leave;
+       }
+
        dirfe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
        if (!dirfe->i_links_count) {
                /* can't make a file in a deleted directory. */
@@ -407,7 +429,7 @@ static int ocfs2_mknod(struct inode *dir,
                        mlog_errno(status);
                        goto leave;
                }
-               dir->i_nlink++;
+               inc_nlink(dir);
        }
 
        status = ocfs2_add_entry(handle, dentry, inode,
@@ -418,6 +440,13 @@ static int ocfs2_mknod(struct inode *dir,
                goto leave;
        }
 
+       status = ocfs2_dentry_attach_lock(dentry, inode,
+                                         OCFS2_I(dir)->ip_blkno);
+       if (status) {
+               mlog_errno(status);
+               goto leave;
+       }
+
        insert_inode_hash(inode);
        dentry->d_op = &ocfs2_dentry_ops;
        d_instantiate(dentry, inode);
@@ -562,9 +591,9 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
 
        if (ocfs2_populate_inode(inode, fe, 1) < 0) {
                mlog(ML_ERROR, "populate inode failed! bh->b_blocknr=%llu, "
-                    "i_blkno=%"MLFu64", i_ino=%lu\n",
+                    "i_blkno=%llu, i_ino=%lu\n",
                     (unsigned long long) (*new_fe_bh)->b_blocknr,
-                    fe->i_blkno, inode->i_ino);
+                    (unsigned long long)fe->i_blkno, inode->i_ino);
                BUG();
        }
 
@@ -642,11 +671,6 @@ static int ocfs2_link(struct dentry *old_dentry,
                goto bail;
        }
 
-       if (inode->i_nlink >= OCFS2_LINK_MAX) {
-               err = -EMLINK;
-               goto bail;
-       }
-
        handle = ocfs2_alloc_handle(osb);
        if (handle == NULL) {
                err = -ENOMEM;
@@ -660,6 +684,11 @@ static int ocfs2_link(struct dentry *old_dentry,
                goto bail;
        }
 
+       if (!dir->i_nlink) {
+               err = -ENOENT;
+               goto bail;
+       }
+
        err = ocfs2_check_dir_for_entry(dir, dentry->d_name.name,
                                        dentry->d_name.len);
        if (err)
@@ -701,7 +730,7 @@ static int ocfs2_link(struct dentry *old_dentry,
                goto bail;
        }
 
-       inode->i_nlink++;
+       inc_nlink(inode);
        inode->i_ctime = CURRENT_TIME;
        fe->i_links_count = cpu_to_le16(inode->i_nlink);
        fe->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
@@ -710,7 +739,7 @@ static int ocfs2_link(struct dentry *old_dentry,
        err = ocfs2_journal_dirty(handle, fe_bh);
        if (err < 0) {
                le16_add_cpu(&fe->i_links_count, -1);
-               inode->i_nlink--;
+               drop_nlink(inode);
                mlog_errno(err);
                goto bail;
        }
@@ -720,7 +749,13 @@ static int ocfs2_link(struct dentry *old_dentry,
                              parent_fe_bh, de_bh);
        if (err) {
                le16_add_cpu(&fe->i_links_count, -1);
-               inode->i_nlink--;
+               drop_nlink(inode);
+               mlog_errno(err);
+               goto bail;
+       }
+
+       err = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno);
+       if (err) {
                mlog_errno(err);
                goto bail;
        }
@@ -743,11 +778,40 @@ bail:
        return err;
 }
 
+/*
+ * Takes and drops an exclusive lock on the given dentry. This will
+ * force other nodes to drop it.
+ */
+static int ocfs2_remote_dentry_delete(struct dentry *dentry)
+{
+       int ret;
+
+       ret = ocfs2_dentry_lock(dentry, 1);
+       if (ret)
+               mlog_errno(ret);
+       else
+               ocfs2_dentry_unlock(dentry, 1);
+
+       return ret;
+}
+
+static inline int inode_is_unlinkable(struct inode *inode)
+{
+       if (S_ISDIR(inode->i_mode)) {
+               if (inode->i_nlink == 2)
+                       return 1;
+               return 0;
+       }
+
+       if (inode->i_nlink == 1)
+               return 1;
+       return 0;
+}
+
 static int ocfs2_unlink(struct inode *dir,
                        struct dentry *dentry)
 {
        int status;
-       unsigned int saved_nlink = 0;
        struct inode *inode = dentry->d_inode;
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
        u64 blkno;
@@ -765,7 +829,7 @@ static int ocfs2_unlink(struct inode *dir,
 
        BUG_ON(dentry->d_parent->d_inode != dir);
 
-       mlog(0, "ino = %"MLFu64"\n", OCFS2_I(inode)->ip_blkno);
+       mlog(0, "ino = %llu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
        if (inode == osb->root_inode) {
                mlog(0, "Cannot delete the root directory\n");
@@ -799,9 +863,9 @@ static int ocfs2_unlink(struct inode *dir,
        if (OCFS2_I(inode)->ip_blkno != blkno) {
                status = -ENOENT;
 
-               mlog(0, "ip_blkno (%"MLFu64") != dirent blkno (%"MLFu64") "
-                    "ip_flags = %x\n", OCFS2_I(inode)->ip_blkno, blkno,
-                    OCFS2_I(inode)->ip_flags);
+               mlog(0, "ip_blkno %llu != dirent blkno %llu ip_flags = %x\n",
+                    (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                    (unsigned long long)blkno, OCFS2_I(inode)->ip_flags);
                goto leave;
        }
 
@@ -822,18 +886,7 @@ static int ocfs2_unlink(struct inode *dir,
                }
        }
 
-       /* There are still a few steps left until we can consider the
-        * unlink to have succeeded. Save off nlink here before
-        * modification so we can set it back in case we hit an issue
-        * before commit. */
-       saved_nlink = inode->i_nlink;
-       if (S_ISDIR(inode->i_mode))
-               inode->i_nlink = 0;
-       else
-               inode->i_nlink--;
-
-       status = ocfs2_request_unlink_vote(inode, dentry,
-                                          (unsigned int) inode->i_nlink);
+       status = ocfs2_remote_dentry_delete(dentry);
        if (status < 0) {
                /* This vote should succeed under all normal
                 * circumstances. */
@@ -841,7 +894,7 @@ static int ocfs2_unlink(struct inode *dir,
                goto leave;
        }
 
-       if (!inode->i_nlink) {
+       if (inode_is_unlinkable(inode)) {
                status = ocfs2_prepare_orphan_dir(osb, handle, inode,
                                                  orphan_name,
                                                  &orphan_entry_bh);
@@ -868,7 +921,7 @@ static int ocfs2_unlink(struct inode *dir,
 
        fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
-       if (!inode->i_nlink) {
+       if (inode_is_unlinkable(inode)) {
                status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name,
                                          orphan_entry_bh);
                if (status < 0) {
@@ -884,10 +937,10 @@ static int ocfs2_unlink(struct inode *dir,
                goto leave;
        }
 
-       /* We can set nlink on the dinode now. clear the saved version
-        * so that it doesn't get set later. */
+       if (S_ISDIR(inode->i_mode))
+               drop_nlink(inode);
+       drop_nlink(inode);
        fe->i_links_count = cpu_to_le16(inode->i_nlink);
-       saved_nlink = 0;
 
        status = ocfs2_journal_dirty(handle, fe_bh);
        if (status < 0) {
@@ -896,19 +949,16 @@ static int ocfs2_unlink(struct inode *dir,
        }
 
        if (S_ISDIR(inode->i_mode)) {
-               dir->i_nlink--;
+               drop_nlink(dir);
                status = ocfs2_mark_inode_dirty(handle, dir,
                                                parent_node_bh);
                if (status < 0) {
                        mlog_errno(status);
-                       dir->i_nlink++;
+                       inc_nlink(dir);
                }
        }
 
 leave:
-       if (status < 0 && saved_nlink)
-               inode->i_nlink = saved_nlink;
-
        if (handle)
                ocfs2_commit_trans(handle);
 
@@ -946,8 +996,9 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
        struct buffer_head **tmpbh;
        struct inode *tmpinode;
 
-       mlog_entry("(inode1 = %"MLFu64", inode2 = %"MLFu64")\n",
-                  oi1->ip_blkno, oi2->ip_blkno);
+       mlog_entry("(inode1 = %llu, inode2 = %llu)\n",
+                  (unsigned long long)oi1->ip_blkno,
+                  (unsigned long long)oi2->ip_blkno);
 
        BUG_ON(!handle);
 
@@ -1018,7 +1069,6 @@ static int ocfs2_rename(struct inode *old_dir,
        struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
                                                    // this is the 1st dirent bh
        nlink_t old_dir_nlink = old_dir->i_nlink, new_dir_nlink = new_dir->i_nlink;
-       unsigned int links_count;
 
        /* At some point it might be nice to break this function up a
         * bit. */
@@ -1092,23 +1142,26 @@ static int ocfs2_rename(struct inode *old_dir,
                }
        }
 
-       if (S_ISDIR(old_inode->i_mode)) {
-               /* Directories actually require metadata updates to
-                * the directory info so we can't get away with not
-                * doing node locking on it. */
-               status = ocfs2_meta_lock(old_inode, handle, NULL, 1);
-               if (status < 0) {
-                       if (status != -ENOENT)
-                               mlog_errno(status);
-                       goto bail;
-               }
-
-               status = ocfs2_request_rename_vote(old_inode, old_dentry);
-               if (status < 0) {
+       /*
+        * Though we don't require an inode meta data update if
+        * old_inode is not a directory, we lock anyway here to ensure
+        * the vote thread on other nodes won't have to concurrently
+        * downconvert the inode and the dentry locks.
+        */
+       status = ocfs2_meta_lock(old_inode, handle, NULL, 1);
+       if (status < 0) {
+               if (status != -ENOENT)
                        mlog_errno(status);
-                       goto bail;
-               }
+               goto bail;
+       }
 
+       status = ocfs2_remote_dentry_delete(old_dentry);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       if (S_ISDIR(old_inode->i_mode)) {
                status = -EIO;
                old_inode_de_bh = ocfs2_bread(old_inode, 0, &status, 0);
                if (!old_inode_de_bh)
@@ -1122,14 +1175,6 @@ static int ocfs2_rename(struct inode *old_dir,
                if (!new_inode && new_dir!=old_dir &&
                    new_dir->i_nlink >= OCFS2_LINK_MAX)
                        goto bail;
-       } else {
-               /* Ah, the simple case - we're a file so just send a
-                * message. */
-               status = ocfs2_request_rename_vote(old_inode, old_dentry);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
        }
 
        status = -ENOENT;
@@ -1187,9 +1232,9 @@ static int ocfs2_rename(struct inode *old_dir,
                if (OCFS2_I(new_inode)->ip_blkno != newfe_blkno) {
                        status = -EACCES;
 
-                       mlog(0, "Inode blkno (%"MLFu64") and dir (%"MLFu64") "
-                            "disagree. ip_flags = %x\n",
-                            OCFS2_I(new_inode)->ip_blkno, newfe_blkno,
+                       mlog(0, "Inode %llu and dir %llu disagree. flags = %x\n",
+                            (unsigned long long)OCFS2_I(new_inode)->ip_blkno,
+                            (unsigned long long)newfe_blkno,
                             OCFS2_I(new_inode)->ip_flags);
                        goto bail;
                }
@@ -1201,13 +1246,7 @@ static int ocfs2_rename(struct inode *old_dir,
                        goto bail;
                }
 
-               if (S_ISDIR(new_inode->i_mode))
-                       links_count = 0;
-               else
-                       links_count = (unsigned int) (new_inode->i_nlink - 1);
-
-               status = ocfs2_request_unlink_vote(new_inode, new_dentry,
-                                                  links_count);
+               status = ocfs2_remote_dentry_delete(new_dentry);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
@@ -1215,9 +1254,9 @@ static int ocfs2_rename(struct inode *old_dir,
 
                newfe = (struct ocfs2_dinode *) newfe_bh->b_data;
 
-               mlog(0, "aha rename over existing... new_de=%p "
-                    "new_blkno=%"MLFu64" newfebh=%p bhblocknr=%llu\n",
-                    new_de, newfe_blkno, newfe_bh, newfe_bh ?
+               mlog(0, "aha rename over existing... new_de=%p new_blkno=%llu "
+                    "newfebh=%p bhblocknr=%llu\n", new_de,
+                    (unsigned long long)newfe_blkno, newfe_bh, newfe_bh ?
                     (unsigned long long)newfe_bh->b_blocknr : 0ULL);
 
                if (S_ISDIR(new_inode->i_mode) || (new_inode->i_nlink == 1)) {
@@ -1342,7 +1381,7 @@ static int ocfs2_rename(struct inode *old_dir,
                if (new_inode) {
                        new_inode->i_nlink--;
                } else {
-                       new_dir->i_nlink++;
+                       inc_nlink(new_dir);
                        mark_inode_dirty(new_dir);
                }
        }
@@ -1354,8 +1393,8 @@ static int ocfs2_rename(struct inode *old_dir,
                if (new_dir_nlink != new_dir->i_nlink) {
                        if (!new_dir_bh) {
                                mlog(ML_ERROR, "need to change nlink for new "
-                                    "dir %"MLFu64" from %d to %d but bh is "
-                                    "NULL\n", OCFS2_I(new_dir)->ip_blkno,
+                                    "dir %llu from %d to %d but bh is NULL\n",
+                                    (unsigned long long)OCFS2_I(new_dir)->ip_blkno,
                                     (int)new_dir_nlink, new_dir->i_nlink);
                        } else {
                                struct ocfs2_dinode *fe;
@@ -1372,10 +1411,9 @@ static int ocfs2_rename(struct inode *old_dir,
        if (old_dir_nlink != old_dir->i_nlink) {
                if (!old_dir_bh) {
                        mlog(ML_ERROR, "need to change nlink for old dir "
-                            "%"MLFu64" from %d to %d but bh is NULL!\n",
-                            OCFS2_I(old_dir)->ip_blkno,
-                            (int)old_dir_nlink,
-                            old_dir->i_nlink);
+                            "%llu from %d to %d but bh is NULL!\n",
+                            (unsigned long long)OCFS2_I(old_dir)->ip_blkno,
+                            (int)old_dir_nlink, old_dir->i_nlink);
                } else {
                        struct ocfs2_dinode *fe;
                        status = ocfs2_journal_access(handle, old_dir,
@@ -1387,6 +1425,7 @@ static int ocfs2_rename(struct inode *old_dir,
                }
        }
 
+       ocfs2_dentry_move(old_dentry, new_dentry, old_dir, new_dir);
        status = 0;
 bail:
        if (rename_lock)
@@ -1443,8 +1482,9 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
         * write i_size + 1 bytes. */
        blocks = (bytes_left + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
 
-       mlog_entry("i_blocks = %lu, i_size = %llu, blocks = %d\n",
-                      inode->i_blocks, i_size_read(inode), blocks);
+       mlog_entry("i_blocks = %llu, i_size = %llu, blocks = %d\n",
+                       (unsigned long long)inode->i_blocks,
+                       i_size_read(inode), blocks);
 
        /* Sanity check -- make sure we're going to fit. */
        if (bytes_left >
@@ -1634,9 +1674,9 @@ static int ocfs2_symlink(struct inode *dir,
                                                    NULL);
                if (status < 0) {
                        if (status != -ENOSPC && status != -EINTR) {
-                               mlog(ML_ERROR, "Failed to extend file to "
-                                              "%"MLFu64"\n",
-                                    newsize);
+                               mlog(ML_ERROR,
+                                    "Failed to extend file to %llu\n",
+                                    (unsigned long long)newsize);
                                mlog_errno(status);
                                status = -ENOSPC;
                        }
@@ -1674,6 +1714,12 @@ static int ocfs2_symlink(struct inode *dir,
                goto bail;
        }
 
+       status = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno);
+       if (status) {
+               mlog_errno(status);
+               goto bail;
+       }
+
        insert_inode_hash(inode);
        dentry->d_op = &ocfs2_dentry_ops;
        d_instantiate(dentry, inode);
@@ -1716,10 +1762,11 @@ int ocfs2_check_dir_entry(struct inode * dir,
                error_msg = "directory entry across blocks";
 
        if (error_msg != NULL)
-               mlog(ML_ERROR, "bad entry in directory #%"MLFu64": %s - "
-                    "offset=%lu, inode=%"MLFu64", rec_len=%d, name_len=%d\n",
-                    OCFS2_I(dir)->ip_blkno, error_msg, offset,
-                    le64_to_cpu(de->inode), rlen, de->name_len);
+               mlog(ML_ERROR, "bad entry in directory #%llu: %s - "
+                    "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n",
+                    (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg,
+                    offset, (unsigned long long)le64_to_cpu(de->inode), rlen,
+                    de->name_len);
        return error_msg == NULL ? 1 : 0;
 }
 
@@ -1961,13 +2008,8 @@ restart:
                                }
                                num++;
 
-                               /* XXX: questionable readahead stuff here */
                                bh = ocfs2_bread(dir, b++, &err, 1);
                                bh_use[ra_max] = bh;
-#if 0          // ???
-                               if (bh)
-                                       ll_rw_block(READ, 1, &bh);
-#endif
                        }
                }
                if ((bh = bh_use[ra_ptr++]) == NULL)
@@ -1975,6 +2017,10 @@ restart:
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
                        /* read error, skip block & hope for the best */
+                       ocfs2_error(dir->i_sb, "reading directory %llu, "
+                                   "offset %lu\n",
+                                   (unsigned long long)OCFS2_I(dir)->ip_blkno,
+                                   block);
                        brelse(bh);
                        goto next;
                }
@@ -2021,8 +2067,8 @@ static int ocfs2_blkno_stringify(u64 blkno, char *name)
 
        mlog_entry_void();
 
-       namelen = snprintf(name, OCFS2_ORPHAN_NAMELEN + 1, "%016"MLFx64,
-                          blkno);
+       namelen = snprintf(name, OCFS2_ORPHAN_NAMELEN + 1, "%016llx",
+                          (long long)blkno);
        if (namelen <= 0) {
                if (namelen)
                        status = namelen;
@@ -2167,8 +2213,8 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
        OCFS2_I(inode)->ip_orphaned_slot = osb->slot_num;
        spin_unlock(&OCFS2_I(inode)->ip_lock);
 
-       mlog(0, "Inode %"MLFu64" orphaned in slot %d\n",
-            OCFS2_I(inode)->ip_blkno, osb->slot_num);
+       mlog(0, "Inode %llu orphaned in slot %d\n",
+            (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num);
 
 leave:
        if (orphan_dir_inode)
@@ -2202,8 +2248,9 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
                goto leave;
        }
 
-       mlog(0, "removing '%s' from orphan dir %"MLFu64" (namelen=%d)\n",
-            name, OCFS2_I(orphan_dir_inode)->ip_blkno, OCFS2_ORPHAN_NAMELEN);
+       mlog(0, "removing '%s' from orphan dir %llu (namelen=%d)\n",
+            name, (unsigned long long)OCFS2_I(orphan_dir_inode)->ip_blkno,
+            OCFS2_ORPHAN_NAMELEN);
 
        /* find it's spot in the orphan directory */
        target_de_bh = ocfs2_find_entry(name, OCFS2_ORPHAN_NAMELEN,