diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-03-28 14:14:04 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-03-28 14:14:04 -0500 |
commit | 71b86f562b5eb6f94ea00bba060caa64d0137969 (patch) | |
tree | 63d982e09a9cb934fe656afe115031c0a9dc5e4a /fs/gfs2/dir.c | |
parent | 94aabbd99370f738da4f6cb4ea0b94cd9024002f (diff) |
[GFS2] Further updates to dir and logging code
This reduces the size of the directory code by about 3k and gets
readdir() to use the functions which were introduced in the previous
directory code update.
Two memory allocations are merged into one. Eliminates zeroing of some
buffers which were never used before they were initialised by
other data.
There is still scope for further improvement in the directory code.
On the logging side, a hand created mutex has been replaced by a
standard Linux mutex in the log allocation code.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/dir.c')
-rw-r--r-- | fs/gfs2/dir.c | 412 |
1 files changed, 161 insertions, 251 deletions
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index f31f163da1a1..ba3438553f33 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/buffer_head.h> | 60 | #include <linux/buffer_head.h> |
61 | #include <linux/sort.h> | 61 | #include <linux/sort.h> |
62 | #include <linux/gfs2_ondisk.h> | 62 | #include <linux/gfs2_ondisk.h> |
63 | #include <linux/crc32.h> | ||
63 | #include <asm/semaphore.h> | 64 | #include <asm/semaphore.h> |
64 | 65 | ||
65 | #include "gfs2.h" | 66 | #include "gfs2.h" |
@@ -344,7 +345,8 @@ fail: | |||
344 | } | 345 | } |
345 | 346 | ||
346 | typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, | 347 | typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, |
347 | const struct qstr *name); | 348 | const struct qstr *name, |
349 | void *opaque); | ||
348 | 350 | ||
349 | static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, | 351 | static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, |
350 | const struct qstr *name, int ret) | 352 | const struct qstr *name, int ret) |
@@ -358,13 +360,15 @@ static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent, | |||
358 | } | 360 | } |
359 | 361 | ||
360 | static int gfs2_dirent_find(const struct gfs2_dirent *dent, | 362 | static int gfs2_dirent_find(const struct gfs2_dirent *dent, |
361 | const struct qstr *name) | 363 | const struct qstr *name, |
364 | void *opaque) | ||
362 | { | 365 | { |
363 | return __gfs2_dirent_find(dent, name, 1); | 366 | return __gfs2_dirent_find(dent, name, 1); |
364 | } | 367 | } |
365 | 368 | ||
366 | static int gfs2_dirent_prev(const struct gfs2_dirent *dent, | 369 | static int gfs2_dirent_prev(const struct gfs2_dirent *dent, |
367 | const struct qstr *name) | 370 | const struct qstr *name, |
371 | void *opaque) | ||
368 | { | 372 | { |
369 | return __gfs2_dirent_find(dent, name, 2); | 373 | return __gfs2_dirent_find(dent, name, 2); |
370 | } | 374 | } |
@@ -374,7 +378,8 @@ static int gfs2_dirent_prev(const struct gfs2_dirent *dent, | |||
374 | * name->len holds size of block. | 378 | * name->len holds size of block. |
375 | */ | 379 | */ |
376 | static int gfs2_dirent_last(const struct gfs2_dirent *dent, | 380 | static int gfs2_dirent_last(const struct gfs2_dirent *dent, |
377 | const struct qstr *name) | 381 | const struct qstr *name, |
382 | void *opaque) | ||
378 | { | 383 | { |
379 | const char *start = name->name; | 384 | const char *start = name->name; |
380 | const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len); | 385 | const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len); |
@@ -384,17 +389,36 @@ static int gfs2_dirent_last(const struct gfs2_dirent *dent, | |||
384 | } | 389 | } |
385 | 390 | ||
386 | static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, | 391 | static int gfs2_dirent_find_space(const struct gfs2_dirent *dent, |
387 | const struct qstr *name) | 392 | const struct qstr *name, |
393 | void *opaque) | ||
388 | { | 394 | { |
389 | unsigned required = GFS2_DIRENT_SIZE(name->len); | 395 | unsigned required = GFS2_DIRENT_SIZE(name->len); |
390 | unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); | 396 | unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len)); |
391 | unsigned totlen = be16_to_cpu(dent->de_rec_len); | 397 | unsigned totlen = be16_to_cpu(dent->de_rec_len); |
392 | 398 | ||
399 | if (!dent->de_inum.no_addr) | ||
400 | actual = GFS2_DIRENT_SIZE(0); | ||
393 | if ((totlen - actual) >= required) | 401 | if ((totlen - actual) >= required) |
394 | return 1; | 402 | return 1; |
395 | return 0; | 403 | return 0; |
396 | } | 404 | } |
397 | 405 | ||
406 | struct dirent_gather { | ||
407 | const struct gfs2_dirent **pdent; | ||
408 | unsigned offset; | ||
409 | }; | ||
410 | |||
411 | static int gfs2_dirent_gather(const struct gfs2_dirent *dent, | ||
412 | const struct qstr *name, | ||
413 | void *opaque) | ||
414 | { | ||
415 | struct dirent_gather *g = opaque; | ||
416 | if (dent->de_inum.no_addr) { | ||
417 | g->pdent[g->offset++] = dent; | ||
418 | } | ||
419 | return 0; | ||
420 | } | ||
421 | |||
398 | /* | 422 | /* |
399 | * Other possible things to check: | 423 | * Other possible things to check: |
400 | * - Inode located within filesystem size (and on valid block) | 424 | * - Inode located within filesystem size (and on valid block) |
@@ -431,19 +455,12 @@ error: | |||
431 | return -EIO; | 455 | return -EIO; |
432 | } | 456 | } |
433 | 457 | ||
434 | static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, | 458 | static int gfs2_dirent_offset(const void *buf) |
435 | void *buf, | ||
436 | unsigned int len, gfs2_dscan_t scan, | ||
437 | const struct qstr *name) | ||
438 | { | 459 | { |
439 | struct gfs2_meta_header *h = buf; | 460 | const struct gfs2_meta_header *h = buf; |
440 | struct gfs2_dirent *dent, *prev; | 461 | int offset; |
441 | unsigned offset; | ||
442 | unsigned size; | ||
443 | int ret = 0; | ||
444 | 462 | ||
445 | BUG_ON(buf == NULL); | 463 | BUG_ON(buf == NULL); |
446 | BUG_ON(name == NULL); | ||
447 | 464 | ||
448 | switch(be16_to_cpu(h->mh_type)) { | 465 | switch(be16_to_cpu(h->mh_type)) { |
449 | case GFS2_METATYPE_LF: | 466 | case GFS2_METATYPE_LF: |
@@ -455,14 +472,36 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, | |||
455 | default: | 472 | default: |
456 | goto wrong_type; | 473 | goto wrong_type; |
457 | } | 474 | } |
475 | return offset; | ||
476 | wrong_type: | ||
477 | printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u\n", | ||
478 | be16_to_cpu(h->mh_type)); | ||
479 | return -1; | ||
480 | } | ||
458 | 481 | ||
482 | static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, | ||
483 | void *buf, | ||
484 | unsigned int len, gfs2_dscan_t scan, | ||
485 | const struct qstr *name, | ||
486 | void *opaque) | ||
487 | { | ||
488 | struct gfs2_dirent *dent, *prev; | ||
489 | unsigned offset; | ||
490 | unsigned size; | ||
491 | int ret = 0; | ||
492 | |||
493 | ret = gfs2_dirent_offset(buf); | ||
494 | if (ret < 0) | ||
495 | goto consist_inode; | ||
496 | |||
497 | offset = ret; | ||
459 | prev = NULL; | 498 | prev = NULL; |
460 | dent = (struct gfs2_dirent *)(buf + offset); | 499 | dent = (struct gfs2_dirent *)(buf + offset); |
461 | size = be16_to_cpu(dent->de_rec_len); | 500 | size = be16_to_cpu(dent->de_rec_len); |
462 | if (gfs2_check_dirent(dent, offset, size, len, 1)) | 501 | if (gfs2_check_dirent(dent, offset, size, len, 1)) |
463 | goto consist_inode; | 502 | goto consist_inode; |
464 | do { | 503 | do { |
465 | ret = scan(dent, name); | 504 | ret = scan(dent, name, opaque); |
466 | if (ret) | 505 | if (ret) |
467 | break; | 506 | break; |
468 | offset += size; | 507 | offset += size; |
@@ -487,9 +526,6 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, | |||
487 | return ERR_PTR(ret); | 526 | return ERR_PTR(ret); |
488 | } | 527 | } |
489 | 528 | ||
490 | wrong_type: | ||
491 | printk(KERN_WARNING "gfs2_scan_dirent: %p wrong block type %u\n", scan, | ||
492 | be16_to_cpu(h->mh_type)); | ||
493 | consist_inode: | 529 | consist_inode: |
494 | gfs2_consist_inode(inode->u.generic_ip); | 530 | gfs2_consist_inode(inode->u.generic_ip); |
495 | return ERR_PTR(-EIO); | 531 | return ERR_PTR(-EIO); |
@@ -651,7 +687,8 @@ static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode, | |||
651 | const struct qstr *name) | 687 | const struct qstr *name) |
652 | { | 688 | { |
653 | struct gfs2_dirent *dent; | 689 | struct gfs2_dirent *dent; |
654 | dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, gfs2_dirent_find_space, name); | 690 | dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, |
691 | gfs2_dirent_find_space, name, NULL); | ||
655 | if (!dent || IS_ERR(dent)) | 692 | if (!dent || IS_ERR(dent)) |
656 | return dent; | 693 | return dent; |
657 | return gfs2_init_dirent(inode, dent, name, bh); | 694 | return gfs2_init_dirent(inode, dent, name, bh); |
@@ -734,7 +771,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, | |||
734 | return ERR_PTR(error); | 771 | return ERR_PTR(error); |
735 | do { | 772 | do { |
736 | dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, | 773 | dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, |
737 | scan, name); | 774 | scan, name, NULL); |
738 | if (dent) | 775 | if (dent) |
739 | goto got_dent; | 776 | goto got_dent; |
740 | leaf = (struct gfs2_leaf *)bh->b_data; | 777 | leaf = (struct gfs2_leaf *)bh->b_data; |
@@ -751,7 +788,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, | |||
751 | error = gfs2_meta_inode_buffer(ip, &bh); | 788 | error = gfs2_meta_inode_buffer(ip, &bh); |
752 | if (error) | 789 | if (error) |
753 | return ERR_PTR(error); | 790 | return ERR_PTR(error); |
754 | dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name); | 791 | dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL); |
755 | got_dent: | 792 | got_dent: |
756 | *pbh = bh; | 793 | *pbh = bh; |
757 | return dent; | 794 | return dent; |
@@ -764,6 +801,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, | |||
764 | struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); | 801 | struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); |
765 | struct gfs2_leaf *leaf; | 802 | struct gfs2_leaf *leaf; |
766 | struct gfs2_dirent *dent; | 803 | struct gfs2_dirent *dent; |
804 | struct qstr name = { .name = "", .len = 0, .hash = 0 }; | ||
767 | if (!bh) | 805 | if (!bh) |
768 | return NULL; | 806 | return NULL; |
769 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | 807 | gfs2_trans_add_bh(ip->i_gl, bh, 1); |
@@ -775,12 +813,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, | |||
775 | leaf->lf_next = cpu_to_be64(0); | 813 | leaf->lf_next = cpu_to_be64(0); |
776 | memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); | 814 | memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved)); |
777 | dent = (struct gfs2_dirent *)(leaf+1); | 815 | dent = (struct gfs2_dirent *)(leaf+1); |
778 | dent->de_inum.no_formal_ino = cpu_to_be64(0); | 816 | gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); |
779 | dent->de_inum.no_addr = cpu_to_be64(0); | ||
780 | dent->de_hash = cpu_to_be32(0); | ||
781 | dent->de_rec_len = cpu_to_be16(bh->b_size - sizeof(struct gfs2_leaf)); | ||
782 | dent->de_name_len = cpu_to_be16(0); | ||
783 | dent->de_type = cpu_to_be16(0); | ||
784 | *pbh = bh; | 817 | *pbh = bh; |
785 | return leaf; | 818 | return leaf; |
786 | } | 819 | } |
@@ -831,7 +864,7 @@ static int dir_make_exhash(struct inode *inode) | |||
831 | sizeof(struct gfs2_leaf); | 864 | sizeof(struct gfs2_leaf); |
832 | args.name = bh->b_data; | 865 | args.name = bh->b_data; |
833 | dent = gfs2_dirent_scan(dip->i_vnode, bh->b_data, bh->b_size, | 866 | dent = gfs2_dirent_scan(dip->i_vnode, bh->b_data, bh->b_size, |
834 | gfs2_dirent_last, &args); | 867 | gfs2_dirent_last, &args, NULL); |
835 | if (!dent) { | 868 | if (!dent) { |
836 | brelse(bh); | 869 | brelse(bh); |
837 | brelse(dibh); | 870 | brelse(dibh); |
@@ -939,7 +972,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) | |||
939 | lp[x] = cpu_to_be64(bn); | 972 | lp[x] = cpu_to_be64(bn); |
940 | 973 | ||
941 | error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(uint64_t), | 974 | error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(uint64_t), |
942 | half_len * sizeof(uint64_t)); | 975 | half_len * sizeof(uint64_t)); |
943 | if (error != half_len * sizeof(uint64_t)) { | 976 | if (error != half_len * sizeof(uint64_t)) { |
944 | if (error >= 0) | 977 | if (error >= 0) |
945 | error = -EIO; | 978 | error = -EIO; |
@@ -965,7 +998,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) | |||
965 | str.name = (char*)(dent+1); | 998 | str.name = (char*)(dent+1); |
966 | str.len = be16_to_cpu(dent->de_name_len); | 999 | str.len = be16_to_cpu(dent->de_name_len); |
967 | str.hash = be32_to_cpu(dent->de_hash); | 1000 | str.hash = be32_to_cpu(dent->de_hash); |
968 | new = gfs2_dirent_alloc(dip->i_vnode, nbh, &str); | 1001 | new = gfs2_dirent_alloc(inode, nbh, &str); |
969 | if (IS_ERR(new)) { | 1002 | if (IS_ERR(new)) { |
970 | error = PTR_ERR(new); | 1003 | error = PTR_ERR(new); |
971 | break; | 1004 | break; |
@@ -1154,10 +1187,10 @@ static int compare_dents(const void *a, const void *b) | |||
1154 | 1187 | ||
1155 | static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, | 1188 | static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, |
1156 | void *opaque, gfs2_filldir_t filldir, | 1189 | void *opaque, gfs2_filldir_t filldir, |
1157 | struct gfs2_dirent **darr, uint32_t entries, | 1190 | const struct gfs2_dirent **darr, uint32_t entries, |
1158 | int *copied) | 1191 | int *copied) |
1159 | { | 1192 | { |
1160 | struct gfs2_dirent *dent, *dent_next; | 1193 | const struct gfs2_dirent *dent, *dent_next; |
1161 | struct gfs2_inum inum; | 1194 | struct gfs2_inum inum; |
1162 | uint64_t off, off_next; | 1195 | uint64_t off, off_next; |
1163 | unsigned int x, y; | 1196 | unsigned int x, y; |
@@ -1216,189 +1249,74 @@ static int do_filldir_main(struct gfs2_inode *dip, uint64_t *offset, | |||
1216 | return 0; | 1249 | return 0; |
1217 | } | 1250 | } |
1218 | 1251 | ||
1219 | /** | 1252 | static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, |
1220 | * do_filldir_single - Read directory entries out of a single block | 1253 | gfs2_filldir_t filldir, int *copied, |
1221 | * @dip: The GFS2 inode | 1254 | unsigned *depth, u64 leaf_no) |
1222 | * @offset: The offset in the file to read from | ||
1223 | * @opaque: opaque data to pass to filldir | ||
1224 | * @filldir: The function to pass entries to | ||
1225 | * @bh: the block | ||
1226 | * @entries: the number of entries in the block | ||
1227 | * @copied: pointer to int that's non-zero if a entry has been copied out | ||
1228 | * | ||
1229 | * Returns: errno, >0 on exception from filldir | ||
1230 | */ | ||
1231 | |||
1232 | static int do_filldir_single(struct gfs2_inode *dip, uint64_t *offset, | ||
1233 | void *opaque, gfs2_filldir_t filldir, | ||
1234 | struct buffer_head *bh, uint32_t entries, | ||
1235 | int *copied) | ||
1236 | { | 1255 | { |
1237 | struct gfs2_dirent **darr; | 1256 | struct gfs2_inode *ip = inode->u.generic_ip; |
1238 | struct gfs2_dirent *de; | 1257 | struct buffer_head *bh; |
1239 | unsigned int e = 0; | 1258 | struct gfs2_leaf *lf; |
1240 | int error; | 1259 | unsigned entries = 0; |
1241 | 1260 | unsigned leaves = 0; | |
1242 | if (!entries) | 1261 | const struct gfs2_dirent **darr, *dent; |
1243 | return 0; | 1262 | struct dirent_gather g; |
1244 | 1263 | struct buffer_head **larr; | |
1245 | darr = kcalloc(entries, sizeof(struct gfs2_dirent *), GFP_KERNEL); | 1264 | int leaf = 0; |
1246 | if (!darr) | 1265 | int error, i; |
1247 | return -ENOMEM; | 1266 | u64 lfn = leaf_no; |
1248 | 1267 | ||
1249 | dirent_first(dip, bh, &de); | ||
1250 | do { | 1268 | do { |
1251 | if (!de->de_inum.no_addr) | 1269 | error = get_leaf(ip, lfn, &bh); |
1252 | continue; | ||
1253 | if (e >= entries) { | ||
1254 | gfs2_consist_inode(dip); | ||
1255 | error = -EIO; | ||
1256 | goto out; | ||
1257 | } | ||
1258 | darr[e++] = de; | ||
1259 | } while (dirent_next(dip, bh, &de) == 0); | ||
1260 | |||
1261 | if (e != entries) { | ||
1262 | gfs2_consist_inode(dip); | ||
1263 | error = -EIO; | ||
1264 | goto out; | ||
1265 | } | ||
1266 | |||
1267 | error = do_filldir_main(dip, offset, opaque, filldir, darr, | ||
1268 | entries, copied); | ||
1269 | |||
1270 | out: | ||
1271 | kfree(darr); | ||
1272 | |||
1273 | return error; | ||
1274 | } | ||
1275 | |||
1276 | /** | ||
1277 | * do_filldir_multi - Read directory entries out of a linked leaf list | ||
1278 | * @dip: The GFS2 inode | ||
1279 | * @offset: The offset in the file to read from | ||
1280 | * @opaque: opaque data to pass to filldir | ||
1281 | * @filldir: The function to pass entries to | ||
1282 | * @bh: the first leaf in the list | ||
1283 | * @copied: pointer to int that's non-zero if a entry has been copied out | ||
1284 | * | ||
1285 | * Returns: errno, >0 on exception from filldir | ||
1286 | */ | ||
1287 | |||
1288 | static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, | ||
1289 | void *opaque, gfs2_filldir_t filldir, | ||
1290 | struct buffer_head *bh, int *copied) | ||
1291 | { | ||
1292 | struct buffer_head **larr = NULL; | ||
1293 | struct gfs2_dirent **darr; | ||
1294 | struct gfs2_leaf *leaf; | ||
1295 | struct buffer_head *tmp_bh; | ||
1296 | struct gfs2_dirent *de; | ||
1297 | unsigned int entries, e = 0; | ||
1298 | unsigned int leaves = 0, l = 0; | ||
1299 | unsigned int x; | ||
1300 | uint64_t ln; | ||
1301 | int error = 0; | ||
1302 | |||
1303 | /* Count leaves and entries */ | ||
1304 | |||
1305 | leaf = (struct gfs2_leaf *)bh->b_data; | ||
1306 | entries = be16_to_cpu(leaf->lf_entries); | ||
1307 | ln = be64_to_cpu(leaf->lf_next); | ||
1308 | |||
1309 | while (ln) { | ||
1310 | error = get_leaf(dip, ln, &tmp_bh); | ||
1311 | if (error) | 1270 | if (error) |
1312 | return error; | 1271 | goto out; |
1313 | 1272 | lf = (struct gfs2_leaf *)bh->b_data; | |
1314 | leaf = (struct gfs2_leaf *)tmp_bh->b_data; | 1273 | if (leaves == 0) |
1315 | if (leaf->lf_entries) { | 1274 | *depth = be16_to_cpu(lf->lf_depth); |
1316 | entries += be16_to_cpu(leaf->lf_entries); | 1275 | entries += be16_to_cpu(lf->lf_entries); |
1317 | leaves++; | 1276 | leaves++; |
1318 | } | 1277 | lfn = be64_to_cpu(lf->lf_next); |
1319 | ln = be64_to_cpu(leaf->lf_next); | 1278 | brelse(bh); |
1320 | 1279 | } while(lfn); | |
1321 | brelse(tmp_bh); | ||
1322 | } | ||
1323 | 1280 | ||
1324 | if (!entries) | 1281 | if (!entries) |
1325 | return 0; | 1282 | return 0; |
1326 | 1283 | ||
1327 | if (leaves) { | 1284 | error = -ENOMEM; |
1328 | larr = kcalloc(leaves, sizeof(struct buffer_head *),GFP_KERNEL); | 1285 | larr = kmalloc((leaves + entries) * sizeof(void*), GFP_KERNEL); |
1329 | if (!larr) | 1286 | if (!larr) |
1330 | return -ENOMEM; | 1287 | goto out; |
1331 | } | 1288 | darr = (const struct gfs2_dirent **)(larr + leaves); |
1332 | 1289 | g.pdent = darr; | |
1333 | darr = kcalloc(entries, sizeof(struct gfs2_dirent *), GFP_KERNEL); | 1290 | g.offset = 0; |
1334 | if (!darr) { | 1291 | lfn = leaf_no; |
1335 | kfree(larr); | ||
1336 | return -ENOMEM; | ||
1337 | } | ||
1338 | |||
1339 | leaf = (struct gfs2_leaf *)bh->b_data; | ||
1340 | if (leaf->lf_entries) { | ||
1341 | dirent_first(dip, bh, &de); | ||
1342 | do { | ||
1343 | if (!de->de_inum.no_addr) | ||
1344 | continue; | ||
1345 | if (e >= entries) { | ||
1346 | gfs2_consist_inode(dip); | ||
1347 | error = -EIO; | ||
1348 | goto out; | ||
1349 | } | ||
1350 | darr[e++] = de; | ||
1351 | } while (dirent_next(dip, bh, &de) == 0); | ||
1352 | } | ||
1353 | ln = be64_to_cpu(leaf->lf_next); | ||
1354 | 1292 | ||
1355 | while (ln) { | 1293 | do { |
1356 | error = get_leaf(dip, ln, &tmp_bh); | 1294 | error = get_leaf(ip, lfn, &bh); |
1357 | if (error) | 1295 | if (error) |
1358 | goto out; | 1296 | goto out_kfree; |
1359 | 1297 | lf = (struct gfs2_leaf *)bh->b_data; | |
1360 | leaf = (struct gfs2_leaf *)tmp_bh->b_data; | 1298 | lfn = be64_to_cpu(lf->lf_next); |
1361 | if (leaf->lf_entries) { | 1299 | if (lf->lf_entries) { |
1362 | dirent_first(dip, tmp_bh, &de); | 1300 | dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, |
1363 | do { | 1301 | gfs2_dirent_gather, NULL, &g); |
1364 | if (!de->de_inum.no_addr) | 1302 | error = PTR_ERR(dent); |
1365 | continue; | 1303 | if (IS_ERR(dent)) { |
1366 | if (e >= entries) { | 1304 | goto out_kfree; |
1367 | gfs2_consist_inode(dip); | 1305 | } |
1368 | error = -EIO; | 1306 | error = 0; |
1369 | goto out; | 1307 | larr[leaf++] = bh; |
1370 | } | ||
1371 | darr[e++] = de; | ||
1372 | } while (dirent_next(dip, tmp_bh, &de) == 0); | ||
1373 | |||
1374 | larr[l++] = tmp_bh; | ||
1375 | |||
1376 | ln = be64_to_cpu(leaf->lf_next); | ||
1377 | } else { | 1308 | } else { |
1378 | ln = be64_to_cpu(leaf->lf_next); | 1309 | brelse(bh); |
1379 | brelse(tmp_bh); | ||
1380 | } | 1310 | } |
1381 | } | 1311 | } while(lfn); |
1382 | 1312 | ||
1383 | if (gfs2_assert_withdraw(dip->i_sbd, l == leaves)) { | 1313 | error = do_filldir_main(ip, offset, opaque, filldir, darr, |
1384 | error = -EIO; | ||
1385 | goto out; | ||
1386 | } | ||
1387 | if (e != entries) { | ||
1388 | gfs2_consist_inode(dip); | ||
1389 | error = -EIO; | ||
1390 | goto out; | ||
1391 | } | ||
1392 | |||
1393 | error = do_filldir_main(dip, offset, opaque, filldir, darr, | ||
1394 | entries, copied); | 1314 | entries, copied); |
1395 | 1315 | out_kfree: | |
1396 | out: | 1316 | for(i = 0; i < leaf; i++) |
1397 | kfree(darr); | 1317 | brelse(larr[i]); |
1398 | for (x = 0; x < l; x++) | ||
1399 | brelse(larr[x]); | ||
1400 | kfree(larr); | 1318 | kfree(larr); |
1401 | 1319 | out: | |
1402 | return error; | 1320 | return error; |
1403 | } | 1321 | } |
1404 | 1322 | ||
@@ -1412,18 +1330,18 @@ static int do_filldir_multi(struct gfs2_inode *dip, uint64_t *offset, | |||
1412 | * Returns: errno | 1330 | * Returns: errno |
1413 | */ | 1331 | */ |
1414 | 1332 | ||
1415 | static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, | 1333 | static int dir_e_read(struct inode *inode, uint64_t *offset, void *opaque, |
1416 | gfs2_filldir_t filldir) | 1334 | gfs2_filldir_t filldir) |
1417 | { | 1335 | { |
1336 | struct gfs2_inode *dip = inode->u.generic_ip; | ||
1418 | struct gfs2_sbd *sdp = dip->i_sbd; | 1337 | struct gfs2_sbd *sdp = dip->i_sbd; |
1419 | struct buffer_head *bh; | 1338 | uint32_t hsize, len = 0; |
1420 | struct gfs2_leaf *leaf; | ||
1421 | uint32_t hsize, len; | ||
1422 | uint32_t ht_offset, lp_offset, ht_offset_cur = -1; | 1339 | uint32_t ht_offset, lp_offset, ht_offset_cur = -1; |
1423 | uint32_t hash, index; | 1340 | uint32_t hash, index; |
1424 | uint64_t *lp; | 1341 | uint64_t *lp; |
1425 | int copied = 0; | 1342 | int copied = 0; |
1426 | int error = 0; | 1343 | int error = 0; |
1344 | unsigned depth; | ||
1427 | 1345 | ||
1428 | hsize = 1 << dip->i_di.di_depth; | 1346 | hsize = 1 << dip->i_di.di_depth; |
1429 | if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { | 1347 | if (hsize * sizeof(uint64_t) != dip->i_di.di_size) { |
@@ -1454,61 +1372,66 @@ static int dir_e_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, | |||
1454 | ht_offset_cur = ht_offset; | 1372 | ht_offset_cur = ht_offset; |
1455 | } | 1373 | } |
1456 | 1374 | ||
1457 | error = get_leaf(dip, be64_to_cpu(lp[lp_offset]), &bh); | 1375 | error = gfs2_dir_read_leaf(inode, offset, opaque, filldir, |
1376 | &copied, &depth, | ||
1377 | be64_to_cpu(lp[lp_offset])); | ||
1458 | if (error) | 1378 | if (error) |
1459 | goto out; | 1379 | break; |
1460 | |||
1461 | leaf = (struct gfs2_leaf *)bh->b_data; | ||
1462 | if (leaf->lf_next) | ||
1463 | error = do_filldir_multi(dip, offset, opaque, filldir, | ||
1464 | bh, &copied); | ||
1465 | else | ||
1466 | error = do_filldir_single(dip, offset, opaque, filldir, | ||
1467 | bh, | ||
1468 | be16_to_cpu(leaf->lf_entries), | ||
1469 | &copied); | ||
1470 | |||
1471 | brelse(bh); | ||
1472 | |||
1473 | if (error) { | ||
1474 | if (error > 0) | ||
1475 | error = 0; | ||
1476 | goto out; | ||
1477 | } | ||
1478 | 1380 | ||
1479 | len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); | 1381 | len = 1 << (dip->i_di.di_depth - depth); |
1480 | index = (index & ~(len - 1)) + len; | 1382 | index = (index & ~(len - 1)) + len; |
1481 | } | 1383 | } |
1482 | 1384 | ||
1483 | out: | 1385 | out: |
1484 | kfree(lp); | 1386 | kfree(lp); |
1485 | 1387 | if (error > 0) | |
1388 | error = 0; | ||
1486 | return error; | 1389 | return error; |
1487 | } | 1390 | } |
1488 | 1391 | ||
1489 | static int dir_l_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, | 1392 | int gfs2_dir_read(struct inode *inode, uint64_t *offset, void *opaque, |
1490 | gfs2_filldir_t filldir) | 1393 | gfs2_filldir_t filldir) |
1491 | { | 1394 | { |
1395 | struct gfs2_inode *dip = inode->u.generic_ip; | ||
1396 | struct dirent_gather g; | ||
1397 | const struct gfs2_dirent **darr, *dent; | ||
1492 | struct buffer_head *dibh; | 1398 | struct buffer_head *dibh; |
1493 | int copied = 0; | 1399 | int copied = 0; |
1494 | int error; | 1400 | int error; |
1495 | 1401 | ||
1402 | if (!dip->i_di.di_entries) | ||
1403 | return 0; | ||
1404 | |||
1405 | if (dip->i_di.di_flags & GFS2_DIF_EXHASH) | ||
1406 | return dir_e_read(inode, offset, opaque, filldir); | ||
1407 | |||
1496 | if (!gfs2_is_stuffed(dip)) { | 1408 | if (!gfs2_is_stuffed(dip)) { |
1497 | gfs2_consist_inode(dip); | 1409 | gfs2_consist_inode(dip); |
1498 | return -EIO; | 1410 | return -EIO; |
1499 | } | 1411 | } |
1500 | 1412 | ||
1501 | if (!dip->i_di.di_entries) | ||
1502 | return 0; | ||
1503 | |||
1504 | error = gfs2_meta_inode_buffer(dip, &dibh); | 1413 | error = gfs2_meta_inode_buffer(dip, &dibh); |
1505 | if (error) | 1414 | if (error) |
1506 | return error; | 1415 | return error; |
1507 | 1416 | ||
1508 | error = do_filldir_single(dip, offset, | 1417 | error = -ENOMEM; |
1509 | opaque, filldir, | 1418 | darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *), |
1510 | dibh, dip->i_di.di_entries, | 1419 | GFP_KERNEL); |
1511 | &copied); | 1420 | if (darr) { |
1421 | g.pdent = darr; | ||
1422 | g.offset = 0; | ||
1423 | dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size, | ||
1424 | gfs2_dirent_gather, NULL, &g); | ||
1425 | if (IS_ERR(dent)) { | ||
1426 | error = PTR_ERR(dent); | ||
1427 | goto out; | ||
1428 | } | ||
1429 | error = do_filldir_main(dip, offset, opaque, filldir, darr, | ||
1430 | dip->i_di.di_entries, &copied); | ||
1431 | out: | ||
1432 | kfree(darr); | ||
1433 | } | ||
1434 | |||
1512 | if (error > 0) | 1435 | if (error > 0) |
1513 | error = 0; | 1436 | error = 0; |
1514 | 1437 | ||
@@ -1694,7 +1617,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) | |||
1694 | return PTR_ERR(dent); | 1617 | return PTR_ERR(dent); |
1695 | } | 1618 | } |
1696 | /* If not first in block, adjust pointers accordingly */ | 1619 | /* If not first in block, adjust pointers accordingly */ |
1697 | if (gfs2_dirent_find(dent, name) == 0) { | 1620 | if (gfs2_dirent_find(dent, name, NULL) == 0) { |
1698 | prev = dent; | 1621 | prev = dent; |
1699 | dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len)); | 1622 | dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len)); |
1700 | } | 1623 | } |
@@ -1724,19 +1647,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) | |||
1724 | return error; | 1647 | return error; |
1725 | } | 1648 | } |
1726 | 1649 | ||
1727 | int gfs2_dir_read(struct gfs2_inode *dip, uint64_t *offset, void *opaque, | ||
1728 | gfs2_filldir_t filldir) | ||
1729 | { | ||
1730 | int error; | ||
1731 | |||
1732 | if (dip->i_di.di_flags & GFS2_DIF_EXHASH) | ||
1733 | error = dir_e_read(dip, offset, opaque, filldir); | ||
1734 | else | ||
1735 | error = dir_l_read(dip, offset, opaque, filldir); | ||
1736 | |||
1737 | return error; | ||
1738 | } | ||
1739 | |||
1740 | /** | 1650 | /** |
1741 | * gfs2_dir_mvino - Change inode number of directory entry | 1651 | * gfs2_dir_mvino - Change inode number of directory entry |
1742 | * @dip: The GFS2 inode | 1652 | * @dip: The GFS2 inode |