提交 dc2af6a6 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (42 commits)
  Btrfs: hash the btree inode during  fill_super
  Btrfs: relocate file extents in clusters
  Btrfs: don't rename file into dummy directory
  Btrfs: check size of inode backref before adding hardlink
  Btrfs: fix releasepage to avoid unlocking extents we haven't locked
  Btrfs: Fix test_range_bit for whole file extents
  Btrfs: fix errors handling cached state in set/clear_extent_bit
  Btrfs: fix early enospc during balancing
  Btrfs: deal with NULL space info
  Btrfs: account for space used by the super mirrors
  Btrfs: fix extent entry threshold calculation
  Btrfs: remove dead code
  Btrfs: fix bitmap size tracking
  Btrfs: don't keep retrying a block group if we fail to allocate a cluster
  Btrfs: make balance code choose more wisely when relocating
  Btrfs: fix arithmetic error in clone ioctl
  Btrfs: add snapshot/subvolume destroy ioctl
  Btrfs: change how subvolumes are organized
  Btrfs: do not reuse objectid of deleted snapshot/subvol
  Btrfs: speed up snapshot dropping
  ...
...@@ -48,6 +48,9 @@ struct btrfs_worker_thread { ...@@ -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. */
...@@ -71,7 +74,12 @@ static void check_idle_worker(struct btrfs_worker_thread *worker) ...@@ -71,7 +74,12 @@ static void check_idle_worker(struct btrfs_worker_thread *worker)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&worker->workers->lock, flags); spin_lock_irqsave(&worker->workers->lock, flags);
worker->idle = 1; worker->idle = 1;
list_move(&worker->worker_list, &worker->workers->idle_list);
/* the list may be empty if the worker is just starting */
if (!list_empty(&worker->worker_list)) {
list_move(&worker->worker_list,
&worker->workers->idle_list);
}
spin_unlock_irqrestore(&worker->workers->lock, flags); spin_unlock_irqrestore(&worker->workers->lock, flags);
} }
} }
...@@ -87,23 +95,49 @@ static void check_busy_worker(struct btrfs_worker_thread *worker) ...@@ -87,23 +95,49 @@ static void check_busy_worker(struct btrfs_worker_thread *worker)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&worker->workers->lock, flags); spin_lock_irqsave(&worker->workers->lock, flags);
worker->idle = 0; worker->idle = 0;
list_move_tail(&worker->worker_list,
&worker->workers->worker_list); if (!list_empty(&worker->worker_list)) {
list_move_tail(&worker->worker_list,
&worker->workers->worker_list);
}
spin_unlock_irqrestore(&worker->workers->lock, flags); spin_unlock_irqrestore(&worker->workers->lock, flags);
} }
} }
static noinline int run_ordered_completions(struct btrfs_workers *workers, static void check_pending_worker_creates(struct btrfs_worker_thread *worker)
struct btrfs_work *work)
{ {
struct btrfs_workers *workers = worker->workers;
unsigned long flags; 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,
struct btrfs_work *work)
{
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 +160,118 @@ static noinline int run_ordered_completions(struct btrfs_workers *workers, ...@@ -126,45 +160,118 @@ 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(&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) &&
atomic_read(&worker->num_pending) == 0) {
freeit = 1;
list_del_init(&worker->worker_list);
worker->workers->num_workers--;
}
spin_unlock(&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 +282,13 @@ static int worker_loop(void *arg) ...@@ -175,9 +282,13 @@ static int worker_loop(void *arg)
*/ */
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 +327,10 @@ static int worker_loop(void *arg) ...@@ -216,8 +327,10 @@ static int worker_loop(void *arg)
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 +339,13 @@ static int worker_loop(void *arg) ...@@ -226,8 +339,13 @@ static int worker_loop(void *arg)
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 +360,30 @@ int btrfs_stop_workers(struct btrfs_workers *workers) ...@@ -242,16 +360,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 +398,13 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max) ...@@ -266,10 +398,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 +428,9 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) ...@@ -293,7 +428,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 +440,6 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) ...@@ -303,7 +440,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;
...@@ -350,7 +486,6 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers) ...@@ -350,7 +486,6 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers)
*/ */
next = workers->worker_list.next; next = workers->worker_list.next;
worker = list_entry(next, struct btrfs_worker_thread, worker_list); worker = list_entry(next, struct btrfs_worker_thread, worker_list);
atomic_inc(&worker->num_pending);
worker->sequence++; worker->sequence++;
if (worker->sequence % workers->idle_thresh == 0) if (worker->sequence % workers->idle_thresh == 0)
...@@ -367,28 +502,18 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) ...@@ -367,28 +502,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 +521,28 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) ...@@ -396,6 +521,28 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers)
goto again; goto again;
} }
} }
goto found;
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);
found:
/*
* this makes sure the worker doesn't exit before it is placed
* onto a busy/idle list
*/
atomic_inc(&worker->num_pending);
spin_unlock_irqrestore(&workers->lock, flags);
return worker; return worker;
} }
...@@ -427,7 +574,7 @@ int btrfs_requeue_work(struct btrfs_work *work) ...@@ -427,7 +574,7 @@ int btrfs_requeue_work(struct btrfs_work *work)
spin_lock(&worker->workers->lock); spin_lock(&worker->workers->lock);
worker->idle = 0; worker->idle = 0;
list_move_tail(&worker->worker_list, list_move_tail(&worker->worker_list,
&worker->workers->worker_list); &worker->workers->worker_list);
spin_unlock(&worker->workers->lock); spin_unlock(&worker->workers->lock);
} }
if (!worker->working) { if (!worker->working) {
...@@ -435,9 +582,9 @@ int btrfs_requeue_work(struct btrfs_work *work) ...@@ -435,9 +582,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 +610,18 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) ...@@ -463,14 +610,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);
} }
...@@ -481,7 +632,6 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) ...@@ -481,7 +632,6 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
list_add_tail(&work->list, &worker->prio_pending); list_add_tail(&work->list, &worker->prio_pending);
else else
list_add_tail(&work->list, &worker->pending); list_add_tail(&work->list, &worker->pending);
atomic_inc(&worker->num_pending);
check_busy_worker(worker); check_busy_worker(worker);
/* /*
...@@ -492,10 +642,10 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) ...@@ -492,10 +642,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 { ...@@ -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 { ...@@ -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;
}; };
......
...@@ -138,6 +138,7 @@ struct btrfs_inode { ...@@ -138,6 +138,7 @@ struct btrfs_inode {
* of these. * of these.
*/ */
unsigned ordered_data_close:1; unsigned ordered_data_close:1;
unsigned dummy_inode:1;
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
...@@ -506,10 +506,10 @@ static noinline int add_ra_bio_pages(struct inode *inode, ...@@ -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, ...@@ -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);
......
...@@ -2853,6 +2853,12 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans, ...@@ -2853,6 +2853,12 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
int split; int split;
int num_doubles = 0; int num_doubles = 0;
l = path->nodes[0];
slot = path->slots[0];
if (extend && data_size + btrfs_item_size_nr(l, slot) +
sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root))
return -EOVERFLOW;
/* first try to make some room by pushing left and right */ /* first try to make some room by pushing left and right */
if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) { if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
wret = push_leaf_right(trans, root, path, data_size, 0); wret = push_leaf_right(trans, root, path, data_size, 0);
......
...@@ -114,6 +114,10 @@ struct btrfs_ordered_sum; ...@@ -114,6 +114,10 @@ struct btrfs_ordered_sum;
*/ */
#define BTRFS_DEV_ITEMS_OBJECTID 1ULL #define BTRFS_DEV_ITEMS_OBJECTID 1ULL
#define BTRFS_BTREE_INODE_OBJECTID 1
#define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2
/* /*
* we can actually store much bigger names, but lets not confuse the rest * we can actually store much bigger names, but lets not confuse the rest
* of linux * of linux
...@@ -670,6 +674,7 @@ struct btrfs_space_info { ...@@ -670,6 +674,7 @@ struct btrfs_space_info {
u64 bytes_reserved; /* total bytes the allocator has reserved for u64 bytes_reserved; /* total bytes the allocator has reserved for
current allocations */ current allocations */
u64 bytes_readonly; /* total bytes that are read only */ u64 bytes_readonly; /* total bytes that are read only */
u64 bytes_super; /* total bytes reserved for the super blocks */
/* delalloc accounting */ /* delalloc accounting */
u64 bytes_delalloc; /* number of bytes reserved for allocation, u64 bytes_delalloc; /* number of bytes reserved for allocation,
...@@ -726,6 +731,15 @@ enum btrfs_caching_type { ...@@ -726,6 +731,15 @@ enum btrfs_caching_type {
BTRFS_CACHE_FINISHED = 2, BTRFS_CACHE_FINISHED = 2,
}; };
struct btrfs_caching_control {
struct list_head list;
struct mutex mutex;
wait_queue_head_t wait;
struct btrfs_block_group_cache *block_group;
u64 progress;
atomic_t count;
};
struct btrfs_block_group_cache { struct btrfs_block_group_cache {
struct btrfs_key key; struct btrfs_key key;
struct btrfs_block_group_item item; struct btrfs_block_group_item item;
...@@ -733,6 +747,7 @@ struct btrfs_block_group_cache { ...@@ -733,6 +747,7 @@ struct btrfs_block_group_cache {
spinlock_t lock; spinlock_t lock;
u64 pinned; u64 pinned;
u64 reserved; u64 reserved;
u64 bytes_super;
u64 flags; u64 flags;
u64 sectorsize; u64 sectorsize;
int extents_thresh; int extents_thresh;
...@@ -742,8 +757,9 @@ struct btrfs_block_group_cache { ...@@ -742,8 +757,9 @@ struct btrfs_block_group_cache {
int dirty; int dirty;
/* cache tracking stuff */ /* cache tracking stuff */
wait_queue_head_t caching_q;
int cached; int cached;
struct btrfs_caching_control *caching_ctl;
u64 last_byte_to_unpin;
struct btrfs_space_info *space_info; struct btrfs_space_info *space_info;
...@@ -782,13 +798,16 @@ struct btrfs_fs_info { ...@@ -782,13 +798,16 @@ struct btrfs_fs_info {
/* the log root tree is a directory of all the other log roots */ /* the log root tree is a directory of all the other log roots */
struct btrfs_root *log_root_tree; struct btrfs_root *log_root_tree;
spinlock_t fs_roots_radix_lock;
struct radix_tree_root fs_roots_radix; struct radix_tree_root fs_roots_radix;
/* block group cache stuff */ /* block group cache stuff */
spinlock_t block_group_cache_lock; spinlock_t block_group_cache_lock;
struct rb_root block_group_cache_tree; struct rb_root block_group_cache_tree;
struct extent_io_tree pinned_extents; struct extent_io_tree freed_extents[2];
struct extent_io_tree *pinned_extents;
/* logical->physical extent mapping */ /* logical->physical extent mapping */
struct btrfs_mapping_tree mapping_tree; struct btrfs_mapping_tree mapping_tree;
...@@ -822,11 +841,7 @@ struct btrfs_fs_info { ...@@ -822,11 +841,7 @@ struct btrfs_fs_info {
struct mutex transaction_kthread_mutex; struct mutex transaction_kthread_mutex;
struct mutex cleaner_mutex; struct mutex cleaner_mutex;
struct mutex chunk_mutex; struct mutex chunk_mutex;
struct mutex drop_mutex;
struct mutex volume_mutex; struct mutex volume_mutex;
struct mutex tree_reloc_mutex;
struct rw_semaphore extent_commit_sem;
/* /*
* this protects the ordered operations list only while we are * this protects the ordered operations list only while we are
* processing all of the entries on it. This way we make * processing all of the entries on it. This way we make
...@@ -835,10 +850,16 @@ struct btrfs_fs_info { ...@@ -835,10 +850,16 @@ struct btrfs_fs_info {
* before jumping into the main commit. * before jumping into the main commit.
*/ */
struct mutex ordered_operations_mutex; struct mutex ordered_operations_mutex;
struct rw_semaphore extent_commit_sem;
struct rw_semaphore subvol_sem;
struct srcu_struct subvol_srcu;
struct list_head trans_list; struct list_head trans_list;
struct list_head hashers; struct list_head hashers;
struct list_head dead_roots; struct list_head dead_roots;
struct list_head caching_block_groups;
atomic_t nr_async_submits; atomic_t nr_async_submits;
atomic_t async_submit_draining; atomic_t async_submit_draining;
...@@ -996,10 +1017,12 @@ struct btrfs_root { ...@@ -996,10 +1017,12 @@ struct btrfs_root {
u32 stripesize; u32 stripesize;
u32 type; u32 type;
u64 highest_inode;
u64 last_inode_alloc; u64 highest_objectid;
int ref_cows; int ref_cows;
int track_dirty; int track_dirty;
int in_radix;
u64 defrag_trans_start; u64 defrag_trans_start;
struct btrfs_key defrag_progress; struct btrfs_key defrag_progress;
struct btrfs_key defrag_max; struct btrfs_key defrag_max;
...@@ -1920,8 +1943,8 @@ void btrfs_put_block_group(struct btrfs_block_group_cache *cache); ...@@ -1920,8 +1943,8 @@ void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
struct btrfs_root *root, unsigned long count); struct btrfs_root *root, unsigned long count);
int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len); int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
int btrfs_update_pinned_extents(struct btrfs_root *root, int btrfs_pin_extent(struct btrfs_root *root,
u64 bytenr, u64 num, int pin); u64 bytenr, u64 num, int reserved);
int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *leaf); struct btrfs_root *root, struct extent_buffer *leaf);
int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
...@@ -1971,9 +1994,10 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -1971,9 +1994,10 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
u64 root_objectid, u64 owner, u64 offset); u64 root_objectid, u64 owner, u64 offset);
int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len);
int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root);
struct extent_io_tree *unpin);
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 parent, u64 bytenr, u64 num_bytes, u64 parent,
...@@ -1984,6 +2008,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, ...@@ -1984,6 +2008,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr); int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr);
int btrfs_free_block_groups(struct btrfs_fs_info *info); int btrfs_free_block_groups(struct btrfs_fs_info *info);
int btrfs_read_block_groups(struct btrfs_root *root); int btrfs_read_block_groups(struct btrfs_root *root);
int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr);
int btrfs_make_block_group(struct btrfs_trans_handle *trans, int btrfs_make_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytes_used, struct btrfs_root *root, u64 bytes_used,
u64 type, u64 chunk_objectid, u64 chunk_offset, u64 type, u64 chunk_objectid, u64 chunk_offset,
...@@ -2006,7 +2031,6 @@ void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode, ...@@ -2006,7 +2031,6 @@ void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode,
u64 bytes); u64 bytes);
void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode, void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
u64 bytes); u64 bytes);
void btrfs_free_pinned_extents(struct btrfs_fs_info *info);
/* ctree.c */ /* ctree.c */
int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
int level, int *slot); int level, int *slot);
...@@ -2100,12 +2124,15 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, ...@@ -2100,12 +2124,15 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
struct extent_buffer *parent); struct extent_buffer *parent);
/* root-item.c */ /* root-item.c */
int btrfs_find_root_ref(struct btrfs_root *tree_root, int btrfs_find_root_ref(struct btrfs_root *tree_root,
struct btrfs_path *path, struct btrfs_path *path,
u64 root_id, u64 ref_id); u64 root_id, u64 ref_id);
int btrfs_add_root_ref(struct btrfs_trans_handle *trans, int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *tree_root, struct btrfs_root *tree_root,
u64 root_id, u8 type, u64 ref_id, u64 root_id, u64 ref_id, u64 dirid, u64 sequence,
u64 dirid, u64 sequence, const char *name, int name_len);
int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *tree_root,
u64 root_id, u64 ref_id, u64 dirid, u64 *sequence,
const char *name, int name_len); const char *name, int name_len);
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_key *key); struct btrfs_key *key);
...@@ -2120,6 +2147,7 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct ...@@ -2120,6 +2147,7 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
int btrfs_search_root(struct btrfs_root *root, u64 search_start, int btrfs_search_root(struct btrfs_root *root, u64 search_start,
u64 *found_objectid); u64 *found_objectid);
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid); int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid);
int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
int btrfs_set_root_node(struct btrfs_root_item *item, int btrfs_set_root_node(struct btrfs_root_item *item,
struct extent_buffer *node); struct extent_buffer *node);
/* dir-item.c */ /* dir-item.c */
...@@ -2138,6 +2166,10 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, ...@@ -2138,6 +2166,10 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
struct btrfs_path *path, u64 dir, struct btrfs_path *path, u64 dir,
u64 objectid, const char *name, int name_len, u64 objectid, const char *name, int name_len,
int mod); int mod);
struct btrfs_dir_item *
btrfs_search_dir_index_item(struct btrfs_root *root,
struct btrfs_path *path, u64 dirid,
const char *name, int name_len);
struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
struct btrfs_path *path, struct btrfs_path *path,
const char *name, int name_len); const char *name, int name_len);
...@@ -2160,6 +2192,7 @@ int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, ...@@ -2160,6 +2192,7 @@ int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 offset); struct btrfs_root *root, u64 offset);
int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 offset); struct btrfs_root *root, u64 offset);
int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset);
/* inode-map.c */ /* inode-map.c */
int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
...@@ -2232,6 +2265,10 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans, ...@@ -2232,6 +2265,10 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
int btrfs_add_link(struct btrfs_trans_handle *trans, int btrfs_add_link(struct btrfs_trans_handle *trans,
struct inode *parent_inode, struct inode *inode, struct inode *parent_inode, struct inode *inode,
const char *name, int name_len, int add_backref, u64 index); const char *name, int name_len, int add_backref, u64 index);
int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *dir, u64 objectid,
const char *name, int name_len);
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct inode *inode, u64 new_size, struct inode *inode, u64 new_size,
...@@ -2242,7 +2279,7 @@ int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end); ...@@ -2242,7 +2279,7 @@ int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
int btrfs_writepages(struct address_space *mapping, int btrfs_writepages(struct address_space *mapping,
struct writeback_control *wbc); struct writeback_control *wbc);
int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
struct btrfs_root *new_root, struct dentry *dentry, struct btrfs_root *new_root,
u64 new_dirid, u64 alloc_hint); u64 new_dirid, u64 alloc_hint);
int btrfs_merge_bio_hook(struct page *page, unsigned long offset, int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
size_t size, struct bio *bio, unsigned long bio_flags); size_t size, struct bio *bio, unsigned long bio_flags);
...@@ -2258,6 +2295,7 @@ int btrfs_write_inode(struct inode *inode, int wait); ...@@ -2258,6 +2295,7 @@ int btrfs_write_inode(struct inode *inode, int wait);
void btrfs_dirty_inode(struct inode *inode); void btrfs_dirty_inode(struct inode *inode);
struct inode *btrfs_alloc_inode(struct super_block *sb); struct inode *btrfs_alloc_inode(struct super_block *sb);
void btrfs_destroy_inode(struct inode *inode); void btrfs_destroy_inode(struct inode *inode);
void btrfs_drop_inode(struct inode *inode);
int btrfs_init_cachep(void); int btrfs_init_cachep(void);
void btrfs_destroy_cachep(void); void btrfs_destroy_cachep(void);
long btrfs_ioctl_trans_end(struct file *file); long btrfs_ioctl_trans_end(struct file *file);
...@@ -2275,6 +2313,8 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); ...@@ -2275,6 +2313,8 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
void btrfs_orphan_cleanup(struct btrfs_root *root); void btrfs_orphan_cleanup(struct btrfs_root *root);
int btrfs_cont_expand(struct inode *inode, loff_t size); int btrfs_cont_expand(struct inode *inode, loff_t size);
int btrfs_invalidate_inodes(struct btrfs_root *root);
extern struct dentry_operations btrfs_dentry_operations;
/* ioctl.c */ /* ioctl.c */
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
...@@ -2290,7 +2330,7 @@ extern struct file_operations btrfs_file_operations; ...@@ -2290,7 +2330,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);
......
...@@ -281,6 +281,53 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, ...@@ -281,6 +281,53 @@ btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
return btrfs_match_dir_item_name(root, path, name, name_len); return btrfs_match_dir_item_name(root, path, name, name_len);
} }
struct btrfs_dir_item *
btrfs_search_dir_index_item(struct btrfs_root *root,
struct btrfs_path *path, u64 dirid,
const char *name, int name_len)
{
struct extent_buffer *leaf;
struct btrfs_dir_item *di;
struct btrfs_key key;
u32 nritems;
int ret;
key.objectid = dirid;
key.type = BTRFS_DIR_INDEX_KEY;
key.offset = 0;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
return ERR_PTR(ret);
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
while (1) {
if (path->slots[0] >= nritems) {
ret = btrfs_next_leaf(root, path);
if (ret < 0)
return ERR_PTR(ret);
if (ret > 0)
break;
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
continue;
}
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY)
break;
di = btrfs_match_dir_item_name(root, path, name, name_len);
if (di)
return di;
path->slots[0]++;
}
return NULL;
}
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, u64 dir, struct btrfs_path *path, u64 dir,
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
static struct extent_io_ops btree_extent_io_ops; static struct extent_io_ops btree_extent_io_ops;
static void end_workqueue_fn(struct btrfs_work *work); static void end_workqueue_fn(struct btrfs_work *work);
static void free_fs_root(struct btrfs_root *root);
static atomic_t btrfs_bdi_num = ATOMIC_INIT(0); static atomic_t btrfs_bdi_num = ATOMIC_INIT(0);
...@@ -123,15 +124,15 @@ static struct extent_map *btree_get_extent(struct inode *inode, ...@@ -123,15 +124,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 +145,7 @@ static struct extent_map *btree_get_extent(struct inode *inode, ...@@ -144,7 +145,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 +164,7 @@ static struct extent_map *btree_get_extent(struct inode *inode, ...@@ -163,7 +164,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);
...@@ -895,8 +896,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, ...@@ -895,8 +896,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->fs_info = fs_info; root->fs_info = fs_info;
root->objectid = objectid; root->objectid = objectid;
root->last_trans = 0; root->last_trans = 0;
root->highest_inode = 0; root->highest_objectid = 0;
root->last_inode_alloc = 0;
root->name = NULL; root->name = NULL;
root->in_sysfs = 0; root->in_sysfs = 0;
root->inode_tree.rb_node = NULL; root->inode_tree.rb_node = NULL;
...@@ -952,14 +952,16 @@ static int find_and_setup_root(struct btrfs_root *tree_root, ...@@ -952,14 +952,16 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
root, fs_info, objectid); root, fs_info, objectid);
ret = btrfs_find_last_root(tree_root, objectid, ret = btrfs_find_last_root(tree_root, objectid,
&root->root_item, &root->root_key); &root->root_item, &root->root_key);
if (ret > 0)
return -ENOENT;
BUG_ON(ret); BUG_ON(ret);
generation = btrfs_root_generation(&root->root_item); generation = btrfs_root_generation(&root->root_item);
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation); blocksize, generation);
root->commit_root = btrfs_root_node(root);
BUG_ON(!root->node); BUG_ON(!root->node);
root->commit_root = btrfs_root_node(root);
return 0; return 0;
} }
...@@ -1095,7 +1097,6 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, ...@@ -1095,7 +1097,6 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
struct btrfs_fs_info *fs_info = tree_root->fs_info; struct btrfs_fs_info *fs_info = tree_root->fs_info;
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *l; struct extent_buffer *l;
u64 highest_inode;
u64 generation; u64 generation;
u32 blocksize; u32 blocksize;
int ret = 0; int ret = 0;
...@@ -1110,7 +1111,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, ...@@ -1110,7 +1111,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
kfree(root); kfree(root);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
goto insert; goto out;
} }
__setup_root(tree_root->nodesize, tree_root->leafsize, __setup_root(tree_root->nodesize, tree_root->leafsize,
...@@ -1120,39 +1121,30 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, ...@@ -1120,39 +1121,30 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); BUG_ON(!path);
ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
if (ret != 0) { if (ret == 0) {
if (ret > 0) l = path->nodes[0];
ret = -ENOENT; read_extent_buffer(l, &root->root_item,
goto out; btrfs_item_ptr_offset(l, path->slots[0]),
sizeof(root->root_item));
memcpy(&root->root_key, location, sizeof(*location));
} }
l = path->nodes[0];
read_extent_buffer(l, &root->root_item,
btrfs_item_ptr_offset(l, path->slots[0]),
sizeof(root->root_item));
memcpy(&root->root_key, location, sizeof(*location));
ret = 0;
out:
btrfs_release_path(root, path);
btrfs_free_path(path); btrfs_free_path(path);
if (ret) { if (ret) {
kfree(root); if (ret > 0)
ret = -ENOENT;
return ERR_PTR(ret); return ERR_PTR(ret);
} }
generation = btrfs_root_generation(&root->root_item); generation = btrfs_root_generation(&root->root_item);
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation); blocksize, generation);
root->commit_root = btrfs_root_node(root); root->commit_root = btrfs_root_node(root);
BUG_ON(!root->node); BUG_ON(!root->node);
insert: out:
if (location->objectid != BTRFS_TREE_LOG_OBJECTID) { if (location->objectid != BTRFS_TREE_LOG_OBJECTID)
root->ref_cows = 1; root->ref_cows = 1;
ret = btrfs_find_highest_inode(root, &highest_inode);
if (ret == 0) {
root->highest_inode = highest_inode;
root->last_inode_alloc = highest_inode;
}
}
return root; return root;
} }
...@@ -1187,39 +1179,66 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -1187,39 +1179,66 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
return fs_info->dev_root; return fs_info->dev_root;
if (location->objectid == BTRFS_CSUM_TREE_OBJECTID) if (location->objectid == BTRFS_CSUM_TREE_OBJECTID)
return fs_info->csum_root; return fs_info->csum_root;
again:
spin_lock(&fs_info->fs_roots_radix_lock);
root = radix_tree_lookup(&fs_info->fs_roots_radix, root = radix_tree_lookup(&fs_info->fs_roots_radix,
(unsigned long)location->objectid); (unsigned long)location->objectid);
spin_unlock(&fs_info->fs_roots_radix_lock);
if (root) if (root)
return root; return root;
ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid);
if (ret == 0)
ret = -ENOENT;
if (ret < 0)
return ERR_PTR(ret);
root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location); root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location);
if (IS_ERR(root)) if (IS_ERR(root))
return root; return root;
WARN_ON(btrfs_root_refs(&root->root_item) == 0);
set_anon_super(&root->anon_super, NULL); set_anon_super(&root->anon_super, NULL);
ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
if (ret)
goto fail;
spin_lock(&fs_info->fs_roots_radix_lock);
ret = radix_tree_insert(&fs_info->fs_roots_radix, ret = radix_tree_insert(&fs_info->fs_roots_radix,
(unsigned long)root->root_key.objectid, (unsigned long)root->root_key.objectid,
root); root);
if (ret == 0)
root->in_radix = 1;
spin_unlock(&fs_info->fs_roots_radix_lock);
radix_tree_preload_end();
if (ret) { if (ret) {
free_extent_buffer(root->node); if (ret == -EEXIST) {
kfree(root); free_fs_root(root);
return ERR_PTR(ret); goto again;
}
goto fail;
} }
if (!(fs_info->sb->s_flags & MS_RDONLY)) {
ret = btrfs_find_dead_roots(fs_info->tree_root, ret = btrfs_find_dead_roots(fs_info->tree_root,
root->root_key.objectid); root->root_key.objectid);
BUG_ON(ret); WARN_ON(ret);
if (!(fs_info->sb->s_flags & MS_RDONLY))
btrfs_orphan_cleanup(root); btrfs_orphan_cleanup(root);
}
return root; return root;
fail:
free_fs_root(root);
return ERR_PTR(ret);
} }
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *location, struct btrfs_key *location,
const char *name, int namelen) const char *name, int namelen)
{ {
return btrfs_read_fs_root_no_name(fs_info, location);
#if 0
struct btrfs_root *root; struct btrfs_root *root;
int ret; int ret;
...@@ -1236,7 +1255,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, ...@@ -1236,7 +1255,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
kfree(root); kfree(root);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
#if 0
ret = btrfs_sysfs_add_root(root); ret = btrfs_sysfs_add_root(root);
if (ret) { if (ret) {
free_extent_buffer(root->node); free_extent_buffer(root->node);
...@@ -1244,9 +1263,9 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, ...@@ -1244,9 +1263,9 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
kfree(root); kfree(root);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
#endif
root->in_sysfs = 1; root->in_sysfs = 1;
return root; return root;
#endif
} }
static int btrfs_congested_fn(void *congested_data, int bdi_bits) static int btrfs_congested_fn(void *congested_data, int bdi_bits)
...@@ -1325,9 +1344,9 @@ static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) ...@@ -1325,9 +1344,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;
...@@ -1360,8 +1379,10 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) ...@@ -1360,8 +1379,10 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
err = bdi_register(bdi, NULL, "btrfs-%d", err = bdi_register(bdi, NULL, "btrfs-%d",
atomic_inc_return(&btrfs_bdi_num)); atomic_inc_return(&btrfs_bdi_num));
if (err) if (err) {
bdi_destroy(bdi);
return err; return err;
}
bdi->ra_pages = default_backing_dev_info.ra_pages; bdi->ra_pages = default_backing_dev_info.ra_pages;
bdi->unplug_io_fn = btrfs_unplug_io_fn; bdi->unplug_io_fn = btrfs_unplug_io_fn;
...@@ -1451,9 +1472,12 @@ static int cleaner_kthread(void *arg) ...@@ -1451,9 +1472,12 @@ static int cleaner_kthread(void *arg)
break; break;
vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
mutex_lock(&root->fs_info->cleaner_mutex);
btrfs_clean_old_snapshots(root); if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
mutex_unlock(&root->fs_info->cleaner_mutex); mutex_trylock(&root->fs_info->cleaner_mutex)) {
btrfs_clean_old_snapshots(root);
mutex_unlock(&root->fs_info->cleaner_mutex);
}
if (freezing(current)) { if (freezing(current)) {
refrigerator(); refrigerator();
...@@ -1558,15 +1582,36 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1558,15 +1582,36 @@ struct btrfs_root *open_ctree(struct super_block *sb,
err = -ENOMEM; err = -ENOMEM;
goto fail; goto fail;
} }
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_NOFS);
ret = init_srcu_struct(&fs_info->subvol_srcu);
if (ret) {
err = ret;
goto fail;
}
ret = setup_bdi(fs_info, &fs_info->bdi);
if (ret) {
err = ret;
goto fail_srcu;
}
fs_info->btree_inode = new_inode(sb);
if (!fs_info->btree_inode) {
err = -ENOMEM;
goto fail_bdi;
}
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
INIT_LIST_HEAD(&fs_info->trans_list); INIT_LIST_HEAD(&fs_info->trans_list);
INIT_LIST_HEAD(&fs_info->dead_roots); INIT_LIST_HEAD(&fs_info->dead_roots);
INIT_LIST_HEAD(&fs_info->hashers); INIT_LIST_HEAD(&fs_info->hashers);
INIT_LIST_HEAD(&fs_info->delalloc_inodes); INIT_LIST_HEAD(&fs_info->delalloc_inodes);
INIT_LIST_HEAD(&fs_info->ordered_operations); INIT_LIST_HEAD(&fs_info->ordered_operations);
INIT_LIST_HEAD(&fs_info->caching_block_groups);
spin_lock_init(&fs_info->delalloc_lock); spin_lock_init(&fs_info->delalloc_lock);
spin_lock_init(&fs_info->new_trans_lock); spin_lock_init(&fs_info->new_trans_lock);
spin_lock_init(&fs_info->ref_cache_lock); spin_lock_init(&fs_info->ref_cache_lock);
spin_lock_init(&fs_info->fs_roots_radix_lock);
init_completion(&fs_info->kobj_unregister); init_completion(&fs_info->kobj_unregister);
fs_info->tree_root = tree_root; fs_info->tree_root = tree_root;
...@@ -1585,11 +1630,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1585,11 +1630,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fs_info->sb = sb; fs_info->sb = sb;
fs_info->max_extent = (u64)-1; fs_info->max_extent = (u64)-1;
fs_info->max_inline = 8192 * 1024; fs_info->max_inline = 8192 * 1024;
if (setup_bdi(fs_info, &fs_info->bdi))
goto fail_bdi;
fs_info->btree_inode = new_inode(sb);
fs_info->btree_inode->i_ino = 1;
fs_info->btree_inode->i_nlink = 1;
fs_info->metadata_ratio = 8; fs_info->metadata_ratio = 8;
fs_info->thread_pool_size = min_t(unsigned long, fs_info->thread_pool_size = min_t(unsigned long,
...@@ -1602,6 +1642,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1602,6 +1642,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
sb->s_blocksize_bits = blksize_bits(4096); sb->s_blocksize_bits = blksize_bits(4096);
sb->s_bdi = &fs_info->bdi; sb->s_bdi = &fs_info->bdi;
fs_info->btree_inode->i_ino = BTRFS_BTREE_INODE_OBJECTID;
fs_info->btree_inode->i_nlink = 1;
/* /*
* we set the i_size on the btree inode to the max possible int. * we set the i_size on the btree inode to the max possible int.
* the real end of the address space is determined by all of * the real end of the address space is determined by all of
...@@ -1620,28 +1662,32 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1620,28 +1662,32 @@ struct btrfs_root *open_ctree(struct super_block *sb,
BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops; BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops;
BTRFS_I(fs_info->btree_inode)->root = tree_root;
memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
sizeof(struct btrfs_key));
BTRFS_I(fs_info->btree_inode)->dummy_inode = 1;
insert_inode_hash(fs_info->btree_inode);
spin_lock_init(&fs_info->block_group_cache_lock); spin_lock_init(&fs_info->block_group_cache_lock);
fs_info->block_group_cache_tree.rb_node = NULL; fs_info->block_group_cache_tree.rb_node = NULL;
extent_io_tree_init(&fs_info->pinned_extents, extent_io_tree_init(&fs_info->freed_extents[0],
fs_info->btree_inode->i_mapping, GFP_NOFS); fs_info->btree_inode->i_mapping, GFP_NOFS);
extent_io_tree_init(&fs_info->freed_extents[1],
fs_info->btree_inode->i_mapping, GFP_NOFS);
fs_info->pinned_extents = &fs_info->freed_extents[0];
fs_info->do_barriers = 1; fs_info->do_barriers = 1;
BTRFS_I(fs_info->btree_inode)->root = tree_root;
memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
sizeof(struct btrfs_key));
insert_inode_hash(fs_info->btree_inode);
mutex_init(&fs_info->trans_mutex); mutex_init(&fs_info->trans_mutex);
mutex_init(&fs_info->ordered_operations_mutex); mutex_init(&fs_info->ordered_operations_mutex);
mutex_init(&fs_info->tree_log_mutex); mutex_init(&fs_info->tree_log_mutex);
mutex_init(&fs_info->drop_mutex);
mutex_init(&fs_info->chunk_mutex); mutex_init(&fs_info->chunk_mutex);
mutex_init(&fs_info->transaction_kthread_mutex); mutex_init(&fs_info->transaction_kthread_mutex);
mutex_init(&fs_info->cleaner_mutex); mutex_init(&fs_info->cleaner_mutex);
mutex_init(&fs_info->volume_mutex); mutex_init(&fs_info->volume_mutex);
mutex_init(&fs_info->tree_reloc_mutex);
init_rwsem(&fs_info->extent_commit_sem); init_rwsem(&fs_info->extent_commit_sem);
init_rwsem(&fs_info->subvol_sem);
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster); btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
btrfs_init_free_cluster(&fs_info->data_alloc_cluster); btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
...@@ -1700,7 +1746,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1700,7 +1746,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
...@@ -1745,20 +1791,22 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1745,20 +1791,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,
...@@ -1918,6 +1966,9 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1918,6 +1966,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
} }
} }
ret = btrfs_find_orphan_roots(tree_root);
BUG_ON(ret);
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
ret = btrfs_recover_relocation(tree_root); ret = btrfs_recover_relocation(tree_root);
BUG_ON(ret); BUG_ON(ret);
...@@ -1977,6 +2028,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1977,6 +2028,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
btrfs_mapping_tree_free(&fs_info->mapping_tree); btrfs_mapping_tree_free(&fs_info->mapping_tree);
fail_bdi: fail_bdi:
bdi_destroy(&fs_info->bdi); bdi_destroy(&fs_info->bdi);
fail_srcu:
cleanup_srcu_struct(&fs_info->subvol_srcu);
fail: fail:
kfree(extent_root); kfree(extent_root);
kfree(tree_root); kfree(tree_root);
...@@ -2236,20 +2289,29 @@ int write_ctree_super(struct btrfs_trans_handle *trans, ...@@ -2236,20 +2289,29 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
{ {
WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); spin_lock(&fs_info->fs_roots_radix_lock);
radix_tree_delete(&fs_info->fs_roots_radix, radix_tree_delete(&fs_info->fs_roots_radix,
(unsigned long)root->root_key.objectid); (unsigned long)root->root_key.objectid);
spin_unlock(&fs_info->fs_roots_radix_lock);
if (btrfs_root_refs(&root->root_item) == 0)
synchronize_srcu(&fs_info->subvol_srcu);
free_fs_root(root);
return 0;
}
static void free_fs_root(struct btrfs_root *root)
{
WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree));
if (root->anon_super.s_dev) { if (root->anon_super.s_dev) {
down_write(&root->anon_super.s_umount); down_write(&root->anon_super.s_umount);
kill_anon_super(&root->anon_super); kill_anon_super(&root->anon_super);
} }
if (root->node) free_extent_buffer(root->node);
free_extent_buffer(root->node); free_extent_buffer(root->commit_root);
if (root->commit_root)
free_extent_buffer(root->commit_root);
kfree(root->name); kfree(root->name);
kfree(root); kfree(root);
return 0;
} }
static int del_fs_roots(struct btrfs_fs_info *fs_info) static int del_fs_roots(struct btrfs_fs_info *fs_info)
...@@ -2258,6 +2320,20 @@ static int del_fs_roots(struct btrfs_fs_info *fs_info) ...@@ -2258,6 +2320,20 @@ static int del_fs_roots(struct btrfs_fs_info *fs_info)
struct btrfs_root *gang[8]; struct btrfs_root *gang[8];
int i; int i;
while (!list_empty(&fs_info->dead_roots)) {
gang[0] = list_entry(fs_info->dead_roots.next,
struct btrfs_root, root_list);
list_del(&gang[0]->root_list);
if (gang[0]->in_radix) {
btrfs_free_fs_root(fs_info, gang[0]);
} else {
free_extent_buffer(gang[0]->node);
free_extent_buffer(gang[0]->commit_root);
kfree(gang[0]);
}
}
while (1) { while (1) {
ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
(void **)gang, 0, (void **)gang, 0,
...@@ -2287,9 +2363,6 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) ...@@ -2287,9 +2363,6 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
root_objectid = gang[ret - 1]->root_key.objectid + 1; root_objectid = gang[ret - 1]->root_key.objectid + 1;
for (i = 0; i < ret; i++) { for (i = 0; i < ret; i++) {
root_objectid = gang[i]->root_key.objectid; root_objectid = gang[i]->root_key.objectid;
ret = btrfs_find_dead_roots(fs_info->tree_root,
root_objectid);
BUG_ON(ret);
btrfs_orphan_cleanup(gang[i]); btrfs_orphan_cleanup(gang[i]);
} }
root_objectid++; root_objectid++;
...@@ -2359,7 +2432,6 @@ int close_ctree(struct btrfs_root *root) ...@@ -2359,7 +2432,6 @@ int close_ctree(struct btrfs_root *root)
free_extent_buffer(root->fs_info->csum_root->commit_root); free_extent_buffer(root->fs_info->csum_root->commit_root);
btrfs_free_block_groups(root->fs_info); btrfs_free_block_groups(root->fs_info);
btrfs_free_pinned_extents(root->fs_info);
del_fs_roots(fs_info); del_fs_roots(fs_info);
...@@ -2378,6 +2450,7 @@ int close_ctree(struct btrfs_root *root) ...@@ -2378,6 +2450,7 @@ int close_ctree(struct btrfs_root *root)
btrfs_mapping_tree_free(&fs_info->mapping_tree); btrfs_mapping_tree_free(&fs_info->mapping_tree);
bdi_destroy(&fs_info->bdi); bdi_destroy(&fs_info->bdi);
cleanup_srcu_struct(&fs_info->subvol_srcu);
kfree(fs_info->extent_root); kfree(fs_info->extent_root);
kfree(fs_info->tree_root); kfree(fs_info->tree_root);
......
...@@ -28,7 +28,7 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, ...@@ -28,7 +28,7 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
len = BTRFS_FID_SIZE_NON_CONNECTABLE; len = BTRFS_FID_SIZE_NON_CONNECTABLE;
type = FILEID_BTRFS_WITHOUT_PARENT; type = FILEID_BTRFS_WITHOUT_PARENT;
fid->objectid = BTRFS_I(inode)->location.objectid; fid->objectid = inode->i_ino;
fid->root_objectid = BTRFS_I(inode)->root->objectid; fid->root_objectid = BTRFS_I(inode)->root->objectid;
fid->gen = inode->i_generation; fid->gen = inode->i_generation;
...@@ -60,34 +60,61 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, ...@@ -60,34 +60,61 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
} }
static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
u64 root_objectid, u32 generation) u64 root_objectid, u32 generation,
int check_generation)
{ {
struct btrfs_fs_info *fs_info = btrfs_sb(sb)->fs_info;
struct btrfs_root *root; struct btrfs_root *root;
struct dentry *dentry;
struct inode *inode; struct inode *inode;
struct btrfs_key key; struct btrfs_key key;
int index;
int err = 0;
if (objectid < BTRFS_FIRST_FREE_OBJECTID)
return ERR_PTR(-ESTALE);
key.objectid = root_objectid; key.objectid = root_objectid;
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
key.offset = (u64)-1; key.offset = (u64)-1;
root = btrfs_read_fs_root_no_name(btrfs_sb(sb)->fs_info, &key); index = srcu_read_lock(&fs_info->subvol_srcu);
if (IS_ERR(root))
return ERR_CAST(root); root = btrfs_read_fs_root_no_name(fs_info, &key);
if (IS_ERR(root)) {
err = PTR_ERR(root);
goto fail;
}
if (btrfs_root_refs(&root->root_item) == 0) {
err = -ENOENT;
goto fail;
}
key.objectid = objectid; key.objectid = objectid;
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
key.offset = 0; key.offset = 0;
inode = btrfs_iget(sb, &key, root); inode = btrfs_iget(sb, &key, root);
if (IS_ERR(inode)) if (IS_ERR(inode)) {
return (void *)inode; err = PTR_ERR(inode);
goto fail;
}
srcu_read_unlock(&fs_info->subvol_srcu, index);
if (generation != inode->i_generation) { if (check_generation && generation != inode->i_generation) {
iput(inode); iput(inode);
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
} }
return d_obtain_alias(inode); dentry = d_obtain_alias(inode);
if (!IS_ERR(dentry))
dentry->d_op = &btrfs_dentry_operations;
return dentry;
fail:
srcu_read_unlock(&fs_info->subvol_srcu, index);
return ERR_PTR(err);
} }
static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh, static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
...@@ -111,7 +138,7 @@ static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh, ...@@ -111,7 +138,7 @@ static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
objectid = fid->parent_objectid; objectid = fid->parent_objectid;
generation = fid->parent_gen; generation = fid->parent_gen;
return btrfs_get_dentry(sb, objectid, root_objectid, generation); return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
} }
static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
...@@ -133,66 +160,76 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, ...@@ -133,66 +160,76 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
root_objectid = fid->root_objectid; root_objectid = fid->root_objectid;
generation = fid->gen; generation = fid->gen;
return btrfs_get_dentry(sb, objectid, root_objectid, generation); return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1);
} }
static struct dentry *btrfs_get_parent(struct dentry *child) static struct dentry *btrfs_get_parent(struct dentry *child)
{ {
struct inode *dir = child->d_inode; struct inode *dir = child->d_inode;
static struct dentry *dentry;
struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_root *root = BTRFS_I(dir)->root;
struct btrfs_key key;
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *leaf; struct extent_buffer *leaf;
int slot; struct btrfs_root_ref *ref;
u64 objectid; struct btrfs_key key;
struct btrfs_key found_key;
int ret; int ret;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
key.objectid = dir->i_ino; if (dir->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); key.objectid = root->root_key.objectid;
key.offset = (u64)-1; key.type = BTRFS_ROOT_BACKREF_KEY;
key.offset = (u64)-1;
root = root->fs_info->tree_root;
} else {
key.objectid = dir->i_ino;
key.type = BTRFS_INODE_REF_KEY;
key.offset = (u64)-1;
}
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0) { if (ret < 0)
/* Error */ goto fail;
btrfs_free_path(path);
return ERR_PTR(ret); BUG_ON(ret == 0);
if (path->slots[0] == 0) {
ret = -ENOENT;
goto fail;
} }
path->slots[0]--;
leaf = path->nodes[0]; leaf = path->nodes[0];
slot = path->slots[0];
if (ret) { btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
/* btrfs_search_slot() returns the slot where we'd want to if (found_key.objectid != key.objectid || found_key.type != key.type) {
insert a backref for parent inode #0xFFFFFFFFFFFFFFFF. ret = -ENOENT;
The _real_ backref, telling us what the parent inode goto fail;
_actually_ is, will be in the slot _before_ the one
that btrfs_search_slot() returns. */
if (!slot) {
/* Unless there is _no_ key in the tree before... */
btrfs_free_path(path);
return ERR_PTR(-EIO);
}
slot--;
} }
btrfs_item_key_to_cpu(leaf, &key, slot); if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
ref = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_root_ref);
key.objectid = btrfs_root_ref_dirid(leaf, ref);
} else {
key.objectid = found_key.offset;
}
btrfs_free_path(path); btrfs_free_path(path);
if (key.objectid != dir->i_ino || key.type != BTRFS_INODE_REF_KEY) if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
return ERR_PTR(-EINVAL); return btrfs_get_dentry(root->fs_info->sb, key.objectid,
found_key.offset, 0, 0);
objectid = key.offset; }
/* If we are already at the root of a subvol, return the real root */
if (objectid == dir->i_ino)
return dget(dir->i_sb->s_root);
/* Build a new key for the inode item */ key.type = BTRFS_INODE_ITEM_KEY;
key.objectid = objectid;
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
key.offset = 0; key.offset = 0;
dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root));
return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root)); if (!IS_ERR(dentry))
dentry->d_op = &btrfs_dentry_operations;
return dentry;
fail:
btrfs_free_path(path);
return ERR_PTR(ret);
} }
const struct export_operations btrfs_export_ops = { const struct export_operations btrfs_export_ops = {
......
此差异已折叠。
此差异已折叠。
...@@ -13,10 +13,8 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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);
...@@ -318,6 +366,54 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, ...@@ -318,6 +366,54 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
return em; return em;
} }
/**
* search_extent_mapping - find a nearby extent map
* @tree: tree to lookup in
* @start: byte offset to start the search
* @len: length of the lookup range
*
* Find and return the first extent_map struct in @tree that intersects the
* [start, len] range.
*
* If one can't be found, any nearby extent may be returned
*/
struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
u64 start, u64 len)
{
struct extent_map *em;
struct rb_node *rb_node;
struct rb_node *prev = NULL;
struct rb_node *next = NULL;
rb_node = __tree_search(&tree->map, start, &prev, &next);
if (!rb_node && prev) {
em = rb_entry(prev, struct extent_map, rb_node);
goto found;
}
if (!rb_node && next) {
em = rb_entry(next, struct extent_map, rb_node);
goto found;
}
if (!rb_node) {
em = NULL;
goto out;
}
if (IS_ERR(rb_node)) {
em = ERR_PTR(PTR_ERR(rb_node));
goto out;
}
em = rb_entry(rb_node, struct extent_map, rb_node);
goto found;
em = NULL;
goto out;
found:
atomic_inc(&em->refs);
out:
return em;
}
/** /**
* remove_extent_mapping - removes an extent_map from the extent tree * remove_extent_mapping - removes an extent_map from the extent tree
* @tree: extent tree to remove from * @tree: extent tree to remove from
...@@ -331,7 +427,6 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) ...@@ -331,7 +427,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 { ...@@ -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,7 @@ struct extent_map *alloc_extent_map(gfp_t mask); ...@@ -59,4 +59,7 @@ 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);
struct extent_map *search_extent_mapping(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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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)
......
...@@ -259,7 +259,9 @@ static int link_free_space(struct btrfs_block_group_cache *block_group, ...@@ -259,7 +259,9 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
static void recalculate_thresholds(struct btrfs_block_group_cache *block_group) static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
{ {
u64 max_bytes, possible_bytes; u64 max_bytes;
u64 bitmap_bytes;
u64 extent_bytes;
/* /*
* The goal is to keep the total amount of memory used per 1gb of space * The goal is to keep the total amount of memory used per 1gb of space
...@@ -269,22 +271,27 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group) ...@@ -269,22 +271,27 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
max_bytes = MAX_CACHE_BYTES_PER_GIG * max_bytes = MAX_CACHE_BYTES_PER_GIG *
(div64_u64(block_group->key.offset, 1024 * 1024 * 1024)); (div64_u64(block_group->key.offset, 1024 * 1024 * 1024));
possible_bytes = (block_group->total_bitmaps * PAGE_CACHE_SIZE) + /*
(sizeof(struct btrfs_free_space) * * we want to account for 1 more bitmap than what we have so we can make
block_group->extents_thresh); * sure we don't go over our overall goal of MAX_CACHE_BYTES_PER_GIG as
* we add more bitmaps.
*/
bitmap_bytes = (block_group->total_bitmaps + 1) * PAGE_CACHE_SIZE;
if (possible_bytes > max_bytes) { if (bitmap_bytes >= max_bytes) {
int extent_bytes = max_bytes - block_group->extents_thresh = 0;
(block_group->total_bitmaps * PAGE_CACHE_SIZE); return;
}
if (extent_bytes <= 0) { /*
block_group->extents_thresh = 0; * we want the extent entry threshold to always be at most 1/2 the maxw
return; * bytes we can have, or whatever is less than that.
} */
extent_bytes = max_bytes - bitmap_bytes;
extent_bytes = min_t(u64, extent_bytes, div64_u64(max_bytes, 2));
block_group->extents_thresh = extent_bytes / block_group->extents_thresh =
(sizeof(struct btrfs_free_space)); div64_u64(extent_bytes, (sizeof(struct btrfs_free_space)));
}
} }
static void bitmap_clear_bits(struct btrfs_block_group_cache *block_group, static void bitmap_clear_bits(struct btrfs_block_group_cache *block_group,
...@@ -403,6 +410,7 @@ static void add_new_bitmap(struct btrfs_block_group_cache *block_group, ...@@ -403,6 +410,7 @@ static void add_new_bitmap(struct btrfs_block_group_cache *block_group,
BUG_ON(block_group->total_bitmaps >= max_bitmaps); BUG_ON(block_group->total_bitmaps >= max_bitmaps);
info->offset = offset_to_bitmap(block_group, offset); info->offset = offset_to_bitmap(block_group, offset);
info->bytes = 0;
link_free_space(block_group, info); link_free_space(block_group, info);
block_group->total_bitmaps++; block_group->total_bitmaps++;
......
...@@ -149,6 +149,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, ...@@ -149,6 +149,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
ptr = (unsigned long)(ref + 1); ptr = (unsigned long)(ref + 1);
ret = 0; ret = 0;
} else if (ret < 0) { } else if (ret < 0) {
if (ret == -EOVERFLOW)
ret = -EMLINK;
goto out; goto out;
} else { } else {
ref = btrfs_item_ptr(path->nodes[0], path->slots[0], ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
...@@ -177,8 +179,6 @@ int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, ...@@ -177,8 +179,6 @@ int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
ret = btrfs_insert_empty_item(trans, root, path, &key, ret = btrfs_insert_empty_item(trans, root, path, &key,
sizeof(struct btrfs_inode_item)); sizeof(struct btrfs_inode_item));
if (ret == 0 && objectid > root->highest_inode)
root->highest_inode = objectid;
return ret; return ret;
} }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -65,5 +65,6 @@ struct btrfs_ioctl_clone_range_args { ...@@ -65,5 +65,6 @@ struct btrfs_ioctl_clone_range_args {
#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \ #define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
struct btrfs_ioctl_vol_args) struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
struct btrfs_ioctl_vol_args)
#endif #endif
此差异已折叠。
...@@ -85,6 +85,9 @@ struct btrfs_ordered_extent { ...@@ -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;
......
...@@ -65,3 +65,23 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, ...@@ -65,3 +65,23 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
} }
int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset)
{
struct btrfs_path *path;
struct btrfs_key key;
int ret;
key.objectid = BTRFS_ORPHAN_OBJECTID;
key.type = BTRFS_ORPHAN_ITEM_KEY;
key.offset = offset;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
btrfs_free_path(path);
return ret;
}
此差异已折叠。
此差异已折叠。
...@@ -676,6 +676,7 @@ static int btrfs_unfreeze(struct super_block *sb) ...@@ -676,6 +676,7 @@ static int btrfs_unfreeze(struct super_block *sb)
} }
static const struct super_operations btrfs_super_ops = { static const struct super_operations btrfs_super_ops = {
.drop_inode = btrfs_drop_inode,
.delete_inode = btrfs_delete_inode, .delete_inode = btrfs_delete_inode,
.put_super = btrfs_put_super, .put_super = btrfs_put_super,
.sync_fs = btrfs_sync_fs, .sync_fs = btrfs_sync_fs,
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -181,4 +181,7 @@ int btrfs_balance(struct btrfs_root *dev_root); ...@@ -181,4 +181,7 @@ int btrfs_balance(struct btrfs_root *dev_root);
void btrfs_unlock_volumes(void); void btrfs_unlock_volumes(void);
void btrfs_lock_volumes(void); void btrfs_lock_volumes(void);
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
int find_free_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 num_bytes,
u64 *start, u64 *max_avail);
#endif #endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册