Loading fs/btrfs/backref.c +1 −1 Original line number Original line Diff line number Diff line Loading @@ -1991,7 +1991,7 @@ struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, ifp = kmalloc(sizeof(*ifp), GFP_NOFS); ifp = kmalloc(sizeof(*ifp), GFP_NOFS); if (!ifp) { if (!ifp) { kfree(fspath); vfree(fspath); return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM); } } Loading fs/btrfs/compression.c +61 −24 Original line number Original line Diff line number Diff line Loading @@ -743,8 +743,11 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, static struct { static struct { struct list_head idle_ws; struct list_head idle_ws; spinlock_t ws_lock; spinlock_t ws_lock; int num_ws; /* Number of free workspaces */ atomic_t alloc_ws; int free_ws; /* Total number of allocated workspaces */ atomic_t total_ws; /* Waiters for a free workspace */ wait_queue_head_t ws_wait; wait_queue_head_t ws_wait; } btrfs_comp_ws[BTRFS_COMPRESS_TYPES]; } btrfs_comp_ws[BTRFS_COMPRESS_TYPES]; Loading @@ -758,16 +761,34 @@ void __init btrfs_init_compress(void) int i; int i; for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) { for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) { struct list_head *workspace; INIT_LIST_HEAD(&btrfs_comp_ws[i].idle_ws); INIT_LIST_HEAD(&btrfs_comp_ws[i].idle_ws); spin_lock_init(&btrfs_comp_ws[i].ws_lock); spin_lock_init(&btrfs_comp_ws[i].ws_lock); atomic_set(&btrfs_comp_ws[i].alloc_ws, 0); atomic_set(&btrfs_comp_ws[i].total_ws, 0); init_waitqueue_head(&btrfs_comp_ws[i].ws_wait); init_waitqueue_head(&btrfs_comp_ws[i].ws_wait); /* * Preallocate one workspace for each compression type so * we can guarantee forward progress in the worst case */ workspace = btrfs_compress_op[i]->alloc_workspace(); if (IS_ERR(workspace)) { printk(KERN_WARNING "BTRFS: cannot preallocate compression workspace, will try later"); } else { atomic_set(&btrfs_comp_ws[i].total_ws, 1); btrfs_comp_ws[i].free_ws = 1; list_add(workspace, &btrfs_comp_ws[i].idle_ws); } } } } } /* /* * this finds an available workspace or allocates a new one * This finds an available workspace or allocates a new one. * ERR_PTR is returned if things go bad. * If it's not possible to allocate a new one, waits until there's one. * Preallocation makes a forward progress guarantees and we do not return * errors. */ */ static struct list_head *find_workspace(int type) static struct list_head *find_workspace(int type) { { Loading @@ -777,36 +798,58 @@ static struct list_head *find_workspace(int type) struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; atomic_t *alloc_ws = &btrfs_comp_ws[idx].alloc_ws; atomic_t *total_ws = &btrfs_comp_ws[idx].total_ws; wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; int *num_ws = &btrfs_comp_ws[idx].num_ws; int *free_ws = &btrfs_comp_ws[idx].free_ws; again: again: spin_lock(ws_lock); spin_lock(ws_lock); if (!list_empty(idle_ws)) { if (!list_empty(idle_ws)) { workspace = idle_ws->next; workspace = idle_ws->next; list_del(workspace); list_del(workspace); (*num_ws)--; (*free_ws)--; spin_unlock(ws_lock); spin_unlock(ws_lock); return workspace; return workspace; } } if (atomic_read(alloc_ws) > cpus) { if (atomic_read(total_ws) > cpus) { DEFINE_WAIT(wait); DEFINE_WAIT(wait); spin_unlock(ws_lock); spin_unlock(ws_lock); prepare_to_wait(ws_wait, &wait, TASK_UNINTERRUPTIBLE); prepare_to_wait(ws_wait, &wait, TASK_UNINTERRUPTIBLE); if (atomic_read(alloc_ws) > cpus && !*num_ws) if (atomic_read(total_ws) > cpus && !*free_ws) schedule(); schedule(); finish_wait(ws_wait, &wait); finish_wait(ws_wait, &wait); goto again; goto again; } } atomic_inc(alloc_ws); atomic_inc(total_ws); spin_unlock(ws_lock); spin_unlock(ws_lock); workspace = btrfs_compress_op[idx]->alloc_workspace(); workspace = btrfs_compress_op[idx]->alloc_workspace(); if (IS_ERR(workspace)) { if (IS_ERR(workspace)) { atomic_dec(alloc_ws); atomic_dec(total_ws); wake_up(ws_wait); wake_up(ws_wait); /* * Do not return the error but go back to waiting. There's a * workspace preallocated for each type and the compression * time is bounded so we get to a workspace eventually. This * makes our caller's life easier. * * To prevent silent and low-probability deadlocks (when the * initial preallocation fails), check if there are any * workspaces at all. */ if (atomic_read(total_ws) == 0) { static DEFINE_RATELIMIT_STATE(_rs, /* once per minute */ 60 * HZ, /* no burst */ 1); if (__ratelimit(&_rs)) { printk(KERN_WARNING "no compression workspaces, low memory, retrying"); } } goto again; } } return workspace; return workspace; } } Loading @@ -820,21 +863,21 @@ static void free_workspace(int type, struct list_head *workspace) int idx = type - 1; int idx = type - 1; struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; atomic_t *alloc_ws = &btrfs_comp_ws[idx].alloc_ws; atomic_t *total_ws = &btrfs_comp_ws[idx].total_ws; wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; int *num_ws = &btrfs_comp_ws[idx].num_ws; int *free_ws = &btrfs_comp_ws[idx].free_ws; spin_lock(ws_lock); spin_lock(ws_lock); if (*num_ws < num_online_cpus()) { if (*free_ws < num_online_cpus()) { list_add(workspace, idle_ws); list_add(workspace, idle_ws); (*num_ws)++; (*free_ws)++; spin_unlock(ws_lock); spin_unlock(ws_lock); goto wake; goto wake; } } spin_unlock(ws_lock); spin_unlock(ws_lock); btrfs_compress_op[idx]->free_workspace(workspace); btrfs_compress_op[idx]->free_workspace(workspace); atomic_dec(alloc_ws); atomic_dec(total_ws); wake: wake: /* /* * Make sure counter is updated before we wake up waiters. * Make sure counter is updated before we wake up waiters. Loading @@ -857,7 +900,7 @@ static void free_workspaces(void) workspace = btrfs_comp_ws[i].idle_ws.next; workspace = btrfs_comp_ws[i].idle_ws.next; list_del(workspace); list_del(workspace); btrfs_compress_op[i]->free_workspace(workspace); btrfs_compress_op[i]->free_workspace(workspace); atomic_dec(&btrfs_comp_ws[i].alloc_ws); atomic_dec(&btrfs_comp_ws[i].total_ws); } } } } } } Loading Loading @@ -894,8 +937,6 @@ int btrfs_compress_pages(int type, struct address_space *mapping, int ret; int ret; workspace = find_workspace(type); workspace = find_workspace(type); if (IS_ERR(workspace)) return PTR_ERR(workspace); ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping, ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping, start, len, pages, start, len, pages, Loading Loading @@ -930,8 +971,6 @@ static int btrfs_decompress_biovec(int type, struct page **pages_in, int ret; int ret; workspace = find_workspace(type); workspace = find_workspace(type); if (IS_ERR(workspace)) return PTR_ERR(workspace); ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in, ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in, disk_start, disk_start, Loading @@ -952,8 +991,6 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, int ret; int ret; workspace = find_workspace(type); workspace = find_workspace(type); if (IS_ERR(workspace)) return PTR_ERR(workspace); ret = btrfs_compress_op[type-1]->decompress(workspace, data_in, ret = btrfs_compress_op[type-1]->decompress(workspace, data_in, dest_page, start_byte, dest_page, start_byte, Loading fs/btrfs/ctree.c +3 −3 Original line number Original line Diff line number Diff line Loading @@ -1011,7 +1011,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, return ret; return ret; if (refs == 0) { if (refs == 0) { ret = -EROFS; ret = -EROFS; btrfs_std_error(root->fs_info, ret, NULL); btrfs_handle_fs_error(root->fs_info, ret, NULL); return ret; return ret; } } } else { } else { Loading Loading @@ -1928,7 +1928,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, child = read_node_slot(root, mid, 0); child = read_node_slot(root, mid, 0); if (!child) { if (!child) { ret = -EROFS; ret = -EROFS; btrfs_std_error(root->fs_info, ret, NULL); btrfs_handle_fs_error(root->fs_info, ret, NULL); goto enospc; goto enospc; } } Loading Loading @@ -2031,7 +2031,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, */ */ if (!left) { if (!left) { ret = -EROFS; ret = -EROFS; btrfs_std_error(root->fs_info, ret, NULL); btrfs_handle_fs_error(root->fs_info, ret, NULL); goto enospc; goto enospc; } } wret = balance_node_right(trans, root, mid, left); wret = balance_node_right(trans, root, mid, left); Loading Loading
fs/btrfs/backref.c +1 −1 Original line number Original line Diff line number Diff line Loading @@ -1991,7 +1991,7 @@ struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, ifp = kmalloc(sizeof(*ifp), GFP_NOFS); ifp = kmalloc(sizeof(*ifp), GFP_NOFS); if (!ifp) { if (!ifp) { kfree(fspath); vfree(fspath); return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM); } } Loading
fs/btrfs/compression.c +61 −24 Original line number Original line Diff line number Diff line Loading @@ -743,8 +743,11 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, static struct { static struct { struct list_head idle_ws; struct list_head idle_ws; spinlock_t ws_lock; spinlock_t ws_lock; int num_ws; /* Number of free workspaces */ atomic_t alloc_ws; int free_ws; /* Total number of allocated workspaces */ atomic_t total_ws; /* Waiters for a free workspace */ wait_queue_head_t ws_wait; wait_queue_head_t ws_wait; } btrfs_comp_ws[BTRFS_COMPRESS_TYPES]; } btrfs_comp_ws[BTRFS_COMPRESS_TYPES]; Loading @@ -758,16 +761,34 @@ void __init btrfs_init_compress(void) int i; int i; for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) { for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) { struct list_head *workspace; INIT_LIST_HEAD(&btrfs_comp_ws[i].idle_ws); INIT_LIST_HEAD(&btrfs_comp_ws[i].idle_ws); spin_lock_init(&btrfs_comp_ws[i].ws_lock); spin_lock_init(&btrfs_comp_ws[i].ws_lock); atomic_set(&btrfs_comp_ws[i].alloc_ws, 0); atomic_set(&btrfs_comp_ws[i].total_ws, 0); init_waitqueue_head(&btrfs_comp_ws[i].ws_wait); init_waitqueue_head(&btrfs_comp_ws[i].ws_wait); /* * Preallocate one workspace for each compression type so * we can guarantee forward progress in the worst case */ workspace = btrfs_compress_op[i]->alloc_workspace(); if (IS_ERR(workspace)) { printk(KERN_WARNING "BTRFS: cannot preallocate compression workspace, will try later"); } else { atomic_set(&btrfs_comp_ws[i].total_ws, 1); btrfs_comp_ws[i].free_ws = 1; list_add(workspace, &btrfs_comp_ws[i].idle_ws); } } } } } /* /* * this finds an available workspace or allocates a new one * This finds an available workspace or allocates a new one. * ERR_PTR is returned if things go bad. * If it's not possible to allocate a new one, waits until there's one. * Preallocation makes a forward progress guarantees and we do not return * errors. */ */ static struct list_head *find_workspace(int type) static struct list_head *find_workspace(int type) { { Loading @@ -777,36 +798,58 @@ static struct list_head *find_workspace(int type) struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; atomic_t *alloc_ws = &btrfs_comp_ws[idx].alloc_ws; atomic_t *total_ws = &btrfs_comp_ws[idx].total_ws; wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; int *num_ws = &btrfs_comp_ws[idx].num_ws; int *free_ws = &btrfs_comp_ws[idx].free_ws; again: again: spin_lock(ws_lock); spin_lock(ws_lock); if (!list_empty(idle_ws)) { if (!list_empty(idle_ws)) { workspace = idle_ws->next; workspace = idle_ws->next; list_del(workspace); list_del(workspace); (*num_ws)--; (*free_ws)--; spin_unlock(ws_lock); spin_unlock(ws_lock); return workspace; return workspace; } } if (atomic_read(alloc_ws) > cpus) { if (atomic_read(total_ws) > cpus) { DEFINE_WAIT(wait); DEFINE_WAIT(wait); spin_unlock(ws_lock); spin_unlock(ws_lock); prepare_to_wait(ws_wait, &wait, TASK_UNINTERRUPTIBLE); prepare_to_wait(ws_wait, &wait, TASK_UNINTERRUPTIBLE); if (atomic_read(alloc_ws) > cpus && !*num_ws) if (atomic_read(total_ws) > cpus && !*free_ws) schedule(); schedule(); finish_wait(ws_wait, &wait); finish_wait(ws_wait, &wait); goto again; goto again; } } atomic_inc(alloc_ws); atomic_inc(total_ws); spin_unlock(ws_lock); spin_unlock(ws_lock); workspace = btrfs_compress_op[idx]->alloc_workspace(); workspace = btrfs_compress_op[idx]->alloc_workspace(); if (IS_ERR(workspace)) { if (IS_ERR(workspace)) { atomic_dec(alloc_ws); atomic_dec(total_ws); wake_up(ws_wait); wake_up(ws_wait); /* * Do not return the error but go back to waiting. There's a * workspace preallocated for each type and the compression * time is bounded so we get to a workspace eventually. This * makes our caller's life easier. * * To prevent silent and low-probability deadlocks (when the * initial preallocation fails), check if there are any * workspaces at all. */ if (atomic_read(total_ws) == 0) { static DEFINE_RATELIMIT_STATE(_rs, /* once per minute */ 60 * HZ, /* no burst */ 1); if (__ratelimit(&_rs)) { printk(KERN_WARNING "no compression workspaces, low memory, retrying"); } } goto again; } } return workspace; return workspace; } } Loading @@ -820,21 +863,21 @@ static void free_workspace(int type, struct list_head *workspace) int idx = type - 1; int idx = type - 1; struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; atomic_t *alloc_ws = &btrfs_comp_ws[idx].alloc_ws; atomic_t *total_ws = &btrfs_comp_ws[idx].total_ws; wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; int *num_ws = &btrfs_comp_ws[idx].num_ws; int *free_ws = &btrfs_comp_ws[idx].free_ws; spin_lock(ws_lock); spin_lock(ws_lock); if (*num_ws < num_online_cpus()) { if (*free_ws < num_online_cpus()) { list_add(workspace, idle_ws); list_add(workspace, idle_ws); (*num_ws)++; (*free_ws)++; spin_unlock(ws_lock); spin_unlock(ws_lock); goto wake; goto wake; } } spin_unlock(ws_lock); spin_unlock(ws_lock); btrfs_compress_op[idx]->free_workspace(workspace); btrfs_compress_op[idx]->free_workspace(workspace); atomic_dec(alloc_ws); atomic_dec(total_ws); wake: wake: /* /* * Make sure counter is updated before we wake up waiters. * Make sure counter is updated before we wake up waiters. Loading @@ -857,7 +900,7 @@ static void free_workspaces(void) workspace = btrfs_comp_ws[i].idle_ws.next; workspace = btrfs_comp_ws[i].idle_ws.next; list_del(workspace); list_del(workspace); btrfs_compress_op[i]->free_workspace(workspace); btrfs_compress_op[i]->free_workspace(workspace); atomic_dec(&btrfs_comp_ws[i].alloc_ws); atomic_dec(&btrfs_comp_ws[i].total_ws); } } } } } } Loading Loading @@ -894,8 +937,6 @@ int btrfs_compress_pages(int type, struct address_space *mapping, int ret; int ret; workspace = find_workspace(type); workspace = find_workspace(type); if (IS_ERR(workspace)) return PTR_ERR(workspace); ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping, ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping, start, len, pages, start, len, pages, Loading Loading @@ -930,8 +971,6 @@ static int btrfs_decompress_biovec(int type, struct page **pages_in, int ret; int ret; workspace = find_workspace(type); workspace = find_workspace(type); if (IS_ERR(workspace)) return PTR_ERR(workspace); ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in, ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in, disk_start, disk_start, Loading @@ -952,8 +991,6 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, int ret; int ret; workspace = find_workspace(type); workspace = find_workspace(type); if (IS_ERR(workspace)) return PTR_ERR(workspace); ret = btrfs_compress_op[type-1]->decompress(workspace, data_in, ret = btrfs_compress_op[type-1]->decompress(workspace, data_in, dest_page, start_byte, dest_page, start_byte, Loading
fs/btrfs/ctree.c +3 −3 Original line number Original line Diff line number Diff line Loading @@ -1011,7 +1011,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, return ret; return ret; if (refs == 0) { if (refs == 0) { ret = -EROFS; ret = -EROFS; btrfs_std_error(root->fs_info, ret, NULL); btrfs_handle_fs_error(root->fs_info, ret, NULL); return ret; return ret; } } } else { } else { Loading Loading @@ -1928,7 +1928,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, child = read_node_slot(root, mid, 0); child = read_node_slot(root, mid, 0); if (!child) { if (!child) { ret = -EROFS; ret = -EROFS; btrfs_std_error(root->fs_info, ret, NULL); btrfs_handle_fs_error(root->fs_info, ret, NULL); goto enospc; goto enospc; } } Loading Loading @@ -2031,7 +2031,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, */ */ if (!left) { if (!left) { ret = -EROFS; ret = -EROFS; btrfs_std_error(root->fs_info, ret, NULL); btrfs_handle_fs_error(root->fs_info, ret, NULL); goto enospc; goto enospc; } } wret = balance_node_right(trans, root, mid, left); wret = balance_node_right(trans, root, mid, left); Loading