for-4.16-rc3-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAlqbuK8ACgkQxWXV+ddt WDsiVQ//eE8Axfw4qWOyHHjozoAIu9kifvOFQIhvKviLiXHJNrD/vBI6YwD1hyD1 rbbLilMsEl1OD1Sq3AeOUMNSSl5qUFEB+CA8vg9GznFTNRobTkL+p96Zt5xlRDu3 lsFFV93tED+dK4D/eSGP+xYbknA8hIk/2gWPkd6hpYKyh2QdsPBYDqCnaEXvd79P DIP/cAjIfzqQn0FTiZ9wbaES+LPO+NoZgQRC2w9McYQ5CEMc+oAChEmPJRwpPoKy YdhuwoULniRNHVnVOIVfi4w9jkSPSz7YIgLeRFli/WGBYGcKeHTMFkMa12KdpuUC JUclOogJ5ZMbFV3C0W8XEJ7Vb9ltIevrH8MgfKP/3BScuZzbJZ+n5KkH2Gf7vcpe w5cZGOsKDz+35fDCdTmsFpDK9kpGzHq48JlRifOjARbdyqNwVq4emxOeQlO1ygzq Y9H5UeMpp/FDAm6g/bV8ezCXzwuwUDV9CwAJBD+WCiZhD2nX85FfIp1kfF2zLcUg Y8irqV6A/J/0BFkF7Iu9AuzTxOdo6zMLkcHEKb+sL7yGxZ2248v5gZxDoyV5iNWR WY4Y2GaMemZGu6+NyyLFAJzlFyACD5fSy8vT7KD6upCzwmlAtaJ3VULfTrLyi/uM SNZAKf3WzKBVe5h52GNGRCi5OLTteH6Yqz5m5/h8r74mBO00IrA= =bF96 -----END PGP SIGNATURE----- Merge tag 'for-4.16-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: - when NR_CPUS is large, a SRCU structure can significantly inflate size of the main filesystem structure that would not be possible to allocate by kmalloc, so the kvalloc fallback is used - improved error handling - fix endiannes when printing some filesystem attributes via sysfs, this is could happen when a filesystem is moved between different endianity hosts - send fixes: the NO_HOLE mode should not send a write operation for a file hole - fix log replay for for special files followed by file hardlinks - fix log replay failure after unlink and link combination - fix max chunk size calculation for DUP allocation * tag 'for-4.16-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: Btrfs: fix log replay failure after unlink and link combination Btrfs: fix log replay failure after linking special file and fsync Btrfs: send, fix issuing write op when processing hole in no data mode btrfs: use proper endianness accessors for super_copy btrfs: alloc_chunk: fix DUP stripe size handling btrfs: Handle btrfs_set_extent_delalloc failure in relocate_file_extent_cluster btrfs: handle failure of add_pending_csums btrfs: use kvzalloc to allocate btrfs_fs_info
This commit is contained in:
commit
af8c081627
@ -2974,7 +2974,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
|
|||||||
kfree(fs_info->super_copy);
|
kfree(fs_info->super_copy);
|
||||||
kfree(fs_info->super_for_commit);
|
kfree(fs_info->super_for_commit);
|
||||||
security_free_mnt_opts(&fs_info->security_opts);
|
security_free_mnt_opts(&fs_info->security_opts);
|
||||||
kfree(fs_info);
|
kvfree(fs_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tree mod log functions from ctree.c */
|
/* tree mod log functions from ctree.c */
|
||||||
@ -3095,7 +3095,10 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
|
|||||||
u64 inode_objectid, u64 ref_objectid, int ins_len,
|
u64 inode_objectid, u64 ref_objectid, int ins_len,
|
||||||
int cow);
|
int cow);
|
||||||
|
|
||||||
int btrfs_find_name_in_ext_backref(struct btrfs_path *path,
|
int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot,
|
||||||
|
const char *name,
|
||||||
|
int name_len, struct btrfs_inode_ref **ref_ret);
|
||||||
|
int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
|
||||||
u64 ref_objectid, const char *name,
|
u64 ref_objectid, const char *name,
|
||||||
int name_len,
|
int name_len,
|
||||||
struct btrfs_inode_extref **extref_ret);
|
struct btrfs_inode_extref **extref_ret);
|
||||||
|
@ -22,10 +22,10 @@
|
|||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "print-tree.h"
|
#include "print-tree.h"
|
||||||
|
|
||||||
static int find_name_in_backref(struct btrfs_path *path, const char *name,
|
int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot,
|
||||||
int name_len, struct btrfs_inode_ref **ref_ret)
|
const char *name,
|
||||||
|
int name_len, struct btrfs_inode_ref **ref_ret)
|
||||||
{
|
{
|
||||||
struct extent_buffer *leaf;
|
|
||||||
struct btrfs_inode_ref *ref;
|
struct btrfs_inode_ref *ref;
|
||||||
unsigned long ptr;
|
unsigned long ptr;
|
||||||
unsigned long name_ptr;
|
unsigned long name_ptr;
|
||||||
@ -33,9 +33,8 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name,
|
|||||||
u32 cur_offset = 0;
|
u32 cur_offset = 0;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
item_size = btrfs_item_size_nr(leaf, slot);
|
||||||
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
ptr = btrfs_item_ptr_offset(leaf, slot);
|
||||||
ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
|
|
||||||
while (cur_offset < item_size) {
|
while (cur_offset < item_size) {
|
||||||
ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
|
ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
|
||||||
len = btrfs_inode_ref_name_len(leaf, ref);
|
len = btrfs_inode_ref_name_len(leaf, ref);
|
||||||
@ -44,18 +43,19 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name,
|
|||||||
if (len != name_len)
|
if (len != name_len)
|
||||||
continue;
|
continue;
|
||||||
if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
|
if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
|
||||||
*ref_ret = ref;
|
if (ref_ret)
|
||||||
|
*ref_ret = ref;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
|
int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
|
||||||
|
u64 ref_objectid,
|
||||||
const char *name, int name_len,
|
const char *name, int name_len,
|
||||||
struct btrfs_inode_extref **extref_ret)
|
struct btrfs_inode_extref **extref_ret)
|
||||||
{
|
{
|
||||||
struct extent_buffer *leaf;
|
|
||||||
struct btrfs_inode_extref *extref;
|
struct btrfs_inode_extref *extref;
|
||||||
unsigned long ptr;
|
unsigned long ptr;
|
||||||
unsigned long name_ptr;
|
unsigned long name_ptr;
|
||||||
@ -63,9 +63,8 @@ int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
|
|||||||
u32 cur_offset = 0;
|
u32 cur_offset = 0;
|
||||||
int ref_name_len;
|
int ref_name_len;
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
item_size = btrfs_item_size_nr(leaf, slot);
|
||||||
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
ptr = btrfs_item_ptr_offset(leaf, slot);
|
||||||
ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search all extended backrefs in this item. We're only
|
* Search all extended backrefs in this item. We're only
|
||||||
@ -113,7 +112,9 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
|
|||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref))
|
if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
|
||||||
|
ref_objectid, name, name_len,
|
||||||
|
&extref))
|
||||||
return NULL;
|
return NULL;
|
||||||
return extref;
|
return extref;
|
||||||
}
|
}
|
||||||
@ -155,7 +156,8 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
|
|||||||
* This should always succeed so error here will make the FS
|
* This should always succeed so error here will make the FS
|
||||||
* readonly.
|
* readonly.
|
||||||
*/
|
*/
|
||||||
if (!btrfs_find_name_in_ext_backref(path, ref_objectid,
|
if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
|
||||||
|
ref_objectid,
|
||||||
name, name_len, &extref)) {
|
name, name_len, &extref)) {
|
||||||
btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);
|
btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);
|
||||||
ret = -EROFS;
|
ret = -EROFS;
|
||||||
@ -225,7 +227,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
|
|||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!find_name_in_backref(path, name, name_len, &ref)) {
|
if (!btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
|
||||||
|
name, name_len, &ref)) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
search_ext_refs = 1;
|
search_ext_refs = 1;
|
||||||
goto out;
|
goto out;
|
||||||
@ -293,7 +296,9 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
|
|||||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||||
ins_len);
|
ins_len);
|
||||||
if (ret == -EEXIST) {
|
if (ret == -EEXIST) {
|
||||||
if (btrfs_find_name_in_ext_backref(path, ref_objectid,
|
if (btrfs_find_name_in_ext_backref(path->nodes[0],
|
||||||
|
path->slots[0],
|
||||||
|
ref_objectid,
|
||||||
name, name_len, NULL))
|
name, name_len, NULL))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -351,7 +356,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
|
|||||||
if (ret == -EEXIST) {
|
if (ret == -EEXIST) {
|
||||||
u32 old_size;
|
u32 old_size;
|
||||||
|
|
||||||
if (find_name_in_backref(path, name, name_len, &ref))
|
if (btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
|
||||||
|
name, name_len, &ref))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
|
old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
|
||||||
@ -365,7 +371,9 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
if (ret == -EOVERFLOW) {
|
if (ret == -EOVERFLOW) {
|
||||||
if (find_name_in_backref(path, name, name_len, &ref))
|
if (btrfs_find_name_in_backref(path->nodes[0],
|
||||||
|
path->slots[0],
|
||||||
|
name, name_len, &ref))
|
||||||
ret = -EEXIST;
|
ret = -EEXIST;
|
||||||
else
|
else
|
||||||
ret = -EMLINK;
|
ret = -EMLINK;
|
||||||
|
@ -2043,12 +2043,15 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
|
|||||||
struct inode *inode, struct list_head *list)
|
struct inode *inode, struct list_head *list)
|
||||||
{
|
{
|
||||||
struct btrfs_ordered_sum *sum;
|
struct btrfs_ordered_sum *sum;
|
||||||
|
int ret;
|
||||||
|
|
||||||
list_for_each_entry(sum, list, list) {
|
list_for_each_entry(sum, list, list) {
|
||||||
trans->adding_csums = true;
|
trans->adding_csums = true;
|
||||||
btrfs_csum_file_blocks(trans,
|
ret = btrfs_csum_file_blocks(trans,
|
||||||
BTRFS_I(inode)->root->fs_info->csum_root, sum);
|
BTRFS_I(inode)->root->fs_info->csum_root, sum);
|
||||||
trans->adding_csums = false;
|
trans->adding_csums = false;
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3062,7 +3065,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_pending_csums(trans, inode, &ordered_extent->list);
|
ret = add_pending_csums(trans, inode, &ordered_extent->list);
|
||||||
|
if (ret) {
|
||||||
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_ordered_update_i_size(inode, 0, ordered_extent);
|
btrfs_ordered_update_i_size(inode, 0, ordered_extent);
|
||||||
ret = btrfs_update_inode_fallback(trans, root, inode);
|
ret = btrfs_update_inode_fallback(trans, root, inode);
|
||||||
|
@ -3268,8 +3268,22 @@ static int relocate_file_extent_cluster(struct inode *inode,
|
|||||||
nr++;
|
nr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_set_extent_delalloc(inode, page_start, page_end, 0, NULL,
|
ret = btrfs_set_extent_delalloc(inode, page_start, page_end, 0,
|
||||||
0);
|
NULL, 0);
|
||||||
|
if (ret) {
|
||||||
|
unlock_page(page);
|
||||||
|
put_page(page);
|
||||||
|
btrfs_delalloc_release_metadata(BTRFS_I(inode),
|
||||||
|
PAGE_SIZE);
|
||||||
|
btrfs_delalloc_release_extents(BTRFS_I(inode),
|
||||||
|
PAGE_SIZE);
|
||||||
|
|
||||||
|
clear_extent_bits(&BTRFS_I(inode)->io_tree,
|
||||||
|
page_start, page_end,
|
||||||
|
EXTENT_LOCKED | EXTENT_BOUNDARY);
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
}
|
||||||
set_page_dirty(page);
|
set_page_dirty(page);
|
||||||
|
|
||||||
unlock_extent(&BTRFS_I(inode)->io_tree,
|
unlock_extent(&BTRFS_I(inode)->io_tree,
|
||||||
|
@ -5005,6 +5005,9 @@ static int send_hole(struct send_ctx *sctx, u64 end)
|
|||||||
u64 len;
|
u64 len;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA)
|
||||||
|
return send_update_extent(sctx, offset, end - offset);
|
||||||
|
|
||||||
p = fs_path_alloc();
|
p = fs_path_alloc();
|
||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1545,7 +1545,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
|
|||||||
* it for searching for existing supers, so this lets us do that and
|
* it for searching for existing supers, so this lets us do that and
|
||||||
* then open_ctree will properly initialize everything later.
|
* then open_ctree will properly initialize everything later.
|
||||||
*/
|
*/
|
||||||
fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL);
|
fs_info = kvzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL);
|
||||||
if (!fs_info) {
|
if (!fs_info) {
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
goto error_sec_opts;
|
goto error_sec_opts;
|
||||||
|
@ -423,7 +423,7 @@ static ssize_t btrfs_nodesize_show(struct kobject *kobj,
|
|||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
|
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
|
||||||
|
|
||||||
return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize);
|
return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->nodesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
BTRFS_ATTR(, nodesize, btrfs_nodesize_show);
|
BTRFS_ATTR(, nodesize, btrfs_nodesize_show);
|
||||||
@ -433,8 +433,7 @@ static ssize_t btrfs_sectorsize_show(struct kobject *kobj,
|
|||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
|
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
|
||||||
|
|
||||||
return snprintf(buf, PAGE_SIZE, "%u\n",
|
return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->sectorsize);
|
||||||
fs_info->super_copy->sectorsize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show);
|
BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show);
|
||||||
@ -444,8 +443,7 @@ static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
|
|||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
|
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
|
||||||
|
|
||||||
return snprintf(buf, PAGE_SIZE, "%u\n",
|
return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->sectorsize);
|
||||||
fs_info->super_copy->sectorsize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show);
|
BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show);
|
||||||
|
@ -1722,19 +1722,23 @@ static void update_super_roots(struct btrfs_fs_info *fs_info)
|
|||||||
|
|
||||||
super = fs_info->super_copy;
|
super = fs_info->super_copy;
|
||||||
|
|
||||||
|
/* update latest btrfs_super_block::chunk_root refs */
|
||||||
root_item = &fs_info->chunk_root->root_item;
|
root_item = &fs_info->chunk_root->root_item;
|
||||||
super->chunk_root = root_item->bytenr;
|
btrfs_set_super_chunk_root(super, root_item->bytenr);
|
||||||
super->chunk_root_generation = root_item->generation;
|
btrfs_set_super_chunk_root_generation(super, root_item->generation);
|
||||||
super->chunk_root_level = root_item->level;
|
btrfs_set_super_chunk_root_level(super, root_item->level);
|
||||||
|
|
||||||
|
/* update latest btrfs_super_block::root refs */
|
||||||
root_item = &fs_info->tree_root->root_item;
|
root_item = &fs_info->tree_root->root_item;
|
||||||
super->root = root_item->bytenr;
|
btrfs_set_super_root(super, root_item->bytenr);
|
||||||
super->generation = root_item->generation;
|
btrfs_set_super_generation(super, root_item->generation);
|
||||||
super->root_level = root_item->level;
|
btrfs_set_super_root_level(super, root_item->level);
|
||||||
|
|
||||||
if (btrfs_test_opt(fs_info, SPACE_CACHE))
|
if (btrfs_test_opt(fs_info, SPACE_CACHE))
|
||||||
super->cache_generation = root_item->generation;
|
btrfs_set_super_cache_generation(super, root_item->generation);
|
||||||
if (test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))
|
if (test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))
|
||||||
super->uuid_tree_generation = root_item->generation;
|
btrfs_set_super_uuid_tree_generation(super,
|
||||||
|
root_item->generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_transaction_in_commit(struct btrfs_fs_info *info)
|
int btrfs_transaction_in_commit(struct btrfs_fs_info *info)
|
||||||
|
@ -967,7 +967,9 @@ static noinline int backref_in_log(struct btrfs_root *log,
|
|||||||
ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
|
ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
|
||||||
|
|
||||||
if (key->type == BTRFS_INODE_EXTREF_KEY) {
|
if (key->type == BTRFS_INODE_EXTREF_KEY) {
|
||||||
if (btrfs_find_name_in_ext_backref(path, ref_objectid,
|
if (btrfs_find_name_in_ext_backref(path->nodes[0],
|
||||||
|
path->slots[0],
|
||||||
|
ref_objectid,
|
||||||
name, namelen, NULL))
|
name, namelen, NULL))
|
||||||
match = 1;
|
match = 1;
|
||||||
|
|
||||||
@ -1191,7 +1193,8 @@ static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
|
|||||||
read_extent_buffer(eb, *name, (unsigned long)&extref->name,
|
read_extent_buffer(eb, *name, (unsigned long)&extref->name,
|
||||||
*namelen);
|
*namelen);
|
||||||
|
|
||||||
*index = btrfs_inode_extref_index(eb, extref);
|
if (index)
|
||||||
|
*index = btrfs_inode_extref_index(eb, extref);
|
||||||
if (parent_objectid)
|
if (parent_objectid)
|
||||||
*parent_objectid = btrfs_inode_extref_parent(eb, extref);
|
*parent_objectid = btrfs_inode_extref_parent(eb, extref);
|
||||||
|
|
||||||
@ -1212,11 +1215,101 @@ static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
|
|||||||
|
|
||||||
read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen);
|
read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen);
|
||||||
|
|
||||||
*index = btrfs_inode_ref_index(eb, ref);
|
if (index)
|
||||||
|
*index = btrfs_inode_ref_index(eb, ref);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Take an inode reference item from the log tree and iterate all names from the
|
||||||
|
* inode reference item in the subvolume tree with the same key (if it exists).
|
||||||
|
* For any name that is not in the inode reference item from the log tree, do a
|
||||||
|
* proper unlink of that name (that is, remove its entry from the inode
|
||||||
|
* reference item and both dir index keys).
|
||||||
|
*/
|
||||||
|
static int unlink_old_inode_refs(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path,
|
||||||
|
struct btrfs_inode *inode,
|
||||||
|
struct extent_buffer *log_eb,
|
||||||
|
int log_slot,
|
||||||
|
struct btrfs_key *key)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned long ref_ptr;
|
||||||
|
unsigned long ref_end;
|
||||||
|
struct extent_buffer *eb;
|
||||||
|
|
||||||
|
again:
|
||||||
|
btrfs_release_path(path);
|
||||||
|
ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
|
||||||
|
if (ret > 0) {
|
||||||
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
eb = path->nodes[0];
|
||||||
|
ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]);
|
||||||
|
ref_end = ref_ptr + btrfs_item_size_nr(eb, path->slots[0]);
|
||||||
|
while (ref_ptr < ref_end) {
|
||||||
|
char *name = NULL;
|
||||||
|
int namelen;
|
||||||
|
u64 parent_id;
|
||||||
|
|
||||||
|
if (key->type == BTRFS_INODE_EXTREF_KEY) {
|
||||||
|
ret = extref_get_fields(eb, ref_ptr, &namelen, &name,
|
||||||
|
NULL, &parent_id);
|
||||||
|
} else {
|
||||||
|
parent_id = key->offset;
|
||||||
|
ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (key->type == BTRFS_INODE_EXTREF_KEY)
|
||||||
|
ret = btrfs_find_name_in_ext_backref(log_eb, log_slot,
|
||||||
|
parent_id, name,
|
||||||
|
namelen, NULL);
|
||||||
|
else
|
||||||
|
ret = btrfs_find_name_in_backref(log_eb, log_slot, name,
|
||||||
|
namelen, NULL);
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
struct inode *dir;
|
||||||
|
|
||||||
|
btrfs_release_path(path);
|
||||||
|
dir = read_one_inode(root, parent_id);
|
||||||
|
if (!dir) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
kfree(name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = btrfs_unlink_inode(trans, root, BTRFS_I(dir),
|
||||||
|
inode, name, namelen);
|
||||||
|
kfree(name);
|
||||||
|
iput(dir);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(name);
|
||||||
|
ref_ptr += namelen;
|
||||||
|
if (key->type == BTRFS_INODE_EXTREF_KEY)
|
||||||
|
ref_ptr += sizeof(struct btrfs_inode_extref);
|
||||||
|
else
|
||||||
|
ref_ptr += sizeof(struct btrfs_inode_ref);
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
btrfs_release_path(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* replay one inode back reference item found in the log tree.
|
* replay one inode back reference item found in the log tree.
|
||||||
* eb, slot and key refer to the buffer and key found in the log tree.
|
* eb, slot and key refer to the buffer and key found in the log tree.
|
||||||
@ -1345,6 +1438,19 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before we overwrite the inode reference item in the subvolume tree
|
||||||
|
* with the item from the log tree, we must unlink all names from the
|
||||||
|
* parent directory that are in the subvolume's tree inode reference
|
||||||
|
* item, otherwise we end up with an inconsistent subvolume tree where
|
||||||
|
* dir index entries exist for a name but there is no inode reference
|
||||||
|
* item with the same name.
|
||||||
|
*/
|
||||||
|
ret = unlink_old_inode_refs(trans, root, path, BTRFS_I(inode), eb, slot,
|
||||||
|
key);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/* finally write the back reference in the inode */
|
/* finally write the back reference in the inode */
|
||||||
ret = overwrite_item(trans, root, path, eb, slot, key);
|
ret = overwrite_item(trans, root, path, eb, slot, key);
|
||||||
out:
|
out:
|
||||||
@ -5853,7 +5959,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
|
|||||||
* this will force the logging code to walk the dentry chain
|
* this will force the logging code to walk the dentry chain
|
||||||
* up for the file
|
* up for the file
|
||||||
*/
|
*/
|
||||||
if (S_ISREG(inode->vfs_inode.i_mode))
|
if (!S_ISDIR(inode->vfs_inode.i_mode))
|
||||||
inode->last_unlink_trans = trans->transid;
|
inode->last_unlink_trans = trans->transid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4829,10 +4829,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
|||||||
ndevs = min(ndevs, devs_max);
|
ndevs = min(ndevs, devs_max);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the primary goal is to maximize the number of stripes, so use as many
|
* The primary goal is to maximize the number of stripes, so use as
|
||||||
* devices as possible, even if the stripes are not maximum sized.
|
* many devices as possible, even if the stripes are not maximum sized.
|
||||||
|
*
|
||||||
|
* The DUP profile stores more than one stripe per device, the
|
||||||
|
* max_avail is the total size so we have to adjust.
|
||||||
*/
|
*/
|
||||||
stripe_size = devices_info[ndevs-1].max_avail;
|
stripe_size = div_u64(devices_info[ndevs - 1].max_avail, dev_stripes);
|
||||||
num_stripes = ndevs * dev_stripes;
|
num_stripes = ndevs * dev_stripes;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4867,8 +4870,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
|||||||
stripe_size = devices_info[ndevs-1].max_avail;
|
stripe_size = devices_info[ndevs-1].max_avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
stripe_size = div_u64(stripe_size, dev_stripes);
|
|
||||||
|
|
||||||
/* align to BTRFS_STRIPE_LEN */
|
/* align to BTRFS_STRIPE_LEN */
|
||||||
stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN);
|
stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user