mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
This commit is contained in:
commit
83ebade34b
18 changed files with 580 additions and 317 deletions
|
@ -48,6 +48,9 @@ struct btrfs_worker_thread {
|
||||||
/* number of things on the pending list */
|
/* number of things on the pending list */
|
||||||
atomic_t num_pending;
|
atomic_t num_pending;
|
||||||
|
|
||||||
|
/* reference counter for this struct */
|
||||||
|
atomic_t refs;
|
||||||
|
|
||||||
unsigned long sequence;
|
unsigned long sequence;
|
||||||
|
|
||||||
/* protects the pending list. */
|
/* protects the pending list. */
|
||||||
|
@ -93,17 +96,40 @@ static void check_busy_worker(struct btrfs_worker_thread *worker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_pending_worker_creates(struct btrfs_worker_thread *worker)
|
||||||
|
{
|
||||||
|
struct btrfs_workers *workers = worker->workers;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
rmb();
|
||||||
|
if (!workers->atomic_start_pending)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&workers->lock, flags);
|
||||||
|
if (!workers->atomic_start_pending)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
workers->atomic_start_pending = 0;
|
||||||
|
if (workers->num_workers >= workers->max_workers)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&workers->lock, flags);
|
||||||
|
btrfs_start_workers(workers, 1);
|
||||||
|
return;
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock_irqrestore(&workers->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static noinline int run_ordered_completions(struct btrfs_workers *workers,
|
static noinline int run_ordered_completions(struct btrfs_workers *workers,
|
||||||
struct btrfs_work *work)
|
struct btrfs_work *work)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!workers->ordered)
|
if (!workers->ordered)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
set_bit(WORK_DONE_BIT, &work->flags);
|
set_bit(WORK_DONE_BIT, &work->flags);
|
||||||
|
|
||||||
spin_lock_irqsave(&workers->lock, flags);
|
spin_lock(&workers->order_lock);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!list_empty(&workers->prio_order_list)) {
|
if (!list_empty(&workers->prio_order_list)) {
|
||||||
|
@ -126,45 +152,117 @@ static noinline int run_ordered_completions(struct btrfs_workers *workers,
|
||||||
if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags))
|
if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&workers->lock, flags);
|
spin_unlock(&workers->order_lock);
|
||||||
|
|
||||||
work->ordered_func(work);
|
work->ordered_func(work);
|
||||||
|
|
||||||
/* now take the lock again and call the freeing code */
|
/* now take the lock again and call the freeing code */
|
||||||
spin_lock_irqsave(&workers->lock, flags);
|
spin_lock(&workers->order_lock);
|
||||||
list_del(&work->order_list);
|
list_del(&work->order_list);
|
||||||
work->ordered_free(work);
|
work->ordered_free(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&workers->lock, flags);
|
spin_unlock(&workers->order_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void put_worker(struct btrfs_worker_thread *worker)
|
||||||
|
{
|
||||||
|
if (atomic_dec_and_test(&worker->refs))
|
||||||
|
kfree(worker);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_worker_shutdown(struct btrfs_worker_thread *worker)
|
||||||
|
{
|
||||||
|
int freeit = 0;
|
||||||
|
|
||||||
|
spin_lock_irq(&worker->lock);
|
||||||
|
spin_lock_irq(&worker->workers->lock);
|
||||||
|
if (worker->workers->num_workers > 1 &&
|
||||||
|
worker->idle &&
|
||||||
|
!worker->working &&
|
||||||
|
!list_empty(&worker->worker_list) &&
|
||||||
|
list_empty(&worker->prio_pending) &&
|
||||||
|
list_empty(&worker->pending)) {
|
||||||
|
freeit = 1;
|
||||||
|
list_del_init(&worker->worker_list);
|
||||||
|
worker->workers->num_workers--;
|
||||||
|
}
|
||||||
|
spin_unlock_irq(&worker->workers->lock);
|
||||||
|
spin_unlock_irq(&worker->lock);
|
||||||
|
|
||||||
|
if (freeit)
|
||||||
|
put_worker(worker);
|
||||||
|
return freeit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct btrfs_work *get_next_work(struct btrfs_worker_thread *worker,
|
||||||
|
struct list_head *prio_head,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
struct btrfs_work *work = NULL;
|
||||||
|
struct list_head *cur = NULL;
|
||||||
|
|
||||||
|
if(!list_empty(prio_head))
|
||||||
|
cur = prio_head->next;
|
||||||
|
|
||||||
|
smp_mb();
|
||||||
|
if (!list_empty(&worker->prio_pending))
|
||||||
|
goto refill;
|
||||||
|
|
||||||
|
if (!list_empty(head))
|
||||||
|
cur = head->next;
|
||||||
|
|
||||||
|
if (cur)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
refill:
|
||||||
|
spin_lock_irq(&worker->lock);
|
||||||
|
list_splice_tail_init(&worker->prio_pending, prio_head);
|
||||||
|
list_splice_tail_init(&worker->pending, head);
|
||||||
|
|
||||||
|
if (!list_empty(prio_head))
|
||||||
|
cur = prio_head->next;
|
||||||
|
else if (!list_empty(head))
|
||||||
|
cur = head->next;
|
||||||
|
spin_unlock_irq(&worker->lock);
|
||||||
|
|
||||||
|
if (!cur)
|
||||||
|
goto out_fail;
|
||||||
|
|
||||||
|
out:
|
||||||
|
work = list_entry(cur, struct btrfs_work, list);
|
||||||
|
|
||||||
|
out_fail:
|
||||||
|
return work;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* main loop for servicing work items
|
* main loop for servicing work items
|
||||||
*/
|
*/
|
||||||
static int worker_loop(void *arg)
|
static int worker_loop(void *arg)
|
||||||
{
|
{
|
||||||
struct btrfs_worker_thread *worker = arg;
|
struct btrfs_worker_thread *worker = arg;
|
||||||
struct list_head *cur;
|
struct list_head head;
|
||||||
|
struct list_head prio_head;
|
||||||
struct btrfs_work *work;
|
struct btrfs_work *work;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&head);
|
||||||
|
INIT_LIST_HEAD(&prio_head);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
spin_lock_irq(&worker->lock);
|
again:
|
||||||
again_locked:
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!list_empty(&worker->prio_pending))
|
|
||||||
cur = worker->prio_pending.next;
|
|
||||||
else if (!list_empty(&worker->pending))
|
work = get_next_work(worker, &prio_head, &head);
|
||||||
cur = worker->pending.next;
|
if (!work)
|
||||||
else
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
work = list_entry(cur, struct btrfs_work, list);
|
|
||||||
list_del(&work->list);
|
list_del(&work->list);
|
||||||
clear_bit(WORK_QUEUED_BIT, &work->flags);
|
clear_bit(WORK_QUEUED_BIT, &work->flags);
|
||||||
|
|
||||||
work->worker = worker;
|
work->worker = worker;
|
||||||
spin_unlock_irq(&worker->lock);
|
|
||||||
|
|
||||||
work->func(work);
|
work->func(work);
|
||||||
|
|
||||||
|
@ -175,9 +273,13 @@ again_locked:
|
||||||
*/
|
*/
|
||||||
run_ordered_completions(worker->workers, work);
|
run_ordered_completions(worker->workers, work);
|
||||||
|
|
||||||
spin_lock_irq(&worker->lock);
|
check_pending_worker_creates(worker);
|
||||||
check_idle_worker(worker);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irq(&worker->lock);
|
||||||
|
check_idle_worker(worker);
|
||||||
|
|
||||||
if (freezing(current)) {
|
if (freezing(current)) {
|
||||||
worker->working = 0;
|
worker->working = 0;
|
||||||
spin_unlock_irq(&worker->lock);
|
spin_unlock_irq(&worker->lock);
|
||||||
|
@ -216,8 +318,10 @@ again_locked:
|
||||||
spin_lock_irq(&worker->lock);
|
spin_lock_irq(&worker->lock);
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
if (!list_empty(&worker->pending) ||
|
if (!list_empty(&worker->pending) ||
|
||||||
!list_empty(&worker->prio_pending))
|
!list_empty(&worker->prio_pending)) {
|
||||||
goto again_locked;
|
spin_unlock_irq(&worker->lock);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this makes sure we get a wakeup when someone
|
* this makes sure we get a wakeup when someone
|
||||||
|
@ -226,8 +330,13 @@ again_locked:
|
||||||
worker->working = 0;
|
worker->working = 0;
|
||||||
spin_unlock_irq(&worker->lock);
|
spin_unlock_irq(&worker->lock);
|
||||||
|
|
||||||
if (!kthread_should_stop())
|
if (!kthread_should_stop()) {
|
||||||
schedule();
|
schedule_timeout(HZ * 120);
|
||||||
|
if (!worker->working &&
|
||||||
|
try_worker_shutdown(worker)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
__set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
}
|
}
|
||||||
|
@ -242,16 +351,30 @@ int btrfs_stop_workers(struct btrfs_workers *workers)
|
||||||
{
|
{
|
||||||
struct list_head *cur;
|
struct list_head *cur;
|
||||||
struct btrfs_worker_thread *worker;
|
struct btrfs_worker_thread *worker;
|
||||||
|
int can_stop;
|
||||||
|
|
||||||
|
spin_lock_irq(&workers->lock);
|
||||||
list_splice_init(&workers->idle_list, &workers->worker_list);
|
list_splice_init(&workers->idle_list, &workers->worker_list);
|
||||||
while (!list_empty(&workers->worker_list)) {
|
while (!list_empty(&workers->worker_list)) {
|
||||||
cur = workers->worker_list.next;
|
cur = workers->worker_list.next;
|
||||||
worker = list_entry(cur, struct btrfs_worker_thread,
|
worker = list_entry(cur, struct btrfs_worker_thread,
|
||||||
worker_list);
|
worker_list);
|
||||||
kthread_stop(worker->task);
|
|
||||||
list_del(&worker->worker_list);
|
atomic_inc(&worker->refs);
|
||||||
kfree(worker);
|
workers->num_workers -= 1;
|
||||||
|
if (!list_empty(&worker->worker_list)) {
|
||||||
|
list_del_init(&worker->worker_list);
|
||||||
|
put_worker(worker);
|
||||||
|
can_stop = 1;
|
||||||
|
} else
|
||||||
|
can_stop = 0;
|
||||||
|
spin_unlock_irq(&workers->lock);
|
||||||
|
if (can_stop)
|
||||||
|
kthread_stop(worker->task);
|
||||||
|
spin_lock_irq(&workers->lock);
|
||||||
|
put_worker(worker);
|
||||||
}
|
}
|
||||||
|
spin_unlock_irq(&workers->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,10 +389,13 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max)
|
||||||
INIT_LIST_HEAD(&workers->order_list);
|
INIT_LIST_HEAD(&workers->order_list);
|
||||||
INIT_LIST_HEAD(&workers->prio_order_list);
|
INIT_LIST_HEAD(&workers->prio_order_list);
|
||||||
spin_lock_init(&workers->lock);
|
spin_lock_init(&workers->lock);
|
||||||
|
spin_lock_init(&workers->order_lock);
|
||||||
workers->max_workers = max;
|
workers->max_workers = max;
|
||||||
workers->idle_thresh = 32;
|
workers->idle_thresh = 32;
|
||||||
workers->name = name;
|
workers->name = name;
|
||||||
workers->ordered = 0;
|
workers->ordered = 0;
|
||||||
|
workers->atomic_start_pending = 0;
|
||||||
|
workers->atomic_worker_start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -293,7 +419,9 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
|
||||||
INIT_LIST_HEAD(&worker->prio_pending);
|
INIT_LIST_HEAD(&worker->prio_pending);
|
||||||
INIT_LIST_HEAD(&worker->worker_list);
|
INIT_LIST_HEAD(&worker->worker_list);
|
||||||
spin_lock_init(&worker->lock);
|
spin_lock_init(&worker->lock);
|
||||||
|
|
||||||
atomic_set(&worker->num_pending, 0);
|
atomic_set(&worker->num_pending, 0);
|
||||||
|
atomic_set(&worker->refs, 1);
|
||||||
worker->workers = workers;
|
worker->workers = workers;
|
||||||
worker->task = kthread_run(worker_loop, worker,
|
worker->task = kthread_run(worker_loop, worker,
|
||||||
"btrfs-%s-%d", workers->name,
|
"btrfs-%s-%d", workers->name,
|
||||||
|
@ -303,7 +431,6 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
|
||||||
kfree(worker);
|
kfree(worker);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irq(&workers->lock);
|
spin_lock_irq(&workers->lock);
|
||||||
list_add_tail(&worker->worker_list, &workers->idle_list);
|
list_add_tail(&worker->worker_list, &workers->idle_list);
|
||||||
worker->idle = 1;
|
worker->idle = 1;
|
||||||
|
@ -367,28 +494,18 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers)
|
||||||
{
|
{
|
||||||
struct btrfs_worker_thread *worker;
|
struct btrfs_worker_thread *worker;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct list_head *fallback;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
spin_lock_irqsave(&workers->lock, flags);
|
spin_lock_irqsave(&workers->lock, flags);
|
||||||
worker = next_worker(workers);
|
worker = next_worker(workers);
|
||||||
spin_unlock_irqrestore(&workers->lock, flags);
|
|
||||||
|
|
||||||
if (!worker) {
|
if (!worker) {
|
||||||
spin_lock_irqsave(&workers->lock, flags);
|
|
||||||
if (workers->num_workers >= workers->max_workers) {
|
if (workers->num_workers >= workers->max_workers) {
|
||||||
struct list_head *fallback = NULL;
|
goto fallback;
|
||||||
/*
|
} else if (workers->atomic_worker_start) {
|
||||||
* we have failed to find any workers, just
|
workers->atomic_start_pending = 1;
|
||||||
* return the force one
|
goto fallback;
|
||||||
*/
|
|
||||||
if (!list_empty(&workers->worker_list))
|
|
||||||
fallback = workers->worker_list.next;
|
|
||||||
if (!list_empty(&workers->idle_list))
|
|
||||||
fallback = workers->idle_list.next;
|
|
||||||
BUG_ON(!fallback);
|
|
||||||
worker = list_entry(fallback,
|
|
||||||
struct btrfs_worker_thread, worker_list);
|
|
||||||
spin_unlock_irqrestore(&workers->lock, flags);
|
|
||||||
} else {
|
} else {
|
||||||
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 */
|
||||||
|
@ -396,6 +513,23 @@ again:
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&workers->lock, flags);
|
||||||
|
return worker;
|
||||||
|
|
||||||
|
fallback:
|
||||||
|
fallback = NULL;
|
||||||
|
/*
|
||||||
|
* we have failed to find any workers, just
|
||||||
|
* return the first one we can find.
|
||||||
|
*/
|
||||||
|
if (!list_empty(&workers->worker_list))
|
||||||
|
fallback = workers->worker_list.next;
|
||||||
|
if (!list_empty(&workers->idle_list))
|
||||||
|
fallback = workers->idle_list.next;
|
||||||
|
BUG_ON(!fallback);
|
||||||
|
worker = list_entry(fallback,
|
||||||
|
struct btrfs_worker_thread, worker_list);
|
||||||
|
spin_unlock_irqrestore(&workers->lock, flags);
|
||||||
return worker;
|
return worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,9 +569,9 @@ int btrfs_requeue_work(struct btrfs_work *work)
|
||||||
worker->working = 1;
|
worker->working = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&worker->lock, flags);
|
|
||||||
if (wake)
|
if (wake)
|
||||||
wake_up_process(worker->task);
|
wake_up_process(worker->task);
|
||||||
|
spin_unlock_irqrestore(&worker->lock, flags);
|
||||||
out:
|
out:
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -463,14 +597,18 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
|
||||||
|
|
||||||
worker = find_worker(workers);
|
worker = find_worker(workers);
|
||||||
if (workers->ordered) {
|
if (workers->ordered) {
|
||||||
spin_lock_irqsave(&workers->lock, flags);
|
/*
|
||||||
|
* you're not allowed to do ordered queues from an
|
||||||
|
* interrupt handler
|
||||||
|
*/
|
||||||
|
spin_lock(&workers->order_lock);
|
||||||
if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) {
|
if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) {
|
||||||
list_add_tail(&work->order_list,
|
list_add_tail(&work->order_list,
|
||||||
&workers->prio_order_list);
|
&workers->prio_order_list);
|
||||||
} else {
|
} else {
|
||||||
list_add_tail(&work->order_list, &workers->order_list);
|
list_add_tail(&work->order_list, &workers->order_list);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&workers->lock, flags);
|
spin_unlock(&workers->order_lock);
|
||||||
} else {
|
} else {
|
||||||
INIT_LIST_HEAD(&work->order_list);
|
INIT_LIST_HEAD(&work->order_list);
|
||||||
}
|
}
|
||||||
|
@ -492,10 +630,10 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
|
||||||
wake = 1;
|
wake = 1;
|
||||||
worker->working = 1;
|
worker->working = 1;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&worker->lock, flags);
|
|
||||||
|
|
||||||
if (wake)
|
if (wake)
|
||||||
wake_up_process(worker->task);
|
wake_up_process(worker->task);
|
||||||
|
spin_unlock_irqrestore(&worker->lock, flags);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,15 @@ struct btrfs_workers {
|
||||||
/* force completions in the order they were queued */
|
/* force completions in the order they were queued */
|
||||||
int ordered;
|
int ordered;
|
||||||
|
|
||||||
|
/* more workers required, but in an interrupt handler */
|
||||||
|
int atomic_start_pending;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* are we allowed to sleep while starting workers or are we required
|
||||||
|
* to start them at a later time?
|
||||||
|
*/
|
||||||
|
int 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
|
||||||
* idle thresh limit above.
|
* idle thresh limit above.
|
||||||
|
@ -90,6 +99,9 @@ struct btrfs_workers {
|
||||||
/* lock for finding the next worker thread to queue on */
|
/* lock for finding the next worker thread to queue on */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
|
||||||
|
/* lock for the ordered lists */
|
||||||
|
spinlock_t order_lock;
|
||||||
|
|
||||||
/* extra name for this worker, used for current->name */
|
/* extra name for this worker, used for current->name */
|
||||||
char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
|
@ -506,10 +506,10 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
||||||
*/
|
*/
|
||||||
set_page_extent_mapped(page);
|
set_page_extent_mapped(page);
|
||||||
lock_extent(tree, last_offset, end, GFP_NOFS);
|
lock_extent(tree, last_offset, end, GFP_NOFS);
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, last_offset,
|
em = lookup_extent_mapping(em_tree, last_offset,
|
||||||
PAGE_CACHE_SIZE);
|
PAGE_CACHE_SIZE);
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
|
|
||||||
if (!em || last_offset < em->start ||
|
if (!em || last_offset < em->start ||
|
||||||
(last_offset + PAGE_CACHE_SIZE > extent_map_end(em)) ||
|
(last_offset + PAGE_CACHE_SIZE > extent_map_end(em)) ||
|
||||||
|
@ -593,11 +593,11 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||||
em_tree = &BTRFS_I(inode)->extent_tree;
|
em_tree = &BTRFS_I(inode)->extent_tree;
|
||||||
|
|
||||||
/* we need the actual starting offset of this extent in the file */
|
/* we need the actual starting offset of this extent in the file */
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree,
|
em = lookup_extent_mapping(em_tree,
|
||||||
page_offset(bio->bi_io_vec->bv_page),
|
page_offset(bio->bi_io_vec->bv_page),
|
||||||
PAGE_CACHE_SIZE);
|
PAGE_CACHE_SIZE);
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
|
|
||||||
compressed_len = em->block_len;
|
compressed_len = em->block_len;
|
||||||
cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
|
cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
|
||||||
|
|
|
@ -2290,7 +2290,7 @@ extern struct file_operations btrfs_file_operations;
|
||||||
int btrfs_drop_extents(struct btrfs_trans_handle *trans,
|
int btrfs_drop_extents(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, struct inode *inode,
|
struct btrfs_root *root, struct inode *inode,
|
||||||
u64 start, u64 end, u64 locked_end,
|
u64 start, u64 end, u64 locked_end,
|
||||||
u64 inline_limit, u64 *hint_block);
|
u64 inline_limit, u64 *hint_block, int drop_cache);
|
||||||
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
|
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct inode *inode, u64 start, u64 end);
|
struct inode *inode, u64 start, u64 end);
|
||||||
|
|
|
@ -123,15 +123,15 @@ static struct extent_map *btree_get_extent(struct inode *inode,
|
||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, start, len);
|
em = lookup_extent_mapping(em_tree, start, len);
|
||||||
if (em) {
|
if (em) {
|
||||||
em->bdev =
|
em->bdev =
|
||||||
BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
|
BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
|
|
||||||
em = alloc_extent_map(GFP_NOFS);
|
em = alloc_extent_map(GFP_NOFS);
|
||||||
if (!em) {
|
if (!em) {
|
||||||
|
@ -144,7 +144,7 @@ static struct extent_map *btree_get_extent(struct inode *inode,
|
||||||
em->block_start = 0;
|
em->block_start = 0;
|
||||||
em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
|
em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
ret = add_extent_mapping(em_tree, em);
|
ret = add_extent_mapping(em_tree, em);
|
||||||
if (ret == -EEXIST) {
|
if (ret == -EEXIST) {
|
||||||
u64 failed_start = em->start;
|
u64 failed_start = em->start;
|
||||||
|
@ -163,7 +163,7 @@ static struct extent_map *btree_get_extent(struct inode *inode,
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
em = NULL;
|
em = NULL;
|
||||||
}
|
}
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
em = ERR_PTR(ret);
|
em = ERR_PTR(ret);
|
||||||
|
@ -1325,9 +1325,9 @@ static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
|
||||||
offset = page_offset(page);
|
offset = page_offset(page);
|
||||||
|
|
||||||
em_tree = &BTRFS_I(inode)->extent_tree;
|
em_tree = &BTRFS_I(inode)->extent_tree;
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE);
|
em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE);
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
if (!em) {
|
if (!em) {
|
||||||
__unplug_io_fn(bdi, page);
|
__unplug_io_fn(bdi, page);
|
||||||
return;
|
return;
|
||||||
|
@ -1698,7 +1698,7 @@ 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);
|
||||||
/*
|
/*
|
||||||
* we need to start all the end_io workers up front because the
|
* we need to start all the end_io workers up front because the
|
||||||
* queue work function gets called at interrupt time, and so it
|
* queue work function gets called at interrupt time, and so it
|
||||||
|
@ -1743,20 +1743,22 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||||
fs_info->endio_workers.idle_thresh = 4;
|
fs_info->endio_workers.idle_thresh = 4;
|
||||||
fs_info->endio_meta_workers.idle_thresh = 4;
|
fs_info->endio_meta_workers.idle_thresh = 4;
|
||||||
|
|
||||||
fs_info->endio_write_workers.idle_thresh = 64;
|
fs_info->endio_write_workers.idle_thresh = 2;
|
||||||
fs_info->endio_meta_write_workers.idle_thresh = 64;
|
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->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);
|
||||||
btrfs_start_workers(&fs_info->endio_workers, fs_info->thread_pool_size);
|
btrfs_start_workers(&fs_info->endio_workers, 1);
|
||||||
btrfs_start_workers(&fs_info->endio_meta_workers,
|
btrfs_start_workers(&fs_info->endio_meta_workers, 1);
|
||||||
fs_info->thread_pool_size);
|
btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
|
||||||
btrfs_start_workers(&fs_info->endio_meta_write_workers,
|
btrfs_start_workers(&fs_info->endio_write_workers, 1);
|
||||||
fs_info->thread_pool_size);
|
|
||||||
btrfs_start_workers(&fs_info->endio_write_workers,
|
|
||||||
fs_info->thread_pool_size);
|
|
||||||
|
|
||||||
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,
|
||||||
|
|
|
@ -5396,9 +5396,9 @@ static noinline int relocate_data_extent(struct inode *reloc_inode,
|
||||||
lock_extent(&BTRFS_I(reloc_inode)->io_tree, start, end, GFP_NOFS);
|
lock_extent(&BTRFS_I(reloc_inode)->io_tree, start, end, GFP_NOFS);
|
||||||
while (1) {
|
while (1) {
|
||||||
int ret;
|
int ret;
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
ret = add_extent_mapping(em_tree, em);
|
ret = add_extent_mapping(em_tree, em);
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
if (ret != -EEXIST) {
|
if (ret != -EEXIST) {
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -367,10 +367,10 @@ static int insert_state(struct extent_io_tree *tree,
|
||||||
}
|
}
|
||||||
if (bits & EXTENT_DIRTY)
|
if (bits & EXTENT_DIRTY)
|
||||||
tree->dirty_bytes += end - start + 1;
|
tree->dirty_bytes += end - start + 1;
|
||||||
set_state_cb(tree, state, bits);
|
|
||||||
state->state |= bits;
|
|
||||||
state->start = start;
|
state->start = start;
|
||||||
state->end = end;
|
state->end = end;
|
||||||
|
set_state_cb(tree, state, bits);
|
||||||
|
state->state |= bits;
|
||||||
node = tree_insert(&tree->state, end, &state->rb_node);
|
node = tree_insert(&tree->state, end, &state->rb_node);
|
||||||
if (node) {
|
if (node) {
|
||||||
struct extent_state *found;
|
struct extent_state *found;
|
||||||
|
@ -471,10 +471,14 @@ static int clear_state_bit(struct extent_io_tree *tree,
|
||||||
* bits were already set, or zero if none of the bits were already set.
|
* bits were already set, or zero if none of the bits were already set.
|
||||||
*/
|
*/
|
||||||
int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, int wake, int delete, gfp_t mask)
|
int bits, int wake, int delete,
|
||||||
|
struct extent_state **cached_state,
|
||||||
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
struct extent_state *state;
|
struct extent_state *state;
|
||||||
|
struct extent_state *cached;
|
||||||
struct extent_state *prealloc = NULL;
|
struct extent_state *prealloc = NULL;
|
||||||
|
struct rb_node *next_node;
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
u64 last_end;
|
u64 last_end;
|
||||||
int err;
|
int err;
|
||||||
|
@ -488,6 +492,17 @@ again:
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&tree->lock);
|
spin_lock(&tree->lock);
|
||||||
|
if (cached_state) {
|
||||||
|
cached = *cached_state;
|
||||||
|
*cached_state = NULL;
|
||||||
|
if (cached->tree && cached->start == start) {
|
||||||
|
atomic_dec(&cached->refs);
|
||||||
|
state = cached;
|
||||||
|
last_end = state->end;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
free_extent_state(cached);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* this search will find the extents that end after
|
* this search will find the extents that end after
|
||||||
* our range starts
|
* our range starts
|
||||||
|
@ -496,6 +511,7 @@ again:
|
||||||
if (!node)
|
if (!node)
|
||||||
goto out;
|
goto out;
|
||||||
state = rb_entry(node, struct extent_state, rb_node);
|
state = rb_entry(node, struct extent_state, rb_node);
|
||||||
|
hit_next:
|
||||||
if (state->start > end)
|
if (state->start > end)
|
||||||
goto out;
|
goto out;
|
||||||
WARN_ON(state->end < start);
|
WARN_ON(state->end < start);
|
||||||
|
@ -555,11 +571,21 @@ again:
|
||||||
prealloc = NULL;
|
prealloc = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
found:
|
||||||
|
if (state->end < end && prealloc && !need_resched())
|
||||||
|
next_node = rb_next(&state->rb_node);
|
||||||
|
else
|
||||||
|
next_node = NULL;
|
||||||
set |= clear_state_bit(tree, state, bits, wake, delete);
|
set |= clear_state_bit(tree, state, bits, wake, delete);
|
||||||
if (last_end == (u64)-1)
|
if (last_end == (u64)-1)
|
||||||
goto out;
|
goto out;
|
||||||
start = last_end + 1;
|
start = last_end + 1;
|
||||||
|
if (start <= end && next_node) {
|
||||||
|
state = rb_entry(next_node, struct extent_state,
|
||||||
|
rb_node);
|
||||||
|
if (state->start == start)
|
||||||
|
goto hit_next;
|
||||||
|
}
|
||||||
goto search_again;
|
goto search_again;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -653,26 +679,37 @@ static void set_state_bits(struct extent_io_tree *tree,
|
||||||
state->state |= bits;
|
state->state |= bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cache_state(struct extent_state *state,
|
||||||
|
struct extent_state **cached_ptr)
|
||||||
|
{
|
||||||
|
if (cached_ptr && !(*cached_ptr)) {
|
||||||
|
if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY)) {
|
||||||
|
*cached_ptr = state;
|
||||||
|
atomic_inc(&state->refs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set some bits on a range in the tree. This may require allocations
|
* set some bits on a range in the tree. This may require allocations or
|
||||||
* or sleeping, so the gfp mask is used to indicate what is allowed.
|
* sleeping, so the gfp mask is used to indicate what is allowed.
|
||||||
*
|
*
|
||||||
* If 'exclusive' == 1, this will fail with -EEXIST if some part of the
|
* If any of the exclusive bits are set, this will fail with -EEXIST if some
|
||||||
* range already has the desired bits set. The start of the existing
|
* part of the range already has the desired bits set. The start of the
|
||||||
* range is returned in failed_start in this case.
|
* existing range is returned in failed_start in this case.
|
||||||
*
|
*
|
||||||
* [start, end] is inclusive
|
* [start, end] is inclusive This takes the tree lock.
|
||||||
* This takes the tree lock.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, int exclusive, u64 *failed_start,
|
int bits, int exclusive_bits, u64 *failed_start,
|
||||||
|
struct extent_state **cached_state,
|
||||||
gfp_t mask)
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
struct extent_state *state;
|
struct extent_state *state;
|
||||||
struct extent_state *prealloc = NULL;
|
struct extent_state *prealloc = NULL;
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int set;
|
|
||||||
u64 last_start;
|
u64 last_start;
|
||||||
u64 last_end;
|
u64 last_end;
|
||||||
again:
|
again:
|
||||||
|
@ -683,6 +720,13 @@ again:
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&tree->lock);
|
spin_lock(&tree->lock);
|
||||||
|
if (cached_state && *cached_state) {
|
||||||
|
state = *cached_state;
|
||||||
|
if (state->start == start && state->tree) {
|
||||||
|
node = &state->rb_node;
|
||||||
|
goto hit_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* this search will find all the extents that end after
|
* this search will find all the extents that end after
|
||||||
* our range starts.
|
* our range starts.
|
||||||
|
@ -694,8 +738,8 @@ again:
|
||||||
BUG_ON(err == -EEXIST);
|
BUG_ON(err == -EEXIST);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = rb_entry(node, struct extent_state, rb_node);
|
state = rb_entry(node, struct extent_state, rb_node);
|
||||||
|
hit_next:
|
||||||
last_start = state->start;
|
last_start = state->start;
|
||||||
last_end = state->end;
|
last_end = state->end;
|
||||||
|
|
||||||
|
@ -706,17 +750,28 @@ again:
|
||||||
* Just lock what we found and keep going
|
* Just lock what we found and keep going
|
||||||
*/
|
*/
|
||||||
if (state->start == start && state->end <= end) {
|
if (state->start == start && state->end <= end) {
|
||||||
set = state->state & bits;
|
struct rb_node *next_node;
|
||||||
if (set && exclusive) {
|
if (state->state & exclusive_bits) {
|
||||||
*failed_start = state->start;
|
*failed_start = state->start;
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
set_state_bits(tree, state, bits);
|
set_state_bits(tree, state, bits);
|
||||||
|
cache_state(state, cached_state);
|
||||||
merge_state(tree, state);
|
merge_state(tree, state);
|
||||||
if (last_end == (u64)-1)
|
if (last_end == (u64)-1)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
start = last_end + 1;
|
start = last_end + 1;
|
||||||
|
if (start < end && prealloc && !need_resched()) {
|
||||||
|
next_node = rb_next(node);
|
||||||
|
if (next_node) {
|
||||||
|
state = rb_entry(next_node, struct extent_state,
|
||||||
|
rb_node);
|
||||||
|
if (state->start == start)
|
||||||
|
goto hit_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
goto search_again;
|
goto search_again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,8 +792,7 @@ again:
|
||||||
* desired bit on it.
|
* desired bit on it.
|
||||||
*/
|
*/
|
||||||
if (state->start < start) {
|
if (state->start < start) {
|
||||||
set = state->state & bits;
|
if (state->state & exclusive_bits) {
|
||||||
if (exclusive && set) {
|
|
||||||
*failed_start = start;
|
*failed_start = start;
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -750,6 +804,7 @@ again:
|
||||||
goto out;
|
goto out;
|
||||||
if (state->end <= end) {
|
if (state->end <= end) {
|
||||||
set_state_bits(tree, state, bits);
|
set_state_bits(tree, state, bits);
|
||||||
|
cache_state(state, cached_state);
|
||||||
merge_state(tree, state);
|
merge_state(tree, state);
|
||||||
if (last_end == (u64)-1)
|
if (last_end == (u64)-1)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -774,6 +829,7 @@ again:
|
||||||
this_end = last_start - 1;
|
this_end = last_start - 1;
|
||||||
err = insert_state(tree, prealloc, start, this_end,
|
err = insert_state(tree, prealloc, start, this_end,
|
||||||
bits);
|
bits);
|
||||||
|
cache_state(prealloc, cached_state);
|
||||||
prealloc = NULL;
|
prealloc = NULL;
|
||||||
BUG_ON(err == -EEXIST);
|
BUG_ON(err == -EEXIST);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -788,8 +844,7 @@ again:
|
||||||
* on the first half
|
* on the first half
|
||||||
*/
|
*/
|
||||||
if (state->start <= end && state->end > end) {
|
if (state->start <= end && state->end > end) {
|
||||||
set = state->state & bits;
|
if (state->state & exclusive_bits) {
|
||||||
if (exclusive && set) {
|
|
||||||
*failed_start = start;
|
*failed_start = start;
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -798,6 +853,7 @@ again:
|
||||||
BUG_ON(err == -EEXIST);
|
BUG_ON(err == -EEXIST);
|
||||||
|
|
||||||
set_state_bits(tree, prealloc, bits);
|
set_state_bits(tree, prealloc, bits);
|
||||||
|
cache_state(prealloc, cached_state);
|
||||||
merge_state(tree, prealloc);
|
merge_state(tree, prealloc);
|
||||||
prealloc = NULL;
|
prealloc = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -826,86 +882,64 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
gfp_t mask)
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
return set_extent_bit(tree, start, end, EXTENT_DIRTY, 0, NULL,
|
return set_extent_bit(tree, start, end, EXTENT_DIRTY, 0, NULL,
|
||||||
mask);
|
NULL, mask);
|
||||||
}
|
|
||||||
|
|
||||||
int set_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end,
|
|
||||||
gfp_t mask)
|
|
||||||
{
|
|
||||||
return set_extent_bit(tree, start, end, EXTENT_ORDERED, 0, NULL, mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, gfp_t mask)
|
int bits, gfp_t mask)
|
||||||
{
|
{
|
||||||
return set_extent_bit(tree, start, end, bits, 0, NULL,
|
return set_extent_bit(tree, start, end, bits, 0, NULL,
|
||||||
mask);
|
NULL, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, gfp_t mask)
|
int bits, gfp_t mask)
|
||||||
{
|
{
|
||||||
return clear_extent_bit(tree, start, end, bits, 0, 0, mask);
|
return clear_extent_bit(tree, start, end, bits, 0, 0, NULL, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
|
int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
gfp_t mask)
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
return set_extent_bit(tree, start, end,
|
return set_extent_bit(tree, start, end,
|
||||||
EXTENT_DELALLOC | EXTENT_DIRTY,
|
EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_UPTODATE,
|
||||||
0, NULL, mask);
|
0, NULL, NULL, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
|
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, mask);
|
EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0,
|
||||||
}
|
NULL, mask);
|
||||||
|
|
||||||
int clear_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end,
|
|
||||||
gfp_t mask)
|
|
||||||
{
|
|
||||||
return clear_extent_bit(tree, start, end, EXTENT_ORDERED, 1, 0, mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
|
int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
gfp_t mask)
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
return set_extent_bit(tree, start, end, EXTENT_NEW, 0, NULL,
|
return set_extent_bit(tree, start, end, EXTENT_NEW, 0, NULL,
|
||||||
mask);
|
NULL, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clear_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
|
static int clear_extent_new(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
gfp_t mask)
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
return clear_extent_bit(tree, start, end, EXTENT_NEW, 0, 0, mask);
|
return clear_extent_bit(tree, start, end, EXTENT_NEW, 0, 0,
|
||||||
|
NULL, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
|
int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
gfp_t mask)
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, NULL,
|
return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, NULL,
|
||||||
mask);
|
NULL, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
|
static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start,
|
||||||
u64 end, gfp_t mask)
|
u64 end, gfp_t mask)
|
||||||
{
|
{
|
||||||
return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0, mask);
|
return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0,
|
||||||
}
|
NULL, mask);
|
||||||
|
|
||||||
static int set_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end,
|
|
||||||
gfp_t mask)
|
|
||||||
{
|
|
||||||
return set_extent_bit(tree, start, end, EXTENT_WRITEBACK,
|
|
||||||
0, NULL, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int clear_extent_writeback(struct extent_io_tree *tree, u64 start,
|
|
||||||
u64 end, gfp_t mask)
|
|
||||||
{
|
|
||||||
return clear_extent_bit(tree, start, end, EXTENT_WRITEBACK, 1, 0, mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end)
|
int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end)
|
||||||
|
@ -917,13 +951,15 @@ int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end)
|
||||||
* either insert or lock state struct between start and end use mask to tell
|
* either insert or lock state struct between start and end use mask to tell
|
||||||
* us if waiting is desired.
|
* us if waiting is desired.
|
||||||
*/
|
*/
|
||||||
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask)
|
int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
|
int bits, struct extent_state **cached_state, gfp_t mask)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
u64 failed_start;
|
u64 failed_start;
|
||||||
while (1) {
|
while (1) {
|
||||||
err = set_extent_bit(tree, start, end, EXTENT_LOCKED, 1,
|
err = set_extent_bit(tree, start, end, EXTENT_LOCKED | bits,
|
||||||
&failed_start, mask);
|
EXTENT_LOCKED, &failed_start,
|
||||||
|
cached_state, mask);
|
||||||
if (err == -EEXIST && (mask & __GFP_WAIT)) {
|
if (err == -EEXIST && (mask & __GFP_WAIT)) {
|
||||||
wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED);
|
wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED);
|
||||||
start = failed_start;
|
start = failed_start;
|
||||||
|
@ -935,27 +971,40 @@ int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask)
|
||||||
|
{
|
||||||
|
return lock_extent_bits(tree, start, end, 0, NULL, mask);
|
||||||
|
}
|
||||||
|
|
||||||
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
gfp_t mask)
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
u64 failed_start;
|
u64 failed_start;
|
||||||
|
|
||||||
err = set_extent_bit(tree, start, end, EXTENT_LOCKED, 1,
|
err = set_extent_bit(tree, start, end, EXTENT_LOCKED, EXTENT_LOCKED,
|
||||||
&failed_start, mask);
|
&failed_start, NULL, mask);
|
||||||
if (err == -EEXIST) {
|
if (err == -EEXIST) {
|
||||||
if (failed_start > start)
|
if (failed_start > start)
|
||||||
clear_extent_bit(tree, start, failed_start - 1,
|
clear_extent_bit(tree, start, failed_start - 1,
|
||||||
EXTENT_LOCKED, 1, 0, mask);
|
EXTENT_LOCKED, 1, 0, NULL, mask);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
|
struct extent_state **cached, gfp_t mask)
|
||||||
|
{
|
||||||
|
return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, cached,
|
||||||
|
mask);
|
||||||
|
}
|
||||||
|
|
||||||
int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
gfp_t mask)
|
gfp_t mask)
|
||||||
{
|
{
|
||||||
return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, mask);
|
return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL,
|
||||||
|
mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -974,7 +1023,6 @@ int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end)
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
set_extent_dirty(tree, start, end, GFP_NOFS);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,7 +1042,6 @@ static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
set_extent_writeback(tree, start, end, GFP_NOFS);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1232,6 +1279,7 @@ static noinline u64 find_lock_delalloc_range(struct inode *inode,
|
||||||
u64 delalloc_start;
|
u64 delalloc_start;
|
||||||
u64 delalloc_end;
|
u64 delalloc_end;
|
||||||
u64 found;
|
u64 found;
|
||||||
|
struct extent_state *cached_state = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
int loops = 0;
|
int loops = 0;
|
||||||
|
|
||||||
|
@ -1269,6 +1317,7 @@ again:
|
||||||
/* some of the pages are gone, lets avoid looping by
|
/* some of the pages are gone, lets avoid looping by
|
||||||
* shortening the size of the delalloc range we're searching
|
* shortening the size of the delalloc range we're searching
|
||||||
*/
|
*/
|
||||||
|
free_extent_state(cached_state);
|
||||||
if (!loops) {
|
if (!loops) {
|
||||||
unsigned long offset = (*start) & (PAGE_CACHE_SIZE - 1);
|
unsigned long offset = (*start) & (PAGE_CACHE_SIZE - 1);
|
||||||
max_bytes = PAGE_CACHE_SIZE - offset;
|
max_bytes = PAGE_CACHE_SIZE - offset;
|
||||||
|
@ -1282,18 +1331,21 @@ again:
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
/* step three, lock the state bits for the whole range */
|
/* step three, lock the state bits for the whole range */
|
||||||
lock_extent(tree, delalloc_start, delalloc_end, GFP_NOFS);
|
lock_extent_bits(tree, delalloc_start, delalloc_end,
|
||||||
|
0, &cached_state, GFP_NOFS);
|
||||||
|
|
||||||
/* then test to make sure it is all still delalloc */
|
/* then test to make sure it is all still delalloc */
|
||||||
ret = test_range_bit(tree, delalloc_start, delalloc_end,
|
ret = test_range_bit(tree, delalloc_start, delalloc_end,
|
||||||
EXTENT_DELALLOC, 1);
|
EXTENT_DELALLOC, 1, cached_state);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
unlock_extent(tree, delalloc_start, delalloc_end, GFP_NOFS);
|
unlock_extent_cached(tree, delalloc_start, delalloc_end,
|
||||||
|
&cached_state, GFP_NOFS);
|
||||||
__unlock_for_delalloc(inode, locked_page,
|
__unlock_for_delalloc(inode, locked_page,
|
||||||
delalloc_start, delalloc_end);
|
delalloc_start, delalloc_end);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
free_extent_state(cached_state);
|
||||||
*start = delalloc_start;
|
*start = delalloc_start;
|
||||||
*end = delalloc_end;
|
*end = delalloc_end;
|
||||||
out_failed:
|
out_failed:
|
||||||
|
@ -1307,7 +1359,8 @@ int extent_clear_unlock_delalloc(struct inode *inode,
|
||||||
int clear_unlock,
|
int clear_unlock,
|
||||||
int clear_delalloc, int clear_dirty,
|
int clear_delalloc, int clear_dirty,
|
||||||
int set_writeback,
|
int set_writeback,
|
||||||
int end_writeback)
|
int end_writeback,
|
||||||
|
int set_private2)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct page *pages[16];
|
struct page *pages[16];
|
||||||
|
@ -1325,8 +1378,9 @@ int extent_clear_unlock_delalloc(struct inode *inode,
|
||||||
if (clear_delalloc)
|
if (clear_delalloc)
|
||||||
clear_bits |= EXTENT_DELALLOC;
|
clear_bits |= EXTENT_DELALLOC;
|
||||||
|
|
||||||
clear_extent_bit(tree, start, end, clear_bits, 1, 0, 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 (!(unlock_pages || clear_dirty || set_writeback || end_writeback ||
|
||||||
|
set_private2))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (nr_pages > 0) {
|
while (nr_pages > 0) {
|
||||||
|
@ -1334,6 +1388,10 @@ int extent_clear_unlock_delalloc(struct inode *inode,
|
||||||
min_t(unsigned long,
|
min_t(unsigned long,
|
||||||
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)
|
||||||
|
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;
|
||||||
|
@ -1476,14 +1534,17 @@ out:
|
||||||
* range is found set.
|
* range is found set.
|
||||||
*/
|
*/
|
||||||
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, int filled)
|
int bits, int filled, struct extent_state *cached)
|
||||||
{
|
{
|
||||||
struct extent_state *state = NULL;
|
struct extent_state *state = NULL;
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
int bitset = 0;
|
int bitset = 0;
|
||||||
|
|
||||||
spin_lock(&tree->lock);
|
spin_lock(&tree->lock);
|
||||||
node = tree_search(tree, start);
|
if (cached && cached->tree && cached->start == start)
|
||||||
|
node = &cached->rb_node;
|
||||||
|
else
|
||||||
|
node = tree_search(tree, start);
|
||||||
while (node && start <= end) {
|
while (node && start <= end) {
|
||||||
state = rb_entry(node, struct extent_state, rb_node);
|
state = rb_entry(node, struct extent_state, rb_node);
|
||||||
|
|
||||||
|
@ -1526,7 +1587,7 @@ static int check_page_uptodate(struct extent_io_tree *tree,
|
||||||
{
|
{
|
||||||
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
|
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
|
||||||
u64 end = start + PAGE_CACHE_SIZE - 1;
|
u64 end = start + PAGE_CACHE_SIZE - 1;
|
||||||
if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1))
|
if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL))
|
||||||
SetPageUptodate(page);
|
SetPageUptodate(page);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1540,7 +1601,7 @@ static int check_page_locked(struct extent_io_tree *tree,
|
||||||
{
|
{
|
||||||
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
|
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
|
||||||
u64 end = start + PAGE_CACHE_SIZE - 1;
|
u64 end = start + PAGE_CACHE_SIZE - 1;
|
||||||
if (!test_range_bit(tree, start, end, EXTENT_LOCKED, 0))
|
if (!test_range_bit(tree, start, end, EXTENT_LOCKED, 0, NULL))
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1552,10 +1613,7 @@ static int check_page_locked(struct extent_io_tree *tree,
|
||||||
static int check_page_writeback(struct extent_io_tree *tree,
|
static int check_page_writeback(struct extent_io_tree *tree,
|
||||||
struct page *page)
|
struct page *page)
|
||||||
{
|
{
|
||||||
u64 start = (u64)page->index << PAGE_CACHE_SHIFT;
|
end_page_writeback(page);
|
||||||
u64 end = start + PAGE_CACHE_SIZE - 1;
|
|
||||||
if (!test_range_bit(tree, start, end, EXTENT_WRITEBACK, 0))
|
|
||||||
end_page_writeback(page);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1613,13 +1671,11 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uptodate) {
|
if (!uptodate) {
|
||||||
clear_extent_uptodate(tree, start, end, GFP_ATOMIC);
|
clear_extent_uptodate(tree, start, end, GFP_NOFS);
|
||||||
ClearPageUptodate(page);
|
ClearPageUptodate(page);
|
||||||
SetPageError(page);
|
SetPageError(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_extent_writeback(tree, start, end, GFP_ATOMIC);
|
|
||||||
|
|
||||||
if (whole_page)
|
if (whole_page)
|
||||||
end_page_writeback(page);
|
end_page_writeback(page);
|
||||||
else
|
else
|
||||||
|
@ -1983,7 +2039,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* the get_extent function already copied into the page */
|
/* the get_extent function already copied into the page */
|
||||||
if (test_range_bit(tree, cur, cur_end, EXTENT_UPTODATE, 1)) {
|
if (test_range_bit(tree, cur, cur_end,
|
||||||
|
EXTENT_UPTODATE, 1, NULL)) {
|
||||||
check_page_uptodate(tree, page);
|
check_page_uptodate(tree, page);
|
||||||
unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
|
unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS);
|
||||||
cur = cur + iosize;
|
cur = cur + iosize;
|
||||||
|
@ -2078,6 +2135,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
u64 iosize;
|
u64 iosize;
|
||||||
u64 unlock_start;
|
u64 unlock_start;
|
||||||
sector_t sector;
|
sector_t sector;
|
||||||
|
struct extent_state *cached_state = NULL;
|
||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -2124,6 +2182,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
delalloc_end = 0;
|
delalloc_end = 0;
|
||||||
page_started = 0;
|
page_started = 0;
|
||||||
if (!epd->extent_locked) {
|
if (!epd->extent_locked) {
|
||||||
|
u64 delalloc_to_write;
|
||||||
/*
|
/*
|
||||||
* make sure the wbc mapping index is at least updated
|
* make sure the wbc mapping index is at least updated
|
||||||
* to this page.
|
* to this page.
|
||||||
|
@ -2143,6 +2202,14 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
tree->ops->fill_delalloc(inode, page, delalloc_start,
|
tree->ops->fill_delalloc(inode, page, delalloc_start,
|
||||||
delalloc_end, &page_started,
|
delalloc_end, &page_started,
|
||||||
&nr_written);
|
&nr_written);
|
||||||
|
delalloc_to_write = (delalloc_end -
|
||||||
|
max_t(u64, page_offset(page),
|
||||||
|
delalloc_start) + 1) >>
|
||||||
|
PAGE_CACHE_SHIFT;
|
||||||
|
if (wbc->nr_to_write < delalloc_to_write) {
|
||||||
|
wbc->nr_to_write = min_t(long, 8192,
|
||||||
|
delalloc_to_write);
|
||||||
|
}
|
||||||
delalloc_start = delalloc_end + 1;
|
delalloc_start = delalloc_end + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2160,15 +2227,10 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
goto done_unlocked;
|
goto done_unlocked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock_extent(tree, start, page_end, GFP_NOFS);
|
|
||||||
|
|
||||||
unlock_start = start;
|
|
||||||
|
|
||||||
if (tree->ops && tree->ops->writepage_start_hook) {
|
if (tree->ops && tree->ops->writepage_start_hook) {
|
||||||
ret = tree->ops->writepage_start_hook(page, start,
|
ret = tree->ops->writepage_start_hook(page, start,
|
||||||
page_end);
|
page_end);
|
||||||
if (ret == -EAGAIN) {
|
if (ret == -EAGAIN) {
|
||||||
unlock_extent(tree, start, page_end, GFP_NOFS);
|
|
||||||
redirty_page_for_writepage(wbc, page);
|
redirty_page_for_writepage(wbc, page);
|
||||||
update_nr_written(page, wbc, nr_written);
|
update_nr_written(page, wbc, nr_written);
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
|
@ -2184,12 +2246,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
update_nr_written(page, wbc, nr_written + 1);
|
update_nr_written(page, wbc, nr_written + 1);
|
||||||
|
|
||||||
end = page_end;
|
end = page_end;
|
||||||
if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0))
|
|
||||||
printk(KERN_ERR "btrfs delalloc bits after lock_extent\n");
|
|
||||||
|
|
||||||
if (last_byte <= start) {
|
if (last_byte <= start) {
|
||||||
clear_extent_dirty(tree, start, page_end, GFP_NOFS);
|
|
||||||
unlock_extent(tree, start, page_end, GFP_NOFS);
|
|
||||||
if (tree->ops && tree->ops->writepage_end_io_hook)
|
if (tree->ops && tree->ops->writepage_end_io_hook)
|
||||||
tree->ops->writepage_end_io_hook(page, start,
|
tree->ops->writepage_end_io_hook(page, start,
|
||||||
page_end, NULL, 1);
|
page_end, NULL, 1);
|
||||||
|
@ -2197,13 +2254,10 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_extent_uptodate(tree, start, page_end, GFP_NOFS);
|
|
||||||
blocksize = inode->i_sb->s_blocksize;
|
blocksize = inode->i_sb->s_blocksize;
|
||||||
|
|
||||||
while (cur <= end) {
|
while (cur <= end) {
|
||||||
if (cur >= last_byte) {
|
if (cur >= last_byte) {
|
||||||
clear_extent_dirty(tree, cur, page_end, GFP_NOFS);
|
|
||||||
unlock_extent(tree, unlock_start, page_end, GFP_NOFS);
|
|
||||||
if (tree->ops && tree->ops->writepage_end_io_hook)
|
if (tree->ops && tree->ops->writepage_end_io_hook)
|
||||||
tree->ops->writepage_end_io_hook(page, cur,
|
tree->ops->writepage_end_io_hook(page, cur,
|
||||||
page_end, NULL, 1);
|
page_end, NULL, 1);
|
||||||
|
@ -2235,12 +2289,6 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
*/
|
*/
|
||||||
if (compressed || block_start == EXTENT_MAP_HOLE ||
|
if (compressed || block_start == EXTENT_MAP_HOLE ||
|
||||||
block_start == EXTENT_MAP_INLINE) {
|
block_start == EXTENT_MAP_INLINE) {
|
||||||
clear_extent_dirty(tree, cur,
|
|
||||||
cur + iosize - 1, GFP_NOFS);
|
|
||||||
|
|
||||||
unlock_extent(tree, unlock_start, cur + iosize - 1,
|
|
||||||
GFP_NOFS);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* end_io notification does not happen here for
|
* end_io notification does not happen here for
|
||||||
* compressed extents
|
* compressed extents
|
||||||
|
@ -2265,13 +2313,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
||||||
}
|
}
|
||||||
/* leave this out until we have a page_mkwrite call */
|
/* leave this out until we have a page_mkwrite call */
|
||||||
if (0 && !test_range_bit(tree, cur, cur + iosize - 1,
|
if (0 && !test_range_bit(tree, cur, cur + iosize - 1,
|
||||||
EXTENT_DIRTY, 0)) {
|
EXTENT_DIRTY, 0, NULL)) {
|
||||||
cur = cur + iosize;
|
cur = cur + iosize;
|
||||||
pg_offset += iosize;
|
pg_offset += iosize;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_extent_dirty(tree, cur, cur + iosize - 1, GFP_NOFS);
|
|
||||||
if (tree->ops && tree->ops->writepage_io_hook) {
|
if (tree->ops && tree->ops->writepage_io_hook) {
|
||||||
ret = tree->ops->writepage_io_hook(page, cur,
|
ret = tree->ops->writepage_io_hook(page, cur,
|
||||||
cur + iosize - 1);
|
cur + iosize - 1);
|
||||||
|
@ -2309,12 +2356,12 @@ done:
|
||||||
set_page_writeback(page);
|
set_page_writeback(page);
|
||||||
end_page_writeback(page);
|
end_page_writeback(page);
|
||||||
}
|
}
|
||||||
if (unlock_start <= page_end)
|
|
||||||
unlock_extent(tree, unlock_start, page_end, GFP_NOFS);
|
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
|
|
||||||
done_unlocked:
|
done_unlocked:
|
||||||
|
|
||||||
|
/* drop our reference on any cached states */
|
||||||
|
free_extent_state(cached_state);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2339,7 +2386,6 @@ static int extent_write_cache_pages(struct extent_io_tree *tree,
|
||||||
writepage_t writepage, void *data,
|
writepage_t writepage, void *data,
|
||||||
void (*flush_fn)(void *))
|
void (*flush_fn)(void *))
|
||||||
{
|
{
|
||||||
struct backing_dev_info *bdi = mapping->backing_dev_info;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
struct pagevec pvec;
|
struct pagevec pvec;
|
||||||
|
@ -2414,10 +2460,6 @@ retry:
|
||||||
}
|
}
|
||||||
if (ret || wbc->nr_to_write <= 0)
|
if (ret || wbc->nr_to_write <= 0)
|
||||||
done = 1;
|
done = 1;
|
||||||
if (wbc->nonblocking && bdi_write_congested(bdi)) {
|
|
||||||
wbc->encountered_congestion = 1;
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pagevec_release(&pvec);
|
pagevec_release(&pvec);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
@ -2604,10 +2646,10 @@ int extent_invalidatepage(struct extent_io_tree *tree,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
lock_extent(tree, start, end, GFP_NOFS);
|
lock_extent(tree, start, end, GFP_NOFS);
|
||||||
wait_on_extent_writeback(tree, start, end);
|
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,
|
||||||
1, 1, GFP_NOFS);
|
1, 1, NULL, GFP_NOFS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2687,7 +2729,7 @@ int extent_prepare_write(struct extent_io_tree *tree,
|
||||||
!isnew && !PageUptodate(page) &&
|
!isnew && !PageUptodate(page) &&
|
||||||
(block_off_end > to || block_off_start < from) &&
|
(block_off_end > to || block_off_start < from) &&
|
||||||
!test_range_bit(tree, block_start, cur_end,
|
!test_range_bit(tree, block_start, cur_end,
|
||||||
EXTENT_UPTODATE, 1)) {
|
EXTENT_UPTODATE, 1, NULL)) {
|
||||||
u64 sector;
|
u64 sector;
|
||||||
u64 extent_offset = block_start - em->start;
|
u64 extent_offset = block_start - em->start;
|
||||||
size_t iosize;
|
size_t iosize;
|
||||||
|
@ -2701,7 +2743,7 @@ int extent_prepare_write(struct extent_io_tree *tree,
|
||||||
*/
|
*/
|
||||||
set_extent_bit(tree, block_start,
|
set_extent_bit(tree, block_start,
|
||||||
block_start + iosize - 1,
|
block_start + iosize - 1,
|
||||||
EXTENT_LOCKED, 0, NULL, GFP_NOFS);
|
EXTENT_LOCKED, 0, NULL, NULL, GFP_NOFS);
|
||||||
ret = submit_extent_page(READ, tree, page,
|
ret = submit_extent_page(READ, tree, page,
|
||||||
sector, iosize, page_offset, em->bdev,
|
sector, iosize, page_offset, em->bdev,
|
||||||
NULL, 1,
|
NULL, 1,
|
||||||
|
@ -2742,13 +2784,13 @@ int try_release_extent_state(struct extent_map_tree *map,
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
|
||||||
if (test_range_bit(tree, start, end,
|
if (test_range_bit(tree, start, end,
|
||||||
EXTENT_IOBITS | EXTENT_ORDERED, 0))
|
EXTENT_IOBITS, 0, NULL))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
else {
|
else {
|
||||||
if ((mask & GFP_NOFS) == GFP_NOFS)
|
if ((mask & GFP_NOFS) == GFP_NOFS)
|
||||||
mask = GFP_NOFS;
|
mask = GFP_NOFS;
|
||||||
clear_extent_bit(tree, start, end, EXTENT_UPTODATE,
|
clear_extent_bit(tree, start, end, EXTENT_UPTODATE,
|
||||||
1, 1, mask);
|
1, 1, NULL, mask);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2771,29 +2813,28 @@ int try_release_extent_mapping(struct extent_map_tree *map,
|
||||||
u64 len;
|
u64 len;
|
||||||
while (start <= end) {
|
while (start <= end) {
|
||||||
len = end - start + 1;
|
len = end - start + 1;
|
||||||
spin_lock(&map->lock);
|
write_lock(&map->lock);
|
||||||
em = lookup_extent_mapping(map, start, len);
|
em = lookup_extent_mapping(map, start, len);
|
||||||
if (!em || IS_ERR(em)) {
|
if (!em || IS_ERR(em)) {
|
||||||
spin_unlock(&map->lock);
|
write_unlock(&map->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (test_bit(EXTENT_FLAG_PINNED, &em->flags) ||
|
if (test_bit(EXTENT_FLAG_PINNED, &em->flags) ||
|
||||||
em->start != start) {
|
em->start != start) {
|
||||||
spin_unlock(&map->lock);
|
write_unlock(&map->lock);
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!test_range_bit(tree, em->start,
|
if (!test_range_bit(tree, em->start,
|
||||||
extent_map_end(em) - 1,
|
extent_map_end(em) - 1,
|
||||||
EXTENT_LOCKED | EXTENT_WRITEBACK |
|
EXTENT_LOCKED | EXTENT_WRITEBACK,
|
||||||
EXTENT_ORDERED,
|
0, NULL)) {
|
||||||
0)) {
|
|
||||||
remove_extent_mapping(map, em);
|
remove_extent_mapping(map, em);
|
||||||
/* once for the rb tree */
|
/* once for the rb tree */
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
}
|
}
|
||||||
start = extent_map_end(em);
|
start = extent_map_end(em);
|
||||||
spin_unlock(&map->lock);
|
write_unlock(&map->lock);
|
||||||
|
|
||||||
/* once for us */
|
/* once for us */
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
@ -3203,7 +3244,7 @@ int extent_range_uptodate(struct extent_io_tree *tree,
|
||||||
int uptodate;
|
int uptodate;
|
||||||
unsigned long index;
|
unsigned long index;
|
||||||
|
|
||||||
ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1);
|
ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 1;
|
return 1;
|
||||||
while (start <= end) {
|
while (start <= end) {
|
||||||
|
@ -3233,7 +3274,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree,
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
|
ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
|
||||||
EXTENT_UPTODATE, 1);
|
EXTENT_UPTODATE, 1, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -3269,7 +3310,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (test_range_bit(tree, eb->start, eb->start + eb->len - 1,
|
if (test_range_bit(tree, eb->start, eb->start + eb->len - 1,
|
||||||
EXTENT_UPTODATE, 1)) {
|
EXTENT_UPTODATE, 1, NULL)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,8 @@
|
||||||
#define EXTENT_DEFRAG (1 << 6)
|
#define EXTENT_DEFRAG (1 << 6)
|
||||||
#define EXTENT_DEFRAG_DONE (1 << 7)
|
#define EXTENT_DEFRAG_DONE (1 << 7)
|
||||||
#define EXTENT_BUFFER_FILLED (1 << 8)
|
#define EXTENT_BUFFER_FILLED (1 << 8)
|
||||||
#define EXTENT_ORDERED (1 << 9)
|
#define EXTENT_BOUNDARY (1 << 9)
|
||||||
#define EXTENT_ORDERED_METADATA (1 << 10)
|
#define EXTENT_NODATASUM (1 << 10)
|
||||||
#define EXTENT_BOUNDARY (1 << 11)
|
|
||||||
#define EXTENT_NODATASUM (1 << 12)
|
|
||||||
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
|
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
|
||||||
|
|
||||||
/* flags for bio submission */
|
/* flags for bio submission */
|
||||||
|
@ -142,6 +140,8 @@ int try_release_extent_state(struct extent_map_tree *map,
|
||||||
struct extent_io_tree *tree, struct page *page,
|
struct extent_io_tree *tree, struct page *page,
|
||||||
gfp_t mask);
|
gfp_t mask);
|
||||||
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
|
int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
|
||||||
|
int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
|
int bits, struct extent_state **cached, gfp_t mask);
|
||||||
int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
|
int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask);
|
||||||
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
gfp_t mask);
|
gfp_t mask);
|
||||||
|
@ -155,11 +155,12 @@ u64 count_range_bits(struct extent_io_tree *tree,
|
||||||
u64 max_bytes, unsigned long bits);
|
u64 max_bytes, unsigned long bits);
|
||||||
|
|
||||||
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, int filled);
|
int bits, int filled, struct extent_state *cached_state);
|
||||||
int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, gfp_t mask);
|
int bits, gfp_t mask);
|
||||||
int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, int wake, int delete, gfp_t mask);
|
int bits, int wake, int delete, struct extent_state **cached,
|
||||||
|
gfp_t mask);
|
||||||
int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
int bits, gfp_t mask);
|
int bits, gfp_t mask);
|
||||||
int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
|
int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
|
||||||
|
@ -282,5 +283,6 @@ int extent_clear_unlock_delalloc(struct inode *inode,
|
||||||
int clear_unlock,
|
int clear_unlock,
|
||||||
int clear_delalloc, int clear_dirty,
|
int clear_delalloc, int clear_dirty,
|
||||||
int set_writeback,
|
int set_writeback,
|
||||||
int end_writeback);
|
int end_writeback,
|
||||||
|
int set_private2);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,7 +36,7 @@ void extent_map_exit(void)
|
||||||
void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask)
|
void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask)
|
||||||
{
|
{
|
||||||
tree->map.rb_node = NULL;
|
tree->map.rb_node = NULL;
|
||||||
spin_lock_init(&tree->lock);
|
rwlock_init(&tree->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -198,6 +198,56 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct extent_map *merge = NULL;
|
||||||
|
struct rb_node *rb;
|
||||||
|
struct extent_map *em;
|
||||||
|
|
||||||
|
write_lock(&tree->lock);
|
||||||
|
em = lookup_extent_mapping(tree, start, len);
|
||||||
|
|
||||||
|
WARN_ON(em->start != start || !em);
|
||||||
|
|
||||||
|
if (!em)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
clear_bit(EXTENT_FLAG_PINNED, &em->flags);
|
||||||
|
|
||||||
|
if (em->start != 0) {
|
||||||
|
rb = rb_prev(&em->rb_node);
|
||||||
|
if (rb)
|
||||||
|
merge = rb_entry(rb, struct extent_map, rb_node);
|
||||||
|
if (rb && mergable_maps(merge, em)) {
|
||||||
|
em->start = merge->start;
|
||||||
|
em->len += merge->len;
|
||||||
|
em->block_len += merge->block_len;
|
||||||
|
em->block_start = merge->block_start;
|
||||||
|
merge->in_tree = 0;
|
||||||
|
rb_erase(&merge->rb_node, &tree->map);
|
||||||
|
free_extent_map(merge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rb = rb_next(&em->rb_node);
|
||||||
|
if (rb)
|
||||||
|
merge = rb_entry(rb, struct extent_map, rb_node);
|
||||||
|
if (rb && mergable_maps(em, merge)) {
|
||||||
|
em->len += merge->len;
|
||||||
|
em->block_len += merge->len;
|
||||||
|
rb_erase(&merge->rb_node, &tree->map);
|
||||||
|
merge->in_tree = 0;
|
||||||
|
free_extent_map(merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_extent_map(em);
|
||||||
|
out:
|
||||||
|
write_unlock(&tree->lock);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add_extent_mapping - add new extent map to the extent tree
|
* add_extent_mapping - add new extent map to the extent tree
|
||||||
* @tree: tree to insert new map in
|
* @tree: tree to insert new map in
|
||||||
|
@ -222,7 +272,6 @@ int add_extent_mapping(struct extent_map_tree *tree,
|
||||||
ret = -EEXIST;
|
ret = -EEXIST;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
assert_spin_locked(&tree->lock);
|
|
||||||
rb = tree_insert(&tree->map, em->start, &em->rb_node);
|
rb = tree_insert(&tree->map, em->start, &em->rb_node);
|
||||||
if (rb) {
|
if (rb) {
|
||||||
ret = -EEXIST;
|
ret = -EEXIST;
|
||||||
|
@ -285,7 +334,6 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
|
||||||
struct rb_node *next = NULL;
|
struct rb_node *next = NULL;
|
||||||
u64 end = range_end(start, len);
|
u64 end = range_end(start, len);
|
||||||
|
|
||||||
assert_spin_locked(&tree->lock);
|
|
||||||
rb_node = __tree_search(&tree->map, start, &prev, &next);
|
rb_node = __tree_search(&tree->map, start, &prev, &next);
|
||||||
if (!rb_node && prev) {
|
if (!rb_node && prev) {
|
||||||
em = rb_entry(prev, struct extent_map, rb_node);
|
em = rb_entry(prev, struct extent_map, rb_node);
|
||||||
|
@ -331,7 +379,6 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
|
WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
|
||||||
assert_spin_locked(&tree->lock);
|
|
||||||
rb_erase(&em->rb_node, &tree->map);
|
rb_erase(&em->rb_node, &tree->map);
|
||||||
em->in_tree = 0;
|
em->in_tree = 0;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct extent_map {
|
||||||
|
|
||||||
struct extent_map_tree {
|
struct extent_map_tree {
|
||||||
struct rb_root map;
|
struct rb_root map;
|
||||||
spinlock_t lock;
|
rwlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline u64 extent_map_end(struct extent_map *em)
|
static inline u64 extent_map_end(struct extent_map *em)
|
||||||
|
@ -59,4 +59,5 @@ struct extent_map *alloc_extent_map(gfp_t mask);
|
||||||
void free_extent_map(struct extent_map *em);
|
void free_extent_map(struct extent_map *em);
|
||||||
int __init extent_map_init(void);
|
int __init extent_map_init(void);
|
||||||
void extent_map_exit(void);
|
void extent_map_exit(void);
|
||||||
|
int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -112,8 +112,6 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int i;
|
int i;
|
||||||
struct inode *inode = fdentry(file)->d_inode;
|
struct inode *inode = fdentry(file)->d_inode;
|
||||||
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
|
|
||||||
u64 hint_byte;
|
|
||||||
u64 num_bytes;
|
u64 num_bytes;
|
||||||
u64 start_pos;
|
u64 start_pos;
|
||||||
u64 end_of_last_block;
|
u64 end_of_last_block;
|
||||||
|
@ -125,22 +123,6 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
|
||||||
root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
|
root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
|
||||||
|
|
||||||
end_of_last_block = start_pos + num_bytes - 1;
|
end_of_last_block = start_pos + num_bytes - 1;
|
||||||
|
|
||||||
lock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
|
|
||||||
trans = btrfs_join_transaction(root, 1);
|
|
||||||
if (!trans) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
btrfs_set_trans_block_group(trans, inode);
|
|
||||||
hint_byte = 0;
|
|
||||||
|
|
||||||
set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS);
|
|
||||||
|
|
||||||
/* check for reserved extents on each page, we don't want
|
|
||||||
* to reset the delalloc bit on things that already have
|
|
||||||
* extents reserved.
|
|
||||||
*/
|
|
||||||
btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block);
|
btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block);
|
||||||
for (i = 0; i < num_pages; i++) {
|
for (i = 0; i < num_pages; i++) {
|
||||||
struct page *p = pages[i];
|
struct page *p = pages[i];
|
||||||
|
@ -155,9 +137,6 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
|
||||||
* at this time.
|
* at this time.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
err = btrfs_end_transaction(trans, root);
|
|
||||||
out_unlock:
|
|
||||||
unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,18 +168,18 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
if (!split2)
|
if (!split2)
|
||||||
split2 = alloc_extent_map(GFP_NOFS);
|
split2 = alloc_extent_map(GFP_NOFS);
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, start, len);
|
em = lookup_extent_mapping(em_tree, start, len);
|
||||||
if (!em) {
|
if (!em) {
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
flags = em->flags;
|
flags = em->flags;
|
||||||
if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
|
if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
|
||||||
spin_unlock(&em_tree->lock);
|
|
||||||
if (em->start <= start &&
|
if (em->start <= start &&
|
||||||
(!testend || em->start + em->len >= start + len)) {
|
(!testend || em->start + em->len >= start + len)) {
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
write_unlock(&em_tree->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (start < em->start) {
|
if (start < em->start) {
|
||||||
|
@ -210,6 +189,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
start = em->start + em->len;
|
start = em->start + em->len;
|
||||||
}
|
}
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
write_unlock(&em_tree->lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
|
compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
|
||||||
|
@ -260,7 +240,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
free_extent_map(split);
|
free_extent_map(split);
|
||||||
split = NULL;
|
split = NULL;
|
||||||
}
|
}
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
|
|
||||||
/* once for us */
|
/* once for us */
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
@ -289,7 +269,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
|
noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, struct inode *inode,
|
struct btrfs_root *root, struct inode *inode,
|
||||||
u64 start, u64 end, u64 locked_end,
|
u64 start, u64 end, u64 locked_end,
|
||||||
u64 inline_limit, u64 *hint_byte)
|
u64 inline_limit, u64 *hint_byte, int drop_cache)
|
||||||
{
|
{
|
||||||
u64 extent_end = 0;
|
u64 extent_end = 0;
|
||||||
u64 search_start = start;
|
u64 search_start = start;
|
||||||
|
@ -314,7 +294,8 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
inline_limit = 0;
|
inline_limit = 0;
|
||||||
btrfs_drop_extent_cache(inode, start, end - 1, 0);
|
if (drop_cache)
|
||||||
|
btrfs_drop_extent_cache(inode, start, end - 1, 0);
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
|
|
112
fs/btrfs/inode.c
112
fs/btrfs/inode.c
|
@ -231,7 +231,8 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_drop_extents(trans, root, inode, start,
|
ret = btrfs_drop_extents(trans, root, inode, start,
|
||||||
aligned_end, aligned_end, start, &hint_byte);
|
aligned_end, aligned_end, start,
|
||||||
|
&hint_byte, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
if (isize > actual_end)
|
if (isize > actual_end)
|
||||||
|
@ -240,7 +241,7 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
|
||||||
inline_len, compressed_size,
|
inline_len, compressed_size,
|
||||||
compressed_pages);
|
compressed_pages);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
btrfs_drop_extent_cache(inode, start, aligned_end, 0);
|
btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +426,7 @@ again:
|
||||||
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, 1, 0,
|
||||||
0, 1, 1, 1);
|
0, 1, 1, 1, 0);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto free_pages_out;
|
goto free_pages_out;
|
||||||
}
|
}
|
||||||
|
@ -611,9 +612,9 @@ static noinline int submit_compressed_extents(struct inode *inode,
|
||||||
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
|
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
ret = add_extent_mapping(em_tree, em);
|
ret = add_extent_mapping(em_tree, em);
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
if (ret != -EEXIST) {
|
if (ret != -EEXIST) {
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
break;
|
break;
|
||||||
|
@ -640,7 +641,7 @@ static noinline int submit_compressed_extents(struct inode *inode,
|
||||||
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);
|
NULL, 1, 1, 0, 1, 1, 0, 0);
|
||||||
|
|
||||||
ret = btrfs_submit_compressed_write(inode,
|
ret = btrfs_submit_compressed_write(inode,
|
||||||
async_extent->start,
|
async_extent->start,
|
||||||
|
@ -713,7 +714,7 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
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, 1, 1);
|
1, 1, 1, 1, 0);
|
||||||
*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;
|
||||||
|
@ -747,9 +748,9 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
set_bit(EXTENT_FLAG_PINNED, &em->flags);
|
set_bit(EXTENT_FLAG_PINNED, &em->flags);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
ret = add_extent_mapping(em_tree, em);
|
ret = add_extent_mapping(em_tree, em);
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
if (ret != -EEXIST) {
|
if (ret != -EEXIST) {
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
break;
|
break;
|
||||||
|
@ -776,11 +777,14 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
/* we're not doing compressed IO, don't unlock the first
|
/* we're not doing compressed IO, don't unlock the first
|
||||||
* page (which the caller expects to stay locked), don't
|
* page (which the caller expects to stay locked), don't
|
||||||
* clear any dirty bits and don't set any writeback bits
|
* clear any dirty bits and don't set any writeback bits
|
||||||
|
*
|
||||||
|
* Do set the Private2 bit so we know this page was properly
|
||||||
|
* setup for writepage
|
||||||
*/
|
*/
|
||||||
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, unlock, 1,
|
||||||
1, 0, 0, 0);
|
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;
|
||||||
|
@ -853,7 +857,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
|
||||||
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, GFP_NOFS);
|
EXTENT_DELALLOC, 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;
|
||||||
|
@ -1080,9 +1084,9 @@ out_check:
|
||||||
em->bdev = root->fs_info->fs_devices->latest_bdev;
|
em->bdev = root->fs_info->fs_devices->latest_bdev;
|
||||||
set_bit(EXTENT_FLAG_PINNED, &em->flags);
|
set_bit(EXTENT_FLAG_PINNED, &em->flags);
|
||||||
while (1) {
|
while (1) {
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
ret = add_extent_mapping(em_tree, em);
|
ret = add_extent_mapping(em_tree, em);
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
if (ret != -EEXIST) {
|
if (ret != -EEXIST) {
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
break;
|
break;
|
||||||
|
@ -1101,7 +1105,7 @@ out_check:
|
||||||
|
|
||||||
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);
|
locked_page, 1, 1, 1, 0, 0, 0, 1);
|
||||||
cur_offset = extent_end;
|
cur_offset = extent_end;
|
||||||
if (cur_offset > end)
|
if (cur_offset > end)
|
||||||
break;
|
break;
|
||||||
|
@ -1374,10 +1378,8 @@ again:
|
||||||
lock_extent(&BTRFS_I(inode)->io_tree, page_start, page_end, GFP_NOFS);
|
lock_extent(&BTRFS_I(inode)->io_tree, page_start, page_end, GFP_NOFS);
|
||||||
|
|
||||||
/* already ordered? We're done */
|
/* already ordered? We're done */
|
||||||
if (test_range_bit(&BTRFS_I(inode)->io_tree, page_start, page_end,
|
if (PagePrivate2(page))
|
||||||
EXTENT_ORDERED, 0)) {
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, page_start);
|
ordered = btrfs_lookup_ordered_extent(inode, page_start);
|
||||||
if (ordered) {
|
if (ordered) {
|
||||||
|
@ -1413,11 +1415,9 @@ static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
|
||||||
struct inode *inode = page->mapping->host;
|
struct inode *inode = page->mapping->host;
|
||||||
struct btrfs_writepage_fixup *fixup;
|
struct btrfs_writepage_fixup *fixup;
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = test_range_bit(&BTRFS_I(inode)->io_tree, start, end,
|
/* this page is properly in the ordered list */
|
||||||
EXTENT_ORDERED, 0);
|
if (TestClearPagePrivate2(page))
|
||||||
if (ret)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (PageChecked(page))
|
if (PageChecked(page))
|
||||||
|
@ -1455,9 +1455,19 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||||
BUG_ON(!path);
|
BUG_ON(!path);
|
||||||
|
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we may be replacing one extent in the tree with another.
|
||||||
|
* The new extent is pinned in the extent map, and we don't want
|
||||||
|
* to drop it from the cache until it is completely in the btree.
|
||||||
|
*
|
||||||
|
* So, tell btrfs_drop_extents to leave this extent in the cache.
|
||||||
|
* the caller is expected to unpin it and allow it to be merged
|
||||||
|
* with the others.
|
||||||
|
*/
|
||||||
ret = btrfs_drop_extents(trans, root, inode, file_pos,
|
ret = btrfs_drop_extents(trans, root, inode, file_pos,
|
||||||
file_pos + num_bytes, locked_end,
|
file_pos + num_bytes, locked_end,
|
||||||
file_pos, &hint);
|
file_pos, &hint, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
ins.objectid = inode->i_ino;
|
ins.objectid = inode->i_ino;
|
||||||
|
@ -1485,7 +1495,6 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
|
||||||
inode_add_bytes(inode, num_bytes);
|
inode_add_bytes(inode, num_bytes);
|
||||||
btrfs_drop_extent_cache(inode, file_pos, file_pos + num_bytes - 1, 0);
|
|
||||||
|
|
||||||
ins.objectid = disk_bytenr;
|
ins.objectid = disk_bytenr;
|
||||||
ins.offset = disk_num_bytes;
|
ins.offset = disk_num_bytes;
|
||||||
|
@ -1596,6 +1605,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
||||||
ordered_extent->len,
|
ordered_extent->len,
|
||||||
compressed, 0, 0,
|
compressed, 0, 0,
|
||||||
BTRFS_FILE_EXTENT_REG);
|
BTRFS_FILE_EXTENT_REG);
|
||||||
|
unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
|
||||||
|
ordered_extent->file_offset,
|
||||||
|
ordered_extent->len);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
unlock_extent(io_tree, ordered_extent->file_offset,
|
unlock_extent(io_tree, ordered_extent->file_offset,
|
||||||
|
@ -1623,6 +1635,7 @@ nocow:
|
||||||
static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
|
static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
|
||||||
struct extent_state *state, int uptodate)
|
struct extent_state *state, int uptodate)
|
||||||
{
|
{
|
||||||
|
ClearPagePrivate2(page);
|
||||||
return btrfs_finish_ordered_io(page->mapping->host, start, end);
|
return btrfs_finish_ordered_io(page->mapping->host, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1669,13 +1682,13 @@ static int btrfs_io_failed_hook(struct bio *failed_bio,
|
||||||
failrec->last_mirror = 0;
|
failrec->last_mirror = 0;
|
||||||
failrec->bio_flags = 0;
|
failrec->bio_flags = 0;
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, start, failrec->len);
|
em = lookup_extent_mapping(em_tree, start, failrec->len);
|
||||||
if (em->start > start || em->start + em->len < start) {
|
if (em->start > start || em->start + em->len < start) {
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
em = NULL;
|
em = NULL;
|
||||||
}
|
}
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
|
|
||||||
if (!em || IS_ERR(em)) {
|
if (!em || IS_ERR(em)) {
|
||||||
kfree(failrec);
|
kfree(failrec);
|
||||||
|
@ -1794,7 +1807,7 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID &&
|
if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID &&
|
||||||
test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1)) {
|
test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1, NULL)) {
|
||||||
clear_extent_bits(io_tree, start, end, EXTENT_NODATASUM,
|
clear_extent_bits(io_tree, start, end, EXTENT_NODATASUM,
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2935,7 +2948,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
|
||||||
cur_offset,
|
cur_offset,
|
||||||
cur_offset + hole_size,
|
cur_offset + hole_size,
|
||||||
block_end,
|
block_end,
|
||||||
cur_offset, &hint_byte);
|
cur_offset, &hint_byte, 1);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
err = btrfs_insert_file_extent(trans, root,
|
err = btrfs_insert_file_extent(trans, root,
|
||||||
|
@ -4064,11 +4077,11 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
|
||||||
int compressed;
|
int compressed;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, start, len);
|
em = lookup_extent_mapping(em_tree, start, len);
|
||||||
if (em)
|
if (em)
|
||||||
em->bdev = root->fs_info->fs_devices->latest_bdev;
|
em->bdev = root->fs_info->fs_devices->latest_bdev;
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
|
|
||||||
if (em) {
|
if (em) {
|
||||||
if (em->start > start || em->start + em->len <= start)
|
if (em->start > start || em->start + em->len <= start)
|
||||||
|
@ -4215,6 +4228,11 @@ again:
|
||||||
map = kmap(page);
|
map = kmap(page);
|
||||||
read_extent_buffer(leaf, map + pg_offset, ptr,
|
read_extent_buffer(leaf, map + pg_offset, ptr,
|
||||||
copy_size);
|
copy_size);
|
||||||
|
if (pg_offset + copy_size < PAGE_CACHE_SIZE) {
|
||||||
|
memset(map + pg_offset + copy_size, 0,
|
||||||
|
PAGE_CACHE_SIZE - pg_offset -
|
||||||
|
copy_size);
|
||||||
|
}
|
||||||
kunmap(page);
|
kunmap(page);
|
||||||
}
|
}
|
||||||
flush_dcache_page(page);
|
flush_dcache_page(page);
|
||||||
|
@ -4259,7 +4277,7 @@ insert:
|
||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
ret = add_extent_mapping(em_tree, em);
|
ret = add_extent_mapping(em_tree, em);
|
||||||
/* it is possible that someone inserted the extent into the tree
|
/* it is possible that someone inserted the extent into the tree
|
||||||
* while we had the lock dropped. It is also possible that
|
* while we had the lock dropped. It is also possible that
|
||||||
|
@ -4299,7 +4317,7 @@ insert:
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
out:
|
out:
|
||||||
if (path)
|
if (path)
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
@ -4398,13 +4416,21 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
|
||||||
u64 page_start = page_offset(page);
|
u64 page_start = page_offset(page);
|
||||||
u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
|
u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we have the page locked, so new writeback can't start,
|
||||||
|
* and the dirty bit won't be cleared while we are here.
|
||||||
|
*
|
||||||
|
* Wait for IO on this page so that we can safely clear
|
||||||
|
* the PagePrivate2 bit and do ordered accounting
|
||||||
|
*/
|
||||||
wait_on_page_writeback(page);
|
wait_on_page_writeback(page);
|
||||||
|
|
||||||
tree = &BTRFS_I(page->mapping->host)->io_tree;
|
tree = &BTRFS_I(page->mapping->host)->io_tree;
|
||||||
if (offset) {
|
if (offset) {
|
||||||
btrfs_releasepage(page, GFP_NOFS);
|
btrfs_releasepage(page, GFP_NOFS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_extent(tree, page_start, page_end, GFP_NOFS);
|
lock_extent(tree, page_start, page_end, GFP_NOFS);
|
||||||
ordered = btrfs_lookup_ordered_extent(page->mapping->host,
|
ordered = btrfs_lookup_ordered_extent(page->mapping->host,
|
||||||
page_offset(page));
|
page_offset(page));
|
||||||
|
@ -4415,16 +4441,21 @@ 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, GFP_NOFS);
|
EXTENT_LOCKED, 1, 0, NULL, GFP_NOFS);
|
||||||
btrfs_finish_ordered_io(page->mapping->host,
|
/*
|
||||||
page_start, page_end);
|
* whoever cleared the private bit is responsible
|
||||||
|
* for the finish_ordered_io
|
||||||
|
*/
|
||||||
|
if (TestClearPagePrivate2(page)) {
|
||||||
|
btrfs_finish_ordered_io(page->mapping->host,
|
||||||
|
page_start, page_end);
|
||||||
|
}
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
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,
|
||||||
EXTENT_ORDERED,
|
1, 1, NULL, GFP_NOFS);
|
||||||
1, 1, GFP_NOFS);
|
|
||||||
__btrfs_releasepage(page, GFP_NOFS);
|
__btrfs_releasepage(page, GFP_NOFS);
|
||||||
|
|
||||||
ClearPageChecked(page);
|
ClearPageChecked(page);
|
||||||
|
@ -4521,11 +4552,14 @@ again:
|
||||||
}
|
}
|
||||||
ClearPageChecked(page);
|
ClearPageChecked(page);
|
||||||
set_page_dirty(page);
|
set_page_dirty(page);
|
||||||
|
SetPageUptodate(page);
|
||||||
|
|
||||||
BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
|
BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
|
||||||
unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
|
unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
|
if (!ret)
|
||||||
|
return VM_FAULT_LOCKED;
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -5058,6 +5092,8 @@ static int prealloc_file_range(struct btrfs_trans_handle *trans,
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
BTRFS_FILE_EXTENT_PREALLOC);
|
BTRFS_FILE_EXTENT_PREALLOC);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
btrfs_drop_extent_cache(inode, cur_offset,
|
||||||
|
cur_offset + ins.offset -1, 0);
|
||||||
num_bytes -= ins.offset;
|
num_bytes -= ins.offset;
|
||||||
cur_offset += ins.offset;
|
cur_offset += ins.offset;
|
||||||
alloc_hint = ins.objectid + ins.offset;
|
alloc_hint = ins.objectid + ins.offset;
|
||||||
|
|
|
@ -596,9 +596,8 @@ again:
|
||||||
clear_page_dirty_for_io(page);
|
clear_page_dirty_for_io(page);
|
||||||
|
|
||||||
btrfs_set_extent_delalloc(inode, page_start, page_end);
|
btrfs_set_extent_delalloc(inode, page_start, page_end);
|
||||||
|
|
||||||
unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
|
|
||||||
set_page_dirty(page);
|
set_page_dirty(page);
|
||||||
|
unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1);
|
balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1);
|
||||||
|
@ -976,7 +975,7 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||||
|
|
||||||
/* punch hole in destination first */
|
/* punch hole in destination first */
|
||||||
btrfs_drop_extents(trans, root, inode, off, off + len,
|
btrfs_drop_extents(trans, root, inode, off, off + len,
|
||||||
off + len, 0, &hint_byte);
|
off + len, 0, &hint_byte, 1);
|
||||||
|
|
||||||
/* clone data */
|
/* clone data */
|
||||||
key.objectid = src->i_ino;
|
key.objectid = src->i_ino;
|
||||||
|
|
|
@ -159,8 +159,6 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
|
||||||
*
|
*
|
||||||
* len is the length of the extent
|
* len is the length of the extent
|
||||||
*
|
*
|
||||||
* This also sets the EXTENT_ORDERED bit on the range in the inode.
|
|
||||||
*
|
|
||||||
* The tree is given a single reference on the ordered extent that was
|
* The tree is given a single reference on the ordered extent that was
|
||||||
* inserted.
|
* inserted.
|
||||||
*/
|
*/
|
||||||
|
@ -181,6 +179,7 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
|
||||||
entry->start = start;
|
entry->start = start;
|
||||||
entry->len = len;
|
entry->len = len;
|
||||||
entry->disk_len = disk_len;
|
entry->disk_len = disk_len;
|
||||||
|
entry->bytes_left = len;
|
||||||
entry->inode = inode;
|
entry->inode = inode;
|
||||||
if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE)
|
if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE)
|
||||||
set_bit(type, &entry->flags);
|
set_bit(type, &entry->flags);
|
||||||
|
@ -195,9 +194,6 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
|
||||||
&entry->rb_node);
|
&entry->rb_node);
|
||||||
BUG_ON(node);
|
BUG_ON(node);
|
||||||
|
|
||||||
set_extent_ordered(&BTRFS_I(inode)->io_tree, file_offset,
|
|
||||||
entry_end(entry) - 1, GFP_NOFS);
|
|
||||||
|
|
||||||
spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
|
spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
|
||||||
list_add_tail(&entry->root_extent_list,
|
list_add_tail(&entry->root_extent_list,
|
||||||
&BTRFS_I(inode)->root->fs_info->ordered_extents);
|
&BTRFS_I(inode)->root->fs_info->ordered_extents);
|
||||||
|
@ -241,13 +237,10 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
|
||||||
struct btrfs_ordered_inode_tree *tree;
|
struct btrfs_ordered_inode_tree *tree;
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
struct btrfs_ordered_extent *entry;
|
struct btrfs_ordered_extent *entry;
|
||||||
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
tree = &BTRFS_I(inode)->ordered_tree;
|
tree = &BTRFS_I(inode)->ordered_tree;
|
||||||
mutex_lock(&tree->mutex);
|
mutex_lock(&tree->mutex);
|
||||||
clear_extent_ordered(io_tree, file_offset, file_offset + io_size - 1,
|
|
||||||
GFP_NOFS);
|
|
||||||
node = tree_search(tree, file_offset);
|
node = tree_search(tree, file_offset);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
@ -260,11 +253,16 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = test_range_bit(io_tree, entry->file_offset,
|
if (io_size > entry->bytes_left) {
|
||||||
entry->file_offset + entry->len - 1,
|
printk(KERN_CRIT "bad ordered accounting left %llu size %llu\n",
|
||||||
EXTENT_ORDERED, 0);
|
(unsigned long long)entry->bytes_left,
|
||||||
if (ret == 0)
|
(unsigned long long)io_size);
|
||||||
|
}
|
||||||
|
entry->bytes_left -= io_size;
|
||||||
|
if (entry->bytes_left == 0)
|
||||||
ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
|
ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags);
|
||||||
|
else
|
||||||
|
ret = 1;
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&tree->mutex);
|
mutex_unlock(&tree->mutex);
|
||||||
return ret == 0;
|
return ret == 0;
|
||||||
|
@ -476,6 +474,7 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
|
||||||
u64 orig_end;
|
u64 orig_end;
|
||||||
u64 wait_end;
|
u64 wait_end;
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
|
int found;
|
||||||
|
|
||||||
if (start + len < start) {
|
if (start + len < start) {
|
||||||
orig_end = INT_LIMIT(loff_t);
|
orig_end = INT_LIMIT(loff_t);
|
||||||
|
@ -502,6 +501,7 @@ again:
|
||||||
orig_end >> PAGE_CACHE_SHIFT);
|
orig_end >> PAGE_CACHE_SHIFT);
|
||||||
|
|
||||||
end = orig_end;
|
end = orig_end;
|
||||||
|
found = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
ordered = btrfs_lookup_first_ordered_extent(inode, end);
|
ordered = btrfs_lookup_first_ordered_extent(inode, end);
|
||||||
if (!ordered)
|
if (!ordered)
|
||||||
|
@ -514,6 +514,7 @@ again:
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
found++;
|
||||||
btrfs_start_ordered_extent(inode, ordered, 1);
|
btrfs_start_ordered_extent(inode, ordered, 1);
|
||||||
end = ordered->file_offset;
|
end = ordered->file_offset;
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
|
@ -521,8 +522,8 @@ again:
|
||||||
break;
|
break;
|
||||||
end--;
|
end--;
|
||||||
}
|
}
|
||||||
if (test_range_bit(&BTRFS_I(inode)->io_tree, start, orig_end,
|
if (found || test_range_bit(&BTRFS_I(inode)->io_tree, start, orig_end,
|
||||||
EXTENT_ORDERED | EXTENT_DELALLOC, 0)) {
|
EXTENT_DELALLOC, 0, NULL)) {
|
||||||
schedule_timeout(1);
|
schedule_timeout(1);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
@ -613,7 +614,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
|
||||||
*/
|
*/
|
||||||
if (test_range_bit(io_tree, disk_i_size,
|
if (test_range_bit(io_tree, disk_i_size,
|
||||||
ordered->file_offset + ordered->len - 1,
|
ordered->file_offset + ordered->len - 1,
|
||||||
EXTENT_DELALLOC, 0)) {
|
EXTENT_DELALLOC, 0, NULL)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -664,7 +665,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
|
||||||
*/
|
*/
|
||||||
if (i_size_test > entry_end(ordered) &&
|
if (i_size_test > entry_end(ordered) &&
|
||||||
!test_range_bit(io_tree, entry_end(ordered), i_size_test - 1,
|
!test_range_bit(io_tree, entry_end(ordered), i_size_test - 1,
|
||||||
EXTENT_DELALLOC, 0)) {
|
EXTENT_DELALLOC, 0, NULL)) {
|
||||||
new_i_size = min_t(u64, i_size_test, i_size_read(inode));
|
new_i_size = min_t(u64, i_size_test, i_size_read(inode));
|
||||||
}
|
}
|
||||||
BTRFS_I(inode)->disk_i_size = new_i_size;
|
BTRFS_I(inode)->disk_i_size = new_i_size;
|
||||||
|
|
|
@ -85,6 +85,9 @@ struct btrfs_ordered_extent {
|
||||||
/* extent length on disk */
|
/* extent length on disk */
|
||||||
u64 disk_len;
|
u64 disk_len;
|
||||||
|
|
||||||
|
/* number of bytes that still need writing */
|
||||||
|
u64 bytes_left;
|
||||||
|
|
||||||
/* flags (described above) */
|
/* flags (described above) */
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
|
|
@ -2180,7 +2180,7 @@ static int tree_block_processed(u64 bytenr, u32 blocksize,
|
||||||
struct reloc_control *rc)
|
struct reloc_control *rc)
|
||||||
{
|
{
|
||||||
if (test_range_bit(&rc->processed_blocks, bytenr,
|
if (test_range_bit(&rc->processed_blocks, bytenr,
|
||||||
bytenr + blocksize - 1, EXTENT_DIRTY, 1))
|
bytenr + blocksize - 1, EXTENT_DIRTY, 1, NULL))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2646,9 +2646,9 @@ int relocate_data_extent(struct inode *inode, struct btrfs_key *extent_key)
|
||||||
lock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
|
lock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS);
|
||||||
while (1) {
|
while (1) {
|
||||||
int ret;
|
int ret;
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
ret = add_extent_mapping(em_tree, em);
|
ret = add_extent_mapping(em_tree, em);
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
if (ret != -EEXIST) {
|
if (ret != -EEXIST) {
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -534,7 +534,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||||
saved_nbytes = inode_get_bytes(inode);
|
saved_nbytes = inode_get_bytes(inode);
|
||||||
/* drop any overlapping extents */
|
/* drop any overlapping extents */
|
||||||
ret = btrfs_drop_extents(trans, root, inode,
|
ret = btrfs_drop_extents(trans, root, inode,
|
||||||
start, extent_end, extent_end, start, &alloc_hint);
|
start, extent_end, extent_end, start, &alloc_hint, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
if (found_type == BTRFS_FILE_EXTENT_REG ||
|
if (found_type == BTRFS_FILE_EXTENT_REG ||
|
||||||
|
|
|
@ -276,7 +276,7 @@ loop_lock:
|
||||||
* is now congested. Back off and let other work structs
|
* is now congested. Back off and let other work structs
|
||||||
* run instead
|
* run instead
|
||||||
*/
|
*/
|
||||||
if (pending && bdi_write_congested(bdi) && batch_run > 32 &&
|
if (pending && bdi_write_congested(bdi) && batch_run > 8 &&
|
||||||
fs_info->fs_devices->open_devices > 1) {
|
fs_info->fs_devices->open_devices > 1) {
|
||||||
struct io_context *ioc;
|
struct io_context *ioc;
|
||||||
|
|
||||||
|
@ -1749,9 +1749,9 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
|
||||||
* step two, delete the device extents and the
|
* step two, delete the device extents and the
|
||||||
* chunk tree entries
|
* chunk tree entries
|
||||||
*/
|
*/
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, chunk_offset, 1);
|
em = lookup_extent_mapping(em_tree, chunk_offset, 1);
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
|
|
||||||
BUG_ON(em->start > chunk_offset ||
|
BUG_ON(em->start > chunk_offset ||
|
||||||
em->start + em->len < chunk_offset);
|
em->start + em->len < chunk_offset);
|
||||||
|
@ -1780,9 +1780,9 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
|
||||||
ret = btrfs_remove_block_group(trans, extent_root, chunk_offset);
|
ret = btrfs_remove_block_group(trans, extent_root, chunk_offset);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
remove_extent_mapping(em_tree, em);
|
remove_extent_mapping(em_tree, em);
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
|
|
||||||
kfree(map);
|
kfree(map);
|
||||||
em->bdev = NULL;
|
em->bdev = NULL;
|
||||||
|
@ -2294,9 +2294,9 @@ again:
|
||||||
em->block_len = em->len;
|
em->block_len = em->len;
|
||||||
|
|
||||||
em_tree = &extent_root->fs_info->mapping_tree.map_tree;
|
em_tree = &extent_root->fs_info->mapping_tree.map_tree;
|
||||||
spin_lock(&em_tree->lock);
|
write_lock(&em_tree->lock);
|
||||||
ret = add_extent_mapping(em_tree, em);
|
ret = add_extent_mapping(em_tree, em);
|
||||||
spin_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
|
@ -2491,9 +2491,9 @@ int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
|
||||||
int readonly = 0;
|
int readonly = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
spin_lock(&map_tree->map_tree.lock);
|
read_lock(&map_tree->map_tree.lock);
|
||||||
em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
|
em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
|
||||||
spin_unlock(&map_tree->map_tree.lock);
|
read_unlock(&map_tree->map_tree.lock);
|
||||||
if (!em)
|
if (!em)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -2518,11 +2518,11 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
|
||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
spin_lock(&tree->map_tree.lock);
|
write_lock(&tree->map_tree.lock);
|
||||||
em = lookup_extent_mapping(&tree->map_tree, 0, (u64)-1);
|
em = lookup_extent_mapping(&tree->map_tree, 0, (u64)-1);
|
||||||
if (em)
|
if (em)
|
||||||
remove_extent_mapping(&tree->map_tree, em);
|
remove_extent_mapping(&tree->map_tree, em);
|
||||||
spin_unlock(&tree->map_tree.lock);
|
write_unlock(&tree->map_tree.lock);
|
||||||
if (!em)
|
if (!em)
|
||||||
break;
|
break;
|
||||||
kfree(em->bdev);
|
kfree(em->bdev);
|
||||||
|
@ -2540,9 +2540,9 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
|
||||||
struct extent_map_tree *em_tree = &map_tree->map_tree;
|
struct extent_map_tree *em_tree = &map_tree->map_tree;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, logical, len);
|
em = lookup_extent_mapping(em_tree, logical, len);
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
BUG_ON(!em);
|
BUG_ON(!em);
|
||||||
|
|
||||||
BUG_ON(em->start > logical || em->start + em->len < logical);
|
BUG_ON(em->start > logical || em->start + em->len < logical);
|
||||||
|
@ -2604,9 +2604,9 @@ again:
|
||||||
atomic_set(&multi->error, 0);
|
atomic_set(&multi->error, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, logical, *length);
|
em = lookup_extent_mapping(em_tree, logical, *length);
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
|
|
||||||
if (!em && unplug_page)
|
if (!em && unplug_page)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2763,9 +2763,9 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
|
||||||
u64 stripe_nr;
|
u64 stripe_nr;
|
||||||
int i, j, nr = 0;
|
int i, j, nr = 0;
|
||||||
|
|
||||||
spin_lock(&em_tree->lock);
|
read_lock(&em_tree->lock);
|
||||||
em = lookup_extent_mapping(em_tree, chunk_start, 1);
|
em = lookup_extent_mapping(em_tree, chunk_start, 1);
|
||||||
spin_unlock(&em_tree->lock);
|
read_unlock(&em_tree->lock);
|
||||||
|
|
||||||
BUG_ON(!em || em->start != chunk_start);
|
BUG_ON(!em || em->start != chunk_start);
|
||||||
map = (struct map_lookup *)em->bdev;
|
map = (struct map_lookup *)em->bdev;
|
||||||
|
@ -3053,9 +3053,9 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
||||||
logical = key->offset;
|
logical = key->offset;
|
||||||
length = btrfs_chunk_length(leaf, chunk);
|
length = btrfs_chunk_length(leaf, chunk);
|
||||||
|
|
||||||
spin_lock(&map_tree->map_tree.lock);
|
read_lock(&map_tree->map_tree.lock);
|
||||||
em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
|
em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
|
||||||
spin_unlock(&map_tree->map_tree.lock);
|
read_unlock(&map_tree->map_tree.lock);
|
||||||
|
|
||||||
/* already mapped? */
|
/* already mapped? */
|
||||||
if (em && em->start <= logical && em->start + em->len > logical) {
|
if (em && em->start <= logical && em->start + em->len > logical) {
|
||||||
|
@ -3114,9 +3114,9 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
|
||||||
map->stripes[i].dev->in_fs_metadata = 1;
|
map->stripes[i].dev->in_fs_metadata = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&map_tree->map_tree.lock);
|
write_lock(&map_tree->map_tree.lock);
|
||||||
ret = add_extent_mapping(&map_tree->map_tree, em);
|
ret = add_extent_mapping(&map_tree->map_tree, em);
|
||||||
spin_unlock(&map_tree->map_tree.lock);
|
write_unlock(&map_tree->map_tree.lock);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue