Commit d25223a0 authored by Li Zefan's avatar Li Zefan

Merge branch 'for-linus' of...

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs into for-linus
parents 396e6e49 08c422c2
...@@ -63,8 +63,8 @@ IRC network. ...@@ -63,8 +63,8 @@ IRC network.
Userspace tools for creating and manipulating Btrfs file systems are Userspace tools for creating and manipulating Btrfs file systems are
available from the git repository at the following location: available from the git repository at the following location:
http://git.kernel.org/?p=linux/kernel/git/mason/btrfs-progs-unstable.git http://git.kernel.org/?p=linux/kernel/git/mason/btrfs-progs.git
git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-progs-unstable.git git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-progs.git
These include the following tools: These include the following tools:
......
...@@ -7,6 +7,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ ...@@ -7,6 +7,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
export.o tree-log.o free-space-cache.o zlib.o lzo.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o \
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
reada.o backref.o
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
...@@ -59,22 +59,19 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) ...@@ -59,22 +59,19 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
if (!value) if (!value)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
size = __btrfs_getxattr(inode, name, value, size); size = __btrfs_getxattr(inode, name, value, size);
if (size > 0) { }
acl = posix_acl_from_xattr(value, size); if (size > 0) {
if (IS_ERR(acl)) { acl = posix_acl_from_xattr(value, size);
kfree(value);
return acl;
}
set_cached_acl(inode, type, acl);
}
kfree(value);
} else if (size == -ENOENT || size == -ENODATA || size == 0) { } else if (size == -ENOENT || size == -ENODATA || size == 0) {
/* FIXME, who returns -ENOENT? I think nobody */ /* FIXME, who returns -ENOENT? I think nobody */
acl = NULL; acl = NULL;
set_cached_acl(inode, type, acl);
} else { } else {
acl = ERR_PTR(-EIO); acl = ERR_PTR(-EIO);
} }
kfree(value);
if (!IS_ERR(acl))
set_cached_acl(inode, type, acl);
return acl; return acl;
} }
......
...@@ -64,6 +64,8 @@ struct btrfs_worker_thread { ...@@ -64,6 +64,8 @@ struct btrfs_worker_thread {
int idle; int idle;
}; };
static int __btrfs_start_workers(struct btrfs_workers *workers);
/* /*
* btrfs_start_workers uses kthread_run, which can block waiting for memory * btrfs_start_workers uses kthread_run, which can block waiting for memory
* for a very long time. It will actually throttle on page writeback, * for a very long time. It will actually throttle on page writeback,
...@@ -88,27 +90,10 @@ static void start_new_worker_func(struct btrfs_work *work) ...@@ -88,27 +90,10 @@ static void start_new_worker_func(struct btrfs_work *work)
{ {
struct worker_start *start; struct worker_start *start;
start = container_of(work, struct worker_start, work); start = container_of(work, struct worker_start, work);
btrfs_start_workers(start->queue, 1); __btrfs_start_workers(start->queue);
kfree(start); kfree(start);
} }
static int start_new_worker(struct btrfs_workers *queue)
{
struct worker_start *start;
int ret;
start = kzalloc(sizeof(*start), GFP_NOFS);
if (!start)
return -ENOMEM;
start->work.func = start_new_worker_func;
start->queue = queue;
ret = btrfs_queue_worker(queue->atomic_worker_start, &start->work);
if (ret)
kfree(start);
return ret;
}
/* /*
* helper function to move a thread onto the idle list after it * helper function to move a thread onto the idle list after it
* has finished some requests. * has finished some requests.
...@@ -153,12 +138,20 @@ static void check_busy_worker(struct btrfs_worker_thread *worker) ...@@ -153,12 +138,20 @@ static void check_busy_worker(struct btrfs_worker_thread *worker)
static void check_pending_worker_creates(struct btrfs_worker_thread *worker) static void check_pending_worker_creates(struct btrfs_worker_thread *worker)
{ {
struct btrfs_workers *workers = worker->workers; struct btrfs_workers *workers = worker->workers;
struct worker_start *start;
unsigned long flags; unsigned long flags;
rmb(); rmb();
if (!workers->atomic_start_pending) if (!workers->atomic_start_pending)
return; return;
start = kzalloc(sizeof(*start), GFP_NOFS);
if (!start)
return;
start->work.func = start_new_worker_func;
start->queue = workers;
spin_lock_irqsave(&workers->lock, flags); spin_lock_irqsave(&workers->lock, flags);
if (!workers->atomic_start_pending) if (!workers->atomic_start_pending)
goto out; goto out;
...@@ -170,10 +163,11 @@ static void check_pending_worker_creates(struct btrfs_worker_thread *worker) ...@@ -170,10 +163,11 @@ static void check_pending_worker_creates(struct btrfs_worker_thread *worker)
workers->num_workers_starting += 1; workers->num_workers_starting += 1;
spin_unlock_irqrestore(&workers->lock, flags); spin_unlock_irqrestore(&workers->lock, flags);
start_new_worker(workers); btrfs_queue_worker(workers->atomic_worker_start, &start->work);
return; return;
out: out:
kfree(start);
spin_unlock_irqrestore(&workers->lock, flags); spin_unlock_irqrestore(&workers->lock, flags);
} }
...@@ -331,7 +325,7 @@ static int worker_loop(void *arg) ...@@ -331,7 +325,7 @@ static int worker_loop(void *arg)
run_ordered_completions(worker->workers, work); run_ordered_completions(worker->workers, work);
check_pending_worker_creates(worker); check_pending_worker_creates(worker);
cond_resched();
} }
spin_lock_irq(&worker->lock); spin_lock_irq(&worker->lock);
...@@ -462,56 +456,55 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max, ...@@ -462,56 +456,55 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
* starts new worker threads. This does not enforce the max worker * starts new worker threads. This does not enforce the max worker
* count in case you need to temporarily go past it. * count in case you need to temporarily go past it.
*/ */
static int __btrfs_start_workers(struct btrfs_workers *workers, static int __btrfs_start_workers(struct btrfs_workers *workers)
int num_workers)
{ {
struct btrfs_worker_thread *worker; struct btrfs_worker_thread *worker;
int ret = 0; int ret = 0;
int i;
for (i = 0; i < num_workers; i++) { worker = kzalloc(sizeof(*worker), GFP_NOFS);
worker = kzalloc(sizeof(*worker), GFP_NOFS); if (!worker) {
if (!worker) { ret = -ENOMEM;
ret = -ENOMEM; goto fail;
goto fail; }
}
INIT_LIST_HEAD(&worker->pending); INIT_LIST_HEAD(&worker->pending);
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); 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,
workers->num_workers + i); workers->num_workers + 1);
if (IS_ERR(worker->task)) { if (IS_ERR(worker->task)) {
ret = PTR_ERR(worker->task); ret = PTR_ERR(worker->task);
kfree(worker); kfree(worker);
goto fail; goto fail;
}
spin_lock_irq(&workers->lock);
list_add_tail(&worker->worker_list, &workers->idle_list);
worker->idle = 1;
workers->num_workers++;
workers->num_workers_starting--;
WARN_ON(workers->num_workers_starting < 0);
spin_unlock_irq(&workers->lock);
} }
spin_lock_irq(&workers->lock);
list_add_tail(&worker->worker_list, &workers->idle_list);
worker->idle = 1;
workers->num_workers++;
workers->num_workers_starting--;
WARN_ON(workers->num_workers_starting < 0);
spin_unlock_irq(&workers->lock);
return 0; return 0;
fail: fail:
btrfs_stop_workers(workers); spin_lock_irq(&workers->lock);
workers->num_workers_starting--;
spin_unlock_irq(&workers->lock);
return ret; return ret;
} }
int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) int btrfs_start_workers(struct btrfs_workers *workers)
{ {
spin_lock_irq(&workers->lock); spin_lock_irq(&workers->lock);
workers->num_workers_starting += num_workers; workers->num_workers_starting++;
spin_unlock_irq(&workers->lock); spin_unlock_irq(&workers->lock);
return __btrfs_start_workers(workers, num_workers); return __btrfs_start_workers(workers);
} }
/* /*
...@@ -568,9 +561,10 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) ...@@ -568,9 +561,10 @@ 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; struct list_head *fallback;
int ret;
again:
spin_lock_irqsave(&workers->lock, flags); spin_lock_irqsave(&workers->lock, flags);
again:
worker = next_worker(workers); worker = next_worker(workers);
if (!worker) { if (!worker) {
...@@ -584,7 +578,10 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) ...@@ -584,7 +578,10 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers)
workers->num_workers_starting++; workers->num_workers_starting++;
spin_unlock_irqrestore(&workers->lock, flags); spin_unlock_irqrestore(&workers->lock, flags);
/* we're below the limit, start another worker */ /* we're below the limit, start another worker */
__btrfs_start_workers(workers, 1); ret = __btrfs_start_workers(workers);
spin_lock_irqsave(&workers->lock, flags);
if (ret)
goto fallback;
goto again; goto again;
} }
} }
...@@ -665,7 +662,7 @@ void btrfs_set_work_high_prio(struct btrfs_work *work) ...@@ -665,7 +662,7 @@ void btrfs_set_work_high_prio(struct btrfs_work *work)
/* /*
* places a struct btrfs_work into the pending queue of one of the kthreads * places a struct btrfs_work into the pending queue of one of the kthreads
*/ */
int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
{ {
struct btrfs_worker_thread *worker; struct btrfs_worker_thread *worker;
unsigned long flags; unsigned long flags;
...@@ -673,7 +670,7 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) ...@@ -673,7 +670,7 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
/* don't requeue something already on a list */ /* don't requeue something already on a list */
if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags)) if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags))
goto out; return;
worker = find_worker(workers); worker = find_worker(workers);
if (workers->ordered) { if (workers->ordered) {
...@@ -712,7 +709,4 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) ...@@ -712,7 +709,4 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
if (wake) if (wake)
wake_up_process(worker->task); wake_up_process(worker->task);
spin_unlock_irqrestore(&worker->lock, flags); spin_unlock_irqrestore(&worker->lock, flags);
out:
return 0;
} }
...@@ -109,8 +109,8 @@ struct btrfs_workers { ...@@ -109,8 +109,8 @@ struct btrfs_workers {
char *name; char *name;
}; };
int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work); void btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work);
int btrfs_start_workers(struct btrfs_workers *workers, int num_workers); int btrfs_start_workers(struct btrfs_workers *workers);
int btrfs_stop_workers(struct btrfs_workers *workers); int btrfs_stop_workers(struct btrfs_workers *workers);
void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max, void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
struct btrfs_workers *async_starter); struct btrfs_workers *async_starter);
......
This diff is collapsed.
/*
* Copyright (C) 2011 STRATO. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#ifndef __BTRFS_BACKREF__
#define __BTRFS_BACKREF__
#include "ioctl.h"
struct inode_fs_paths {
struct btrfs_path *btrfs_path;
struct btrfs_root *fs_root;
struct btrfs_data_container *fspath;
};
typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root,
void *ctx);
typedef int (iterate_irefs_t)(u64 parent, struct btrfs_inode_ref *iref,
struct extent_buffer *eb, void *ctx);
int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
struct btrfs_path *path);
int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
struct btrfs_path *path, struct btrfs_key *found_key);
int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
struct btrfs_extent_item *ei, u32 item_size,
u64 *out_root, u8 *out_level);
int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
struct btrfs_path *path,
u64 extent_item_objectid,
u64 extent_offset,
iterate_extent_inodes_t *iterate, void *ctx);
int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
struct btrfs_path *path,
iterate_extent_inodes_t *iterate, void *ctx);
int paths_from_inode(u64 inum, struct inode_fs_paths *ipath);
struct btrfs_data_container *init_data_container(u32 total_bytes);
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
struct btrfs_path *path);
void free_ipath(struct inode_fs_paths *ipath);
#endif
...@@ -103,11 +103,6 @@ struct btrfs_inode { ...@@ -103,11 +103,6 @@ struct btrfs_inode {
*/ */
u64 delalloc_bytes; u64 delalloc_bytes;
/* total number of bytes that may be used for this inode for
* delalloc
*/
u64 reserved_bytes;
/* /*
* the size of the file stored in the metadata on disk. data=ordered * the size of the file stored in the metadata on disk. data=ordered
* means the in-memory i_size might be larger than the size on disk * means the in-memory i_size might be larger than the size on disk
...@@ -115,9 +110,6 @@ struct btrfs_inode { ...@@ -115,9 +110,6 @@ struct btrfs_inode {
*/ */
u64 disk_i_size; u64 disk_i_size;
/* flags field from the on disk inode */
u32 flags;
/* /*
* if this is a directory then index_cnt is the counter for the index * if this is a directory then index_cnt is the counter for the index
* number for new files that are created * number for new files that are created
...@@ -131,6 +123,15 @@ struct btrfs_inode { ...@@ -131,6 +123,15 @@ struct btrfs_inode {
*/ */
u64 last_unlink_trans; u64 last_unlink_trans;
/*
* Number of bytes outstanding that are going to need csums. This is
* used in ENOSPC accounting.
*/
u64 csum_bytes;
/* flags field from the on disk inode */
u32 flags;
/* /*
* Counters to keep track of the number of extent item's we may use due * Counters to keep track of the number of extent item's we may use due
* to delalloc and such. outstanding_extents is the number of extent * to delalloc and such. outstanding_extents is the number of extent
...@@ -146,14 +147,12 @@ struct btrfs_inode { ...@@ -146,14 +147,12 @@ struct btrfs_inode {
* the btrfs file release call will add this inode to the * the btrfs file release call will add this inode to the
* ordered operations list so that we make sure to flush out any * ordered operations list so that we make sure to flush out any
* new data the application may have written before commit. * new data the application may have written before commit.
*
* yes, its silly to have a single bitflag, but we might grow more
* of these.
*/ */
unsigned ordered_data_close:1; unsigned ordered_data_close:1;
unsigned orphan_meta_reserved:1; unsigned orphan_meta_reserved:1;
unsigned dummy_inode:1; unsigned dummy_inode:1;
unsigned in_defrag:1; unsigned in_defrag:1;
unsigned delalloc_meta_reserved:1;
/* /*
* always compress this one file * always compress this one file
......
...@@ -85,7 +85,8 @@ struct compressed_bio { ...@@ -85,7 +85,8 @@ struct compressed_bio {
static inline int compressed_bio_size(struct btrfs_root *root, static inline int compressed_bio_size(struct btrfs_root *root,
unsigned long disk_size) unsigned long disk_size)
{ {
u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
return sizeof(struct compressed_bio) + return sizeof(struct compressed_bio) +
((disk_size + root->sectorsize - 1) / root->sectorsize) * ((disk_size + root->sectorsize - 1) / root->sectorsize) *
csum_size; csum_size;
......
...@@ -514,10 +514,25 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans, ...@@ -514,10 +514,25 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_buffer *buf) struct extent_buffer *buf)
{ {
/* ensure we can see the force_cow */
smp_rmb();
/*
* We do not need to cow a block if
* 1) this block is not created or changed in this transaction;
* 2) this block does not belong to TREE_RELOC tree;
* 3) the root is not forced COW.
*
* What is forced COW:
* when we create snapshot during commiting the transaction,
* after we've finished coping src root, we must COW the shared
* block to ensure the metadata consistency.
*/
if (btrfs_header_generation(buf) == trans->transid && if (btrfs_header_generation(buf) == trans->transid &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) && !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&
!(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID &&
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) &&
!root->force_cow)
return 0; return 0;
return 1; return 1;
} }
...@@ -902,9 +917,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -902,9 +917,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
orig_ptr = btrfs_node_blockptr(mid, orig_slot); orig_ptr = btrfs_node_blockptr(mid, orig_slot);
if (level < BTRFS_MAX_LEVEL - 1) if (level < BTRFS_MAX_LEVEL - 1) {
parent = path->nodes[level + 1]; parent = path->nodes[level + 1];
pslot = path->slots[level + 1]; pslot = path->slots[level + 1];
}
/* /*
* deal with the case where there is only one pointer in the root * deal with the case where there is only one pointer in the root
...@@ -1107,9 +1123,10 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -1107,9 +1123,10 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
mid = path->nodes[level]; mid = path->nodes[level];
WARN_ON(btrfs_header_generation(mid) != trans->transid); WARN_ON(btrfs_header_generation(mid) != trans->transid);
if (level < BTRFS_MAX_LEVEL - 1) if (level < BTRFS_MAX_LEVEL - 1) {
parent = path->nodes[level + 1]; parent = path->nodes[level + 1];
pslot = path->slots[level + 1]; pslot = path->slots[level + 1];
}
if (!parent) if (!parent)
return 1; return 1;
......
This diff is collapsed.
...@@ -591,7 +591,7 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans, ...@@ -591,7 +591,7 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
return 0; return 0;
src_rsv = trans->block_rsv; src_rsv = trans->block_rsv;
dst_rsv = &root->fs_info->global_block_rsv; dst_rsv = &root->fs_info->delayed_block_rsv;
num_bytes = btrfs_calc_trans_metadata_size(root, 1); num_bytes = btrfs_calc_trans_metadata_size(root, 1);
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes); ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
...@@ -609,7 +609,7 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root, ...@@ -609,7 +609,7 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
if (!item->bytes_reserved) if (!item->bytes_reserved)
return; return;
rsv = &root->fs_info->global_block_rsv; rsv = &root->fs_info->delayed_block_rsv;
btrfs_block_rsv_release(root, rsv, btrfs_block_rsv_release(root, rsv,
item->bytes_reserved); item->bytes_reserved);
} }
...@@ -617,24 +617,102 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root, ...@@ -617,24 +617,102 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
static int btrfs_delayed_inode_reserve_metadata( static int btrfs_delayed_inode_reserve_metadata(
struct btrfs_trans_handle *trans, struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct inode *inode,
struct btrfs_delayed_node *node) struct btrfs_delayed_node *node)
{ {
struct btrfs_block_rsv *src_rsv; struct btrfs_block_rsv *src_rsv;
struct btrfs_block_rsv *dst_rsv; struct btrfs_block_rsv *dst_rsv;
u64 num_bytes; u64 num_bytes;
int ret; int ret;
int release = false;
if (!trans->bytes_reserved)
return 0;
src_rsv = trans->block_rsv; src_rsv = trans->block_rsv;
dst_rsv = &root->fs_info->global_block_rsv; dst_rsv = &root->fs_info->delayed_block_rsv;
num_bytes = btrfs_calc_trans_metadata_size(root, 1); num_bytes = btrfs_calc_trans_metadata_size(root, 1);
/*
* btrfs_dirty_inode will update the inode under btrfs_join_transaction
* which doesn't reserve space for speed. This is a problem since we
* still need to reserve space for this update, so try to reserve the
* space.
*
* Now if src_rsv == delalloc_block_rsv we'll let it just steal since
* we're accounted for.
*/
if (!src_rsv || (!trans->bytes_reserved &&
src_rsv != &root->fs_info->delalloc_block_rsv)) {
ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
/*
* Since we're under a transaction reserve_metadata_bytes could
* try to commit the transaction which will make it return
* EAGAIN to make us stop the transaction we have, so return
* ENOSPC instead so that btrfs_dirty_inode knows what to do.
*/
if (ret == -EAGAIN)
ret = -ENOSPC;
if (!ret)
node->bytes_reserved = num_bytes;
return ret;
} else if (src_rsv == &root->fs_info->delalloc_block_rsv) {
spin_lock(&BTRFS_I(inode)->lock);
if (BTRFS_I(inode)->delalloc_meta_reserved) {
BTRFS_I(inode)->delalloc_meta_reserved = 0;
spin_unlock(&BTRFS_I(inode)->lock);
release = true;
goto migrate;
}
spin_unlock(&BTRFS_I(inode)->lock);
/* Ok we didn't have space pre-reserved. This shouldn't happen
* too often but it can happen if we do delalloc to an existing
* inode which gets dirtied because of the time update, and then
* isn't touched again until after the transaction commits and
* then we try to write out the data. First try to be nice and
* reserve something strictly for us. If not be a pain and try
* to steal from the delalloc block rsv.
*/
ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
if (!ret)
goto out;
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
if (!ret)
goto out;
/*
* Ok this is a problem, let's just steal from the global rsv
* since this really shouldn't happen that often.
*/
WARN_ON(1);
ret = btrfs_block_rsv_migrate(&root->fs_info->global_block_rsv,
dst_rsv, num_bytes);
goto out;
}
migrate:
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes); ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
out:
/*
* Migrate only takes a reservation, it doesn't touch the size of the
* block_rsv. This is to simplify people who don't normally have things
* migrated from their block rsv. If they go to release their
* reservation, that will decrease the size as well, so if migrate
* reduced size we'd end up with a negative size. But for the
* delalloc_meta_reserved stuff we will only know to drop 1 reservation,
* but we could in fact do this reserve/migrate dance several times
* between the time we did the original reservation and we'd clean it
* up. So to take care of this, release the space for the meta
* reservation here. I think it may be time for a documentation page on
* how block rsvs. work.
*/
if (!ret) if (!ret)
node->bytes_reserved = num_bytes; node->bytes_reserved = num_bytes;
if (release)
btrfs_block_rsv_release(root, src_rsv, num_bytes);
return ret; return ret;
} }
...@@ -646,7 +724,7 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root, ...@@ -646,7 +724,7 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root,
if (!node->bytes_reserved) if (!node->bytes_reserved)
return; return;
rsv = &root->fs_info->global_block_rsv; rsv = &root->fs_info->delayed_block_rsv;
btrfs_block_rsv_release(root, rsv, btrfs_block_rsv_release(root, rsv,
node->bytes_reserved); node->bytes_reserved);
node->bytes_reserved = 0; node->bytes_reserved = 0;
...@@ -1026,7 +1104,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, ...@@ -1026,7 +1104,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
path->leave_spinning = 1; path->leave_spinning = 1;
block_rsv = trans->block_rsv; block_rsv = trans->block_rsv;
trans->block_rsv = &root->fs_info->global_block_rsv; trans->block_rsv = &root->fs_info->delayed_block_rsv;
delayed_root = btrfs_get_delayed_root(root); delayed_root = btrfs_get_delayed_root(root);
...@@ -1069,7 +1147,7 @@ static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, ...@@ -1069,7 +1147,7 @@ static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
path->leave_spinning = 1; path->leave_spinning = 1;
block_rsv = trans->block_rsv; block_rsv = trans->block_rsv;
trans->block_rsv = &node->root->fs_info->global_block_rsv; trans->block_rsv = &node->root->fs_info->delayed_block_rsv;
ret = btrfs_insert_delayed_items(trans, path, node->root, node); ret = btrfs_insert_delayed_items(trans, path, node->root, node);
if (!ret) if (!ret)
...@@ -1149,7 +1227,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work) ...@@ -1149,7 +1227,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
goto free_path; goto free_path;
block_rsv = trans->block_rsv; block_rsv = trans->block_rsv;
trans->block_rsv = &root->fs_info->global_block_rsv; trans->block_rsv = &root->fs_info->delayed_block_rsv;
ret = btrfs_insert_delayed_items(trans, path, root, delayed_node); ret = btrfs_insert_delayed_items(trans, path, root, delayed_node);
if (!ret) if (!ret)
...@@ -1685,12 +1763,10 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, ...@@ -1685,12 +1763,10 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
goto release_node; goto release_node;
} }
ret = btrfs_delayed_inode_reserve_metadata(trans, root, delayed_node); ret = btrfs_delayed_inode_reserve_metadata(trans, root, inode,
/* delayed_node);
* we must reserve enough space when we start a new transaction, if (ret)
* so reserving metadata failure is impossible goto release_node;
*/
BUG_ON(ret);
fill_stack_inode_item(trans, &delayed_node->inode_item, inode); fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
delayed_node->inode_dirty = 1; delayed_node->inode_dirty = 1;
......
This diff is collapsed.
...@@ -40,6 +40,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, ...@@ -40,6 +40,8 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize, u64 parent_transid); u32 blocksize, u64 parent_transid);
int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
u64 parent_transid); u64 parent_transid);
int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, u32 blocksize,
int mirror_num, struct extent_buffer **eb);
struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
u64 bytenr, u32 blocksize); u64 bytenr, u32 blocksize);
int clean_tree_block(struct btrfs_trans_handle *trans, int clean_tree_block(struct btrfs_trans_handle *trans,
...@@ -83,8 +85,6 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, ...@@ -83,8 +85,6 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info); struct btrfs_fs_info *fs_info);
int btrfs_add_log_tree(struct btrfs_trans_handle *trans, int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
int btree_lock_page_hook(struct page *page);
#ifdef CONFIG_DEBUG_LOCK_ALLOC #ifdef CONFIG_DEBUG_LOCK_ALLOC
void btrfs_init_lockdep(void); void btrfs_init_lockdep(void);
......
This diff is collapsed.
This diff is collapsed.
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#define EXTENT_NODATASUM (1 << 10) #define EXTENT_NODATASUM (1 << 10)
#define EXTENT_DO_ACCOUNTING (1 << 11) #define EXTENT_DO_ACCOUNTING (1 << 11)
#define EXTENT_FIRST_DELALLOC (1 << 12) #define EXTENT_FIRST_DELALLOC (1 << 12)
#define EXTENT_NEED_WAIT (1 << 13)
#define EXTENT_DAMAGED (1 << 14)
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
#define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC) #define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC)
...@@ -32,6 +34,7 @@ ...@@ -32,6 +34,7 @@
#define EXTENT_BUFFER_BLOCKING 1 #define EXTENT_BUFFER_BLOCKING 1
#define EXTENT_BUFFER_DIRTY 2 #define EXTENT_BUFFER_DIRTY 2
#define EXTENT_BUFFER_CORRUPT 3 #define EXTENT_BUFFER_CORRUPT 3
#define EXTENT_BUFFER_READAHEAD 4 /* this got triggered by readahead */
/* these are flags for extent_clear_unlock_delalloc */ /* these are flags for extent_clear_unlock_delalloc */
#define EXTENT_CLEAR_UNLOCK_PAGE 0x1 #define EXTENT_CLEAR_UNLOCK_PAGE 0x1
...@@ -67,7 +70,7 @@ struct extent_io_ops { ...@@ -67,7 +70,7 @@ struct extent_io_ops {
unsigned long bio_flags); unsigned long bio_flags);
int (*readpage_io_hook)(struct page *page, u64 start, u64 end); int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
int (*readpage_io_failed_hook)(struct bio *bio, struct page *page, int (*readpage_io_failed_hook)(struct bio *bio, struct page *page,
u64 start, u64 end, u64 start, u64 end, int failed_mirror,
struct extent_state *state); struct extent_state *state);
int (*writepage_io_failed_hook)(struct bio *bio, struct page *page, int (*writepage_io_failed_hook)(struct bio *bio, struct page *page,
u64 start, u64 end, u64 start, u64 end,
...@@ -85,7 +88,8 @@ struct extent_io_ops { ...@@ -85,7 +88,8 @@ struct extent_io_ops {
struct extent_state *other); struct extent_state *other);
void (*split_extent_hook)(struct inode *inode, void (*split_extent_hook)(struct inode *inode,
struct extent_state *orig, u64 split); struct extent_state *orig, u64 split);
int (*write_cache_pages_lock_hook)(struct page *page); int (*write_cache_pages_lock_hook)(struct page *page, void *data,
void (*flush_fn)(void *));
}; };
struct extent_io_tree { struct extent_io_tree {
...@@ -185,7 +189,7 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -185,7 +189,7 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
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 extent_read_full_page(struct extent_io_tree *tree, struct page *page, int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
get_extent_t *get_extent); get_extent_t *get_extent, int mirror_num);
int __init extent_io_init(void); int __init extent_io_init(void);
void extent_io_exit(void); void extent_io_exit(void);
...@@ -214,6 +218,8 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -214,6 +218,8 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
gfp_t mask); gfp_t 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);
int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
int bits, int clear_bits, gfp_t 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,
struct extent_state **cached_state, gfp_t mask); struct extent_state **cached_state, gfp_t mask);
int find_first_extent_bit(struct extent_io_tree *tree, u64 start, int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
...@@ -248,9 +254,14 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, ...@@ -248,9 +254,14 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
u64 start, unsigned long len); u64 start, unsigned long len);
void free_extent_buffer(struct extent_buffer *eb); void free_extent_buffer(struct extent_buffer *eb);
#define WAIT_NONE 0
#define WAIT_COMPLETE 1
#define WAIT_PAGE_LOCK 2
int read_extent_buffer_pages(struct extent_io_tree *tree, int read_extent_buffer_pages(struct extent_io_tree *tree,
struct extent_buffer *eb, u64 start, int wait, struct extent_buffer *eb, u64 start, int wait,
get_extent_t *get_extent, int mirror_num); get_extent_t *get_extent, int mirror_num);
unsigned long num_extent_pages(u64 start, u64 len);
struct page *extent_buffer_page(struct extent_buffer *eb, unsigned long i);
static inline void extent_buffer_get(struct extent_buffer *eb) static inline void extent_buffer_get(struct extent_buffer *eb)
{ {
...@@ -300,4 +311,10 @@ int extent_clear_unlock_delalloc(struct inode *inode, ...@@ -300,4 +311,10 @@ int extent_clear_unlock_delalloc(struct inode *inode,
struct bio * struct bio *
btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
gfp_t gfp_flags); gfp_t gfp_flags);
struct btrfs_mapping_tree;
int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
u64 length, u64 logical, struct page *page,
int mirror_num);
#endif #endif
...@@ -91,8 +91,7 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, ...@@ -91,8 +91,7 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_csum_item *item; struct btrfs_csum_item *item;
struct extent_buffer *leaf; struct extent_buffer *leaf;
u64 csum_offset = 0; u64 csum_offset = 0;
u16 csum_size = u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
btrfs_super_csum_size(&root->fs_info->super_copy);
int csums_in_item; int csums_in_item;
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
...@@ -162,8 +161,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, ...@@ -162,8 +161,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
u64 item_last_offset = 0; u64 item_last_offset = 0;
u64 disk_bytenr; u64 disk_bytenr;
u32 diff; u32 diff;
u16 csum_size = u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
btrfs_super_csum_size(&root->fs_info->super_copy);
int ret; int ret;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_csum_item *item = NULL; struct btrfs_csum_item *item = NULL;
...@@ -290,7 +288,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, ...@@ -290,7 +288,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
int ret; int ret;
size_t size; size_t size;
u64 csum_end; u64 csum_end;
u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
...@@ -492,8 +490,7 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, ...@@ -492,8 +490,7 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
u64 bytenr, u64 len) u64 bytenr, u64 len)
{ {
struct extent_buffer *leaf; struct extent_buffer *leaf;
u16 csum_size = u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
btrfs_super_csum_size(&root->fs_info->super_copy);
u64 csum_end; u64 csum_end;
u64 end_byte = bytenr + len; u64 end_byte = bytenr + len;
u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits;
...@@ -549,8 +546,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, ...@@ -549,8 +546,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
u64 csum_end; u64 csum_end;
struct extent_buffer *leaf; struct extent_buffer *leaf;
int ret; int ret;
u16 csum_size = u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
btrfs_super_csum_size(&root->fs_info->super_copy);
int blocksize_bits = root->fs_info->sb->s_blocksize_bits; int blocksize_bits = root->fs_info->sb->s_blocksize_bits;
root = root->fs_info->csum_root; root = root->fs_info->csum_root;
...@@ -676,8 +672,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -676,8 +672,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
struct btrfs_sector_sum *sector_sum; struct btrfs_sector_sum *sector_sum;
u32 nritems; u32 nritems;
u32 ins_size; u32 ins_size;
u16 csum_size = u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
btrfs_super_csum_size(&root->fs_info->super_copy);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
......
...@@ -1069,6 +1069,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file, ...@@ -1069,6 +1069,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
int i; int i;
unsigned long index = pos >> PAGE_CACHE_SHIFT; unsigned long index = pos >> PAGE_CACHE_SHIFT;
struct inode *inode = fdentry(file)->d_inode; struct inode *inode = fdentry(file)->d_inode;
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
int err = 0; int err = 0;
int faili = 0; int faili = 0;
u64 start_pos; u64 start_pos;
...@@ -1080,7 +1081,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file, ...@@ -1080,7 +1081,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
again: again:
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
pages[i] = find_or_create_page(inode->i_mapping, index + i, pages[i] = find_or_create_page(inode->i_mapping, index + i,
GFP_NOFS); mask);
if (!pages[i]) { if (!pages[i]) {
faili = i - 1; faili = i - 1;
err = -ENOMEM; err = -ENOMEM;
...@@ -1386,7 +1387,11 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, ...@@ -1386,7 +1387,11 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
goto out; goto out;
} }
file_update_time(file); err = btrfs_update_time(file);
if (err) {
mutex_unlock(&inode->i_mutex);
goto out;
}
BTRFS_I(inode)->sequence++; BTRFS_I(inode)->sequence++;
start_pos = round_down(pos, root->sectorsize); start_pos = round_down(pos, root->sectorsize);
...@@ -1615,10 +1620,6 @@ static long btrfs_fallocate(struct file *file, int mode, ...@@ -1615,10 +1620,6 @@ static long btrfs_fallocate(struct file *file, int mode,
goto out; goto out;
} }
ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
if (ret)
goto out;
locked_end = alloc_end - 1; locked_end = alloc_end - 1;
while (1) { while (1) {
struct btrfs_ordered_extent *ordered; struct btrfs_ordered_extent *ordered;
...@@ -1664,11 +1665,27 @@ static long btrfs_fallocate(struct file *file, int mode, ...@@ -1664,11 +1665,27 @@ static long btrfs_fallocate(struct file *file, int mode,
if (em->block_start == EXTENT_MAP_HOLE || if (em->block_start == EXTENT_MAP_HOLE ||
(cur_offset >= inode->i_size && (cur_offset >= inode->i_size &&
!test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
/*
* Make sure we have enough space before we do the
* allocation.
*/
ret = btrfs_check_data_free_space(inode, last_byte -
cur_offset);
if (ret) {
free_extent_map(em);
break;
}
ret = btrfs_prealloc_file_range(inode, mode, cur_offset, ret = btrfs_prealloc_file_range(inode, mode, cur_offset,
last_byte - cur_offset, last_byte - cur_offset,
1 << inode->i_blkbits, 1 << inode->i_blkbits,
offset + len, offset + len,
&alloc_hint); &alloc_hint);
/* Let go of our reservation. */
btrfs_free_reserved_data_space(inode, last_byte -
cur_offset);
if (ret < 0) { if (ret < 0) {
free_extent_map(em); free_extent_map(em);
break; break;
...@@ -1694,8 +1711,6 @@ static long btrfs_fallocate(struct file *file, int mode, ...@@ -1694,8 +1711,6 @@ static long btrfs_fallocate(struct file *file, int mode,
} }
unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
&cached_state, GFP_NOFS); &cached_state, GFP_NOFS);
btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
out: out:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
return ret; return ret;
......
This diff is collapsed.
...@@ -398,6 +398,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root, ...@@ -398,6 +398,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
struct btrfs_path *path; struct btrfs_path *path;
struct inode *inode; struct inode *inode;
struct btrfs_block_rsv *rsv;
u64 num_bytes;
u64 alloc_hint = 0; u64 alloc_hint = 0;
int ret; int ret;
int prealloc; int prealloc;
...@@ -421,11 +423,26 @@ int btrfs_save_ino_cache(struct btrfs_root *root, ...@@ -421,11 +423,26 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
rsv = trans->block_rsv;
trans->block_rsv = &root->fs_info->trans_block_rsv;
num_bytes = trans->bytes_reserved;
/*
* 1 item for inode item insertion if need
* 3 items for inode item update (in the worst case)
* 1 item for free space object
* 3 items for pre-allocation
*/
trans->bytes_reserved = btrfs_calc_trans_metadata_size(root, 8);
ret = btrfs_block_rsv_add_noflush(root, trans->block_rsv,
trans->bytes_reserved);
if (ret)
goto out;
again: again:
inode = lookup_free_ino_inode(root, path); inode = lookup_free_ino_inode(root, path);
if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) { if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
ret = PTR_ERR(inode); ret = PTR_ERR(inode);
goto out; goto out_release;
} }
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
...@@ -434,7 +451,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root, ...@@ -434,7 +451,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
ret = create_free_ino_inode(root, trans, path); ret = create_free_ino_inode(root, trans, path);
if (ret) if (ret)
goto out; goto out_release;
goto again; goto again;
} }
...@@ -465,21 +482,26 @@ int btrfs_save_ino_cache(struct btrfs_root *root, ...@@ -465,21 +482,26 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
/* Just to make sure we have enough space */ /* Just to make sure we have enough space */
prealloc += 8 * PAGE_CACHE_SIZE; prealloc += 8 * PAGE_CACHE_SIZE;
ret = btrfs_check_data_free_space(inode, prealloc); ret = btrfs_delalloc_reserve_space(inode, prealloc);
if (ret) if (ret)
goto out_put; goto out_put;
ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc, ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc,
prealloc, prealloc, &alloc_hint); prealloc, prealloc, &alloc_hint);
if (ret) if (ret) {
btrfs_delalloc_release_space(inode, prealloc);
goto out_put; goto out_put;
}
btrfs_free_reserved_data_space(inode, prealloc); btrfs_free_reserved_data_space(inode, prealloc);
ret = btrfs_write_out_ino_cache(root, trans, path);
out_put: out_put:
iput(inode); iput(inode);
out_release:
btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
out: out:
if (ret == 0) trans->block_rsv = rsv;
ret = btrfs_write_out_ino_cache(root, trans, path); trans->bytes_reserved = num_bytes;
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
......
This diff is collapsed.
This diff is collapsed.
...@@ -193,6 +193,30 @@ struct btrfs_ioctl_space_args { ...@@ -193,6 +193,30 @@ struct btrfs_ioctl_space_args {
struct btrfs_ioctl_space_info spaces[0]; struct btrfs_ioctl_space_info spaces[0];
}; };
struct btrfs_data_container {
__u32 bytes_left; /* out -- bytes not needed to deliver output */
__u32 bytes_missing; /* out -- additional bytes needed for result */
__u32 elem_cnt; /* out */
__u32 elem_missed; /* out */
__u64 val[0]; /* out */
};
struct btrfs_ioctl_ino_path_args {
__u64 inum; /* in */
__u32 size; /* in */
__u64 reserved[4];
/* struct btrfs_data_container *fspath; out */
__u64 fspath; /* out */
};
struct btrfs_ioctl_logical_ino_args {
__u64 logical; /* in */
__u32 size; /* in */
__u64 reserved[4];
/* struct btrfs_data_container *inodes; out */
__u64 inodes;
};
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args) struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
...@@ -248,4 +272,9 @@ struct btrfs_ioctl_space_args { ...@@ -248,4 +272,9 @@ struct btrfs_ioctl_space_args {
struct btrfs_ioctl_dev_info_args) struct btrfs_ioctl_dev_info_args)
#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
struct btrfs_ioctl_fs_info_args) struct btrfs_ioctl_fs_info_args)
#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
struct btrfs_ioctl_ino_path_args)
#endif #endif
...@@ -158,8 +158,7 @@ static void print_extent_ref_v0(struct extent_buffer *eb, int slot) ...@@ -158,8 +158,7 @@ static void print_extent_ref_v0(struct extent_buffer *eb, int slot)
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
{ {
int i; int i;
u32 type; u32 type, nr;
u32 nr = btrfs_header_nritems(l);
struct btrfs_item *item; struct btrfs_item *item;
struct btrfs_root_item *ri; struct btrfs_root_item *ri;
struct btrfs_dir_item *di; struct btrfs_dir_item *di;
...@@ -172,6 +171,11 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) ...@@ -172,6 +171,11 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
struct btrfs_key key; struct btrfs_key key;
struct btrfs_key found_key; struct btrfs_key found_key;
if (!l)
return;
nr = btrfs_header_nritems(l);
printk(KERN_INFO "leaf %llu total ptrs %d free space %d\n", printk(KERN_INFO "leaf %llu total ptrs %d free space %d\n",
(unsigned long long)btrfs_header_bytenr(l), nr, (unsigned long long)btrfs_header_bytenr(l), nr,
btrfs_leaf_free_space(root, l)); btrfs_leaf_free_space(root, l));
......
This diff is collapsed.
...@@ -1174,6 +1174,8 @@ static int clone_backref_node(struct btrfs_trans_handle *trans, ...@@ -1174,6 +1174,8 @@ static int clone_backref_node(struct btrfs_trans_handle *trans,
list_add_tail(&new_edge->list[UPPER], list_add_tail(&new_edge->list[UPPER],
&new_node->lower); &new_node->lower);
} }
} else {
list_add_tail(&new_node->lower, &cache->leaves);
} }
rb_node = tree_insert(&cache->rb_root, new_node->bytenr, rb_node = tree_insert(&cache->rb_root, new_node->bytenr,
...@@ -2041,8 +2043,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, ...@@ -2041,8 +2043,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
BUG_ON(IS_ERR(trans)); BUG_ON(IS_ERR(trans));
trans->block_rsv = rc->block_rsv; trans->block_rsv = rc->block_rsv;
ret = btrfs_block_rsv_check(trans, root, rc->block_rsv, ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved);
min_reserved, 0);
if (ret) { if (ret) {
BUG_ON(ret != -EAGAIN); BUG_ON(ret != -EAGAIN);
ret = btrfs_commit_transaction(trans, root); ret = btrfs_commit_transaction(trans, root);
...@@ -2152,8 +2153,7 @@ int prepare_to_merge(struct reloc_control *rc, int err) ...@@ -2152,8 +2153,7 @@ int prepare_to_merge(struct reloc_control *rc, int err)
again: again:
if (!err) { if (!err) {
num_bytes = rc->merging_rsv_size; num_bytes = rc->merging_rsv_size;
ret = btrfs_block_rsv_add(NULL, root, rc->block_rsv, ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes);
num_bytes);
if (ret) if (ret)
err = ret; err = ret;
} }
...@@ -2427,7 +2427,7 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans, ...@@ -2427,7 +2427,7 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans,
num_bytes = calcu_metadata_size(rc, node, 1) * 2; num_bytes = calcu_metadata_size(rc, node, 1) * 2;
trans->block_rsv = rc->block_rsv; trans->block_rsv = rc->block_rsv;
ret = btrfs_block_rsv_add(trans, root, rc->block_rsv, num_bytes); ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes);
if (ret) { if (ret) {
if (ret == -EAGAIN) if (ret == -EAGAIN)
rc->commit_transaction = 1; rc->commit_transaction = 1;
...@@ -2922,6 +2922,7 @@ static int relocate_file_extent_cluster(struct inode *inode, ...@@ -2922,6 +2922,7 @@ static int relocate_file_extent_cluster(struct inode *inode,
unsigned long last_index; unsigned long last_index;
struct page *page; struct page *page;
struct file_ra_state *ra; struct file_ra_state *ra;
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
int nr = 0; int nr = 0;
int ret = 0; int ret = 0;
...@@ -2946,7 +2947,9 @@ static int relocate_file_extent_cluster(struct inode *inode, ...@@ -2946,7 +2947,9 @@ static int relocate_file_extent_cluster(struct inode *inode,
index = (cluster->start - offset) >> PAGE_CACHE_SHIFT; index = (cluster->start - offset) >> PAGE_CACHE_SHIFT;
last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT; last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT;
while (index <= last_index) { while (index <= last_index) {
mutex_lock(&inode->i_mutex);
ret = btrfs_delalloc_reserve_metadata(inode, PAGE_CACHE_SIZE); ret = btrfs_delalloc_reserve_metadata(inode, PAGE_CACHE_SIZE);
mutex_unlock(&inode->i_mutex);
if (ret) if (ret)
goto out; goto out;
...@@ -2956,7 +2959,7 @@ static int relocate_file_extent_cluster(struct inode *inode, ...@@ -2956,7 +2959,7 @@ static int relocate_file_extent_cluster(struct inode *inode,
ra, NULL, index, ra, NULL, index,
last_index + 1 - index); last_index + 1 - index);
page = find_or_create_page(inode->i_mapping, index, page = find_or_create_page(inode->i_mapping, index,
GFP_NOFS); mask);
if (!page) { if (!page) {
btrfs_delalloc_release_metadata(inode, btrfs_delalloc_release_metadata(inode,
PAGE_CACHE_SIZE); PAGE_CACHE_SIZE);
...@@ -3323,8 +3326,11 @@ static int find_data_references(struct reloc_control *rc, ...@@ -3323,8 +3326,11 @@ static int find_data_references(struct reloc_control *rc,
} }
key.objectid = ref_objectid; key.objectid = ref_objectid;
key.offset = ref_offset;
key.type = BTRFS_EXTENT_DATA_KEY; key.type = BTRFS_EXTENT_DATA_KEY;
if (ref_offset > ((u64)-1 << 32))
key.offset = 0;
else
key.offset = ref_offset;
path->search_commit_root = 1; path->search_commit_root = 1;
path->skip_locking = 1; path->skip_locking = 1;
...@@ -3645,14 +3651,11 @@ int prepare_to_relocate(struct reloc_control *rc) ...@@ -3645,14 +3651,11 @@ int prepare_to_relocate(struct reloc_control *rc)
* btrfs_init_reloc_root will use them when there * btrfs_init_reloc_root will use them when there
* is no reservation in transaction handle. * is no reservation in transaction handle.
*/ */
ret = btrfs_block_rsv_add(NULL, rc->extent_root, rc->block_rsv, ret = btrfs_block_rsv_add(rc->extent_root, rc->block_rsv,
rc->extent_root->nodesize * 256); rc->extent_root->nodesize * 256);
if (ret) if (ret)
return ret; return ret;
rc->block_rsv->refill_used = 1;
btrfs_add_durable_block_rsv(rc->extent_root->fs_info, rc->block_rsv);
memset(&rc->cluster, 0, sizeof(rc->cluster)); memset(&rc->cluster, 0, sizeof(rc->cluster));
rc->search_start = rc->block_group->key.objectid; rc->search_start = rc->block_group->key.objectid;
rc->extents_found = 0; rc->extents_found = 0;
...@@ -3777,8 +3780,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc) ...@@ -3777,8 +3780,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
} }
} }
ret = btrfs_block_rsv_check(trans, rc->extent_root, ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 5);
rc->block_rsv, 0, 5);
if (ret < 0) { if (ret < 0) {
if (ret != -EAGAIN) { if (ret != -EAGAIN) {
err = ret; err = ret;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment