diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-03-20 12:30:04 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-03-20 12:30:04 -0500 |
commit | c752666c17f870fa8ae9f16804dd457e9e6daaec (patch) | |
tree | c3c48383f386a24edbdf3c6292f25b587e6d9368 /fs/gfs2/ops_inode.c | |
parent | 419c93e0b6b9eef0bf26b8ad415f2a5bf4300119 (diff) |
[GFS2] Fix bug in directory code and tidy up
Due to a typo, the dir leaf split operation was (for the first
split in a directory) writing the new hash vaules at the
wrong offset. This is now fixed.
Also some other tidy ups are included:
- We use GFS2's hash function for dentries (see ops_dentry.c) so that
we don't have to keep recalculating the hash values.
- A lot of common code is eliminated between the various directory
lookup routines.
- Better error checking on directory lookup (previously different
routines checked for different errors)
- The leaf split operation has a couple of redundant operations
removed from it, so it should be faster.
There is still further scope for further clean ups in the directory
code, and readdir in particular could do with slimming down a bit.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_inode.c')
-rw-r--r-- | fs/gfs2/ops_inode.c | 72 |
1 files changed, 35 insertions, 37 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 7633a8584b0d..e8ab9d254b76 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -58,7 +58,6 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, | |||
58 | struct gfs2_holder ghs[2]; | 58 | struct gfs2_holder ghs[2]; |
59 | struct inode *inode; | 59 | struct inode *inode; |
60 | int new = 1; | 60 | int new = 1; |
61 | int error; | ||
62 | 61 | ||
63 | gfs2_holder_init(dip->i_gl, 0, 0, ghs); | 62 | gfs2_holder_init(dip->i_gl, 0, 0, ghs); |
64 | 63 | ||
@@ -78,14 +77,16 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, | |||
78 | return PTR_ERR(inode); | 77 | return PTR_ERR(inode); |
79 | } | 78 | } |
80 | 79 | ||
81 | error = gfs2_lookupi(dir, &dentry->d_name, 0, &inode); | 80 | inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd); |
82 | if (!error) { | 81 | if (inode) { |
83 | new = 0; | 82 | if (!IS_ERR(inode)) { |
84 | gfs2_holder_uninit(ghs); | 83 | new = 0; |
85 | break; | 84 | gfs2_holder_uninit(ghs); |
86 | } else if (error != -ENOENT) { | 85 | break; |
87 | gfs2_holder_uninit(ghs); | 86 | } else { |
88 | return error; | 87 | gfs2_holder_uninit(ghs); |
88 | return PTR_ERR(inode); | ||
89 | } | ||
89 | } | 90 | } |
90 | } | 91 | } |
91 | 92 | ||
@@ -110,17 +111,13 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, | |||
110 | static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, | 111 | static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, |
111 | struct nameidata *nd) | 112 | struct nameidata *nd) |
112 | { | 113 | { |
113 | struct gfs2_inode *dip = dir->u.generic_ip; | ||
114 | struct gfs2_sbd *sdp = dip->i_sbd; | ||
115 | struct inode *inode = NULL; | 114 | struct inode *inode = NULL; |
116 | int error; | ||
117 | 115 | ||
118 | if (!sdp->sd_args.ar_localcaching) | 116 | dentry->d_op = &gfs2_dops; |
119 | dentry->d_op = &gfs2_dops; | ||
120 | 117 | ||
121 | error = gfs2_lookupi(dir, &dentry->d_name, 0, &inode); | 118 | inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd); |
122 | if (error && error != -ENOENT) | 119 | if (inode && IS_ERR(inode)) |
123 | return ERR_PTR(error); | 120 | return ERR_PTR(PTR_ERR(inode)); |
124 | 121 | ||
125 | if (inode) | 122 | if (inode) |
126 | return d_splice_alias(inode, dentry); | 123 | return d_splice_alias(inode, dentry); |
@@ -166,7 +163,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, | |||
166 | if (error) | 163 | if (error) |
167 | goto out_gunlock; | 164 | goto out_gunlock; |
168 | 165 | ||
169 | error = gfs2_dir_search(dip, &dentry->d_name, NULL, NULL); | 166 | error = gfs2_dir_search(dir, &dentry->d_name, NULL, NULL); |
170 | switch (error) { | 167 | switch (error) { |
171 | case -ENOENT: | 168 | case -ENOENT: |
172 | break; | 169 | break; |
@@ -192,10 +189,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, | |||
192 | if (ip->i_di.di_nlink == (uint32_t)-1) | 189 | if (ip->i_di.di_nlink == (uint32_t)-1) |
193 | goto out_gunlock; | 190 | goto out_gunlock; |
194 | 191 | ||
195 | error = gfs2_diradd_alloc_required(dip, &dentry->d_name, | 192 | alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); |
196 | &alloc_required); | 193 | if (error < 0) |
197 | if (error) | ||
198 | goto out_gunlock; | 194 | goto out_gunlock; |
195 | error = 0; | ||
199 | 196 | ||
200 | if (alloc_required) { | 197 | if (alloc_required) { |
201 | struct gfs2_alloc *al = gfs2_alloc_get(dip); | 198 | struct gfs2_alloc *al = gfs2_alloc_get(dip); |
@@ -228,7 +225,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, | |||
228 | goto out_ipres; | 225 | goto out_ipres; |
229 | } | 226 | } |
230 | 227 | ||
231 | error = gfs2_dir_add(dip, &dentry->d_name, &ip->i_num, | 228 | error = gfs2_dir_add(dir, &dentry->d_name, &ip->i_num, |
232 | IF2DT(ip->i_di.di_mode)); | 229 | IF2DT(ip->i_di.di_mode)); |
233 | if (error) | 230 | if (error) |
234 | goto out_end_trans; | 231 | goto out_end_trans; |
@@ -419,24 +416,24 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
419 | 416 | ||
420 | if (!gfs2_assert_withdraw(sdp, !error)) { | 417 | if (!gfs2_assert_withdraw(sdp, !error)) { |
421 | struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; | 418 | struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; |
422 | struct gfs2_dirent *dent; | 419 | struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); |
423 | 420 | struct qstr str = { .name = ".", .len = 1 }; | |
424 | gfs2_dirent_alloc(ip, dibh, 1, &dent); | 421 | str.hash = gfs2_disk_hash(str.name, str.len); |
425 | 422 | ||
423 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
424 | gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent); | ||
426 | dent->de_inum = di->di_num; /* already GFS2 endian */ | 425 | dent->de_inum = di->di_num; /* already GFS2 endian */ |
427 | dent->de_hash = gfs2_disk_hash(".", 1); | ||
428 | dent->de_hash = cpu_to_be32(dent->de_hash); | ||
429 | dent->de_type = DT_DIR; | 426 | dent->de_type = DT_DIR; |
430 | memcpy((char *) (dent + 1), ".", 1); | ||
431 | di->di_entries = cpu_to_be32(1); | 427 | di->di_entries = cpu_to_be32(1); |
432 | 428 | ||
433 | gfs2_dirent_alloc(ip, dibh, 2, &dent); | 429 | str.name = ".."; |
430 | str.len = 2; | ||
431 | str.hash = gfs2_disk_hash(str.name, str.len); | ||
432 | dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1)); | ||
433 | gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); | ||
434 | 434 | ||
435 | gfs2_inum_out(&dip->i_num, (char *) &dent->de_inum); | 435 | gfs2_inum_out(&dip->i_num, (char *) &dent->de_inum); |
436 | dent->de_hash = gfs2_disk_hash("..", 2); | ||
437 | dent->de_hash = cpu_to_be32(dent->de_hash); | ||
438 | dent->de_type = DT_DIR; | 436 | dent->de_type = DT_DIR; |
439 | memcpy((char *) (dent + 1), "..", 2); | ||
440 | 437 | ||
441 | gfs2_dinode_out(&ip->i_di, (char *)di); | 438 | gfs2_dinode_out(&ip->i_di, (char *)di); |
442 | 439 | ||
@@ -687,7 +684,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
687 | if (error) | 684 | if (error) |
688 | goto out_gunlock; | 685 | goto out_gunlock; |
689 | 686 | ||
690 | error = gfs2_dir_search(ndip, &ndentry->d_name, NULL, NULL); | 687 | error = gfs2_dir_search(ndir, &ndentry->d_name, NULL, NULL); |
691 | switch (error) { | 688 | switch (error) { |
692 | case -ENOENT: | 689 | case -ENOENT: |
693 | error = 0; | 690 | error = 0; |
@@ -723,10 +720,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
723 | goto out_gunlock; | 720 | goto out_gunlock; |
724 | } | 721 | } |
725 | 722 | ||
726 | error = gfs2_diradd_alloc_required(ndip, &ndentry->d_name, | 723 | alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); |
727 | &alloc_required); | 724 | if (error < 0) |
728 | if (error) | ||
729 | goto out_gunlock; | 725 | goto out_gunlock; |
726 | error = 0; | ||
730 | 727 | ||
731 | if (alloc_required) { | 728 | if (alloc_required) { |
732 | struct gfs2_alloc *al = gfs2_alloc_get(ndip); | 729 | struct gfs2_alloc *al = gfs2_alloc_get(ndip); |
@@ -777,6 +774,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
777 | struct qstr name; | 774 | struct qstr name; |
778 | name.len = 2; | 775 | name.len = 2; |
779 | name.name = ".."; | 776 | name.name = ".."; |
777 | name.hash = gfs2_disk_hash(name.name, name.len); | ||
780 | 778 | ||
781 | error = gfs2_change_nlink(ndip, +1); | 779 | error = gfs2_change_nlink(ndip, +1); |
782 | if (error) | 780 | if (error) |
@@ -803,7 +801,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
803 | if (error) | 801 | if (error) |
804 | goto out_end_trans; | 802 | goto out_end_trans; |
805 | 803 | ||
806 | error = gfs2_dir_add(ndip, &ndentry->d_name, &ip->i_num, | 804 | error = gfs2_dir_add(ndir, &ndentry->d_name, &ip->i_num, |
807 | IF2DT(ip->i_di.di_mode)); | 805 | IF2DT(ip->i_di.di_mode)); |
808 | if (error) | 806 | if (error) |
809 | goto out_end_trans; | 807 | goto out_end_trans; |