Message ID | 4e836f2ec21820d3be2022fa2a6d6a441fdff4b8.1308397267.git.list.btrfs@jan-o-sch.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Sat, Jun 18, 2011 at 01:45:58PM +0200, Jan Schmidt wrote: > +/* > + * returns 0 if the path could be dumped (probably truncated) > + * returns <0 in case of an error > + */ > +static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, > + struct extent_buffer *eb_ir, int slot, > + void *ctx) > +{ > + struct inode_fs_paths *ipath = ctx; > + struct extent_buffer *eb_i = ipath->eb; > + u32 path_len; > + char *fs_path; > + > + if (ipath->bytes_left < 2) > + return -EOVERFLOW; > + > + *ipath->dest++ = ' '; > + --ipath->bytes_left; this actually prepends a space before the first entry. I've played a bit with this interface, it's the missing piece to implement the 'inode nubmer -> directory names' search :) All the names are placed into one buffer, 4k sized, separated by a space. Not all files fit, so I suggest to print one filename at a time. Me-user wants to see all the filenames, even if the list is potentially long. I've also noticed that in iref_to_path() 130 len = btrfs_inode_ref_name_len(eb, iref); returns very large values, which do not fit into the 4k buffer and the function returns. When trying to print the data by read_extent_buffer to a temporary array, a pagefault occurs (and seems to come from reading the extent buffer). The numbers are like 19000 or higher, which are way above path or filename maximum size. I don't think this is the intentional behaviour, it relies on some side effect rather than clear logic. Example: ipath buffer and scratch are 32K, each, ie. the overly sized ref_name_len will fit there: [ 8766.928232] btrfs: ino2name: 266 p1/ [ 8767.440964] i2p: [4] namelen 10, left 32766 [ 8767.446417] i2p: [7] path: [ 8767.450445] i2p: [4] namelen 2, left 32755 [ 8767.455733] i2p: [7] path: / [ 8767.459834] i2p: [2] p1/ [ 8767.463593] i2p: [4] namelen 0, left 32752 [ 8767.468903] i2p: [7] path: [ 8767.472908] i2p: [4] namelen 2, left 32751 [ 8767.478188] i2p: [7] path: / [ 8767.482280] i2p: [2] p1/ [ 8767.486024] i2p: [4] namelen 0, left 32748 [ 8767.491293] i2p: [7] path: [ 8767.495283] i2p: [4] namelen 2, left 32747 [ 8767.500587] i2p: [7] path: / [ 8767.504680] i2p: [2] p1/ [ 8767.508430] i2p: [4] namelen 0, left 32744 [ 8767.513708] i2p: [7] path: [ 8767.517702] i2p: [4] namelen 2, left 32743 [ 8767.522969] i2p: [7] path: / [ 8767.527042] i2p: [2] p1/ [ 8767.530787] i2p: [4] namelen 0, left 32740 [ 8767.536049] i2p: [7] path: [ 8767.539991] i2p: [4] namelen 2, left 32739 [ 8767.545282] i2p: [7] path: / [ 8767.549374] i2p: [2] p1/ [ 8767.553109] i2p: [4] namelen 0, left 32736 [ 8767.558377] i2p: [7] path: [ 8767.562354] i2p: [4] namelen 2, left 32735 [ 8767.567615] i2p: [7] path: / [ 8767.571713] i2p: [2] p1/ [ 8767.575443] i2p: [4] namelen 0, left 32732 [ 8767.580701] i2p: [7] path: [ 8767.584678] i2p: [4] namelen 2, left 32731 [ 8767.589933] i2p: [7] path: / [ 8767.594007] i2p: [2] p1/ [ 8767.597713] i2p: [4] namelen 0, left 32728 [ 8767.602908] i2p: [7] path: [ 8767.606832] i2p: [4] namelen 2, left 32727 [ 8767.612030] i2p: [7] path: / [ 8767.616050] i2p: [2] p1/ [ 8767.619676] i2p: [4] namelen 0, left 32724 [ 8767.624873] i2p: [7] path: [ 8767.628782] i2p: [4] namelen 2, left 32723 [ 8767.633970] i2p: [7] path: / [ 8767.637962] i2p: [2] p1/ [ 8767.641639] i2p: [4] namelen 0, left 32720 [ 8767.646838] i2p: [7] path: [ 8767.650757] i2p: [4] namelen 2, left 32719 [ 8767.655952] i2p: [7] path: / [ 8767.659940] i2p: [2] p1/ [ 8767.663604] i2p: [4] namelen 0, left 32716 [ 8767.668790] i2p: [7] path: [ 8767.672696] i2p: [4] namelen 2, left 32715 [ 8767.677881] i2p: [7] path: / [ 8767.681878] i2p: [2] p1/ [ 8767.685549] i2p: [4] namelen 0, left 32712 [ 8767.690742] i2p: [7] path: [ 8767.694655] i2p: [4] namelen 2, left 32711 [ 8767.699843] i2p: [7] path: / [ 8767.703840] i2p: [2] p1/ [ 8767.707520] i2p: [4] namelen 19967, left 32708 [ 8767.713057] i2p: [7] path: [ 8767.716955] BUG: unable to handle kernel NULL pointer dereference at (null) [ 8767.720932] IP: [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] [ 8767.720932] PGD 77bd0067 PUD 79d35067 PMD 0 [ 8767.720932] Oops: 0000 [#1] SMP [ 8767.720932] CPU 1 [ 8767.720932] Modules linked in: btrfs loop [ 8767.720932] [ 8767.720932] Pid: 10859, comm: btrfs-ino2path Not tainted 3.0.0-rc3-default+ #75 Intel Corporation Santa Rosa platform/Matanzas [ 8767.720932] RIP: 0010:[<ffffffffa005f1d2>] [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] [ 8767.720932] RSP: 0018:ffff880074acbc58 EFLAGS: 00010202 [ 8767.720932] RAX: 0000000000000000 RBX: 0000000000003deb RCX: 0000000000001000 [ 8767.720932] RDX: 00000000000001e0 RSI: 0000000000000000 RDI: 0000000000000246 [ 8767.720932] RBP: ffff880074acbcb8 R08: 0000000000000000 R09: 0000000000000001 [ 8767.720932] R10: 0000000000000000 R11: 0000000000001c04 R12: 0000000000000002 [ 8767.720932] R13: 0000000000000000 R14: ffff880079bac1d9 R15: ffff880074acbfd8 [ 8767.720932] FS: 00007f1399198740(0000) GS:ffff88007de00000(0000) knlGS:0000000000000000 [ 8767.720932] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 8767.720932] CR2: 0000000000000000 CR3: 0000000074b13000 CR4: 00000000000006e0 [ 8767.720932] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 8767.720932] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 8767.720932] Process btrfs-ino2path (pid: 10859, threadinfo ffff880074aca000, task ffff880077085340) [ 8767.720932] Stack: [ 8767.720932] ffffffffa005f282 ffffffff81b21e74 ffff88002f2ef668 0000000000000000 [ 8767.720932] ffff880073f94dd8 ffff880074acbfd8 ffff8800780bd000 00000000000031c5 [ 8767.720932] 00000000000031c5 0000000000000104 ffff880073f94dd8 ffff880074132130 [ 8767.720932] Call Trace: [ 8767.720932] [<ffffffffa005f282>] ? read_extent_buffer+0x152/0x220 [btrfs] [ 8767.720932] [<ffffffff81b21e74>] ? printk+0x68/0x6c [ 8767.720932] [<ffffffffa008924d>] inode_to_path+0x10d/0x2d0 [btrfs] [ 8767.720932] [<ffffffffa0089883>] paths_from_inode+0xe3/0x120 [btrfs] [ 8767.720932] [<ffffffffa006de9f>] btrfs_ioctl+0xb5f/0xf80 [btrfs] [ 8767.720932] [<ffffffff810d3e55>] ? trace_hardirqs_on_caller+0x155/0x1a0 [ 8767.720932] [<ffffffff81080e4c>] ? finish_task_switch+0x7c/0x110 [ 8767.720932] [<ffffffff81080e0f>] ? finish_task_switch+0x3f/0x110 [ 8767.720932] [<ffffffff81193578>] do_vfs_ioctl+0x98/0x570 [ 8767.720932] [<ffffffff811828be>] ? fget_light+0x33e/0x430 [ 8767.720932] [<ffffffff81b2ed3a>] ? sysret_check+0x2e/0x69 [ 8767.720932] [<ffffffff81193a9f>] sys_ioctl+0x4f/0x80 [ 8767.720932] [<ffffffff81b2ed02>] system_call_fastpath+0x16/0x1b [ 8767.720932] Code: 66 0f 1f 84 00 00 00 00 00 48 8b 55 c0 48 8b 42 30 48 89 c6 b9 00 10 00 00 4c 29 e9 48 39 d9 48 0f 47 cb 41 83 87 44 e0 ff ff 01 [ 8767.720932] 8b 00 48 c1 e8 2d 48 89 c2 48 c1 ea 08 48 8b 3c d5 00 95 f7 [ 8767.720932] RIP [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] [ 8767.720932] RSP <ffff880074acbc58> [ 8767.720932] CR2: 0000000000000000 [ 8768.067994] ---[ end trace b9afe483f6289b6f ]--- Let's see the inode 266 by hand: dsterba@:/mnt/sda10$ find . -inum 266 ./p1/d6/d7/d1f/c41 something is wrong ... The file hierarchy is a leftover from fs_mark runs, directories to depth 9, short names. david > + > + fs_path = iref_to_path(ipath->fs_root, ipath->path, iref, eb_i, > + inum, ipath->scratch_buf, ipath->bytes_left); > + if (IS_ERR(fs_path)) > + return PTR_ERR(fs_path); > + path_len = ipath->scratch_buf + ipath->bytes_left - fs_path - 1; > + if (path_len+1 > ipath->bytes_left) > + return -EOVERFLOW; > + memcpy(ipath->dest, fs_path, path_len+1); > + ipath->bytes_left -= path_len; > + ipath->dest += path_len; > + > + return 0; > +} > + > +int paths_from_inode(u64 inum, struct inode_fs_paths *ipath) > +{ > + return iterate_irefs(inum, ipath->eb, ipath->fs_root, ipath->path, > + inode_to_path, ipath); > +} -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 21.06.2011 16:37, David Sterba wrote: > On Sat, Jun 18, 2011 at 01:45:58PM +0200, Jan Schmidt wrote: >> +/* >> + * returns 0 if the path could be dumped (probably truncated) >> + * returns <0 in case of an error >> + */ >> +static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, >> + struct extent_buffer *eb_ir, int slot, >> + void *ctx) >> +{ >> + struct inode_fs_paths *ipath = ctx; >> + struct extent_buffer *eb_i = ipath->eb; >> + u32 path_len; >> + char *fs_path; >> + >> + if (ipath->bytes_left < 2) >> + return -EOVERFLOW; >> + >> + *ipath->dest++ = ' '; >> + --ipath->bytes_left; > > this actually prepends a space before the first entry. Which is fine because we print the buffer with "(path:%s)" in scrub.c:257, and a space is well appropriate there. That way we don't need to handle the first path differently. (Makes only sense as long as we stick to multiple files per line). > I've played a bit with this interface, it's the missing piece to > implement the 'inode nubmer -> directory names' search :) > All the names are placed into one buffer, 4k sized, separated by a > space. Not all files fit, so I suggest to print one filename at a time. It does print all references to one *inode* to the same buffer, right. If there are more inodes refering to that extent, those paths are printed to a separate buffer. You can make some reflinks to try that out. > Me-user wants to see all the filenames, even if the list is potentially > long. Well, maybe. However, for me, the number of hardlinks created is either very low, or I know why a file has a whole bunch of hardlinks myself (e.g. some kind of backup strategy). In both cases, this approach would fit. I don't want to see some thousands of printk messages for that one file I know to have a lot of hardlinks - maybe even missing some error of a non-hardlinked file due to rate limiting. On the other hand, you could argue, when I deliberately create a bunch of reflinks, I will get the same problem. Another approach would be to put it all into one buffer, no matter which inode it comes from. Either way shouldn't be hard to accomplish. > I've also noticed that in iref_to_path() > > 130 len = btrfs_inode_ref_name_len(eb, iref); > > returns very large values, which do not fit into the 4k buffer and the > function returns. When trying to print the data by read_extent_buffer to > a temporary array, a pagefault occurs (and seems to come from reading > the extent buffer). The numbers are like 19000 or higher, which are way > above path or filename maximum size. I don't think this is the > intentional behaviour, it relies on some side effect rather than clear > logic. Something is going wrong here: > Example: > ipath buffer and scratch are 32K, each, ie. the overly sized > ref_name_len will fit there: > > [ 8766.928232] btrfs: ino2name: 266 p1/ > [ 8767.440964] i2p: [4] namelen 10, left 32766 > [ 8767.446417] i2p: [7] path: > [ 8767.450445] i2p: [4] namelen 2, left 32755 > [ 8767.455733] i2p: [7] path: / > [ 8767.459834] i2p: [2] p1/ Do I get that right? This is inode 266, which should refer to ./p1/d6/d7/d1f/c41 (as you state below). Already on second iteration, we're at something named "pl", which shouldn't happen as we construct the path bottom-up. And those namelen 0 in the following lines shouldn't happen, either. Furthermore, the path should change on every iteration (I guess, that might depend on the printk behind, of course). > [ 8767.463593] i2p: [4] namelen 0, left 32752 > [ 8767.468903] i2p: [7] path: > [ 8767.472908] i2p: [4] namelen 2, left 32751 > [ 8767.478188] i2p: [7] path: / > [ 8767.482280] i2p: [2] p1/ > [ 8767.486024] i2p: [4] namelen 0, left 32748 > [ 8767.491293] i2p: [7] path: > [ 8767.495283] i2p: [4] namelen 2, left 32747 > [ 8767.500587] i2p: [7] path: / > [ 8767.504680] i2p: [2] p1/ > [ 8767.508430] i2p: [4] namelen 0, left 32744 > [ 8767.513708] i2p: [7] path: > [ 8767.517702] i2p: [4] namelen 2, left 32743 > [ 8767.522969] i2p: [7] path: / > [ 8767.527042] i2p: [2] p1/ > [ 8767.530787] i2p: [4] namelen 0, left 32740 > [ 8767.536049] i2p: [7] path: > [ 8767.539991] i2p: [4] namelen 2, left 32739 > [ 8767.545282] i2p: [7] path: / > [ 8767.549374] i2p: [2] p1/ > [ 8767.553109] i2p: [4] namelen 0, left 32736 > [ 8767.558377] i2p: [7] path: > [ 8767.562354] i2p: [4] namelen 2, left 32735 > [ 8767.567615] i2p: [7] path: / > [ 8767.571713] i2p: [2] p1/ > [ 8767.575443] i2p: [4] namelen 0, left 32732 > [ 8767.580701] i2p: [7] path: > [ 8767.584678] i2p: [4] namelen 2, left 32731 > [ 8767.589933] i2p: [7] path: / > [ 8767.594007] i2p: [2] p1/ > [ 8767.597713] i2p: [4] namelen 0, left 32728 > [ 8767.602908] i2p: [7] path: > [ 8767.606832] i2p: [4] namelen 2, left 32727 > [ 8767.612030] i2p: [7] path: / > [ 8767.616050] i2p: [2] p1/ > [ 8767.619676] i2p: [4] namelen 0, left 32724 > [ 8767.624873] i2p: [7] path: > [ 8767.628782] i2p: [4] namelen 2, left 32723 > [ 8767.633970] i2p: [7] path: / > [ 8767.637962] i2p: [2] p1/ > [ 8767.641639] i2p: [4] namelen 0, left 32720 > [ 8767.646838] i2p: [7] path: > [ 8767.650757] i2p: [4] namelen 2, left 32719 > [ 8767.655952] i2p: [7] path: / > [ 8767.659940] i2p: [2] p1/ > [ 8767.663604] i2p: [4] namelen 0, left 32716 > [ 8767.668790] i2p: [7] path: > [ 8767.672696] i2p: [4] namelen 2, left 32715 > [ 8767.677881] i2p: [7] path: / > [ 8767.681878] i2p: [2] p1/ > [ 8767.685549] i2p: [4] namelen 0, left 32712 > [ 8767.690742] i2p: [7] path: > [ 8767.694655] i2p: [4] namelen 2, left 32711 > [ 8767.699843] i2p: [7] path: / > [ 8767.703840] i2p: [2] p1/ > [ 8767.707520] i2p: [4] namelen 19967, left 32708 > [ 8767.713057] i2p: [7] path: > [ 8767.716955] BUG: unable to handle kernel NULL pointer dereference at (null) > [ 8767.720932] IP: [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] > [ 8767.720932] PGD 77bd0067 PUD 79d35067 PMD 0 > [ 8767.720932] Oops: 0000 [#1] SMP > [ 8767.720932] CPU 1 > [ 8767.720932] Modules linked in: btrfs loop > [ 8767.720932] > [ 8767.720932] Pid: 10859, comm: btrfs-ino2path Not tainted 3.0.0-rc3-default+ #75 Intel Corporation Santa Rosa platform/Matanzas > [ 8767.720932] RIP: 0010:[<ffffffffa005f1d2>] [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] > [ 8767.720932] RSP: 0018:ffff880074acbc58 EFLAGS: 00010202 > [ 8767.720932] RAX: 0000000000000000 RBX: 0000000000003deb RCX: 0000000000001000 > [ 8767.720932] RDX: 00000000000001e0 RSI: 0000000000000000 RDI: 0000000000000246 > [ 8767.720932] RBP: ffff880074acbcb8 R08: 0000000000000000 R09: 0000000000000001 > [ 8767.720932] R10: 0000000000000000 R11: 0000000000001c04 R12: 0000000000000002 > [ 8767.720932] R13: 0000000000000000 R14: ffff880079bac1d9 R15: ffff880074acbfd8 > [ 8767.720932] FS: 00007f1399198740(0000) GS:ffff88007de00000(0000) knlGS:0000000000000000 > [ 8767.720932] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b > [ 8767.720932] CR2: 0000000000000000 CR3: 0000000074b13000 CR4: 00000000000006e0 > [ 8767.720932] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 > [ 8767.720932] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 > [ 8767.720932] Process btrfs-ino2path (pid: 10859, threadinfo ffff880074aca000, task ffff880077085340) > [ 8767.720932] Stack: > [ 8767.720932] ffffffffa005f282 ffffffff81b21e74 ffff88002f2ef668 0000000000000000 > [ 8767.720932] ffff880073f94dd8 ffff880074acbfd8 ffff8800780bd000 00000000000031c5 > [ 8767.720932] 00000000000031c5 0000000000000104 ffff880073f94dd8 ffff880074132130 > [ 8767.720932] Call Trace: > [ 8767.720932] [<ffffffffa005f282>] ? read_extent_buffer+0x152/0x220 [btrfs] > [ 8767.720932] [<ffffffff81b21e74>] ? printk+0x68/0x6c > [ 8767.720932] [<ffffffffa008924d>] inode_to_path+0x10d/0x2d0 [btrfs] > [ 8767.720932] [<ffffffffa0089883>] paths_from_inode+0xe3/0x120 [btrfs] > [ 8767.720932] [<ffffffffa006de9f>] btrfs_ioctl+0xb5f/0xf80 [btrfs] > [ 8767.720932] [<ffffffff810d3e55>] ? trace_hardirqs_on_caller+0x155/0x1a0 > [ 8767.720932] [<ffffffff81080e4c>] ? finish_task_switch+0x7c/0x110 > [ 8767.720932] [<ffffffff81080e0f>] ? finish_task_switch+0x3f/0x110 > [ 8767.720932] [<ffffffff81193578>] do_vfs_ioctl+0x98/0x570 > [ 8767.720932] [<ffffffff811828be>] ? fget_light+0x33e/0x430 > [ 8767.720932] [<ffffffff81b2ed3a>] ? sysret_check+0x2e/0x69 > [ 8767.720932] [<ffffffff81193a9f>] sys_ioctl+0x4f/0x80 > [ 8767.720932] [<ffffffff81b2ed02>] system_call_fastpath+0x16/0x1b > [ 8767.720932] Code: 66 0f 1f 84 00 00 00 00 00 48 8b 55 c0 48 8b 42 30 48 89 c6 b9 00 10 00 00 4c 29 e9 48 39 d9 48 0f 47 cb 41 83 87 44 e0 ff ff 01 > [ 8767.720932] 8b 00 48 c1 e8 2d 48 89 c2 48 c1 ea 08 48 8b 3c d5 00 95 f7 > [ 8767.720932] RIP [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] > [ 8767.720932] RSP <ffff880074acbc58> > [ 8767.720932] CR2: 0000000000000000 > [ 8768.067994] ---[ end trace b9afe483f6289b6f ]--- > > Let's see the inode 266 by hand: > > dsterba@:/mnt/sda10$ find . -inum 266 > ./p1/d6/d7/d1f/c41 > > something is wrong ... > > The file hierarchy is a leftover from fs_mark runs, directories to depth 9, > short names. Sounds like I missed something. There is definitely a bug in the path construction or lower iteration code I added. I used a fs_mark created btrfs for my tests as well, but those worked well. If you could share that file system (image or debug-tree output), that'd be great help debugging this. Thanks! Jan -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 21.06.2011 17:12, Jan Schmidt wrote: > On 21.06.2011 16:37, David Sterba wrote: >> [...] > Something is going wrong here: > >> Example: >> ipath buffer and scratch are 32K, each, ie. the overly sized >> ref_name_len will fit there: >> >> [ 8766.928232] btrfs: ino2name: 266 p1/ >> [ 8767.440964] i2p: [4] namelen 10, left 32766 >> [ 8767.446417] i2p: [7] path: >> [ 8767.450445] i2p: [4] namelen 2, left 32755 >> [ 8767.455733] i2p: [7] path: / >> [ 8767.459834] i2p: [2] p1/ > > Do I get that right? This is inode 266, which should refer to > ./p1/d6/d7/d1f/c41 (as you state below). Already on second iteration, > we're at something named "pl", which shouldn't happen as we construct > the path bottom-up. And those namelen 0 in the following lines shouldn't > happen, either. Furthermore, the path should change on every iteration > (I guess, that might depend on the printk behind, of course). > >> [ 8767.463593] i2p: [4] namelen 0, left 32752 >> [ 8767.468903] i2p: [7] path: >> [ 8767.472908] i2p: [4] namelen 2, left 32751 >> [ 8767.478188] i2p: [7] path: / >> [ 8767.482280] i2p: [2] p1/ >> [ 8767.486024] i2p: [4] namelen 0, left 32748 >> [ 8767.491293] i2p: [7] path: >> [ 8767.495283] i2p: [4] namelen 2, left 32747 >> [ 8767.500587] i2p: [7] path: / >> [ 8767.504680] i2p: [2] p1/ >> [ 8767.508430] i2p: [4] namelen 0, left 32744 >> [ 8767.513708] i2p: [7] path: >> [ 8767.517702] i2p: [4] namelen 2, left 32743 >> [ 8767.522969] i2p: [7] path: / >> [ 8767.527042] i2p: [2] p1/ >> [ 8767.530787] i2p: [4] namelen 0, left 32740 >> [ 8767.536049] i2p: [7] path: >> [ 8767.539991] i2p: [4] namelen 2, left 32739 >> [ 8767.545282] i2p: [7] path: / >> [ 8767.549374] i2p: [2] p1/ >> [ 8767.553109] i2p: [4] namelen 0, left 32736 >> [ 8767.558377] i2p: [7] path: >> [ 8767.562354] i2p: [4] namelen 2, left 32735 >> [ 8767.567615] i2p: [7] path: / >> [ 8767.571713] i2p: [2] p1/ >> [ 8767.575443] i2p: [4] namelen 0, left 32732 >> [ 8767.580701] i2p: [7] path: >> [ 8767.584678] i2p: [4] namelen 2, left 32731 >> [ 8767.589933] i2p: [7] path: / >> [ 8767.594007] i2p: [2] p1/ >> [ 8767.597713] i2p: [4] namelen 0, left 32728 >> [ 8767.602908] i2p: [7] path: >> [ 8767.606832] i2p: [4] namelen 2, left 32727 >> [ 8767.612030] i2p: [7] path: / >> [ 8767.616050] i2p: [2] p1/ >> [ 8767.619676] i2p: [4] namelen 0, left 32724 >> [ 8767.624873] i2p: [7] path: >> [ 8767.628782] i2p: [4] namelen 2, left 32723 >> [ 8767.633970] i2p: [7] path: / >> [ 8767.637962] i2p: [2] p1/ >> [ 8767.641639] i2p: [4] namelen 0, left 32720 >> [ 8767.646838] i2p: [7] path: >> [ 8767.650757] i2p: [4] namelen 2, left 32719 >> [ 8767.655952] i2p: [7] path: / >> [ 8767.659940] i2p: [2] p1/ >> [ 8767.663604] i2p: [4] namelen 0, left 32716 >> [ 8767.668790] i2p: [7] path: >> [ 8767.672696] i2p: [4] namelen 2, left 32715 >> [ 8767.677881] i2p: [7] path: / >> [ 8767.681878] i2p: [2] p1/ >> [ 8767.685549] i2p: [4] namelen 0, left 32712 >> [ 8767.690742] i2p: [7] path: >> [ 8767.694655] i2p: [4] namelen 2, left 32711 >> [ 8767.699843] i2p: [7] path: / >> [ 8767.703840] i2p: [2] p1/ >> [ 8767.707520] i2p: [4] namelen 19967, left 32708 >> [ 8767.713057] i2p: [7] path: >> [ 8767.716955] BUG: unable to handle kernel NULL pointer dereference at (null) >> [ 8767.720932] IP: [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] >> [ 8767.720932] PGD 77bd0067 PUD 79d35067 PMD 0 >> [ 8767.720932] Oops: 0000 [#1] SMP >> [ 8767.720932] CPU 1 >> [ 8767.720932] Modules linked in: btrfs loop >> [ 8767.720932] >> [ 8767.720932] Pid: 10859, comm: btrfs-ino2path Not tainted 3.0.0-rc3-default+ #75 Intel Corporation Santa Rosa platform/Matanzas >> [ 8767.720932] RIP: 0010:[<ffffffffa005f1d2>] [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] >> [ 8767.720932] RSP: 0018:ffff880074acbc58 EFLAGS: 00010202 >> [ 8767.720932] RAX: 0000000000000000 RBX: 0000000000003deb RCX: 0000000000001000 >> [ 8767.720932] RDX: 00000000000001e0 RSI: 0000000000000000 RDI: 0000000000000246 >> [ 8767.720932] RBP: ffff880074acbcb8 R08: 0000000000000000 R09: 0000000000000001 >> [ 8767.720932] R10: 0000000000000000 R11: 0000000000001c04 R12: 0000000000000002 >> [ 8767.720932] R13: 0000000000000000 R14: ffff880079bac1d9 R15: ffff880074acbfd8 >> [ 8767.720932] FS: 00007f1399198740(0000) GS:ffff88007de00000(0000) knlGS:0000000000000000 >> [ 8767.720932] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b >> [ 8767.720932] CR2: 0000000000000000 CR3: 0000000074b13000 CR4: 00000000000006e0 >> [ 8767.720932] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 >> [ 8767.720932] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 >> [ 8767.720932] Process btrfs-ino2path (pid: 10859, threadinfo ffff880074aca000, task ffff880077085340) >> [ 8767.720932] Stack: >> [ 8767.720932] ffffffffa005f282 ffffffff81b21e74 ffff88002f2ef668 0000000000000000 >> [ 8767.720932] ffff880073f94dd8 ffff880074acbfd8 ffff8800780bd000 00000000000031c5 >> [ 8767.720932] 00000000000031c5 0000000000000104 ffff880073f94dd8 ffff880074132130 >> [ 8767.720932] Call Trace: >> [ 8767.720932] [<ffffffffa005f282>] ? read_extent_buffer+0x152/0x220 [btrfs] >> [ 8767.720932] [<ffffffff81b21e74>] ? printk+0x68/0x6c >> [ 8767.720932] [<ffffffffa008924d>] inode_to_path+0x10d/0x2d0 [btrfs] >> [ 8767.720932] [<ffffffffa0089883>] paths_from_inode+0xe3/0x120 [btrfs] >> [ 8767.720932] [<ffffffffa006de9f>] btrfs_ioctl+0xb5f/0xf80 [btrfs] >> [ 8767.720932] [<ffffffff810d3e55>] ? trace_hardirqs_on_caller+0x155/0x1a0 >> [ 8767.720932] [<ffffffff81080e4c>] ? finish_task_switch+0x7c/0x110 >> [ 8767.720932] [<ffffffff81080e0f>] ? finish_task_switch+0x3f/0x110 >> [ 8767.720932] [<ffffffff81193578>] do_vfs_ioctl+0x98/0x570 >> [ 8767.720932] [<ffffffff811828be>] ? fget_light+0x33e/0x430 >> [ 8767.720932] [<ffffffff81b2ed3a>] ? sysret_check+0x2e/0x69 >> [ 8767.720932] [<ffffffff81193a9f>] sys_ioctl+0x4f/0x80 >> [ 8767.720932] [<ffffffff81b2ed02>] system_call_fastpath+0x16/0x1b >> [ 8767.720932] Code: 66 0f 1f 84 00 00 00 00 00 48 8b 55 c0 48 8b 42 30 48 89 c6 b9 00 10 00 00 4c 29 e9 48 39 d9 48 0f 47 cb 41 83 87 44 e0 ff ff 01 >> [ 8767.720932] 8b 00 48 c1 e8 2d 48 89 c2 48 c1 ea 08 48 8b 3c d5 00 95 f7 >> [ 8767.720932] RIP [<ffffffffa005f1d2>] read_extent_buffer+0xa2/0x220 [btrfs] >> [ 8767.720932] RSP <ffff880074acbc58> >> [ 8767.720932] CR2: 0000000000000000 >> [ 8768.067994] ---[ end trace b9afe483f6289b6f ]--- >> >> Let's see the inode 266 by hand: >> >> dsterba@:/mnt/sda10$ find . -inum 266 >> ./p1/d6/d7/d1f/c41 >> >> something is wrong ... >> >> The file hierarchy is a leftover from fs_mark runs, directories to depth 9, >> short names. > > Sounds like I missed something. There is definitely a bug in the path > construction or lower iteration code I added. > > I used a fs_mark created btrfs for my tests as well, but those worked > well. If you could share that file system (image or debug-tree output), > that'd be great help debugging this. I got that fs from David (thanks) and it turned out that there was a silly mistake in iref_to_path() in my code. I used the wrong extent buffer which worked only as long as INODE_ITEM and INODE_REF resided in the same leaf. That's fixed now and I'll send a new version later. This will also contain a fix to find EXTENT_DATA_REF that are not inline refs but separately in the tree (v2 will miss some paths once you have more than 6 reflinks). Thanks, -Jan -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index 9b72dcf..c63f649 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -7,4 +7,5 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \ - compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o + compression.o delayed-ref.o relocation.o delayed-inode.o backref.o \ + scrub.o diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c new file mode 100644 index 0000000..64611e6 --- /dev/null +++ b/fs/btrfs/backref.c @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2011 STRATO. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include "ctree.h" +#include "backref.h" + +static int __inode_info(u64 inum, u64 ioff, u8 key_type, + struct btrfs_root *fs_root, struct btrfs_path *path, + struct btrfs_key *found_key) +{ + int ret; + struct btrfs_key key; + struct extent_buffer *eb; + + key.type = key_type; + key.objectid = inum; + key.offset = ioff; + + ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); + if (ret < 0) + return ret; + + eb = path->nodes[0]; + if (ret && path->slots[0] >= btrfs_header_nritems(eb)) { + ret = btrfs_next_leaf(fs_root, path); + if (ret) + return ret; + eb = path->nodes[0]; + } + + btrfs_item_key_to_cpu(eb, found_key, path->slots[0]); + if (found_key->type != key.type || found_key->objectid != key.objectid) + return 1; + + return 0; +} + +/* + * this makes the path point to (inum INODE_ITEM ioff) + */ +int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, + struct btrfs_path *path) +{ + struct btrfs_key key; + return __inode_info(inum, ioff, BTRFS_INODE_ITEM_KEY, fs_root, path, + &key); +} + +static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, + struct btrfs_path *path, int strict, + u64 *out_parent_inum, + struct extent_buffer **out_iref_eb, + int *out_slot) +{ + int ret; + struct btrfs_key found_key; + + ret = __inode_info(inum, ioff, BTRFS_INODE_REF_KEY, fs_root, path, + &found_key); + + if (!ret) { + if (out_slot) + *out_slot = path->slots[0]; + if (out_iref_eb) + *out_iref_eb = path->nodes[0]; + if (out_parent_inum) + *out_parent_inum = found_key.offset; + } + + btrfs_release_path(path); + return ret; +} + +/* + * this iterates to turn a btrfs_inode_ref into a full filesystem path. elements + * of the path are separated by '/' and the path is guaranteed to be + * 0-terminated. the path is only given within the current file system. + * Therefore, it never starts with a '/'. the caller is responsible to provide + * "size" bytes in "dest". the dest buffer will be filled backwards! the idea is + * that in case of an overflow, the lower part in the hierarchie is most + * important to the user. finally, the start point of the resulting string is + * returned. in case the path would overflow, "..." is added at the front of + * the string and iteration stops regularly. + */ +static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, + struct btrfs_inode_ref *iref, + struct extent_buffer *eb, u64 parent, + char *dest, u32 size) +{ + u32 len; + int slot; + u64 inum; + int ret; + u32 bytes_left = size - 1; + + dest[bytes_left] = '\0'; + + while (1) { + len = btrfs_inode_ref_name_len(eb, iref); + if (len > bytes_left) { + if (size < 4) + break; + if (bytes_left > 3) + bytes_left -= 3; + else + bytes_left = 0; + memcpy(dest + bytes_left, "...", 3); + break; + } + bytes_left -= len; + read_extent_buffer(eb, dest + bytes_left, + (unsigned long)(iref + 1), len); + + ret = inode_item_info(parent, 0, fs_root, path); + if (ret) + return ERR_PTR(ret); + eb = path->nodes[0]; + btrfs_release_path(path); + + ret = inode_ref_info(parent, 0, fs_root, path, 0, + &inum, NULL, &slot); + if (ret) + return ERR_PTR(ret); + + /* regular exit ahead */ + if (parent == inum) + break; + + iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); + parent = inum; + if (bytes_left > 0) { + --bytes_left; + dest[bytes_left] = '/'; + } + } + + return dest + bytes_left; +} + +/* + * this makes the path point to (logical EXTENT_ITEM *) + * returns 0 for data blocks, 1 for tree blocks and <0 on error + */ +int data_extent_from_logical(struct btrfs_root *root, u64 logical, + struct btrfs_path *path, + struct btrfs_key *found_key) +{ + int ret; + u64 flags; + u32 item_size; + struct extent_buffer *eb; + struct btrfs_extent_item *ei; + struct btrfs_key key; + + key.type = BTRFS_EXTENT_ITEM_KEY; + key.objectid = logical; + key.offset = (u64)-1; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + return ret; + ret = btrfs_previous_item(root->fs_info->extent_root, path, + 0, BTRFS_EXTENT_ITEM_KEY); + if (ret < 0) + return ret; + btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); + if (found_key->type != BTRFS_EXTENT_ITEM_KEY || + found_key->objectid > logical || + found_key->objectid + found_key->offset <= logical) + return -ENOENT; + + eb = path->nodes[0]; + item_size = btrfs_item_size_nr(eb, path->slots[0]); + BUG_ON(item_size < sizeof(*ei)); + + ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); + flags = btrfs_extent_flags(eb, ei); + + if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) + return 1; + + return 0; +} + +/* + * helper function to iterate extent backrefs. ptr must point to a 0 value for + * the first call and may be modified. it is used to track state. + * if more backrefs exist, 0 is returned and the next call to __get_extent_ref + * must pass the modified ptr parameter to get to the next backref. + * after the last backref was processed, 1 is returned. + * returns <0 on error + */ +static int __get_extent_ref(u64 flags_wanted, u8 type_wanted, + unsigned long *ptr, struct extent_buffer *eb, + struct btrfs_extent_item *ei, u32 item_size, + struct btrfs_extent_inline_ref **eiref) +{ + int type; + unsigned long end; + u64 flags; + struct btrfs_tree_block_info *info; + + if (!*ptr) { + /* first call */ + flags = btrfs_extent_flags(eb, ei); + if (!(flags & flags_wanted)) + return -EINVAL; + if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { + info = (struct btrfs_tree_block_info *)(ei + 1); + *eiref = (struct btrfs_extent_inline_ref *)(info + 1); + } else { + *eiref = (struct btrfs_extent_inline_ref *)(ei + 1); + } + *ptr = (unsigned long)*eiref; + } + + end = (unsigned long)ei + item_size; + + do { + *eiref = (struct btrfs_extent_inline_ref *)*ptr; + type = btrfs_extent_inline_ref_type(eb, *eiref); + + *ptr += btrfs_extent_inline_ref_size(type); + + WARN_ON(*ptr > end); + if (*ptr == end) + return 1; /* last */ + } while (type != type_wanted); + + return 0; +} + +/* + * reads the tree block backref for an extent. tree level and root are returned + * through out_level and out_root. ptr must point to a 0 value for the first + * call and may be modified (see __get_extent_ref comment). + * returns 0 on success, <0 on error. note: in contrast to __get_extent_ref this + * one never returns 1! + */ +int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, + struct btrfs_extent_item *ei, u32 item_size, + u64 *out_root, u8 *out_level) +{ + int ret; + struct btrfs_tree_block_info *info; + struct btrfs_extent_inline_ref *eiref; + + ret = __get_extent_ref(BTRFS_EXTENT_FLAG_TREE_BLOCK, + BTRFS_TREE_BLOCK_REF_KEY, ptr, eb, ei, + item_size, &eiref); + if (ret < 0) + return ret; + + if (!ret) { + printk(KERN_ERR "btrfs: tree_backtef_for_extent detected " + "multiple tree backrefs for an extent at %llu\n", + (unsigned long long)eb->start); + WARN_ON(1); + } + + info = (struct btrfs_tree_block_info *)(ei + 1); + *out_root = btrfs_extent_inline_ref_offset(eb, eiref); + *out_level = btrfs_tree_block_level(eb, info); + + return 0; +} + +static int data_inode_for_extent(unsigned long *ptr, struct extent_buffer *eb, + struct btrfs_extent_item *ei, + u32 item_size, u64 *out_inum, + u64 *out_ioff) +{ + int ret; + struct btrfs_extent_inline_ref *eiref; + struct btrfs_extent_data_ref *dref; + + ret = __get_extent_ref(BTRFS_EXTENT_FLAG_DATA, + BTRFS_EXTENT_DATA_REF_KEY, ptr, eb, ei, + item_size, &eiref); + if (ret < 0) + return ret; + + dref = (struct btrfs_extent_data_ref *)(&eiref->offset); + if (btrfs_extent_data_ref_root(eb, dref) != BTRFS_FS_TREE_OBJECTID) { + WARN_ON(1); + return -EIO; + } + + *out_inum = btrfs_extent_data_ref_objectid(eb, dref); + *out_ioff = btrfs_extent_data_ref_offset(eb, dref); + + return ret; +} + +/* + * calls iterate() for every inode that references the extent identified by + * the given parameters. + * when the iterator function returns a non-zero value, iteration stops. + */ +int iterate_extent_inodes(struct extent_buffer *eb, + struct btrfs_extent_item *ei, + u64 extent_item_offset, u32 item_size, + iterate_extent_inodes_t *iterate, void *ctx) +{ + int last; + u64 inum; + unsigned long ptr = 0; + u64 extent_data_item_offset; + int ret; + + do { + last = data_inode_for_extent(&ptr, eb, ei, item_size, &inum, + &extent_data_item_offset); + if (last < 0) + return last; + + ret = iterate(inum, extent_item_offset+extent_data_item_offset, + ctx); + if (ret) + return ret; + + } while (!last); + + return 0; +} + +int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, + struct btrfs_path *path, + iterate_extent_inodes_t *iterate, void *ctx) +{ + int ret; + u32 item_size; + struct extent_buffer *l; + struct btrfs_extent_item *extent; + u64 offset; + struct btrfs_key found_key; + + ret = data_extent_from_logical(fs_info->extent_root, logical, path, + &found_key); + if (ret) + return ret; + + offset = logical - found_key.objectid; + l = path->nodes[0]; + extent = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); + item_size = btrfs_item_size_nr(l, path->slots[0]); + btrfs_release_path(path); + + ret = iterate_extent_inodes(l, extent, offset, item_size, iterate, ctx); + + return ret; +} + +static int iterate_irefs(u64 inum, struct extent_buffer *eb_i, + struct btrfs_root *fs_root, + struct btrfs_path *path, + iterate_irefs_t *iterate, void *ctx) +{ + int ret; + int slot; + u32 cur; + u32 len; + u32 name_len; + u64 parent = 0; + struct extent_buffer *eb_ir; + struct btrfs_item *item; + struct btrfs_inode_ref *iref; + + while (1) { + ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path, + 1, &parent, &eb_ir, &slot); + if (ret < 0) + return ret; + if (ret) + break; + + item = btrfs_item_nr(eb_i, slot); + iref = btrfs_item_ptr(eb_i, slot, struct btrfs_inode_ref); + + for (cur = 0; cur < btrfs_item_size(eb_i, item); cur += len) { + name_len = btrfs_inode_ref_name_len(eb_i, iref); + ret = iterate(parent, iref, eb_ir, slot, ctx); + if (ret) + return ret; + len = sizeof(*iref) + name_len; + iref = (struct btrfs_inode_ref *)((char *)iref + len); + } + } + + return 0; +} + +/* + * returns 0 if the path could be dumped (probably truncated) + * returns <0 in case of an error + */ +static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, + struct extent_buffer *eb_ir, int slot, + void *ctx) +{ + struct inode_fs_paths *ipath = ctx; + struct extent_buffer *eb_i = ipath->eb; + u32 path_len; + char *fs_path; + + if (ipath->bytes_left < 2) + return -EOVERFLOW; + + *ipath->dest++ = ' '; + --ipath->bytes_left; + + fs_path = iref_to_path(ipath->fs_root, ipath->path, iref, eb_i, + inum, ipath->scratch_buf, ipath->bytes_left); + if (IS_ERR(fs_path)) + return PTR_ERR(fs_path); + path_len = ipath->scratch_buf + ipath->bytes_left - fs_path - 1; + if (path_len+1 > ipath->bytes_left) + return -EOVERFLOW; + memcpy(ipath->dest, fs_path, path_len+1); + ipath->bytes_left -= path_len; + ipath->dest += path_len; + + return 0; +} + +int paths_from_inode(u64 inum, struct inode_fs_paths *ipath) +{ + return iterate_irefs(inum, ipath->eb, ipath->fs_root, ipath->path, + inode_to_path, ipath); +} diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h new file mode 100644 index 0000000..d208321 --- /dev/null +++ b/fs/btrfs/backref.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2011 STRATO. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#ifndef __BTRFS_BACKREF__ +#define __BTRFS_BACKREF__ + +struct inode_fs_paths { + int bytes_left; + char *dest; + struct btrfs_path *path; + char *scratch_buf; + struct btrfs_root *fs_root; + int scratch_bufsize; + struct extent_buffer *eb; +}; + +typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, void *ctx); +typedef int (iterate_irefs_t)(u64 parent, struct btrfs_inode_ref *iref, + struct extent_buffer *eb_ir, + int slot, void *ctx); + +int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root, + struct btrfs_path *path); + +int data_extent_from_logical(struct btrfs_root *root, u64 logical, + struct btrfs_path *path, + struct btrfs_key *found_key); + +int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, + struct btrfs_extent_item *ei, u32 item_size, + u64 *out_root, u8 *out_level); + +int iterate_extent_inodes(struct extent_buffer *eb, + struct btrfs_extent_item *ei, + u64 extent_item_offset, u32 item_size, + iterate_extent_inodes_t *iterate, void *ctx); + +int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, + struct btrfs_path *path, + iterate_extent_inodes_t *iterate, void *ctx); + +int paths_from_inode(u64 inum, struct inode_fs_paths *ipath); + +#endif
These helper functions iterate back references and call a function for each backref. There is also a function to resolve an inode to a path in the file system. Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net> --- fs/btrfs/Makefile | 3 +- fs/btrfs/backref.c | 445 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/backref.h | 59 +++++++ 3 files changed, 506 insertions(+), 1 deletions(-)