diff options
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 |