diff options
author | Chris Mason <chris.mason@fusionio.com> | 2012-12-17 14:26:57 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-12-17 14:48:21 -0500 |
commit | 9c52057c698fb96f8f07e7a4bcf4801a092bda89 (patch) | |
tree | 5c26913c90c079ea1f8c287a925e2f7c0a3936fe /fs/btrfs/ioctl.c | |
parent | c64c2bd890df3b9a66c52c33df110777058c011e (diff) | |
download | op-kernel-dev-9c52057c698fb96f8f07e7a4bcf4801a092bda89.zip op-kernel-dev-9c52057c698fb96f8f07e7a4bcf4801a092bda89.tar.gz |
Btrfs: fix hash overflow handling
The handling for directory crc hash overflows was fairly obscure,
split_leaf returns EOVERFLOW when we try to extend the item and that is
supposed to bubble up to userland. For a while it did so, but along the
way we added better handling of errors and forced the FS readonly if we
hit IO errors during the directory insertion.
Along the way, we started testing only for EEXIST and the EOVERFLOW case
was dropped. The end result is that we may force the FS readonly if we
catch a directory hash bucket overflow.
This fixes a few problem spots. First I add tests for EOVERFLOW in the
places where we can safely just return the error up the chain.
btrfs_rename is harder though, because it tries to insert the new
directory item only after it has already unlinked anything the rename
was going to overwrite. Rather than adding very complex logic, I added
a helper to test for the hash overflow case early while it is still safe
to bail out.
Snapshot and subvolume creation had a similar problem, so they are using
the new helper now too.
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Reported-by: Pascal Junod <pascal@junod.info>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 657d83c..d4608ab 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -710,6 +710,16 @@ static noinline int btrfs_mksubvol(struct path *parent, if (error) goto out_dput; + /* + * even if this name doesn't exist, we may get hash collisions. + * check for them now when we can safely fail + */ + error = btrfs_check_dir_item_collision(BTRFS_I(dir)->root, + dir->i_ino, name, + namelen); + if (error) + goto out_dput; + down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0) |