diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2013-06-11 08:45:29 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2013-06-11 08:45:29 -0400 |
commit | 5a00f3cc978be45b9d2597851bedaa40630bc597 (patch) | |
tree | 716a1b29594e352c4c793b699331d4d57578cce9 | |
parent | a9aefd707c65aa5a7945b3f16bd39f314aa8414d (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.c | 23 | ||||
-rw-r--r-- | fs/gfs2/dir.h | 3 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 27 |
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 | ||
1568 | struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) | 1568 | struct 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; | |||
18 | struct gfs2_inum; | 18 | struct gfs2_inum; |
19 | 19 | ||
20 | extern struct inode *gfs2_dir_search(struct inode *dir, | 20 | extern struct inode *gfs2_dir_search(struct inode *dir, |
21 | const struct qstr *filename); | 21 | const struct qstr *filename, |
22 | bool fail_on_exist); | ||
22 | extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, | 23 | extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, |
23 | const struct gfs2_inode *ip); | 24 | const struct gfs2_inode *ip); |
24 | extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename, | 25 | extern 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); |
319 | out: | 319 | out: |
@@ -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) |