[GFS2] Fix bz 229831, lookup returns wrong inode
[powerpc.git] / fs / gfs2 / inode.c
index e467780..df0b8b3 100644 (file)
 #include "trans.h"
 #include "util.h"
 
-/**
- * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode
- * @ip: The GFS2 inode (with embedded disk inode data)
- * @inode:  The Linux VFS inode
- *
- */
-
-void gfs2_inode_attr_in(struct gfs2_inode *ip)
-{
-       struct inode *inode = &ip->i_inode;
-       struct gfs2_dinode_host *di = &ip->i_di;
-
-       inode->i_ino = ip->i_num.no_addr;
-       i_size_write(inode, di->di_size);
-       inode->i_blocks = di->di_blocks <<
-               (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT);
-
-       if (di->di_flags & GFS2_DIF_IMMUTABLE)
-               inode->i_flags |= S_IMMUTABLE;
-       else
-               inode->i_flags &= ~S_IMMUTABLE;
-
-       if (di->di_flags & GFS2_DIF_APPENDONLY)
-               inode->i_flags |= S_APPEND;
-       else
-               inode->i_flags &= ~S_APPEND;
-}
-
 static int iget_test(struct inode *inode, void *opaque)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_inum_host *inum = opaque;
 
-       if (ip && ip->i_num.no_addr == inum->no_addr)
+       if (ip->i_num.no_addr == inum->no_addr &&
+           inode->i_private != NULL)
                return 1;
 
        return 0;
@@ -83,18 +56,19 @@ static int iget_set(struct inode *inode, void *opaque)
        struct gfs2_inum_host *inum = opaque;
 
        ip->i_num = *inum;
+       inode->i_ino = inum->no_addr;
        return 0;
 }
 
 struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum_host *inum)
 {
-       return ilookup5(sb, (unsigned long)inum->no_formal_ino,
+       return ilookup5(sb, (unsigned long)inum->no_addr,
                        iget_test, inum);
 }
 
 static struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum_host *inum)
 {
-       return iget5_locked(sb, (unsigned long)inum->no_formal_ino,
+       return iget5_locked(sb, (unsigned long)inum->no_addr,
                     iget_test, iget_set, inum);
 }
 
@@ -197,7 +171,9 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
         */
        ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink);
        di->di_size = be64_to_cpu(str->di_size);
+       i_size_write(&ip->i_inode, di->di_size);
        di->di_blocks = be64_to_cpu(str->di_blocks);
+       gfs2_set_inode_blocks(&ip->i_inode);
        ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime);
        ip->i_inode.i_atime.tv_nsec = 0;
        ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);
@@ -210,6 +186,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
        di->di_generation = be64_to_cpu(str->di_generation);
 
        di->di_flags = be32_to_cpu(str->di_flags);
+       gfs2_set_inode_flags(&ip->i_inode);
        di->di_height = be16_to_cpu(str->di_height);
 
        di->di_depth = be16_to_cpu(str->di_depth);
@@ -311,10 +288,8 @@ out:
  *
  * Returns: errno
  */
-
 int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
 {
-       struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
        struct buffer_head *dibh;
        u32 nlink;
        int error;
@@ -339,42 +314,34 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
        else
                drop_nlink(&ip->i_inode);
 
-       ip->i_inode.i_ctime.tv_sec = get_seconds();
+       ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        gfs2_dinode_out(ip, dibh->b_data);
        brelse(dibh);
        mark_inode_dirty(&ip->i_inode);
 
-       if (ip->i_inode.i_nlink == 0) {
-               struct gfs2_rgrpd *rgd;
-               struct gfs2_holder ri_gh, rg_gh;
-
-               error = gfs2_rindex_hold(sdp, &ri_gh);
-               if (error)
-                       goto out;
-               error = -EIO;
-               rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
-               if (!rgd)
-                       goto out_norgrp;
-               error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
-               if (error)
-                       goto out_norgrp;
-
+       if (ip->i_inode.i_nlink == 0)
                gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
-               gfs2_glock_dq_uninit(&rg_gh);
-out_norgrp:
-               gfs2_glock_dq_uninit(&ri_gh);
-       }
-out:
+
        return error;
 }
 
 struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
 {
        struct qstr qstr;
+       struct inode *inode;
        gfs2_str2qstr(&qstr, name);
-       return gfs2_lookupi(dip, &qstr, 1, NULL);
+       inode = gfs2_lookupi(dip, &qstr, 1, NULL);
+       /* gfs2_lookupi has inconsistent callers: vfs
+        * related routines expect NULL for no entry found,
+        * gfs2_lookup_simple callers expect ENOENT
+        * and do not check for NULL.
+        */
+       if (inode == NULL)
+               return ERR_PTR(-ENOENT);
+       else
+               return inode;
 }
 
 
@@ -385,8 +352,10 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
  * @is_root: If 1, ignore the caller's permissions
  * @i_gh: An uninitialized holder for the new inode glock
  *
- * There will always be a vnode (Linux VFS inode) for the d_gh inode unless
- * @is_root is true.
+ * This can be called via the VFS filldir function when NFS is doing
+ * a readdirplus and the inode which its intending to stat isn't
+ * already in cache. In this case we must not take the directory glock
+ * again, since the readdir call will have already taken that lock.
  *
  * Returns: errno
  */
@@ -399,8 +368,9 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
        struct gfs2_holder d_gh;
        struct gfs2_inum_host inum;
        unsigned int type;
-       int error = 0;
+       int error;
        struct inode *inode = NULL;
+       int unlock = 0;
 
        if (!name->len || name->len > GFS2_FNAMESIZE)
                return ERR_PTR(-ENAMETOOLONG);
@@ -412,9 +382,12 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
                return dir;
        }
 
-       error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
-       if (error)
-               return ERR_PTR(error);
+       if (gfs2_glock_is_locked_by_me(dip->i_gl) == 0) {
+               error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+               if (error)
+                       return ERR_PTR(error);
+               unlock = 1;
+       }
 
        if (!is_root) {
                error = permission(dir, MAY_EXEC, NULL);
@@ -429,10 +402,11 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
        inode = gfs2_inode_lookup(sb, &inum, type);
 
 out:
-       gfs2_glock_dq_uninit(&d_gh);
+       if (unlock)
+               gfs2_glock_dq_uninit(&d_gh);
        if (error == -ENOENT)
                return NULL;
-       return inode;
+       return inode ? inode : ERR_PTR(error);
 }
 
 static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino)
@@ -673,15 +647,15 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
        di->di_mode = cpu_to_be32(mode);
        di->di_uid = cpu_to_be32(uid);
        di->di_gid = cpu_to_be32(gid);
-       di->di_nlink = cpu_to_be32(0);
-       di->di_size = cpu_to_be64(0);
+       di->di_nlink = 0;
+       di->di_size = 0;
        di->di_blocks = cpu_to_be64(1);
        di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds());
        di->di_major = cpu_to_be32(MAJOR(dev));
        di->di_minor = cpu_to_be32(MINOR(dev));
        di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr);
        di->di_generation = cpu_to_be64(*generation);
-       di->di_flags = cpu_to_be32(0);
+       di->di_flags = 0;
 
        if (S_ISREG(mode)) {
                if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA) ||
@@ -699,13 +673,13 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
 
        di->__pad1 = 0;
        di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0);
-       di->di_height = cpu_to_be32(0);
+       di->di_height = 0;
        di->__pad2 = 0;
        di->__pad3 = 0;
-       di->di_depth = cpu_to_be16(0);
-       di->di_entries = cpu_to_be32(0);
+       di->di_depth = 0;
+       di->di_entries = 0;
        memset(&di->__pad4, 0, sizeof(di->__pad4));
-       di->di_eattr = cpu_to_be64(0);
+       di->di_eattr = 0;
        memset(&di->di_reserved, 0, sizeof(di->di_reserved));
 
        brelse(dibh);
@@ -894,33 +868,10 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
        if (error)
                goto fail_gunlock;
 
-       if (inum.no_addr < dip->i_num.no_addr) {
-               gfs2_glock_dq(ghs);
-
-               error = gfs2_glock_nq_num(sdp, inum.no_addr,
-                                         &gfs2_inode_glops, LM_ST_EXCLUSIVE,
-                                         GL_SKIP, ghs + 1);
-               if (error) {
-                       return ERR_PTR(error);
-               }
-
-               gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
-               error = gfs2_glock_nq(ghs);
-               if (error) {
-                       gfs2_glock_dq_uninit(ghs + 1);
-                       return ERR_PTR(error);
-               }
-
-               error = create_ok(dip, name, mode);
-               if (error)
-                       goto fail_gunlock2;
-       } else {
-               error = gfs2_glock_nq_num(sdp, inum.no_addr,
-                                         &gfs2_inode_glops, LM_ST_EXCLUSIVE,
-                                         GL_SKIP, ghs + 1);
-               if (error)
-                       goto fail_gunlock;
-       }
+       error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
+                                 LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
+       if (error)
+               goto fail_gunlock;
 
        error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev);
        if (error)
@@ -1258,92 +1209,6 @@ fail:
        return error;
 }
 
-/**
- * glock_compare_atime - Compare two struct gfs2_glock structures for sort
- * @arg_a: the first structure
- * @arg_b: the second structure
- *
- * Returns: 1 if A > B
- *         -1 if A < B
- *          0 if A == B
- */
-
-static int glock_compare_atime(const void *arg_a, const void *arg_b)
-{
-       const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a;
-       const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b;
-       const struct lm_lockname *a = &gh_a->gh_gl->gl_name;
-       const struct lm_lockname *b = &gh_b->gh_gl->gl_name;
-
-       if (a->ln_number > b->ln_number)
-               return 1;
-       if (a->ln_number < b->ln_number)
-               return -1;
-       if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
-               return 1;
-       if (gh_a->gh_state == LM_ST_SHARED && (gh_b->gh_flags & GL_ATIME))
-               return 1;
-
-       return 0;
-}
-
-/**
- * gfs2_glock_nq_m_atime - acquire multiple glocks where one may need an
- *      atime update
- * @num_gh: the number of structures
- * @ghs: an array of struct gfs2_holder structures
- *
- * Returns: 0 on success (all glocks acquired),
- *          errno on failure (no glocks acquired)
- */
-
-int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs)
-{
-       struct gfs2_holder **p;
-       unsigned int x;
-       int error = 0;
-
-       if (!num_gh)
-               return 0;
-
-       if (num_gh == 1) {
-               ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
-               if (ghs->gh_flags & GL_ATIME)
-                       error = gfs2_glock_nq_atime(ghs);
-               else
-                       error = gfs2_glock_nq(ghs);
-               return error;
-       }
-
-       p = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       for (x = 0; x < num_gh; x++)
-               p[x] = &ghs[x];
-
-       sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare_atime,NULL);
-
-       for (x = 0; x < num_gh; x++) {
-               p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
-
-               if (p[x]->gh_flags & GL_ATIME)
-                       error = gfs2_glock_nq_atime(p[x]);
-               else
-                       error = gfs2_glock_nq(p[x]);
-
-               if (error) {
-                       while (x--)
-                               gfs2_glock_dq(p[x]);
-                       break;
-               }
-       }
-
-       kfree(p);
-       return error;
-}
-
-
 static int
 __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
 {