Commit f2741d98 authored by Steven Whitehouse's avatar Steven Whitehouse

GFS2: Move all locking inside the inode creation function

Now that there are no longer any exceptions to the normal inode
creation code path, we can move the parts of the locking code
which were duplicated in mkdir/mknod/create/symlink into the
inode create function.
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 160b4026
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -413,7 +413,8 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) ...@@ -413,7 +413,8 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
return error; return error;
} }
static void gfs2_init_dir(struct buffer_head *dibh, const struct gfs2_inode *parent) static void gfs2_init_dir(struct buffer_head *dibh,
const struct gfs2_inode *parent)
{ {
struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
...@@ -431,12 +432,17 @@ static void gfs2_init_dir(struct buffer_head *dibh, const struct gfs2_inode *par ...@@ -431,12 +432,17 @@ static void gfs2_init_dir(struct buffer_head *dibh, const struct gfs2_inode *par
/** /**
* init_dinode - Fill in a new dinode structure * init_dinode - Fill in a new dinode structure
* @dip: the directory this inode is being created in * @dip: The directory this inode is being created in
* @gl: The glock covering the new inode * @gl: The glock covering the new inode
* @inum: the inode number * @inum: The inode number
* @mode: the file permissions * @mode: The file permissions
* @uid: * @uid: The uid of the new inode
* @gid: * @gid: The gid of the new inode
* @generation: The generation number of the new inode
* @dev: The device number (if a device node)
* @symname: The symlink destination (if a symlink)
* @size: The inode size (ignored for directories)
* @bhp: The buffer head (returned to caller)
* *
*/ */
...@@ -644,29 +650,25 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, ...@@ -644,29 +650,25 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
} }
/** /**
* gfs2_createi - Create a new inode * gfs2_create_inode - Create a new inode
* @ghs: An array of two holders * @dir: The parent directory
* @name: The name of the new file * @dentry: The new dentry
* @mode: the permissions on the new inode * @mode: The permissions on the new inode
* @dev: For device nodes, this is the device number
* @symname: For symlinks, this is the link destination
* @size: The initial size of the inode (ignored for directories)
* *
* @ghs[0] is an initialized holder for the directory * Returns: 0 on success, or error code
* @ghs[1] is the holder for the inode lock
*
* If the return value is not NULL, the glocks on both the directory and the new
* file are held. A transaction has been started and an inplace reservation
* is held, as well.
*
* Returns: An inode
*/ */
static struct inode *gfs2_createi(struct gfs2_holder *ghs, static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
const struct qstr *name, unsigned int mode, unsigned int mode, dev_t dev, const char *symname,
dev_t dev, const char *symname,
unsigned int size) unsigned int size)
{ {
const struct qstr *name = &dentry->d_name;
struct gfs2_holder ghs[2];
struct inode *inode = NULL; struct inode *inode = NULL;
struct gfs2_inode *dip = ghs->gh_gl->gl_object; struct gfs2_inode *dip = GFS2_I(dir);
struct inode *dir = &dip->i_inode;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
int error; int error;
...@@ -674,10 +676,9 @@ static struct inode *gfs2_createi(struct gfs2_holder *ghs, ...@@ -674,10 +676,9 @@ static struct inode *gfs2_createi(struct gfs2_holder *ghs,
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
if (!name->len || name->len > GFS2_FNAMESIZE) if (!name->len || name->len > GFS2_FNAMESIZE)
return ERR_PTR(-ENAMETOOLONG); return -ENAMETOOLONG;
gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
error = gfs2_glock_nq(ghs);
if (error) if (error)
goto fail; goto fail;
...@@ -722,19 +723,29 @@ static struct inode *gfs2_createi(struct gfs2_holder *ghs, ...@@ -722,19 +723,29 @@ static struct inode *gfs2_createi(struct gfs2_holder *ghs,
if (bh) if (bh)
brelse(bh); brelse(bh);
return inode;
gfs2_trans_end(sdp);
if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip);
gfs2_quota_unlock(dip);
gfs2_alloc_put(dip);
gfs2_glock_dq_uninit_m(2, ghs);
mark_inode_dirty(inode);
d_instantiate(dentry, inode);
return 0;
fail_gunlock2: fail_gunlock2:
gfs2_glock_dq_uninit(ghs + 1); gfs2_glock_dq_uninit(ghs + 1);
if (inode && !IS_ERR(inode)) if (inode && !IS_ERR(inode))
iput(inode); iput(inode);
fail_gunlock: fail_gunlock:
gfs2_glock_dq(ghs); gfs2_glock_dq_uninit(ghs);
fail: fail:
if (bh) if (bh)
brelse(bh); brelse(bh);
return ERR_PTR(error); return error;
} }
/** /**
* gfs2_create - Create a file * gfs2_create - Create a file
* @dir: The directory in which to create the file * @dir: The directory in which to create the file
...@@ -747,44 +758,23 @@ static struct inode *gfs2_createi(struct gfs2_holder *ghs, ...@@ -747,44 +758,23 @@ static struct inode *gfs2_createi(struct gfs2_holder *ghs,
static int gfs2_create(struct inode *dir, struct dentry *dentry, static int gfs2_create(struct inode *dir, struct dentry *dentry,
int mode, struct nameidata *nd) int mode, struct nameidata *nd)
{ {
struct gfs2_inode *dip = GFS2_I(dir);
struct gfs2_sbd *sdp = GFS2_SB(dir);
struct gfs2_holder ghs[2];
struct inode *inode; struct inode *inode;
int ret;
gfs2_holder_init(dip->i_gl, 0, 0, ghs);
for (;;) { for (;;) {
inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0, NULL, 0); ret = gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0);
if (!IS_ERR(inode)) { if (ret != -EEXIST || (nd && (nd->flags & LOOKUP_EXCL)))
gfs2_trans_end(sdp); return ret;
if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip);
gfs2_quota_unlock(dip);
gfs2_alloc_put(dip);
gfs2_glock_dq_uninit_m(2, ghs);
mark_inode_dirty(inode);
break;
} else if (PTR_ERR(inode) != -EEXIST ||
(nd && nd->flags & LOOKUP_EXCL)) {
gfs2_holder_uninit(ghs);
return PTR_ERR(inode);
}
inode = gfs2_lookupi(dir, &dentry->d_name, 0); inode = gfs2_lookupi(dir, &dentry->d_name, 0);
if (inode) { if (inode) {
if (!IS_ERR(inode)) { if (!IS_ERR(inode))
gfs2_holder_uninit(ghs);
break; break;
} else {
gfs2_holder_uninit(ghs);
return PTR_ERR(inode); return PTR_ERR(inode);
} }
} }
}
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
return 0; return 0;
} }
...@@ -1150,36 +1140,14 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1150,36 +1140,14 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
static int gfs2_symlink(struct inode *dir, struct dentry *dentry, static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
const char *symname) const char *symname)
{ {
struct gfs2_inode *dip = GFS2_I(dir);
struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_sbd *sdp = GFS2_SB(dir);
struct gfs2_holder ghs[2];
struct inode *inode;
unsigned int size; unsigned int size;
size = strlen(symname); size = strlen(symname);
if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
return -ENAMETOOLONG; return -ENAMETOOLONG;
gfs2_holder_init(dip->i_gl, 0, 0, ghs); return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size);
inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0, symname, size);
if (IS_ERR(inode)) {
gfs2_holder_uninit(ghs);
return PTR_ERR(inode);
}
gfs2_trans_end(sdp);
if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip);
gfs2_quota_unlock(dip);
gfs2_alloc_put(dip);
gfs2_glock_dq_uninit_m(2, ghs);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
return 0;
} }
/** /**
...@@ -1193,31 +1161,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1193,31 +1161,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{ {
struct gfs2_inode *dip = GFS2_I(dir); return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0);
struct gfs2_sbd *sdp = GFS2_SB(dir);
struct gfs2_holder ghs[2];
struct inode *inode;
gfs2_holder_init(dip->i_gl, 0, 0, ghs);
inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0, NULL, 0);
if (IS_ERR(inode)) {
gfs2_holder_uninit(ghs);
return PTR_ERR(inode);
}
gfs2_trans_end(sdp);
if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip);
gfs2_quota_unlock(dip);
gfs2_alloc_put(dip);
gfs2_glock_dq_uninit_m(2, ghs);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
return 0;
} }
/** /**
...@@ -1225,38 +1169,14 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -1225,38 +1169,14 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
* @dir: The directory in which the special file will reside * @dir: The directory in which the special file will reside
* @dentry: The dentry of the special file * @dentry: The dentry of the special file
* @mode: The mode of the special file * @mode: The mode of the special file
* @rdev: The device specification of the special file * @dev: The device specification of the special file
* *
*/ */
static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t dev) dev_t dev)
{ {
struct gfs2_inode *dip = GFS2_I(dir); return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0);
struct gfs2_sbd *sdp = GFS2_SB(dir);
struct gfs2_holder ghs[2];
struct inode *inode;
gfs2_holder_init(dip->i_gl, 0, 0, ghs);
inode = gfs2_createi(ghs, &dentry->d_name, mode, dev, NULL, 0);
if (IS_ERR(inode)) {
gfs2_holder_uninit(ghs);
return PTR_ERR(inode);
}
gfs2_trans_end(sdp);
if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip);
gfs2_quota_unlock(dip);
gfs2_alloc_put(dip);
gfs2_glock_dq_uninit_m(2, ghs);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
return 0;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment