]> err.no Git - linux-2.6/blobdiff - fs/ocfs2/namei.c
x86: cpa move the flush into set and clear functions
[linux-2.6] / fs / ocfs2 / namei.c
index aae6c0bf66964ea56a54985271ff5deadce2db52..ae9ad9587516641366ddcb5753b61a120d9b137b 100644 (file)
@@ -60,7 +60,6 @@
 #include "symlink.h"
 #include "sysfile.h"
 #include "uptodate.h"
-#include "vote.h"
 
 #include "buffer_head_io.h"
 
@@ -101,10 +100,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
 {
        int status;
        u64 blkno;
-       struct buffer_head *dirent_bh = NULL;
        struct inode *inode = NULL;
        struct dentry *ret;
-       struct ocfs2_dir_entry *dirent;
        struct ocfs2_inode_info *oi;
 
        mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,
@@ -118,7 +115,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
        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, 0);
+       status = ocfs2_inode_lock(dir, NULL, 0);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -126,13 +123,12 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
                goto bail;
        }
 
-       status = ocfs2_find_files_on_disk(dentry->d_name.name,
-                                         dentry->d_name.len, &blkno,
-                                         dir, &dirent_bh, &dirent);
+       status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name,
+                                           dentry->d_name.len, &blkno);
        if (status < 0)
                goto bail_add;
 
