Commit 474a503d authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable

* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable:
  Btrfs: fix file clone ioctl for bookend extents
  Btrfs: fix uninit compiler warning in cow_file_range_nocow
  Btrfs: constify dentry_operations
  Btrfs: optimize back reference update during btrfs_drop_snapshot
  Btrfs: remove negative dentry when deleting subvolumne
  Btrfs: optimize fsync for the single writer case
  Btrfs: async delalloc flushing under space pressure
  Btrfs: release delalloc reservations on extent item insertion
  Btrfs: delay clearing EXTENT_DELALLOC for compressed extents
  Btrfs: cleanup extent_clear_unlock_delalloc flags
  Btrfs: fix possible softlockup in the allocator
  Btrfs: fix deadlock on async thread startup
parents d43c36dc ac6889cb
...@@ -63,6 +63,51 @@ struct btrfs_worker_thread { ...@@ -63,6 +63,51 @@ struct btrfs_worker_thread {
int idle; int idle;
}; };
/*
* btrfs_start_workers uses kthread_run, which can block waiting for memory
* for a very long time. It will actually throttle on page writeback,
* and so it may not make progress until after our btrfs worker threads
* process all of the pending work structs in their queue
*
* This means we can't use btrfs_start_workers from inside a btrfs worker
* thread that is used as part of cleaning dirty memory, which pretty much
* involves all of the worker threads.
*
* Instead we have a helper queue who never has more than one thread
* where we scheduler thread start operations. This worker_start struct
* is used to contain the work and hold a pointer to the queue that needs
* another worker.
*/
struct worker_start {
struct btrfs_work work;
struct btrfs_workers *queue;
};
static void start_new_worker_func(struct btrfs_work *work)
{
struct worker_start *start;
start = container_of(work, struct worker_start, work);
btrfs_start_workers(start->queue, 1);
kfree(start);
}
static int start_new_worker(struct btrfs_workers *queue)
{
struct worker_start *start;
int ret;
start = kzalloc(sizeof(*start), GFP_NOFS);
if (!start)
return -ENOMEM;
start->work.func = start_new_worker_func;
start->queue = queue;
ret = btrfs_queue_worker(queue->atomic_worker_start, &start->work);
if (ret)
kfree(start);
return ret;
}
/* /*
* helper function to move a thread onto the idle list after it * helper function to move a thread onto the idle list after it
* has finished some requests. * has finished some requests.
...@@ -118,11 +163,13 @@ static void check_pending_worker_creates(struct btrfs_worker_thread *worker) ...@@ -118,11 +163,13 @@ static void check_pending_worker_creates(struct btrfs_worker_thread *worker)
goto out; goto out;
workers->atomic_start_pending = 0; workers->atomic_start_pending = 0;
if (workers->num_workers >= workers->max_workers) if (workers->num_workers + workers->num_workers_starting >=
workers->max_workers)
goto out; goto out;
workers->num_workers_starting += 1;
spin_unlock_irqrestore(&workers->lock, flags); spin_unlock_irqrestore(&workers->lock, flags);
btrfs_start_workers(workers, 1); start_new_worker(workers);
return; return;
out: out:
...@@ -390,9 +437,11 @@ int btrfs_stop_workers(struct btrfs_workers *workers) ...@@ -390,9 +437,11 @@ int btrfs_stop_workers(struct btrfs_workers *workers)
/* /*
* simple init on struct btrfs_workers * simple init on struct btrfs_workers
*/ */
void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max) void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
struct btrfs_workers *async_helper)
{ {
workers->num_workers = 0; workers->num_workers = 0;
workers->num_workers_starting = 0;
INIT_LIST_HEAD(&workers->worker_list); INIT_LIST_HEAD(&workers->worker_list);
INIT_LIST_HEAD(&workers->idle_list); INIT_LIST_HEAD(&workers->idle_list);
INIT_LIST_HEAD(&workers->order_list); INIT_LIST_HEAD(&workers->order_list);
...@@ -404,14 +453,15 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max) ...@@ -404,14 +453,15 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max)
workers->name = name; workers->name = name;
workers->ordered = 0; workers->ordered = 0;
workers->atomic_start_pending = 0; workers->atomic_start_pending = 0;
workers->atomic_worker_start = 0; workers->atomic_worker_start = async_helper;
} }
/* /*
* starts new worker threads. This does not enforce the max worker * starts new worker threads. This does not enforce the max worker
* count in case you need to temporarily go past it. * count in case you need to temporarily go past it.
*/ */
int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) static int __btrfs_start_workers(struct btrfs_workers *workers,
int num_workers)
{ {
struct btrfs_worker_thread *worker; struct btrfs_worker_thread *worker;
int ret = 0; int ret = 0;
...@@ -444,6 +494,8 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) ...@@ -444,6 +494,8 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
list_add_tail(&worker->worker_list, &workers->idle_list); list_add_tail(&worker->worker_list, &workers->idle_list);
worker->idle = 1; worker->idle = 1;
workers->num_workers++; workers->num_workers++;
workers->num_workers_starting--;
WARN_ON(workers->num_workers_starting < 0);
spin_unlock_irq(&workers->lock); spin_unlock_irq(&workers->lock);
} }
return 0; return 0;
...@@ -452,6 +504,14 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) ...@@ -452,6 +504,14 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
return ret; return ret;
} }
int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
{
spin_lock_irq(&workers->lock);
workers->num_workers_starting += num_workers;
spin_unlock_irq(&workers->lock);
return __btrfs_start_workers(workers, num_workers);
}
/* /*
* run through the list and find a worker thread that doesn't have a lot * run through the list and find a worker thread that doesn't have a lot
* to do right now. This can return null if we aren't yet at the thread * to do right now. This can return null if we aren't yet at the thread
...@@ -461,7 +521,10 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers) ...@@ -461,7 +521,10 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers)
{ {
struct btrfs_worker_thread *worker; struct btrfs_worker_thread *worker;
struct list_head *next; struct list_head *next;
int enforce_min = workers->num_workers < workers->max_workers; int enforce_min;
enforce_min = (workers->num_workers + workers->num_workers_starting) <
workers->max_workers;
/* /*
* if we find an idle thread, don't move it to the end of the * if we find an idle thread, don't move it to the end of the
...@@ -509,15 +572,17 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) ...@@ -509,15 +572,17 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers)
worker = next_worker(workers); worker = next_worker(workers);
if (!worker) { if (!worker) {
if (workers->num_workers >= workers->max_workers) { if (workers->num_workers + workers->num_workers_starting >=
workers->max_workers) {
goto fallback; goto fallback;
} else if (workers->atomic_worker_start) { } else if (workers->atomic_worker_start) {
workers->atomic_start_pending = 1; workers->atomic_start_pending = 1;
goto fallback; goto fallback;
} else { } else {
workers->num_workers_starting++;
spin_unlock_irqrestore(&workers->lock, flags); spin_unlock_irqrestore(&workers->lock, flags);
/* we're below the limit, start another worker */ /* we're below the limit, start another worker */
btrfs_start_workers(workers, 1); __btrfs_start_workers(workers, 1);
goto again; goto again;
} }
} }
......
...@@ -64,6 +64,8 @@ struct btrfs_workers { ...@@ -64,6 +64,8 @@ struct btrfs_workers {
/* current number of running workers */ /* current number of running workers */
int num_workers; int num_workers;
int num_workers_starting;
/* max number of workers allowed. changed by btrfs_start_workers */ /* max number of workers allowed. changed by btrfs_start_workers */
int max_workers; int max_workers;
...@@ -78,9 +80,10 @@ struct btrfs_workers { ...@@ -78,9 +80,10 @@ struct btrfs_workers {
/* /*
* are we allowed to sleep while starting workers or are we required * are we allowed to sleep while starting workers or are we required
* to start them at a later time? * to start them at a later time? If we can't sleep, this indicates
* which queue we need to use to schedule thread creation.
*/ */
int atomic_worker_start; struct btrfs_workers *atomic_worker_start;
/* list with all the work threads. The workers on the idle thread /* list with all the work threads. The workers on the idle thread
* may be actively servicing jobs, but they haven't yet hit the * may be actively servicing jobs, but they haven't yet hit the
...@@ -109,7 +112,8 @@ struct btrfs_workers { ...@@ -109,7 +112,8 @@ struct btrfs_workers {
int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work); int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work);
int btrfs_start_workers(struct btrfs_workers *workers, int num_workers); int btrfs_start_workers(struct btrfs_workers *workers, int num_workers);
int btrfs_stop_workers(struct btrfs_workers *workers); int btrfs_stop_workers(struct btrfs_workers *workers);
void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max); void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
struct btrfs_workers *async_starter);
int btrfs_requeue_work(struct btrfs_work *work); int btrfs_requeue_work(struct btrfs_work *work);
void btrfs_set_work_high_prio(struct btrfs_work *work); void btrfs_set_work_high_prio(struct btrfs_work *work);
#endif #endif
...@@ -128,12 +128,14 @@ struct btrfs_inode { ...@@ -128,12 +128,14 @@ struct btrfs_inode {
u64 last_unlink_trans; u64 last_unlink_trans;
/* /*
* These two counters are for delalloc metadata reservations. We keep * Counters to keep track of the number of extent item's we may use due
* track of how many extents we've accounted for vs how many extents we * to delalloc and such. outstanding_extents is the number of extent
* have. * items we think we'll end up using, and reserved_extents is the number
* of extent items we've reserved metadata for.
*/ */
int delalloc_reserved_extents; spinlock_t accounting_lock;
int delalloc_extents; int reserved_extents;
int outstanding_extents;
/* /*
* ordered_data_close is set by truncate when a file that used * ordered_data_close is set by truncate when a file that used
......
...@@ -691,14 +691,17 @@ struct btrfs_space_info { ...@@ -691,14 +691,17 @@ struct btrfs_space_info {
struct list_head list; struct list_head list;
/* for controlling how we free up space for allocations */
wait_queue_head_t allocate_wait;
wait_queue_head_t flush_wait;
int allocating_chunk;
int flushing;
/* for block groups in our same type */ /* for block groups in our same type */
struct list_head block_groups; struct list_head block_groups;
spinlock_t lock; spinlock_t lock;
struct rw_semaphore groups_sem; struct rw_semaphore groups_sem;
atomic_t caching_threads; atomic_t caching_threads;
int allocating_chunk;
wait_queue_head_t wait;
}; };
/* /*
...@@ -907,6 +910,7 @@ struct btrfs_fs_info { ...@@ -907,6 +910,7 @@ struct btrfs_fs_info {
* A third pool does submit_bio to avoid deadlocking with the other * A third pool does submit_bio to avoid deadlocking with the other
* two * two
*/ */
struct btrfs_workers generic_worker;
struct btrfs_workers workers; struct btrfs_workers workers;
struct btrfs_workers delalloc_workers; struct btrfs_workers delalloc_workers;
struct btrfs_workers endio_workers; struct btrfs_workers endio_workers;
...@@ -914,6 +918,7 @@ struct btrfs_fs_info { ...@@ -914,6 +918,7 @@ struct btrfs_fs_info {
struct btrfs_workers endio_meta_write_workers; struct btrfs_workers endio_meta_write_workers;
struct btrfs_workers endio_write_workers; struct btrfs_workers endio_write_workers;
struct btrfs_workers submit_workers; struct btrfs_workers submit_workers;
struct btrfs_workers enospc_workers;
/* /*
* fixup workers take dirty pages that didn't properly go through * fixup workers take dirty pages that didn't properly go through
* the cow mechanism and make them safe to write. It happens * the cow mechanism and make them safe to write. It happens
...@@ -1005,6 +1010,8 @@ struct btrfs_root { ...@@ -1005,6 +1010,8 @@ struct btrfs_root {
atomic_t log_commit[2]; atomic_t log_commit[2];
unsigned long log_transid; unsigned long log_transid;
unsigned long log_batch; unsigned long log_batch;
pid_t log_start_pid;
bool log_multiple_pids;
u64 objectid; u64 objectid;
u64 last_trans; u64 last_trans;
...@@ -2323,7 +2330,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); ...@@ -2323,7 +2330,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
void btrfs_orphan_cleanup(struct btrfs_root *root); void btrfs_orphan_cleanup(struct btrfs_root *root);
int btrfs_cont_expand(struct inode *inode, loff_t size); int btrfs_cont_expand(struct inode *inode, loff_t size);
int btrfs_invalidate_inodes(struct btrfs_root *root); int btrfs_invalidate_inodes(struct btrfs_root *root);
extern struct dentry_operations btrfs_dentry_operations; extern const struct dentry_operations btrfs_dentry_operations;
/* ioctl.c */ /* ioctl.c */
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
......
...@@ -1746,21 +1746,25 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1746,21 +1746,25 @@ struct btrfs_root *open_ctree(struct super_block *sb,
err = -EINVAL; err = -EINVAL;
goto fail_iput; goto fail_iput;
} }
printk("thread pool is %d\n", fs_info->thread_pool_size);
/* btrfs_init_workers(&fs_info->generic_worker,
* we need to start all the end_io workers up front because the "genwork", 1, NULL);
* queue work function gets called at interrupt time, and so it
* cannot dynamically grow.
*/
btrfs_init_workers(&fs_info->workers, "worker", btrfs_init_workers(&fs_info->workers, "worker",
fs_info->thread_pool_size); fs_info->thread_pool_size,
&fs_info->generic_worker);
btrfs_init_workers(&fs_info->delalloc_workers, "delalloc", btrfs_init_workers(&fs_info->delalloc_workers, "delalloc",
fs_info->thread_pool_size); fs_info->thread_pool_size,
&fs_info->generic_worker);
btrfs_init_workers(&fs_info->submit_workers, "submit", btrfs_init_workers(&fs_info->submit_workers, "submit",
min_t(u64, fs_devices->num_devices, min_t(u64, fs_devices->num_devices,
fs_info->thread_pool_size)); fs_info->thread_pool_size),
&fs_info->generic_worker);
btrfs_init_workers(&fs_info->enospc_workers, "enospc",
fs_info->thread_pool_size,
&fs_info->generic_worker);
/* a higher idle thresh on the submit workers makes it much more /* a higher idle thresh on the submit workers makes it much more
* likely that bios will be send down in a sane order to the * likely that bios will be send down in a sane order to the
...@@ -1774,15 +1778,20 @@ printk("thread pool is %d\n", fs_info->thread_pool_size); ...@@ -1774,15 +1778,20 @@ printk("thread pool is %d\n", fs_info->thread_pool_size);
fs_info->delalloc_workers.idle_thresh = 2; fs_info->delalloc_workers.idle_thresh = 2;
fs_info->delalloc_workers.ordered = 1; fs_info->delalloc_workers.ordered = 1;
btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1); btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1,
&fs_info->generic_worker);
btrfs_init_workers(&fs_info->endio_workers, "endio", btrfs_init_workers(&fs_info->endio_workers, "endio",
fs_info->thread_pool_size); fs_info->thread_pool_size,
&fs_info->generic_worker);
btrfs_init_workers(&fs_info->endio_meta_workers, "endio-meta", btrfs_init_workers(&fs_info->endio_meta_workers, "endio-meta",
fs_info->thread_pool_size); fs_info->thread_pool_size,
&fs_info->generic_worker);
btrfs_init_workers(&fs_info->endio_meta_write_workers, btrfs_init_workers(&fs_info->endio_meta_write_workers,
"endio-meta-write", fs_info->thread_pool_size); "endio-meta-write", fs_info->thread_pool_size,
&fs_info->generic_worker);
btrfs_init_workers(&fs_info->endio_write_workers, "endio-write", btrfs_init_workers(&fs_info->endio_write_workers, "endio-write",
fs_info->thread_pool_size); fs_info->thread_pool_size,
&fs_info->generic_worker);
/* /*
* endios are largely parallel and should have a very * endios are largely parallel and should have a very
...@@ -1794,12 +1803,8 @@ printk("thread pool is %d\n", fs_info->thread_pool_size); ...@@ -1794,12 +1803,8 @@ printk("thread pool is %d\n", fs_info->thread_pool_size);
fs_info->endio_write_workers.idle_thresh = 2; fs_info->endio_write_workers.idle_thresh = 2;
fs_info->endio_meta_write_workers.idle_thresh = 2; fs_info->endio_meta_write_workers.idle_thresh = 2;
fs_info->endio_workers.atomic_worker_start = 1;
fs_info->endio_meta_workers.atomic_worker_start = 1;
fs_info->endio_write_workers.atomic_worker_start = 1;
fs_info->endio_meta_write_workers.atomic_worker_start = 1;
btrfs_start_workers(&fs_info->workers, 1); btrfs_start_workers(&fs_info->workers, 1);
btrfs_start_workers(&fs_info->generic_worker, 1);
btrfs_start_workers(&fs_info->submit_workers, 1); btrfs_start_workers(&fs_info->submit_workers, 1);
btrfs_start_workers(&fs_info->delalloc_workers, 1); btrfs_start_workers(&fs_info->delalloc_workers, 1);
btrfs_start_workers(&fs_info->fixup_workers, 1); btrfs_start_workers(&fs_info->fixup_workers, 1);
...@@ -1807,6 +1812,7 @@ printk("thread pool is %d\n", fs_info->thread_pool_size); ...@@ -1807,6 +1812,7 @@ printk("thread pool is %d\n", fs_info->thread_pool_size);
btrfs_start_workers(&fs_info->endio_meta_workers, 1); btrfs_start_workers(&fs_info->endio_meta_workers, 1);
btrfs_start_workers(&fs_info->endio_meta_write_workers, 1); btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
btrfs_start_workers(&fs_info->endio_write_workers, 1); btrfs_start_workers(&fs_info->endio_write_workers, 1);
btrfs_start_workers(&fs_info->enospc_workers, 1);
fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
...@@ -2012,6 +2018,7 @@ printk("thread pool is %d\n", fs_info->thread_pool_size); ...@@ -2012,6 +2018,7 @@ printk("thread pool is %d\n", fs_info->thread_pool_size);
free_extent_buffer(chunk_root->node); free_extent_buffer(chunk_root->node);
free_extent_buffer(chunk_root->commit_root); free_extent_buffer(chunk_root->commit_root);
fail_sb_buffer: fail_sb_buffer:
btrfs_stop_workers(&fs_info->generic_worker);
btrfs_stop_workers(&fs_info->fixup_workers); btrfs_stop_workers(&fs_info->fixup_workers);
btrfs_stop_workers(&fs_info->delalloc_workers); btrfs_stop_workers(&fs_info->delalloc_workers);
btrfs_stop_workers(&fs_info->workers); btrfs_stop_workers(&fs_info->workers);
...@@ -2020,6 +2027,7 @@ printk("thread pool is %d\n", fs_info->thread_pool_size); ...@@ -2020,6 +2027,7 @@ printk("thread pool is %d\n", fs_info->thread_pool_size);
btrfs_stop_workers(&fs_info->endio_meta_write_workers); btrfs_stop_workers(&fs_info->endio_meta_write_workers);
btrfs_stop_workers(&fs_info->endio_write_workers); btrfs_stop_workers(&fs_info->endio_write_workers);
btrfs_stop_workers(&fs_info->submit_workers); btrfs_stop_workers(&fs_info->submit_workers);
btrfs_stop_workers(&fs_info->enospc_workers);
fail_iput: fail_iput:
invalidate_inode_pages2(fs_info->btree_inode->i_mapping); invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
iput(fs_info->btree_inode); iput(fs_info->btree_inode);
...@@ -2437,6 +2445,7 @@ int close_ctree(struct btrfs_root *root) ...@@ -2437,6 +2445,7 @@ int close_ctree(struct btrfs_root *root)
iput(fs_info->btree_inode); iput(fs_info->btree_inode);
btrfs_stop_workers(&fs_info->generic_worker);
btrfs_stop_workers(&fs_info->fixup_workers); btrfs_stop_workers(&fs_info->fixup_workers);
btrfs_stop_workers(&fs_info->delalloc_workers); btrfs_stop_workers(&fs_info->delalloc_workers);
btrfs_stop_workers(&fs_info->workers); btrfs_stop_workers(&fs_info->workers);
...@@ -2445,6 +2454,7 @@ int close_ctree(struct btrfs_root *root) ...@@ -2445,6 +2454,7 @@ int close_ctree(struct btrfs_root *root)
btrfs_stop_workers(&fs_info->endio_meta_write_workers); btrfs_stop_workers(&fs_info->endio_meta_write_workers);
btrfs_stop_workers(&fs_info->endio_write_workers); btrfs_stop_workers(&fs_info->endio_write_workers);
btrfs_stop_workers(&fs_info->submit_workers); btrfs_stop_workers(&fs_info->submit_workers);
btrfs_stop_workers(&fs_info->enospc_workers);
btrfs_close_devices(fs_info->fs_devices); btrfs_close_devices(fs_info->fs_devices);
btrfs_mapping_tree_free(&fs_info->mapping_tree); btrfs_mapping_tree_free(&fs_info->mapping_tree);
......
This diff is collapsed.
...@@ -460,7 +460,8 @@ static int clear_state_bit(struct extent_io_tree *tree, ...@@ -460,7 +460,8 @@ static int clear_state_bit(struct extent_io_tree *tree,
struct extent_state *state, int bits, int wake, struct extent_state *state, int bits, int wake,
int delete) int delete)
{ {
int ret = state->state & bits; int bits_to_clear = bits & ~EXTENT_DO_ACCOUNTING;
int ret = state->state & bits_to_clear;
if ((bits & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) { if ((bits & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) {
u64 range = state->end - state->start + 1; u64 range = state->end - state->start + 1;
...@@ -468,7 +469,7 @@ static int clear_state_bit(struct extent_io_tree *tree, ...@@ -468,7 +469,7 @@ static int clear_state_bit(struct extent_io_tree *tree,
tree->dirty_bytes -= range; tree->dirty_bytes -= range;
} }
clear_state_cb(tree, state, bits); clear_state_cb(tree, state, bits);
state->state &= ~bits; state->state &= ~bits_to_clear;
if (wake) if (wake)
wake_up(&state->wq); wake_up(&state->wq);
if (delete || state->state == 0) { if (delete || state->state == 0) {
...@@ -956,7 +957,8 @@ int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -956,7 +957,8 @@ int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
gfp_t mask) gfp_t mask)
{ {
return clear_extent_bit(tree, start, end, return clear_extent_bit(tree, start, end,
EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING, 0, 0,
NULL, mask); NULL, mask);
} }
...@@ -1401,12 +1403,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode, ...@@ -1401,12 +1403,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
int extent_clear_unlock_delalloc(struct inode *inode, int extent_clear_unlock_delalloc(struct inode *inode,
struct extent_io_tree *tree, struct extent_io_tree *tree,
u64 start, u64 end, struct page *locked_page, u64 start, u64 end, struct page *locked_page,
int unlock_pages, unsigned long op)
int clear_unlock,
int clear_delalloc, int clear_dirty,
int set_writeback,
int end_writeback,
int set_private2)
{ {
int ret; int ret;
struct page *pages[16]; struct page *pages[16];
...@@ -1416,17 +1413,21 @@ int extent_clear_unlock_delalloc(struct inode *inode, ...@@ -1416,17 +1413,21 @@ int extent_clear_unlock_delalloc(struct inode *inode,
int i; int i;
int clear_bits = 0; int clear_bits = 0;
if (clear_unlock) if (op & EXTENT_CLEAR_UNLOCK)
clear_bits |= EXTENT_LOCKED; clear_bits |= EXTENT_LOCKED;
if (clear_dirty) if (op & EXTENT_CLEAR_DIRTY)
clear_bits |= EXTENT_DIRTY; clear_bits |= EXTENT_DIRTY;
if (clear_delalloc) if (op & EXTENT_CLEAR_DELALLOC)
clear_bits |= EXTENT_DELALLOC; clear_bits |= EXTENT_DELALLOC;
if (op & EXTENT_CLEAR_ACCOUNTING)
clear_bits |= EXTENT_DO_ACCOUNTING;
clear_extent_bit(tree, start, end, clear_bits, 1, 0, NULL, GFP_NOFS); clear_extent_bit(tree, start, end, clear_bits, 1, 0, NULL, GFP_NOFS);
if (!(unlock_pages || clear_dirty || set_writeback || end_writeback || if (!(op & (EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY |
set_private2)) EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK |
EXTENT_SET_PRIVATE2)))
return 0; return 0;
while (nr_pages > 0) { while (nr_pages > 0) {
...@@ -1435,20 +1436,20 @@ int extent_clear_unlock_delalloc(struct inode *inode, ...@@ -1435,20 +1436,20 @@ int extent_clear_unlock_delalloc(struct inode *inode,
nr_pages, ARRAY_SIZE(pages)), pages); nr_pages, ARRAY_SIZE(pages)), pages);
for (i = 0; i < ret; i++) { for (i = 0; i < ret; i++) {
if (set_private2) if (op & EXTENT_SET_PRIVATE2)
SetPagePrivate2(pages[i]); SetPagePrivate2(pages[i]);
if (pages[i] == locked_page) { if (pages[i] == locked_page) {
page_cache_release(pages[i]); page_cache_release(pages[i]);
continue; continue;
} }
if (clear_dirty) if (op & EXTENT_CLEAR_DIRTY)
clear_page_dirty_for_io(pages[i]); clear_page_dirty_for_io(pages[i]);
if (set_writeback) if (op & EXTENT_SET_WRITEBACK)
set_page_writeback(pages[i]); set_page_writeback(pages[i]);
if (end_writeback) if (op & EXTENT_END_WRITEBACK)
end_page_writeback(pages[i]); end_page_writeback(pages[i]);
if (unlock_pages) if (op & EXTENT_CLEAR_UNLOCK_PAGE)
unlock_page(pages[i]); unlock_page(pages[i]);
page_cache_release(pages[i]); page_cache_release(pages[i]);
} }
...@@ -2714,7 +2715,8 @@ int extent_invalidatepage(struct extent_io_tree *tree, ...@@ -2714,7 +2715,8 @@ int extent_invalidatepage(struct extent_io_tree *tree,
lock_extent(tree, start, end, GFP_NOFS); lock_extent(tree, start, end, GFP_NOFS);
wait_on_page_writeback(page); wait_on_page_writeback(page);
clear_extent_bit(tree, start, end, clear_extent_bit(tree, start, end,
EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC, EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING,
1, 1, NULL, GFP_NOFS); 1, 1, NULL, GFP_NOFS);
return 0; return 0;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define EXTENT_BUFFER_FILLED (1 << 8) #define EXTENT_BUFFER_FILLED (1 << 8)
#define EXTENT_BOUNDARY (1 << 9) #define EXTENT_BOUNDARY (1 << 9)
#define EXTENT_NODATASUM (1 << 10) #define EXTENT_NODATASUM (1 << 10)
#define EXTENT_DO_ACCOUNTING (1 << 11)
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
/* flags for bio submission */ /* flags for bio submission */
...@@ -25,6 +26,16 @@ ...@@ -25,6 +26,16 @@
#define EXTENT_BUFFER_BLOCKING 1 #define EXTENT_BUFFER_BLOCKING 1
#define EXTENT_BUFFER_DIRTY 2 #define EXTENT_BUFFER_DIRTY 2
/* these are flags for extent_clear_unlock_delalloc */
#define EXTENT_CLEAR_UNLOCK_PAGE 0x1
#define EXTENT_CLEAR_UNLOCK 0x2
#define EXTENT_CLEAR_DELALLOC 0x4
#define EXTENT_CLEAR_DIRTY 0x8
#define EXTENT_SET_WRITEBACK 0x10
#define EXTENT_END_WRITEBACK 0x20
#define EXTENT_SET_PRIVATE2 0x40
#define EXTENT_CLEAR_ACCOUNTING 0x80
/* /*
* page->private values. Every page that is controlled by the extent * page->private values. Every page that is controlled by the extent
* map has page->private set to one. * map has page->private set to one.
...@@ -288,10 +299,5 @@ int extent_range_uptodate(struct extent_io_tree *tree, ...@@ -288,10 +299,5 @@ int extent_range_uptodate(struct extent_io_tree *tree,
int extent_clear_unlock_delalloc(struct inode *inode, int extent_clear_unlock_delalloc(struct inode *inode,
struct extent_io_tree *tree, struct extent_io_tree *tree,
u64 start, u64 end, struct page *locked_page, u64 start, u64 end, struct page *locked_page,
int unlock_page, unsigned long op);
int clear_unlock,
int clear_delalloc, int clear_dirty,
int set_writeback,
int end_writeback,
int set_private2);
#endif #endif
...@@ -878,7 +878,8 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file, ...@@ -878,7 +878,8 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
clear_extent_bits(&BTRFS_I(inode)->io_tree, start_pos, clear_extent_bits(&BTRFS_I(inode)->io_tree, start_pos,
last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC, last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING,
GFP_NOFS); GFP_NOFS);
unlock_extent(&BTRFS_I(inode)->io_tree, unlock_extent(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, GFP_NOFS); start_pos, last_pos - 1, GFP_NOFS);
......
...@@ -424,9 +424,12 @@ static noinline int compress_file_range(struct inode *inode, ...@@ -424,9 +424,12 @@ static noinline int compress_file_range(struct inode *inode,
* and free up our temp pages. * and free up our temp pages.
*/ */
extent_clear_unlock_delalloc(inode, extent_clear_unlock_delalloc(inode,
&BTRFS_I(inode)->io_tree, &BTRFS_I(inode)->io_tree,
start, end, NULL, 1, 0, start, end, NULL,
0, 1, 1, 1, 0); EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY |
EXTENT_CLEAR_DELALLOC |
EXTENT_CLEAR_ACCOUNTING |
EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK);
ret = 0; ret = 0;
goto free_pages_out; goto free_pages_out;
} }
...@@ -637,11 +640,14 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -637,11 +640,14 @@ static noinline int submit_compressed_extents(struct inode *inode,
* clear dirty, set writeback and unlock the pages. * clear dirty, set writeback and unlock the pages.
*/ */
extent_clear_unlock_delalloc(inode, extent_clear_unlock_delalloc(inode,
&BTRFS_I(inode)->io_tree, &BTRFS_I(inode)->io_tree,
async_extent->start, async_extent->start,
async_extent->start + async_extent->start +
async_extent->ram_size - 1, async_extent->ram_size - 1,
NULL, 1, 1, 0, 1, 1, 0, 0); NULL, EXTENT_CLEAR_UNLOCK_PAGE |
EXTENT_CLEAR_UNLOCK |
EXTENT_CLEAR_DELALLOC |
EXTENT_CLEAR_DIRTY | EXTENT_SET_WRITEBACK);
ret = btrfs_submit_compressed_write(inode, ret = btrfs_submit_compressed_write(inode,
async_extent->start, async_extent->start,
...@@ -712,9 +718,15 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -712,9 +718,15 @@ static noinline int cow_file_range(struct inode *inode,
start, end, 0, NULL); start, end, 0, NULL);
if (ret == 0) { if (ret == 0) {
extent_clear_unlock_delalloc(inode, extent_clear_unlock_delalloc(inode,
&BTRFS_I(inode)->io_tree, &BTRFS_I(inode)->io_tree,
start, end, NULL, 1, 1, start, end, NULL,
1, 1, 1, 1, 0); EXTENT_CLEAR_UNLOCK_PAGE |
EXTENT_CLEAR_UNLOCK |
EXTENT_CLEAR_DELALLOC |
EXTENT_CLEAR_ACCOUNTING |
EXTENT_CLEAR_DIRTY |
EXTENT_SET_WRITEBACK |
EXTENT_END_WRITEBACK);
*nr_written = *nr_written + *nr_written = *nr_written +
(end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE; (end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE;
*page_started = 1; *page_started = 1;
...@@ -738,6 +750,8 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -738,6 +750,8 @@ static noinline int cow_file_range(struct inode *inode,
btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0); btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0);
while (disk_num_bytes > 0) { while (disk_num_bytes > 0) {
unsigned long op;
cur_alloc_size = min(disk_num_bytes, root->fs_info->max_extent); cur_alloc_size = min(disk_num_bytes, root->fs_info->max_extent);
ret = btrfs_reserve_extent(trans, root, cur_alloc_size, ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
root->sectorsize, 0, alloc_hint, root->sectorsize, 0, alloc_hint,
...@@ -789,10 +803,13 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -789,10 +803,13 @@ static noinline int cow_file_range(struct inode *inode,
* Do set the Private2 bit so we know this page was properly * Do set the Private2 bit so we know this page was properly
* setup for writepage * setup for writepage
*/ */
op = unlock ? EXTENT_CLEAR_UNLOCK_PAGE : 0;
op |= EXTENT_CLEAR_UNLOCK | EXTENT_CLEAR_DELALLOC |
EXTENT_SET_PRIVATE2;
extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree, extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
start, start + ram_size - 1, start, start + ram_size - 1,
locked_page, unlock, 1, locked_page, op);
1, 0, 0, 0, 1);
disk_num_bytes -= cur_alloc_size; disk_num_bytes -= cur_alloc_size;
num_bytes -= cur_alloc_size; num_bytes -= cur_alloc_size;
alloc_hint = ins.objectid + ins.offset; alloc_hint = ins.objectid + ins.offset;
...@@ -864,8 +881,8 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page, ...@@ -864,8 +881,8 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
u64 cur_end; u64 cur_end;
int limit = 10 * 1024 * 1042; int limit = 10 * 1024 * 1042;
clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED | clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED,
EXTENT_DELALLOC, 1, 0, NULL, GFP_NOFS); 1, 0, NULL, GFP_NOFS);
while (start < end) { while (start < end) {
async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS); async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS);
async_cow->inode = inode; async_cow->inode = inode;
...@@ -1006,6 +1023,7 @@ static noinline int run_delalloc_nocow(struct inode *inode, ...@@ -1006,6 +1023,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
if (found_key.offset > cur_offset) { if (found_key.offset > cur_offset) {
extent_end = found_key.offset; extent_end = found_key.offset;
extent_type = 0;
goto out_check; goto out_check;
} }
...@@ -1112,8 +1130,10 @@ static noinline int run_delalloc_nocow(struct inode *inode, ...@@ -1112,8 +1130,10 @@ static noinline int run_delalloc_nocow(struct inode *inode,
BUG_ON(ret); BUG_ON(ret);
extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree, extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
cur_offset, cur_offset + num_bytes - 1, cur_offset, cur_offset + num_bytes - 1,
locked_page, 1, 1, 1, 0, 0, 0, 1); locked_page, EXTENT_CLEAR_UNLOCK_PAGE |
EXTENT_CLEAR_UNLOCK | EXTENT_CLEAR_DELALLOC |
EXTENT_SET_PRIVATE2);
cur_offset = extent_end; cur_offset = extent_end;
if (cur_offset > end) if (cur_offset > end)
break; break;
...@@ -1178,15 +1198,17 @@ static int btrfs_split_extent_hook(struct inode *inode, ...@@ -1178,15 +1198,17 @@ static int btrfs_split_extent_hook(struct inode *inode,
root->fs_info->max_extent); root->fs_info->max_extent);
/* /*
* if we break a large extent up then leave delalloc_extents be, * if we break a large extent up then leave oustanding_extents
* since we've already accounted for the large extent. * be, since we've already accounted for the large extent.
*/ */
if (div64_u64(new_size + root->fs_info->max_extent - 1, if (div64_u64(new_size + root->fs_info->max_extent - 1,
root->fs_info->max_extent) < num_extents) root->fs_info->max_extent) < num_extents)
return 0; return 0;
} }
BTRFS_I(inode)->delalloc_extents++; spin_lock(&BTRFS_I(inode)->accounting_lock);
BTRFS_I(inode)->outstanding_extents++;
spin_unlock(&BTRFS_I(inode)->accounting_lock);
return 0; return 0;
} }
...@@ -1217,7 +1239,9 @@ static int btrfs_merge_extent_hook(struct inode *inode, ...@@ -1217,7 +1239,9 @@ static int btrfs_merge_extent_hook(struct inode *inode,
/* we're not bigger than the max, unreserve the space and go */ /* we're not bigger than the max, unreserve the space and go */
if (new_size <= root->fs_info->max_extent) { if (new_size <= root->fs_info->max_extent) {
BTRFS_I(inode)->delalloc_extents--; spin_lock(&BTRFS_I(inode)->accounting_lock);
BTRFS_I(inode)->outstanding_extents--;
spin_unlock(&BTRFS_I(inode)->accounting_lock);
return 0; return 0;
} }
...@@ -1231,7 +1255,9 @@ static int btrfs_merge_extent_hook(struct inode *inode, ...@@ -1231,7 +1255,9 @@ static int btrfs_merge_extent_hook(struct inode *inode,
root->fs_info->max_extent) > num_extents) root->fs_info->max_extent) > num_extents)
return 0; return 0;
BTRFS_I(inode)->delalloc_extents--; spin_lock(&BTRFS_I(inode)->accounting_lock);
BTRFS_I(inode)->outstanding_extents--;
spin_unlock(&BTRFS_I(inode)->accounting_lock);
return 0; return 0;
} }
...@@ -1253,7 +1279,9 @@ static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end, ...@@ -1253,7 +1279,9 @@ static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) { if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
BTRFS_I(inode)->delalloc_extents++; spin_lock(&BTRFS_I(inode)->accounting_lock);
BTRFS_I(inode)->outstanding_extents++;
spin_unlock(&BTRFS_I(inode)->accounting_lock);
btrfs_delalloc_reserve_space(root, inode, end - start + 1); btrfs_delalloc_reserve_space(root, inode, end - start + 1);
spin_lock(&root->fs_info->delalloc_lock); spin_lock(&root->fs_info->delalloc_lock);
BTRFS_I(inode)->delalloc_bytes += end - start + 1; BTRFS_I(inode)->delalloc_bytes += end - start + 1;
...@@ -1281,8 +1309,12 @@ static int btrfs_clear_bit_hook(struct inode *inode, ...@@ -1281,8 +1309,12 @@ static int btrfs_clear_bit_hook(struct inode *inode,
if ((state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) { if ((state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
BTRFS_I(inode)->delalloc_extents--; if (bits & EXTENT_DO_ACCOUNTING) {
btrfs_unreserve_metadata_for_delalloc(root, inode, 1); spin_lock(&BTRFS_I(inode)->accounting_lock);
BTRFS_I(inode)->outstanding_extents--;
spin_unlock(&BTRFS_I(inode)->accounting_lock);
btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
}
spin_lock(&root->fs_info->delalloc_lock); spin_lock(&root->fs_info->delalloc_lock);
if (state->end - state->start + 1 > if (state->end - state->start + 1 >
...@@ -3598,12 +3630,14 @@ static int btrfs_dentry_delete(struct dentry *dentry) ...@@ -3598,12 +3630,14 @@ static int btrfs_dentry_delete(struct dentry *dentry)
{ {
struct btrfs_root *root; struct btrfs_root *root;
if (!dentry->d_inode) if (!dentry->d_inode && !IS_ROOT(dentry))
return 0; dentry = dentry->d_parent;
root = BTRFS_I(dentry->d_inode)->root; if (dentry->d_inode) {
if (btrfs_root_refs(&root->root_item) == 0) root = BTRFS_I(dentry->d_inode)->root;
return 1; if (btrfs_root_refs(&root->root_item) == 0)
return 1;
}
return 0; return 0;
} }
...@@ -4808,7 +4842,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset) ...@@ -4808,7 +4842,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
*/ */
clear_extent_bit(tree, page_start, page_end, clear_extent_bit(tree, page_start, page_end,
EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_LOCKED, 1, 0, NULL, GFP_NOFS); EXTENT_LOCKED | EXTENT_DO_ACCOUNTING, 1, 0,
NULL, GFP_NOFS);
/* /*
* whoever cleared the private bit is responsible * whoever cleared the private bit is responsible
* for the finish_ordered_io * for the finish_ordered_io
...@@ -4821,8 +4856,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset) ...@@ -4821,8 +4856,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
lock_extent(tree, page_start, page_end, GFP_NOFS); lock_extent(tree, page_start, page_end, GFP_NOFS);
} }
clear_extent_bit(tree, page_start, page_end, clear_extent_bit(tree, page_start, page_end,
EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC, EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
1, 1, NULL, GFP_NOFS); EXTENT_DO_ACCOUNTING, 1, 1, NULL, GFP_NOFS);
__btrfs_releasepage(page, GFP_NOFS); __btrfs_releasepage(page, GFP_NOFS);
ClearPageChecked(page); ClearPageChecked(page);
...@@ -4917,7 +4952,8 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -4917,7 +4952,8 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
* prepare_pages in the normal write path. * prepare_pages in the normal write path.
*/ */
clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end, clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end,
EXTENT_DIRTY | EXTENT_DELALLOC, GFP_NOFS); EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING,
GFP_NOFS);
ret = btrfs_set_extent_delalloc(inode, page_start, page_end); ret = btrfs_set_extent_delalloc(inode, page_start, page_end);
if (ret) { if (ret) {
...@@ -5065,8 +5101,9 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) ...@@ -5065,8 +5101,9 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
return NULL; return NULL;
ei->last_trans = 0; ei->last_trans = 0;
ei->logged_trans = 0; ei->logged_trans = 0;
ei->delalloc_extents = 0; ei->outstanding_extents = 0;
ei->delalloc_reserved_extents = 0; ei->reserved_extents = 0;
spin_lock_init(&ei->accounting_lock);
btrfs_ordered_inode_tree_init(&ei->ordered_tree); btrfs_ordered_inode_tree_init(&ei->ordered_tree);
INIT_LIST_HEAD(&ei->i_orphan); INIT_LIST_HEAD(&ei->i_orphan);
INIT_LIST_HEAD(&ei->ordered_operations); INIT_LIST_HEAD(&ei->ordered_operations);
...@@ -5805,6 +5842,6 @@ static const struct inode_operations btrfs_symlink_inode_operations = { ...@@ -5805,6 +5842,6 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
.removexattr = btrfs_removexattr, .removexattr = btrfs_removexattr,
}; };
struct dentry_operations btrfs_dentry_operations = { const struct dentry_operations btrfs_dentry_operations = {
.d_delete = btrfs_dentry_delete, .d_delete = btrfs_dentry_delete,
}; };
...@@ -830,6 +830,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -830,6 +830,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
out_unlock: out_unlock:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (!err) { if (!err) {
shrink_dcache_sb(root->fs_info->sb);
btrfs_invalidate_inodes(dest); btrfs_invalidate_inodes(dest);
d_delete(dentry); d_delete(dentry);
} }
...@@ -1122,8 +1123,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, ...@@ -1122,8 +1123,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
datao += off - key.offset; datao += off - key.offset;
datal -= off - key.offset; datal -= off - key.offset;
} }
if (key.offset + datao + datal > off + len)
datal = off + len - key.offset - datao; if (key.offset + datal > off + len)
datal = off + len - key.offset;
/* disko == 0 means it's a hole */ /* disko == 0 means it's a hole */
if (!disko) if (!disko)
datao = 0; datao = 0;
......
...@@ -306,6 +306,12 @@ int btrfs_remove_ordered_extent(struct inode *inode, ...@@ -306,6 +306,12 @@ int btrfs_remove_ordered_extent(struct inode *inode,
tree->last = NULL; tree->last = NULL;
set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags); set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);
spin_lock(&BTRFS_I(inode)->accounting_lock);
BTRFS_I(inode)->outstanding_extents--;
spin_unlock(&BTRFS_I(inode)->accounting_lock);
btrfs_unreserve_metadata_for_delalloc(BTRFS_I(inode)->root,
inode, 1);
spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
list_del_init(&entry->root_extent_list); list_del_init(&entry->root_extent_list);
......
...@@ -3518,7 +3518,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) ...@@ -3518,7 +3518,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
BUG_ON(!rc->block_group); BUG_ON(!rc->block_group);
btrfs_init_workers(&rc->workers, "relocate", btrfs_init_workers(&rc->workers, "relocate",
fs_info->thread_pool_size); fs_info->thread_pool_size, NULL);
rc->extent_root = extent_root; rc->extent_root = extent_root;
btrfs_prepare_block_group_relocation(extent_root, rc->block_group); btrfs_prepare_block_group_relocation(extent_root, rc->block_group);
...@@ -3701,7 +3701,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) ...@@ -3701,7 +3701,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
mapping_tree_init(&rc->reloc_root_tree); mapping_tree_init(&rc->reloc_root_tree);
INIT_LIST_HEAD(&rc->reloc_roots); INIT_LIST_HEAD(&rc->reloc_roots);
btrfs_init_workers(&rc->workers, "relocate", btrfs_init_workers(&rc->workers, "relocate",
root->fs_info->thread_pool_size); root->fs_info->thread_pool_size, NULL);
rc->extent_root = root->fs_info->extent_root; rc->extent_root = root->fs_info->extent_root;
set_reloc_control(rc); set_reloc_control(rc);
......
...@@ -137,11 +137,20 @@ static int start_log_trans(struct btrfs_trans_handle *trans, ...@@ -137,11 +137,20 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
mutex_lock(&root->log_mutex); mutex_lock(&root->log_mutex);
if (root->log_root) { if (root->log_root) {
if (!root->log_start_pid) {
root->log_start_pid = current->pid;
root->log_multiple_pids = false;
} else if (root->log_start_pid != current->pid) {
root->log_multiple_pids = true;
}
root->log_batch++; root->log_batch++;
atomic_inc(&root->log_writers); atomic_inc(&root->log_writers);
mutex_unlock(&root->log_mutex); mutex_unlock(&root->log_mutex);
return 0; return 0;
} }
root->log_multiple_pids = false;
root->log_start_pid = current->pid;
mutex_lock(&root->fs_info->tree_log_mutex); mutex_lock(&root->fs_info->tree_log_mutex);
if (!root->fs_info->log_root_tree) { if (!root->fs_info->log_root_tree) {
ret = btrfs_init_log_root_tree(trans, root->fs_info); ret = btrfs_init_log_root_tree(trans, root->fs_info);
...@@ -1985,7 +1994,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -1985,7 +1994,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
if (atomic_read(&root->log_commit[(index1 + 1) % 2])) if (atomic_read(&root->log_commit[(index1 + 1) % 2]))
wait_log_commit(trans, root, root->log_transid - 1); wait_log_commit(trans, root, root->log_transid - 1);
while (1) { while (root->log_multiple_pids) {
unsigned long batch = root->log_batch; unsigned long batch = root->log_batch;
mutex_unlock(&root->log_mutex); mutex_unlock(&root->log_mutex);
schedule_timeout_uninterruptible(1); schedule_timeout_uninterruptible(1);
...@@ -2011,6 +2020,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -2011,6 +2020,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
root->log_batch = 0; root->log_batch = 0;
root->log_transid++; root->log_transid++;
log->log_transid = root->log_transid; log->log_transid = root->log_transid;
root->log_start_pid = 0;
smp_mb(); smp_mb();
/* /*
* log tree has been flushed to disk, new modifications of * log tree has been flushed to disk, new modifications of
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment