|
@@ -37,9 +37,35 @@
|
|
|
#include "super.h"
|
|
|
#include "glops.h"
|
|
|
|
|
|
-struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr)
|
|
|
+static int iget_test(struct inode *inode, void *opaque)
|
|
|
{
|
|
|
- return ilookup(sb, (unsigned long)no_addr);
|
|
|
+ u64 no_addr = *(u64 *)opaque;
|
|
|
+
|
|
|
+ return GFS2_I(inode)->i_no_addr == no_addr;
|
|
|
+}
|
|
|
+
|
|
|
+static int iget_set(struct inode *inode, void *opaque)
|
|
|
+{
|
|
|
+ u64 no_addr = *(u64 *)opaque;
|
|
|
+
|
|
|
+ GFS2_I(inode)->i_no_addr = no_addr;
|
|
|
+ inode->i_ino = no_addr;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
|
|
|
+{
|
|
|
+ struct inode *inode;
|
|
|
+
|
|
|
+repeat:
|
|
|
+ inode = iget5_locked(sb, no_addr, iget_test, iget_set, &no_addr);
|
|
|
+ if (!inode)
|
|
|
+ return inode;
|
|
|
+ if (is_bad_inode(inode)) {
|
|
|
+ iput(inode);
|
|
|
+ goto repeat;
|
|
|
+ }
|
|
|
+ return inode;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -78,26 +104,37 @@ static void gfs2_set_iop(struct inode *inode)
|
|
|
/**
|
|
|
* gfs2_inode_lookup - Lookup an inode
|
|
|
* @sb: The super block
|
|
|
- * @no_addr: The inode number
|
|
|
* @type: The type of the inode
|
|
|
+ * @no_addr: The inode number
|
|
|
+ * @no_formal_ino: The inode generation number
|
|
|
+ * @blktype: Requested block type (GFS2_BLKST_DINODE or GFS2_BLKST_UNLINKED;
|
|
|
+ * GFS2_BLKST_FREE do indicate not to verify)
|
|
|
+ *
|
|
|
+ * If @type is DT_UNKNOWN, the inode type is fetched from disk.
|
|
|
+ *
|
|
|
+ * If @blktype is anything other than GFS2_BLKST_FREE (which is used as a
|
|
|
+ * placeholder because it doesn't otherwise make sense), the on-disk block type
|
|
|
+ * is verified to be @blktype.
|
|
|
*
|
|
|
* Returns: A VFS inode, or an error
|
|
|
*/
|
|
|
|
|
|
struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
|
|
- u64 no_addr, u64 no_formal_ino)
|
|
|
+ u64 no_addr, u64 no_formal_ino,
|
|
|
+ unsigned int blktype)
|
|
|
{
|
|
|
struct inode *inode;
|
|
|
struct gfs2_inode *ip;
|
|
|
struct gfs2_glock *io_gl = NULL;
|
|
|
+ struct gfs2_holder i_gh;
|
|
|
int error;
|
|
|
|
|
|
- inode = iget_locked(sb, (unsigned long)no_addr);
|
|
|
+ gfs2_holder_mark_uninitialized(&i_gh);
|
|
|
+ inode = gfs2_iget(sb, no_addr);
|
|
|
if (!inode)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
ip = GFS2_I(inode);
|
|
|
- ip->i_no_addr = no_addr;
|
|
|
|
|
|
if (inode->i_state & I_NEW) {
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
|
@@ -112,10 +149,29 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
|
|
if (unlikely(error))
|
|
|
goto fail_put;
|
|
|
|
|
|
+ if (type == DT_UNKNOWN || blktype != GFS2_BLKST_FREE) {
|
|
|
+ /*
|
|
|
+ * The GL_SKIP flag indicates to skip reading the inode
|
|
|
+ * block. We read the inode with gfs2_inode_refresh
|
|
|
+ * after possibly checking the block type.
|
|
|
+ */
|
|
|
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE,
|
|
|
+ GL_SKIP, &i_gh);
|
|
|
+ if (error)
|
|
|
+ goto fail_put;
|
|
|
+
|
|
|
+ if (blktype != GFS2_BLKST_FREE) {
|
|
|
+ error = gfs2_check_blk_type(sdp, no_addr,
|
|
|
+ blktype);
|
|
|
+ if (error)
|
|
|
+ goto fail_put;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
set_bit(GIF_INVALID, &ip->i_flags);
|
|
|
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
|
|
|
if (unlikely(error))
|
|
|
- goto fail_iopen;
|
|
|
+ goto fail_put;
|
|
|
|
|
|
ip->i_iopen_gh.gh_gl->gl_object = ip;
|
|
|
gfs2_glock_put(io_gl);
|
|
@@ -134,6 +190,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
|
|
unlock_new_inode(inode);
|
|
|
}
|
|
|
|
|
|
+ if (gfs2_holder_initialized(&i_gh))
|
|
|
+ gfs2_glock_dq_uninit(&i_gh);
|
|
|
return inode;
|
|
|
|
|
|
fail_refresh:
|
|
@@ -141,10 +199,11 @@ fail_refresh:
|
|
|
ip->i_iopen_gh.gh_gl->gl_object = NULL;
|
|
|
gfs2_glock_dq_wait(&ip->i_iopen_gh);
|
|
|
gfs2_holder_uninit(&ip->i_iopen_gh);
|
|
|
-fail_iopen:
|
|
|
+fail_put:
|
|
|
if (io_gl)
|
|
|
gfs2_glock_put(io_gl);
|
|
|
-fail_put:
|
|
|
+ if (gfs2_holder_initialized(&i_gh))
|
|
|
+ gfs2_glock_dq_uninit(&i_gh);
|
|
|
ip->i_gl->gl_object = NULL;
|
|
|
fail:
|
|
|
iget_failed(inode);
|
|
@@ -155,23 +214,12 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
|
|
|
u64 *no_formal_ino, unsigned int blktype)
|
|
|
{
|
|
|
struct super_block *sb = sdp->sd_vfs;
|
|
|
- struct gfs2_holder i_gh;
|
|
|
- struct inode *inode = NULL;
|
|
|
+ struct inode *inode;
|
|
|
int error;
|
|
|
|
|
|
- /* Must not read in block until block type is verified */
|
|
|
- error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops,
|
|
|
- LM_ST_EXCLUSIVE, GL_SKIP, &i_gh);
|
|
|
- if (error)
|
|
|
- return ERR_PTR(error);
|
|
|
-
|
|
|
- error = gfs2_check_blk_type(sdp, no_addr, blktype);
|
|
|
- if (error)
|
|
|
- goto fail;
|
|
|
-
|
|
|
- inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0);
|
|
|
+ inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, blktype);
|
|
|
if (IS_ERR(inode))
|
|
|
- goto fail;
|
|
|
+ return inode;
|
|
|
|
|
|
/* Two extra checks for NFS only */
|
|
|
if (no_formal_ino) {
|
|
@@ -182,16 +230,12 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
|
|
|
error = -EIO;
|
|
|
if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM)
|
|
|
goto fail_iput;
|
|
|
-
|
|
|
- error = 0;
|
|
|
}
|
|
|
+ return inode;
|
|
|
|
|
|
-fail:
|
|
|
- gfs2_glock_dq_uninit(&i_gh);
|
|
|
- return error ? ERR_PTR(error) : inode;
|
|
|
fail_iput:
|
|
|
iput(inode);
|
|
|
- goto fail;
|
|
|
+ return ERR_PTR(error);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -236,8 +280,8 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
|
|
struct gfs2_holder d_gh;
|
|
|
int error = 0;
|
|
|
struct inode *inode = NULL;
|
|
|
- int unlock = 0;
|
|
|
|
|
|
+ gfs2_holder_mark_uninitialized(&d_gh);
|
|
|
if (!name->len || name->len > GFS2_FNAMESIZE)
|
|
|
return ERR_PTR(-ENAMETOOLONG);
|
|
|
|
|
@@ -252,7 +296,6 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
|
|
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) {
|
|
@@ -265,7 +308,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
|
|
if (IS_ERR(inode))
|
|
|
error = PTR_ERR(inode);
|
|
|
out:
|
|
|
- if (unlock)
|
|
|
+ if (gfs2_holder_initialized(&d_gh))
|
|
|
gfs2_glock_dq_uninit(&d_gh);
|
|
|
if (error == -ENOENT)
|
|
|
return NULL;
|
|
@@ -1309,7 +1352,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|
|
struct gfs2_inode *ip = GFS2_I(d_inode(odentry));
|
|
|
struct gfs2_inode *nip = NULL;
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(odir);
|
|
|
- struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
|
|
|
+ struct gfs2_holder ghs[5], r_gh;
|
|
|
struct gfs2_rgrpd *nrgd;
|
|
|
unsigned int num_gh;
|
|
|
int dir_rename = 0;
|
|
@@ -1317,6 +1360,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|
|
unsigned int x;
|
|
|
int error;
|
|
|
|
|
|
+ gfs2_holder_mark_uninitialized(&r_gh);
|
|
|
if (d_really_is_positive(ndentry)) {
|
|
|
nip = GFS2_I(d_inode(ndentry));
|
|
|
if (ip == nip)
|
|
@@ -1506,7 +1550,7 @@ out_gunlock:
|
|
|
gfs2_holder_uninit(ghs + x);
|
|
|
}
|
|
|
out_gunlock_r:
|
|
|
- if (r_gh.gh_gl)
|
|
|
+ if (gfs2_holder_initialized(&r_gh))
|
|
|
gfs2_glock_dq_uninit(&r_gh);
|
|
|
out:
|
|
|
return error;
|
|
@@ -1532,13 +1576,14 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry,
|
|
|
struct gfs2_inode *oip = GFS2_I(odentry->d_inode);
|
|
|
struct gfs2_inode *nip = GFS2_I(ndentry->d_inode);
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(odir);
|
|
|
- struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
|
|
|
+ struct gfs2_holder ghs[5], r_gh;
|
|
|
unsigned int num_gh;
|
|
|
unsigned int x;
|
|
|
umode_t old_mode = oip->i_inode.i_mode;
|
|
|
umode_t new_mode = nip->i_inode.i_mode;
|
|
|
int error;
|
|
|
|
|
|
+ gfs2_holder_mark_uninitialized(&r_gh);
|
|
|
error = gfs2_rindex_update(sdp);
|
|
|
if (error)
|
|
|
return error;
|
|
@@ -1646,7 +1691,7 @@ out_gunlock:
|
|
|
gfs2_holder_uninit(ghs + x);
|
|
|
}
|
|
|
out_gunlock_r:
|
|
|
- if (r_gh.gh_gl)
|
|
|
+ if (gfs2_holder_initialized(&r_gh))
|
|
|
gfs2_glock_dq_uninit(&r_gh);
|
|
|
out:
|
|
|
return error;
|
|
@@ -1743,9 +1788,8 @@ int gfs2_permission(struct inode *inode, int mask)
|
|
|
struct gfs2_inode *ip;
|
|
|
struct gfs2_holder i_gh;
|
|
|
int error;
|
|
|
- int unlock = 0;
|
|
|
-
|
|
|
|
|
|
+ gfs2_holder_mark_uninitialized(&i_gh);
|
|
|
ip = GFS2_I(inode);
|
|
|
if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
|
|
|
if (mask & MAY_NOT_BLOCK)
|
|
@@ -1753,14 +1797,13 @@ int gfs2_permission(struct inode *inode, int mask)
|
|
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
|
|
|
if (error)
|
|
|
return error;
|
|
|
- unlock = 1;
|
|
|
}
|
|
|
|
|
|
if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
|
|
|
error = -EACCES;
|
|
|
else
|
|
|
error = generic_permission(inode, mask);
|
|
|
- if (unlock)
|
|
|
+ if (gfs2_holder_initialized(&i_gh))
|
|
|
gfs2_glock_dq_uninit(&i_gh);
|
|
|
|
|
|
return error;
|
|
@@ -1932,17 +1975,16 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
|
|
struct gfs2_holder gh;
|
|
|
int error;
|
|
|
- int unlock = 0;
|
|
|
|
|
|
+ gfs2_holder_mark_uninitialized(&gh);
|
|
|
if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
|
|
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
|
|
|
if (error)
|
|
|
return error;
|
|
|
- unlock = 1;
|
|
|
}
|
|
|
|
|
|
generic_fillattr(inode, stat);
|
|
|
- if (unlock)
|
|
|
+ if (gfs2_holder_initialized(&gh))
|
|
|
gfs2_glock_dq_uninit(&gh);
|
|
|
|
|
|
return 0;
|