summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2013-06-11 08:45:29 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2013-06-11 08:45:29 -0400
commit5a00f3cc978be45b9d2597851bedaa40630bc597 (patch)
tree716a1b29594e352c4c793b699331d4d57578cce9
parenta9aefd707c65aa5a7945b3f16bd39f314aa8414d (diff)
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: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/dir.c23
-rw-r--r--fs/gfs2/dir.h3
-rw-r--r--fs/gfs2/inode.c27
3 files changed, 25 insertions, 28 deletions
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index b631c9043460..f0c70529948f 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1555,9 +1555,9 @@ out:
1555 1555
1556/** 1556/**
1557 * gfs2_dir_search - Search a directory 1557 * gfs2_dir_search - Search a directory
1558 * @dip: The GFS2 inode 1558 * @dip: The GFS2 dir inode
1559 * @filename: 1559 * @name: The name we are looking up
1560 * @inode: 1560 * @fail_on_exist: Fail if the name exists rather than looking it up
1561 * 1561 *
1562 * This routine searches a directory for a file or another directory. 1562 * This routine searches a directory for a file or another directory.
1563 * Assumes a glock is held on dip. 1563 * Assumes a glock is held on dip.
@@ -1565,22 +1565,25 @@ out:
1565 * Returns: errno 1565 * Returns: errno
1566 */ 1566 */
1567 1567
1568struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) 1568struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name,
1569 bool fail_on_exist)
1569{ 1570{
1570 struct buffer_head *bh; 1571 struct buffer_head *bh;
1571 struct gfs2_dirent *dent; 1572 struct gfs2_dirent *dent;
1572 struct inode *inode; 1573 u64 addr, formal_ino;
1574 u16 dtype;
1573 1575
1574 dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh); 1576 dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
1575 if (dent) { 1577 if (dent) {
1576 if (IS_ERR(dent)) 1578 if (IS_ERR(dent))
1577 return ERR_CAST(dent); 1579 return ERR_CAST(dent);
1578 inode = gfs2_inode_lookup(dir->i_sb, 1580 dtype = be16_to_cpu(dent->de_type);
1579 be16_to_cpu(dent->de_type), 1581 addr = be64_to_cpu(dent->de_inum.no_addr);
1580 be64_to_cpu(dent->de_inum.no_addr), 1582 formal_ino = be64_to_cpu(dent->de_inum.no_formal_ino);
1581 be64_to_cpu(dent->de_inum.no_formal_ino), 0);
1582 brelse(bh); 1583 brelse(bh);
1583 return inode; 1584 if (fail_on_exist)
1585 return ERR_PTR(-EEXIST);
1586 return gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino, 0);
1584 } 1587 }
1585 return ERR_PTR(-ENOENT); 1588 return ERR_PTR(-ENOENT);
1586} 1589}
diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
index 98c960beab35..d3f273870b49 100644
--- a/fs/gfs2/dir.h
+++ b/fs/gfs2/dir.h
@@ -18,7 +18,8 @@ struct gfs2_inode;
18struct gfs2_inum; 18struct gfs2_inum;
19 19
20extern struct inode *gfs2_dir_search(struct inode *dir, 20extern struct inode *gfs2_dir_search(struct inode *dir,
21 const struct qstr *filename); 21 const struct qstr *filename,
22 bool fail_on_exist);
22extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, 23extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename,
23 const struct gfs2_inode *ip); 24 const struct gfs2_inode *ip);
24extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename, 25extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 5fbb8dfb4653..ede16ae784e2 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -313,7 +313,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
313 goto out; 313 goto out;
314 } 314 }
315 315
316 inode = gfs2_dir_search(dir, name); 316 inode = gfs2_dir_search(dir, name, false);
317 if (IS_ERR(inode)) 317 if (IS_ERR(inode))
318 error = PTR_ERR(inode); 318 error = PTR_ERR(inode);
319out: 319out:
@@ -346,17 +346,6 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
346 if (!dip->i_inode.i_nlink) 346 if (!dip->i_inode.i_nlink)
347 return -ENOENT; 347 return -ENOENT;
348 348
349 error = gfs2_dir_check(&dip->i_inode, name, NULL);
350 switch (error) {
351 case -ENOENT:
352 error = 0;
353 break;
354 case 0:
355 return -EEXIST;
356 default:
357 return error;
358 }
359
360 if (dip->i_entries == (u32)-1) 349 if (dip->i_entries == (u32)-1)
361 return -EFBIG; 350 return -EFBIG;
362 if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1) 351 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 goto fail; 573 goto fail;
585 574
586 error = create_ok(dip, name, mode); 575 error = create_ok(dip, name, mode);
587 if ((error == -EEXIST) && S_ISREG(mode) && !excl) { 576 if (error)
588 inode = gfs2_lookupi(dir, &dentry->d_name, 0); 577 goto fail_gunlock;
578
579 inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl);
580 error = PTR_ERR(inode);
581 if (!IS_ERR(inode)) {
589 gfs2_glock_dq_uninit(ghs); 582 gfs2_glock_dq_uninit(ghs);
590 d_instantiate(dentry, inode); 583 d_instantiate(dentry, inode);
591 return PTR_RET(inode); 584 return 0;
592 } 585 } else if (error != -ENOENT) {
593 if (error)
594 goto fail_gunlock; 586 goto fail_gunlock;
587 }
595 588
596 arq = error = gfs2_diradd_alloc_required(dir, name); 589 arq = error = gfs2_diradd_alloc_required(dir, name);
597 if (error < 0) 590 if (error < 0)