Commit 5a00f3cc authored by Steven Whitehouse's avatar Steven Whitehouse

GFS2: Only do one directory search on create

Creation of a new inode requires a directory search in order to ensure
that we are not trying to create an inode with the same name as an
existing one. This was hidden away inside the create_ok() function.

In the case that there was an existing inode, and a lookup can be
substituted for a create (which is the case with regular files
when the O_EXCL flag is not in use) then we were doing a second
lookup in order to return the inode.

This patch merges these two lookups into one. This can be done by
passing a flag to gfs2_dir_search() to tell it to just return -EEXIST
in the cases where we don't actually want to look up the inode.
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent a9aefd70
...@@ -1555,9 +1555,9 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, ...@@ -1555,9 +1555,9 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
/** /**
* gfs2_dir_search - Search a directory * gfs2_dir_search - Search a directory
* @dip: The GFS2 inode * @dip: The GFS2 dir inode
* @filename: * @name: The name we are looking up
* @inode: * @fail_on_exist: Fail if the name exists rather than looking it up
* *
* This routine searches a directory for a file or another directory. * This routine searches a directory for a file or another directory.
* Assumes a glock is held on dip. * Assumes a glock is held on dip.
...@@ -1565,22 +1565,25 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, ...@@ -1565,22 +1565,25 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
* Returns: errno * Returns: errno
*/ */
struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name,
bool fail_on_exist)
{ {
struct buffer_head *bh; struct buffer_head *bh;
struct gfs2_dirent *dent; struct gfs2_dirent *dent;
struct inode *inode; u64 addr, formal_ino;
u16 dtype;
dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
if (dent) { if (dent) {
if (IS_ERR(dent)) if (IS_ERR(dent))
return ERR_CAST(dent); return ERR_CAST(dent);
inode = gfs2_inode_lookup(dir->i_sb, dtype = be16_to_cpu(dent->de_type);
be16_to_cpu(dent->de_type), addr = be64_to_cpu(dent->de_inum.no_addr);
be64_to_cpu(dent->de_inum.no_addr), formal_ino = be64_to_cpu(dent->de_inum.no_formal_ino);
be64_to_cpu(dent->de_inum.no_formal_ino), 0);
brelse(bh); brelse(bh);
return inode; if (fail_on_exist)
return ERR_PTR(-EEXIST);
return gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino, 0);
} }
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
......
...@@ -18,7 +18,8 @@ struct gfs2_inode; ...@@ -18,7 +18,8 @@ struct gfs2_inode;
struct gfs2_inum; struct gfs2_inum;
extern struct inode *gfs2_dir_search(struct inode *dir, extern struct inode *gfs2_dir_search(struct inode *dir,
const struct qstr *filename); const struct qstr *filename,
bool fail_on_exist);
extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename,
const struct gfs2_inode *ip); const struct gfs2_inode *ip);
extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename, extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
......
...@@ -313,7 +313,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, ...@@ -313,7 +313,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
goto out; goto out;
} }
inode = gfs2_dir_search(dir, name); inode = gfs2_dir_search(dir, name, false);
if (IS_ERR(inode)) if (IS_ERR(inode))
error = PTR_ERR(inode); error = PTR_ERR(inode);
out: out:
...@@ -346,17 +346,6 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, ...@@ -346,17 +346,6 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
if (!dip->i_inode.i_nlink) if (!dip->i_inode.i_nlink)
return -ENOENT; return -ENOENT;
error = gfs2_dir_check(&dip->i_inode, name, NULL);
switch (error) {
case -ENOENT:
error = 0;
break;
case 0:
return -EEXIST;
default:
return error;
}
if (dip->i_entries == (u32)-1) if (dip->i_entries == (u32)-1)
return -EFBIG; return -EFBIG;
if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1) if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1)
...@@ -584,14 +573,18 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -584,14 +573,18 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
goto fail; goto fail;
error = create_ok(dip, name, mode); error = create_ok(dip, name, mode);
if ((error == -EEXIST) && S_ISREG(mode) && !excl) { if (error)
inode = gfs2_lookupi(dir, &dentry->d_name, 0); goto fail_gunlock;
inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl);
error = PTR_ERR(inode);
if (!IS_ERR(inode)) {
gfs2_glock_dq_uninit(ghs); gfs2_glock_dq_uninit(ghs);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
return PTR_RET(inode); return 0;
} } else if (error != -ENOENT) {
if (error)
goto fail_gunlock; goto fail_gunlock;
}
arq = error = gfs2_diradd_alloc_required(dir, name); arq = error = gfs2_diradd_alloc_required(dir, name);
if (error < 0) if (error < 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