Merge tag 'gfs2-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux...
[platform/kernel/linux-rpi.git] / fs / gfs2 / inode.c
index a1337bf..370c3a4 100644 (file)
@@ -115,6 +115,10 @@ static void gfs2_set_iop(struct inode *inode)
  * placeholder because it doesn't otherwise make sense), the on-disk block type
  * is verified to be @blktype.
  *
+ * When @no_formal_ino is non-zero, this function will return ERR_PTR(-ESTALE)
+ * if it detects that @no_formal_ino doesn't match the actual inode generation
+ * number.  However, it doesn't always know unless @type is DT_UNKNOWN.
+ *
  * Returns: A VFS inode, or an error
  */
 
@@ -158,6 +162,11 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
                        if (error)
                                goto fail;
 
+                       error = -ESTALE;
+                       if (no_formal_ino &&
+                           gfs2_inode_already_deleted(ip->i_gl, no_formal_ino))
+                               goto fail;
+
                        if (blktype != GFS2_BLKST_FREE) {
                                error = gfs2_check_blk_type(sdp, no_addr,
                                                            blktype);
@@ -171,6 +180,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
                error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
                if (unlikely(error))
                        goto fail;
+               gfs2_cancel_delete_work(ip->i_iopen_gh.gh_gl);
                glock_set_object(ip->i_iopen_gh.gh_gl, ip);
                gfs2_glock_put(io_gl);
                io_gl = NULL;
@@ -189,13 +199,23 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
                        inode->i_mode = DT2IF(type);
                }
 
+               if (gfs2_holder_initialized(&i_gh))
+                       gfs2_glock_dq_uninit(&i_gh);
+
                gfs2_set_iop(inode);
+       }
 
-               unlock_new_inode(inode);
+       if (no_formal_ino && ip->i_no_formal_ino &&
+           no_formal_ino != ip->i_no_formal_ino) {
+               if (inode->i_state & I_NEW)
+                       goto fail;
+               iput(inode);
+               return ERR_PTR(-ESTALE);
        }
 
-       if (gfs2_holder_initialized(&i_gh))
-               gfs2_glock_dq_uninit(&i_gh);
+       if (inode->i_state & I_NEW)
+               unlock_new_inode(inode);
+
        return inode;
 
 fail:
@@ -207,23 +227,26 @@ fail:
        return ERR_PTR(error);
 }
 
+/**
+ * gfs2_lookup_by_inum - look up an inode by inode number
+ * @sdp: The super block
+ * @no_addr: The inode number
+ * @no_formal_ino: The inode generation number (0 for any)
+ * @blktype: Requested block type (see gfs2_inode_lookup)
+ */
 struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
-                                 u64 *no_formal_ino, unsigned int blktype)
+                                 u64 no_formal_ino, unsigned int blktype)
 {
        struct super_block *sb = sdp->sd_vfs;
        struct inode *inode;
        int error;
 
-       inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, blktype);
+       inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, no_formal_ino,
+                                 blktype);
        if (IS_ERR(inode))
                return inode;
 
-       /* Two extra checks for NFS only */
        if (no_formal_ino) {
-               error = -ESTALE;
-               if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino)
-                       goto fail_iput;
-
                error = -EIO;
                if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM)
                        goto fail_iput;
@@ -725,6 +748,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
        if (error)
                goto fail_gunlock2;
 
+       gfs2_cancel_delete_work(ip->i_iopen_gh.gh_gl);
        glock_set_object(ip->i_iopen_gh.gh_gl, ip);
        gfs2_set_iop(inode);
        insert_inode_hash(inode);
@@ -781,7 +805,8 @@ fail_gunlock2:
 fail_free_inode:
        if (ip->i_gl) {
                glock_clear_object(ip->i_gl, ip);
-               gfs2_glock_put(ip->i_gl);
+               if (free_vfs_inode) /* else evict will do the put for us */
+                       gfs2_glock_put(ip->i_gl);
        }
        gfs2_rs_delete(ip, NULL);
        gfs2_qa_put(ip);