-       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0);
+       inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0);
        if (IS_ERR(inode)) {
                ret = ERR_PTR(-EACCES);
                goto bail_unlock;
@@ -179,12 +175,10 @@ bail_unlock:
        /* Don't drop the cluster lock until *after* the d_add --
         * unlink on another node will message us to remove that
         * dentry under this lock so otherwise we can race this with
-        * the vote thread and have a stale dentry. */
-       ocfs2_meta_unlock(dir, 0);
+        * the downconvert thread and have a stale dentry. */
+       ocfs2_inode_unlock(dir, 0);
 
 bail:
-       if (dirent_bh)
-               brelse(dirent_bh);
 
        mlog_exit_ptr(ret);
 
@@ -214,7 +208,7 @@ static int ocfs2_mknod(struct inode *dir,
        /* get our super block */
        osb = OCFS2_SB(dir->i_sb);
 
-       status = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
+       status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -255,9 +249,8 @@ static int ocfs2_mknod(struct inode *dir,
                goto leave;
        }
 
-       /* are we making a directory? If so, reserve a cluster for his
-        * 1st extent. */
-       if (S_ISDIR(mode)) {
+       /* Reserve a cluster if creating an extent based directory. */
+       if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {
                status = ocfs2_reserve_clusters(osb, 1, &data_ac);
                if (status < 0) {
                        if (status != -ENOSPC)
@@ -329,7 +322,7 @@ leave:
        if (handle)
                ocfs2_commit_trans(osb, handle);
 
-       ocfs2_meta_unlock(dir, 1);
+       ocfs2_inode_unlock(dir, 1);
 
        if (status == -ENOSPC)
                mlog(0, "Disk is full\n");
@@ -454,10 +447,21 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
                cpu_to_le32(CURRENT_TIME.tv_nsec);
        fe->i_dtime = 0;
 
-       fel = &fe->id2.i_list;
-       fel->l_tree_depth = 0;
-       fel->l_next_free_rec = 0;
-       fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
+       /*
+        * If supported, directories start with inline data.
+        */
+       if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) {
+               u16 feat = le16_to_cpu(fe->i_dyn_features);
+
+               fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL);
+
+               fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb));
+       } else {
+               fel = &fe->id2.i_list;
+               fel->l_tree_depth = 0;
+               fel->l_next_free_rec = 0;
+               fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
+       }
 
        status = ocfs2_journal_dirty(handle, *new_fe_bh);
        if (status < 0) {
@@ -548,7 +552,7 @@ static int ocfs2_link(struct dentry *old_dentry,
        if (S_ISDIR(inode->i_mode))
                return -EPERM;
 
-       err = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
+       err = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
        if (err < 0) {
                if (err != -ENOENT)
                        mlog_errno(err);
@@ -573,7 +577,7 @@ static int ocfs2_link(struct dentry *old_dentry,
                goto out;
        }
 
-       err = ocfs2_meta_lock(inode, &fe_bh, 1);
+       err = ocfs2_inode_lock(inode, &fe_bh, 1);
        if (err < 0) {
                if (err != -ENOENT)
                        mlog_errno(err);
@@ -638,10 +642,10 @@ static int ocfs2_link(struct dentry *old_dentry,
 out_commit:
        ocfs2_commit_trans(osb, handle);
 out_unlock_inode:
-       ocfs2_meta_unlock(inode, 1);
+       ocfs2_inode_unlock(inode, 1);
 
 out:
-       ocfs2_meta_unlock(dir, 1);
+       ocfs2_inode_unlock(dir, 1);
 
        if (de_bh)
                brelse(de_bh);
@@ -715,7 +719,7 @@ static int ocfs2_unlink(struct inode *dir,
                return -EPERM;
        }
 
-       status = ocfs2_meta_lock(dir, &parent_node_bh, 1);
+       status = ocfs2_inode_lock(dir, &parent_node_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -740,7 +744,7 @@ static int ocfs2_unlink(struct inode *dir,
                goto leave;
        }
 
-       status = ocfs2_meta_lock(inode, &fe_bh, 1);
+       status = ocfs2_inode_lock(inode, &fe_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -760,7 +764,7 @@ static int ocfs2_unlink(struct inode *dir,
 
        status = ocfs2_remote_dentry_delete(dentry);
        if (status < 0) {
-               /* This vote should succeed under all normal
+               /* This remote delete should succeed under all normal
                 * circumstances. */
                mlog_errno(status);
                goto leave;
@@ -836,13 +840,13 @@ leave:
                ocfs2_commit_trans(osb, handle);
 
        if (child_locked)
-               ocfs2_meta_unlock(inode, 1);
+               ocfs2_inode_unlock(inode, 1);
 
-       ocfs2_meta_unlock(dir, 1);
+       ocfs2_inode_unlock(dir, 1);
 
        if (orphan_dir) {
                /* This was locked for us in ocfs2_prepare_orphan_dir() */
-               ocfs2_meta_unlock(orphan_dir, 1);
+               ocfs2_inode_unlock(orphan_dir, 1);
                mutex_unlock(&orphan_dir->i_mutex);
                iput(orphan_dir);
        }
@@ -903,7 +907,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
                        inode1 = tmpinode;
                }
                /* lock id2 */
-               status = ocfs2_meta_lock(inode2, bh2, 1);
+               status = ocfs2_inode_lock(inode2, bh2, 1);
                if (status < 0) {
                        if (status != -ENOENT)
                                mlog_errno(status);
@@ -912,14 +916,14 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
        }
 
        /* lock id1 */
-       status = ocfs2_meta_lock(inode1, bh1, 1);
+       status = ocfs2_inode_lock(inode1, bh1, 1);
        if (status < 0) {
                /*
                 * An error return must mean that no cluster locks
                 * were held on function exit.
                 */
                if (oi1->ip_blkno != oi2->ip_blkno)
-                       ocfs2_meta_unlock(inode2, 1);
+                       ocfs2_inode_unlock(inode2, 1);
 
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -932,17 +936,12 @@ bail:
 
 static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2)
 {
-       ocfs2_meta_unlock(inode1, 1);
+       ocfs2_inode_unlock(inode1, 1);
 
        if (inode1 != inode2)
-               ocfs2_meta_unlock(inode2, 1);
+               ocfs2_inode_unlock(inode2, 1);
 }
 
-#define PARENT_INO(buffer) \
-       ((struct ocfs2_dir_entry *) \
-        ((char *)buffer + \
-         le16_to_cpu(((struct ocfs2_dir_entry *)buffer)->rec_len)))->inode
-
 static int ocfs2_rename(struct inode *old_dir,
                        struct dentry *old_dentry,
                        struct inode *new_dir,
@@ -960,12 +959,12 @@ static int ocfs2_rename(struct inode *old_dir,
        struct buffer_head *old_inode_bh = NULL;
        struct buffer_head *insert_entry_bh = NULL;
        struct ocfs2_super *osb = NULL;
-       u64 newfe_blkno;
+       u64 newfe_blkno, old_de_ino;
        handle_t *handle = NULL;
        struct buffer_head *old_dir_bh = NULL;
        struct buffer_head *new_dir_bh = NULL;
-       struct ocfs2_dir_entry *old_de = NULL, *new_de = NULL; // dirent for old_dentry
-                                                              // and new_dentry
+       struct ocfs2_dir_entry *old_inode_dot_dot_de = NULL, *old_de = NULL,
+               *new_de = NULL;
        struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above
        struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
                                                    // this is the 1st dirent bh
@@ -1031,10 +1030,11 @@ static int ocfs2_rename(struct inode *old_dir,
 
        /*
         * Aside from allowing a meta data update, the locking here
-        * also ensures that the vote thread on other nodes won't have
-        * to concurrently downconvert the inode and the dentry locks.
+        * also ensures that the downconvert thread on other nodes
+        * won't have to concurrently downconvert the inode and the
+        * dentry locks.
         */
-       status = ocfs2_meta_lock(old_inode, &old_inode_bh, 1);
+       status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -1049,27 +1049,35 @@ static int ocfs2_rename(struct inode *old_dir,
        }
 
        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)
+               u64 old_inode_parent;
+
+               status = ocfs2_find_files_on_disk("..", 2, &old_inode_parent,
+                                                 old_inode, &old_inode_de_bh,
+                                                 &old_inode_dot_dot_de);
+               if (status) {
+                       status = -EIO;
                        goto bail;
+               }
 
-               status = -EIO;
-               if (le64_to_cpu(PARENT_INO(old_inode_de_bh->b_data)) !=
-                   OCFS2_I(old_dir)->ip_blkno)
+               if (old_inode_parent != OCFS2_I(old_dir)->ip_blkno) {
+                       status = -EIO;
                        goto bail;
-               status = -EMLINK;
-               if (!new_inode && new_dir!=old_dir &&
-                   new_dir->i_nlink >= OCFS2_LINK_MAX)
+               }
+
+               if (!new_inode && new_dir != old_dir &&
+                   new_dir->i_nlink >= OCFS2_LINK_MAX) {
+                       status = -EMLINK;
                        goto bail;
+               }
        }
 
-       status = -ENOENT;
-       old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
-                                    old_dentry->d_name.len,
-                                    old_dir, &old_de);
-       if (!old_de_bh)
+       status = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name,
+                                           old_dentry->d_name.len,
+                                           &old_de_ino);
+       if (status) {
+               status = -ENOENT;
                goto bail;
+       }
 
        /*
         *  Check for inode number is _not_ due to possible IO errors.
@@ -1077,8 +1085,10 @@ static int ocfs2_rename(struct inode *old_dir,
         *  and merrily kill the link to whatever was created under the
         *  same name. Goodbye sticky bit ;-<
         */
-       if (le64_to_cpu(old_de->inode) != OCFS2_I(old_inode)->ip_blkno)
+       if (old_de_ino != OCFS2_I(old_inode)->ip_blkno) {
+               status = -ENOENT;
                goto bail;
+       }
 
        /* check if the target already exists (in which case we need
         * to delete it */
@@ -1095,9 +1105,16 @@ static int ocfs2_rename(struct inode *old_dir,
                goto bail;
        }
 
-       if (!new_de && new_inode)
-               mlog(ML_ERROR, "inode %lu does not exist in it's parent "
-                    "directory!", new_inode->i_ino);
+       if (!new_de && new_inode) {
+               /*
+                * Target was unlinked by another node while we were
+                * waiting to get to ocfs2_rename(). There isn't
+                * anything we can do here to help the situation, so
+                * bubble up the appropriate error.
+                */
+               status = -ENOENT;
+               goto bail;
+       }
 
        /* In case we need to overwrite an existing file, we blow it
         * away first */
@@ -1126,7 +1143,7 @@ static int ocfs2_rename(struct inode *old_dir,
                        goto bail;
                }
 
-               status = ocfs2_meta_lock(new_inode, &newfe_bh, 1);
+               status = ocfs2_inode_lock(new_inode, &newfe_bh, 1);
                if (status < 0) {
                        if (status != -ENOENT)
                                mlog_errno(status);
@@ -1211,20 +1228,13 @@ static int ocfs2_rename(struct inode *old_dir,
                }
 
                /* change the dirent to point to the correct inode */
-               status = ocfs2_journal_access(handle, new_dir, new_de_bh,
-                                             OCFS2_JOURNAL_ACCESS_WRITE);
+               status = ocfs2_update_entry(new_dir, handle, new_de_bh,
+                                           new_de, old_inode);
                if (status < 0) {
                        mlog_errno(status);
                        goto bail;
                }
-               new_de->inode = cpu_to_le64(OCFS2_I(old_inode)->ip_blkno);
-               new_de->file_type = old_de->file_type;
                new_dir->i_version++;
-               status = ocfs2_journal_dirty(handle, new_de_bh);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
 
                if (S_ISDIR(new_inode->i_mode))
                        newfe->i_links_count = 0;
@@ -1260,7 +1270,21 @@ static int ocfs2_rename(struct inode *old_dir,
        } else
                mlog_errno(status);
 
-       /* now that the name has been added to new_dir, remove the old name */
+       /*
+        * Now that the name has been added to new_dir, remove the old name.
+        *
+        * We don't keep any directory entry context around until now
+        * because the insert might have changed the type of directory
+        * we're dealing with.
+        */
+       old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
+                                    old_dentry->d_name.len,
+                                    old_dir, &old_de);
+       if (!old_de_bh) {
+               status = -EIO;
+               goto bail;
+       }
+
        status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh);
        if (status < 0) {
                mlog_errno(status);
@@ -1273,12 +1297,8 @@ static int ocfs2_rename(struct inode *old_dir,
        }
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        if (old_inode_de_bh) {
-               status = ocfs2_journal_access(handle, old_inode,
-                                            old_inode_de_bh,
-                                            OCFS2_JOURNAL_ACCESS_WRITE);
-               PARENT_INO(old_inode_de_bh->b_data) =
-                       cpu_to_le64(OCFS2_I(new_dir)->ip_blkno);
-               status = ocfs2_journal_dirty(handle, old_inode_de_bh);
+               status = ocfs2_update_entry(old_inode, handle, old_inode_de_bh,
+                                           old_inode_dot_dot_de, new_dir);
                old_dir->i_nlink--;
                if (new_inode) {
                        new_inode->i_nlink--;
@@ -1335,14 +1355,14 @@ bail:
                ocfs2_double_unlock(old_dir, new_dir);
 
        if (old_child_locked)
-               ocfs2_meta_unlock(old_inode, 1);
+               ocfs2_inode_unlock(old_inode, 1);
 
        if (new_child_locked)
-               ocfs2_meta_unlock(new_inode, 1);
+               ocfs2_inode_unlock(new_inode, 1);
 
        if (orphan_dir) {
                /* This was locked for us in ocfs2_prepare_orphan_dir() */
-               ocfs2_meta_unlock(orphan_dir, 1);
+               ocfs2_inode_unlock(orphan_dir, 1);
                mutex_unlock(&orphan_dir->i_mutex);
                iput(orphan_dir);
        }
@@ -1510,7 +1530,7 @@ static int ocfs2_symlink(struct inode *dir,
        credits = ocfs2_calc_symlink_credits(sb);
 
        /* lock the parent directory */
-       status = ocfs2_meta_lock(dir, &parent_fe_bh, 1);
+       status = ocfs2_inode_lock(dir, &parent_fe_bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -1637,7 +1657,7 @@ bail:
        if (handle)
                ocfs2_commit_trans(osb, handle);
 
-       ocfs2_meta_unlock(dir, 1);
+       ocfs2_inode_unlock(dir, 1);
 
        if (new_fe_bh)
                brelse(new_fe_bh);
@@ -1715,7 +1735,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
 
        mutex_lock(&orphan_dir_inode->i_mutex);
 
-       status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1);
+       status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -1725,7 +1745,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
                                              orphan_dir_bh, name,
                                              OCFS2_ORPHAN_NAMELEN, de_bh);
        if (status < 0) {
-               ocfs2_meta_unlock(orphan_dir_inode, 1);
+               ocfs2_inode_unlock(orphan_dir_inode, 1);
 
                mlog_errno(status);
                goto leave;