summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/inode.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-15 12:34:21 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-15 12:34:21 -0800
commit08242bc2210938761230f79c5288dbcf72e94808 (patch)
treef0e880673fb5139c692bd4004e9f165c249613ed /fs/gfs2/inode.c
parentbe354f40812314dee2b1e3aa272528c056bb827d (diff)
parent1e2d9d44f3ceb7dac7cb14d2476d0a8128c8e169 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw
Pull GFS2 updates from Steven Whitehouse: "The main feature this time is the new Orlov allocator and the patches leading up to it which allow us to allocate new inodes from their own allocation context, rather than borrowing that of their parent directory. It is this change which then allows us to choose a different location for subdirectories when required. This works exactly as per the ext3 implementation from the users point of view. In addition to that, we've got a speed up in gfs2_rbm_from_block() from Bob Peterson, three locking related improvements from Dave Teigland plus a selection of smaller bug fixes and clean ups." * git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw: GFS2: Set gl_object during inode create GFS2: add error check while allocating new inodes GFS2: don't reference inode's glock during block allocation trace GFS2: remove redundant lvb pointer GFS2: only use lvb on glocks that need it GFS2: skip dlm_unlock calls in unmount GFS2: Fix one RG corner case GFS2: Eliminate redundant buffer_head manipulation in gfs2_unlink_inode GFS2: Use dirty_inode in gfs2_dir_add GFS2: Fix truncation of journaled data files GFS2: Add Orlov allocator GFS2: Use proper allocation context for new inodes GFS2: Add test for resource group congestion status GFS2: Rename glops go_xmote_th to go_sync GFS2: Speed up gfs2_rbm_from_block GFS2: Review bug traps in glops.c
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r--fs/gfs2/inode.c209
1 files changed, 109 insertions, 100 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 381893ceefa..2b6f5698ef1 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -364,34 +364,34 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
return 0;
}
-static void munge_mode_uid_gid(struct gfs2_inode *dip, umode_t *mode,
- unsigned int *uid, unsigned int *gid)
+static void munge_mode_uid_gid(const struct gfs2_inode *dip,
+ struct inode *inode)
{
if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir &&
(dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) {
- if (S_ISDIR(*mode))
- *mode |= S_ISUID;
+ if (S_ISDIR(inode->i_mode))
+ inode->i_mode |= S_ISUID;
else if (dip->i_inode.i_uid != current_fsuid())
- *mode &= ~07111;
- *uid = dip->i_inode.i_uid;
+ inode->i_mode &= ~07111;
+ inode->i_uid = dip->i_inode.i_uid;
} else
- *uid = current_fsuid();
+ inode->i_uid = current_fsuid();
if (dip->i_inode.i_mode & S_ISGID) {
- if (S_ISDIR(*mode))
- *mode |= S_ISGID;
- *gid = dip->i_inode.i_gid;
+ if (S_ISDIR(inode->i_mode))
+ inode->i_mode |= S_ISGID;
+ inode->i_gid = dip->i_inode.i_gid;
} else
- *gid = current_fsgid();
+ inode->i_gid = current_fsgid();
}
-static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
+static int alloc_dinode(struct gfs2_inode *ip, u32 flags)
{
- struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
int error;
int dblocks = 1;
- error = gfs2_inplace_reserve(dip, RES_DINODE);
+ error = gfs2_inplace_reserve(ip, RES_DINODE, flags);
if (error)
goto out;
@@ -399,12 +399,15 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
if (error)
goto out_ipreserv;
- error = gfs2_alloc_blocks(dip, no_addr, &dblocks, 1, generation);
+ error = gfs2_alloc_blocks(ip, &ip->i_no_addr, &dblocks, 1, &ip->i_generation);
+ ip->i_no_formal_ino = ip->i_generation;
+ ip->i_inode.i_ino = ip->i_no_addr;
+ ip->i_goal = ip->i_no_addr;
gfs2_trans_end(sdp);
out_ipreserv:
- gfs2_inplace_release(dip);
+ gfs2_inplace_release(ip);
out:
return error;
}
@@ -429,52 +432,42 @@ static void gfs2_init_dir(struct buffer_head *dibh,
/**
* init_dinode - Fill in a new dinode structure
* @dip: The directory this inode is being created in
- * @gl: The glock covering the new inode
- * @inum: The inode number
- * @mode: The file permissions
- * @uid: The uid of the new inode
- * @gid: The gid of the new inode
- * @generation: The generation number of the new inode
- * @dev: The device number (if a device node)
+ * @ip: The inode
* @symname: The symlink destination (if a symlink)
- * @size: The inode size (ignored for directories)
* @bhp: The buffer head (returned to caller)
*
*/
-static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
- const struct gfs2_inum_host *inum, umode_t mode,
- unsigned int uid, unsigned int gid,
- const u64 *generation, dev_t dev, const char *symname,
- unsigned size, struct buffer_head **bhp)
+static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
+ const char *symname, struct buffer_head **bhp)
{
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_dinode *di;
struct buffer_head *dibh;
struct timespec tv = CURRENT_TIME;
- dibh = gfs2_meta_new(gl, inum->no_addr);
- gfs2_trans_add_bh(gl, dibh, 1);
+ dibh = gfs2_meta_new(ip->i_gl, ip->i_no_addr);
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI);
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
di = (struct gfs2_dinode *)dibh->b_data;
- di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino);
- di->di_num.no_addr = cpu_to_be64(inum->no_addr);
- di->di_mode = cpu_to_be32(mode);
- di->di_uid = cpu_to_be32(uid);
- di->di_gid = cpu_to_be32(gid);
+ di->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino);
+ di->di_num.no_addr = cpu_to_be64(ip->i_no_addr);
+ di->di_mode = cpu_to_be32(ip->i_inode.i_mode);
+ di->di_uid = cpu_to_be32(ip->i_inode.i_uid);
+ di->di_gid = cpu_to_be32(ip->i_inode.i_gid);
di->di_nlink = 0;
- di->di_size = cpu_to_be64(size);
+ di->di_size = cpu_to_be64(ip->i_inode.i_size);
di->di_blocks = cpu_to_be64(1);
di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(tv.tv_sec);
- 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_major = cpu_to_be32(MAJOR(ip->i_inode.i_rdev));
+ di->di_minor = cpu_to_be32(MINOR(ip->i_inode.i_rdev));
+ di->di_goal_meta = di->di_goal_data = cpu_to_be64(ip->i_no_addr);
+ di->di_generation = cpu_to_be64(ip->i_generation);
di->di_flags = 0;
di->__pad1 = 0;
- di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0);
+ di->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) ? GFS2_FORMAT_DE : 0);
di->di_height = 0;
di->__pad2 = 0;
di->__pad3 = 0;
@@ -487,7 +480,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec);
memset(&di->di_reserved, 0, sizeof(di->di_reserved));
- switch(mode & S_IFMT) {
+ switch(ip->i_inode.i_mode & S_IFMT) {
case S_IFREG:
if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) ||
gfs2_tune_get(sdp, gt_new_files_jdata))
@@ -502,7 +495,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
gfs2_init_dir(dibh, dip);
break;
case S_IFLNK:
- memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, size);
+ memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, ip->i_inode.i_size);
break;
}
@@ -511,25 +504,22 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
*bhp = dibh;
}
-static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
- umode_t mode, const struct gfs2_inum_host *inum,
- const u64 *generation, dev_t dev, const char *symname,
- unsigned int size, struct buffer_head **bhp)
+static int make_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
+ const char *symname, struct buffer_head **bhp)
{
+ struct inode *inode = &ip->i_inode;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
- unsigned int uid, gid;
int error;
- munge_mode_uid_gid(dip, &mode, &uid, &gid);
error = gfs2_rindex_update(sdp);
if (error)
return error;
- error = gfs2_quota_lock(dip, uid, gid);
+ error = gfs2_quota_lock(dip, inode->i_uid, inode->i_gid);
if (error)
return error;
- error = gfs2_quota_check(dip, uid, gid);
+ error = gfs2_quota_check(dip, inode->i_uid, inode->i_gid);
if (error)
goto out_quota;
@@ -537,8 +527,8 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
if (error)
goto out_quota;
- init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, symname, size, bhp);
- gfs2_quota_change(dip, +1, uid, gid);
+ init_dinode(dip, ip, symname, bhp);
+ gfs2_quota_change(dip, +1, inode->i_uid, inode->i_gid);
gfs2_trans_end(sdp);
out_quota:
@@ -570,7 +560,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
if (error)
goto fail_quota_locks;
- error = gfs2_inplace_reserve(dip, sdp->sd_max_dirres);
+ error = gfs2_inplace_reserve(dip, sdp->sd_max_dirres, 0);
if (error)
goto fail_quota_locks;
@@ -657,19 +647,14 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
struct inode *inode = NULL;
struct gfs2_inode *dip = GFS2_I(dir), *ip;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
- struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
+ struct gfs2_glock *io_gl;
int error;
- u64 generation;
struct buffer_head *bh = NULL;
+ u32 aflags = 0;
if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG;
- /* We need a reservation to allocate the new dinode block. The
- directory ip temporarily points to the reservation, but this is
- being done to get a set of contiguous blocks for the new dinode.
- Since this is a create, we don't have a sizehint yet, so it will
- have to use the minimum reservation size. */
error = gfs2_rs_alloc(dip);
if (error)
return error;
@@ -688,45 +673,72 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error)
goto fail_gunlock;
- error = alloc_dinode(dip, &inum.no_addr, &generation);
+ inode = new_inode(sdp->sd_vfs);
+ if (!inode) {
+ gfs2_glock_dq_uninit(ghs);
+ return -ENOMEM;
+ }
+ ip = GFS2_I(inode);
+ error = gfs2_rs_alloc(ip);
if (error)
- goto fail_gunlock;
- inum.no_formal_ino = generation;
+ goto fail_free_inode;
+
+ set_bit(GIF_INVALID, &ip->i_flags);
+ inode->i_mode = mode;
+ inode->i_rdev = dev;
+ inode->i_size = size;
+ munge_mode_uid_gid(dip, inode);
+ ip->i_goal = dip->i_goal;
- error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops,
- LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
+ if ((GFS2_I(sdp->sd_root_dir->d_inode) == dip) ||
+ (dip->i_diskflags & GFS2_DIF_TOPDIR))
+ aflags |= GFS2_AF_ORLOV;
+
+ error = alloc_dinode(ip, aflags);
if (error)
- goto fail_gunlock;
+ goto fail_free_inode;
- error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, symname, size, &bh);
+ error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
if (error)
- goto fail_gunlock2;
+ goto fail_free_inode;
- inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr,
- inum.no_formal_ino, 0);
- if (IS_ERR(inode))
+ ip->i_gl->gl_object = ip;
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
+ if (error)
+ goto fail_free_inode;
+
+ error = make_dinode(dip, ip, symname, &bh);
+ if (error)
goto fail_gunlock2;
- ip = GFS2_I(inode);
- error = gfs2_inode_refresh(ip);
+ error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
if (error)
goto fail_gunlock2;
- error = gfs2_rs_alloc(ip);
+ error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
if (error)
goto fail_gunlock2;
+ ip->i_iopen_gh.gh_gl->gl_object = ip;
+ gfs2_glock_put(io_gl);
+ gfs2_set_iop(inode);
+ insert_inode_hash(inode);
+
+ error = gfs2_inode_refresh(ip);
+ if (error)
+ goto fail_gunlock3;
+
error = gfs2_acl_create(dip, inode);
if (error)
- goto fail_gunlock2;
+ goto fail_gunlock3;
error = gfs2_security_init(dip, ip, name);
if (error)
- goto fail_gunlock2;
+ goto fail_gunlock3;
error = link_dinode(dip, name, ip);
if (error)
- goto fail_gunlock2;
+ goto fail_gunlock3;
if (bh)
brelse(bh);
@@ -739,8 +751,20 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
d_instantiate(dentry, inode);
return 0;
+fail_gunlock3:
+ gfs2_glock_dq_uninit(ghs + 1);
+ if (ip->i_gl)
+ gfs2_glock_put(ip->i_gl);
+ goto fail_gunlock;
+
fail_gunlock2:
gfs2_glock_dq_uninit(ghs + 1);
+fail_free_inode:
+ if (ip->i_gl)
+ gfs2_glock_put(ip->i_gl);
+ gfs2_rs_delete(ip);
+ free_inode_nonrcu(inode);
+ inode = NULL;
fail_gunlock:
gfs2_glock_dq_uninit(ghs);
if (inode && !IS_ERR(inode)) {
@@ -748,7 +772,6 @@ fail_gunlock:
iput(inode);
}
fail:
- gfs2_rs_delete(dip);
if (bh)
brelse(bh);
return error;
@@ -884,7 +907,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
if (error)
goto out_gunlock;
- error = gfs2_inplace_reserve(dip, sdp->sd_max_dirres);
+ error = gfs2_inplace_reserve(dip, sdp->sd_max_dirres, 0);
if (error)
goto out_gunlock_q;
@@ -977,7 +1000,6 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
* gfs2_unlink_inode - Removes an inode from its parent dir and unlinks it
* @dip: The parent directory
* @name: The name of the entry in the parent directory
- * @bh: The inode buffer for the inode to be removed
* @inode: The inode to be removed
*
* Called with all the locks and in a transaction. This will only be
@@ -987,8 +1009,7 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
*/
static int gfs2_unlink_inode(struct gfs2_inode *dip,
- const struct dentry *dentry,
- struct buffer_head *bh)
+ const struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
@@ -1028,7 +1049,6 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
struct gfs2_sbd *sdp = GFS2_SB(dir);
struct inode *inode = dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
- struct buffer_head *bh;
struct gfs2_holder ghs[3];
struct gfs2_rgrpd *rgd;
int error;
@@ -1077,14 +1097,9 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
error = gfs2_trans_begin(sdp, 2*RES_DINODE + 3*RES_LEAF + RES_RG_BIT, 0);
if (error)
- goto out_gunlock;
-
- error = gfs2_meta_inode_buffer(ip, &bh);
- if (error)
goto out_end_trans;
- error = gfs2_unlink_inode(dip, dentry, bh);
- brelse(bh);
+ error = gfs2_unlink_inode(dip, dentry);
out_end_trans:
gfs2_trans_end(sdp);
@@ -1365,7 +1380,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (error)
goto out_gunlock;
- error = gfs2_inplace_reserve(ndip, sdp->sd_max_dirres);
+ error = gfs2_inplace_reserve(ndip, sdp->sd_max_dirres, 0);
if (error)
goto out_gunlock_q;
@@ -1384,14 +1399,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
/* Remove the target file, if it exists */
- if (nip) {
- struct buffer_head *bh;
- error = gfs2_meta_inode_buffer(nip, &bh);
- if (error)
- goto out_end_trans;
- error = gfs2_unlink_inode(ndip, ndentry, bh);
- brelse(bh);
- }
+ if (nip)
+ error = gfs2_unlink_inode(ndip, ndentry);
if (dir_rename) {
error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR);