Commit ae1a25da authored by Linus Torvalds's avatar Linus Torvalds

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

* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (37 commits)
  Btrfs: Make sure dir is non-null before doing S_ISGID checks
  Btrfs: Fix memory leak in cache_drop_leaf_ref
  Btrfs: don't return congestion in write_cache_pages as often
  Btrfs: Only prep for btree deletion balances when nodes are mostly empty
  Btrfs: fix btrfs_unlock_up_safe to walk the entire path
  Btrfs: change btrfs_del_leaf to drop locks earlier
  Btrfs: Change btrfs_truncate_inode_items to stop when it hits the inode
  Btrfs: Don't try to compress pages past i_size
  Btrfs: join the transaction in __btrfs_setxattr
  Btrfs: Handle SGID bit when creating inodes
  Btrfs: Make btrfs_drop_snapshot work in larger and more efficient chunks
  Btrfs: Change btree locking to use explicit blocking points
  Btrfs: hash_lock is no longer needed
  Btrfs: disable leak debugging checks in extent_io.c
  Btrfs: sort references by byte number during btrfs_inc_ref
  Btrfs: async threads should try harder to find work
  Btrfs: selinux support
  Btrfs: make btrfs acls selectable
  Btrfs: Catch missed bios in the async bio submission thread
  Btrfs: fix readdir on 32 bit machines
  ...
parents fd9fc842 42f15d77
...@@ -1021,6 +1021,14 @@ M: mb@bu3sch.de ...@@ -1021,6 +1021,14 @@ M: mb@bu3sch.de
W: http://bu3sch.de/btgpio.php W: http://bu3sch.de/btgpio.php
S: Maintained S: Maintained
BTRFS FILE SYSTEM
P: Chris Mason
M: chris.mason@oracle.com
L: linux-btrfs@vger.kernel.org
W: http://btrfs.wiki.kernel.org/
T: git kernel.org:/pub/scm/linux/kernel/git/mason/btrfs-unstable.git
S: Maintained
BTTV VIDEO4LINUX DRIVER BTTV VIDEO4LINUX DRIVER
P: Mauro Carvalho Chehab P: Mauro Carvalho Chehab
M: mchehab@infradead.org M: mchehab@infradead.org
......
...@@ -16,3 +16,16 @@ config BTRFS_FS ...@@ -16,3 +16,16 @@ config BTRFS_FS
module will be called btrfs. module will be called btrfs.
If unsure, say N. If unsure, say N.
config BTRFS_FS_POSIX_ACL
bool "Btrfs POSIX Access Control Lists"
depends on BTRFS_FS
select FS_POSIX_ACL
help
POSIX Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
To learn more about Access Control Lists, visit the POSIX ACLs for
Linux website <http://acl.bestbits.at/>.
If you don't know what Access Control Lists are, say N
...@@ -16,11 +16,11 @@ ...@@ -16,11 +16,11 @@
* Boston, MA 021110-1307, USA. * Boston, MA 021110-1307, USA.
*/ */
#include <linux/version.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
# include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/ftrace.h>
#include "async-thread.h" #include "async-thread.h"
#define WORK_QUEUED_BIT 0 #define WORK_QUEUED_BIT 0
...@@ -143,6 +143,7 @@ static int worker_loop(void *arg) ...@@ -143,6 +143,7 @@ static int worker_loop(void *arg)
struct btrfs_work *work; struct btrfs_work *work;
do { do {
spin_lock_irq(&worker->lock); spin_lock_irq(&worker->lock);
again_locked:
while (!list_empty(&worker->pending)) { while (!list_empty(&worker->pending)) {
cur = worker->pending.next; cur = worker->pending.next;
work = list_entry(cur, struct btrfs_work, list); work = list_entry(cur, struct btrfs_work, list);
...@@ -165,14 +166,50 @@ static int worker_loop(void *arg) ...@@ -165,14 +166,50 @@ static int worker_loop(void *arg)
check_idle_worker(worker); check_idle_worker(worker);
} }
worker->working = 0;
if (freezing(current)) { if (freezing(current)) {
worker->working = 0;
spin_unlock_irq(&worker->lock);
refrigerator(); refrigerator();
} else { } else {
spin_unlock_irq(&worker->lock);
if (!kthread_should_stop()) {
cpu_relax();
/*
* we've dropped the lock, did someone else
* jump_in?
*/
smp_mb();
if (!list_empty(&worker->pending))
continue;
/*
* this short schedule allows more work to
* come in without the queue functions
* needing to go through wake_up_process()
*
* worker->working is still 1, so nobody
* is going to try and wake us up
*/
schedule_timeout(1);
smp_mb();
if (!list_empty(&worker->pending))
continue;
/* still no more work?, sleep for real */
spin_lock_irq(&worker->lock);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (!list_empty(&worker->pending))
goto again_locked;
/*
* this makes sure we get a wakeup when someone
* adds something new to the queue
*/
worker->working = 0;
spin_unlock_irq(&worker->lock); spin_unlock_irq(&worker->lock);
if (!kthread_should_stop())
schedule(); schedule();
}
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
} }
} while (!kthread_should_stop()); } while (!kthread_should_stop());
...@@ -350,13 +387,14 @@ int btrfs_requeue_work(struct btrfs_work *work) ...@@ -350,13 +387,14 @@ int btrfs_requeue_work(struct btrfs_work *work)
{ {
struct btrfs_worker_thread *worker = work->worker; struct btrfs_worker_thread *worker = work->worker;
unsigned long flags; unsigned long flags;
int wake = 0;
if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags)) if (test_and_set_bit(WORK_QUEUED_BIT, &work->flags))
goto out; goto out;
spin_lock_irqsave(&worker->lock, flags); spin_lock_irqsave(&worker->lock, flags);
atomic_inc(&worker->num_pending);
list_add_tail(&work->list, &worker->pending); list_add_tail(&work->list, &worker->pending);
atomic_inc(&worker->num_pending);
/* by definition we're busy, take ourselves off the idle /* by definition we're busy, take ourselves off the idle
* list * list
...@@ -368,10 +406,16 @@ int btrfs_requeue_work(struct btrfs_work *work) ...@@ -368,10 +406,16 @@ int btrfs_requeue_work(struct btrfs_work *work)
&worker->workers->worker_list); &worker->workers->worker_list);
spin_unlock_irqrestore(&worker->workers->lock, flags); spin_unlock_irqrestore(&worker->workers->lock, flags);
} }
if (!worker->working) {
wake = 1;
worker->working = 1;
}
spin_unlock_irqrestore(&worker->lock, flags); spin_unlock_irqrestore(&worker->lock, flags);
if (wake)
wake_up_process(worker->task);
out: out:
return 0; return 0;
} }
...@@ -398,9 +442,10 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) ...@@ -398,9 +442,10 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
} }
spin_lock_irqsave(&worker->lock, flags); spin_lock_irqsave(&worker->lock, flags);
list_add_tail(&work->list, &worker->pending);
atomic_inc(&worker->num_pending); atomic_inc(&worker->num_pending);
check_busy_worker(worker); check_busy_worker(worker);
list_add_tail(&work->list, &worker->pending);
/* /*
* avoid calling into wake_up_process if this thread has already * avoid calling into wake_up_process if this thread has already
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/bit_spinlock.h> #include <linux/bit_spinlock.h>
#include <linux/version.h>
#include <linux/pagevec.h> #include <linux/pagevec.h>
#include "compat.h" #include "compat.h"
#include "ctree.h" #include "ctree.h"
......
This diff is collapsed.
...@@ -454,17 +454,11 @@ struct btrfs_timespec { ...@@ -454,17 +454,11 @@ struct btrfs_timespec {
__le32 nsec; __le32 nsec;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
typedef enum { enum btrfs_compression_type {
BTRFS_COMPRESS_NONE = 0, BTRFS_COMPRESS_NONE = 0,
BTRFS_COMPRESS_ZLIB = 1, BTRFS_COMPRESS_ZLIB = 1,
BTRFS_COMPRESS_LAST = 2, BTRFS_COMPRESS_LAST = 2,
} btrfs_compression_type; };
/* we don't understand any encryption methods right now */
typedef enum {
BTRFS_ENCRYPTION_NONE = 0,
BTRFS_ENCRYPTION_LAST = 1,
} btrfs_encryption_type;
struct btrfs_inode_item { struct btrfs_inode_item {
/* nfs style generation number */ /* nfs style generation number */
...@@ -701,9 +695,7 @@ struct btrfs_fs_info { ...@@ -701,9 +695,7 @@ struct btrfs_fs_info {
struct btrfs_transaction *running_transaction; struct btrfs_transaction *running_transaction;
wait_queue_head_t transaction_throttle; wait_queue_head_t transaction_throttle;
wait_queue_head_t transaction_wait; wait_queue_head_t transaction_wait;
wait_queue_head_t async_submit_wait; wait_queue_head_t async_submit_wait;
wait_queue_head_t tree_log_wait;
struct btrfs_super_block super_copy; struct btrfs_super_block super_copy;
struct btrfs_super_block super_for_commit; struct btrfs_super_block super_for_commit;
...@@ -711,7 +703,6 @@ struct btrfs_fs_info { ...@@ -711,7 +703,6 @@ struct btrfs_fs_info {
struct super_block *sb; struct super_block *sb;
struct inode *btree_inode; struct inode *btree_inode;
struct backing_dev_info bdi; struct backing_dev_info bdi;
spinlock_t hash_lock;
struct mutex trans_mutex; struct mutex trans_mutex;
struct mutex tree_log_mutex; struct mutex tree_log_mutex;
struct mutex transaction_kthread_mutex; struct mutex transaction_kthread_mutex;
...@@ -730,10 +721,6 @@ struct btrfs_fs_info { ...@@ -730,10 +721,6 @@ struct btrfs_fs_info {
atomic_t async_submit_draining; atomic_t async_submit_draining;
atomic_t nr_async_bios; atomic_t nr_async_bios;
atomic_t async_delalloc_pages; atomic_t async_delalloc_pages;
atomic_t tree_log_writers;
atomic_t tree_log_commit;
unsigned long tree_log_batch;
u64 tree_log_transid;
/* /*
* this is used by the balancing code to wait for all the pending * this is used by the balancing code to wait for all the pending
...@@ -833,7 +820,14 @@ struct btrfs_root { ...@@ -833,7 +820,14 @@ struct btrfs_root {
struct kobject root_kobj; struct kobject root_kobj;
struct completion kobj_unregister; struct completion kobj_unregister;
struct mutex objectid_mutex; struct mutex objectid_mutex;
struct mutex log_mutex; struct mutex log_mutex;
wait_queue_head_t log_writer_wait;
wait_queue_head_t log_commit_wait[2];
atomic_t log_writers;
atomic_t log_commit[2];
unsigned long log_transid;
unsigned long log_batch;
u64 objectid; u64 objectid;
u64 last_trans; u64 last_trans;
...@@ -1841,6 +1835,10 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p); ...@@ -1841,6 +1835,10 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
struct btrfs_path *btrfs_alloc_path(void); struct btrfs_path *btrfs_alloc_path(void);
void btrfs_free_path(struct btrfs_path *p); void btrfs_free_path(struct btrfs_path *p);
void btrfs_init_path(struct btrfs_path *p); void btrfs_init_path(struct btrfs_path *p);
void btrfs_set_path_blocking(struct btrfs_path *p);
void btrfs_clear_path_blocking(struct btrfs_path *p);
void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int slot, int nr); struct btrfs_path *path, int slot, int nr);
int btrfs_del_leaf(struct btrfs_trans_handle *trans, int btrfs_del_leaf(struct btrfs_trans_handle *trans,
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
* Boston, MA 021110-1307, USA. * Boston, MA 021110-1307, USA.
*/ */
#include <linux/version.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
...@@ -800,7 +799,7 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, ...@@ -800,7 +799,7 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid); ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
if (ret == 0) if (ret == 0)
buf->flags |= EXTENT_UPTODATE; set_bit(EXTENT_BUFFER_UPTODATE, &buf->bflags);
else else
WARN_ON(1); WARN_ON(1);
return buf; return buf;
...@@ -814,6 +813,10 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -814,6 +813,10 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
if (btrfs_header_generation(buf) == if (btrfs_header_generation(buf) ==
root->fs_info->running_transaction->transid) { root->fs_info->running_transaction->transid) {
WARN_ON(!btrfs_tree_locked(buf)); WARN_ON(!btrfs_tree_locked(buf));
/* ugh, clear_extent_buffer_dirty can be expensive */
btrfs_set_lock_blocking(buf);
clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, clear_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree,
buf); buf);
} }
...@@ -850,6 +853,14 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, ...@@ -850,6 +853,14 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
spin_lock_init(&root->list_lock); spin_lock_init(&root->list_lock);
mutex_init(&root->objectid_mutex); mutex_init(&root->objectid_mutex);
mutex_init(&root->log_mutex); mutex_init(&root->log_mutex);
init_waitqueue_head(&root->log_writer_wait);
init_waitqueue_head(&root->log_commit_wait[0]);
init_waitqueue_head(&root->log_commit_wait[1]);
atomic_set(&root->log_commit[0], 0);
atomic_set(&root->log_commit[1], 0);
atomic_set(&root->log_writers, 0);
root->log_batch = 0;
root->log_transid = 0;
extent_io_tree_init(&root->dirty_log_pages, extent_io_tree_init(&root->dirty_log_pages,
fs_info->btree_inode->i_mapping, GFP_NOFS); fs_info->btree_inode->i_mapping, GFP_NOFS);
...@@ -934,15 +945,16 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, ...@@ -934,15 +945,16 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info) struct btrfs_fs_info *fs_info)
{ {
struct btrfs_root *root; struct btrfs_root *root;
struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *tree_root = fs_info->tree_root;
struct extent_buffer *leaf;
root = kzalloc(sizeof(*root), GFP_NOFS); root = kzalloc(sizeof(*root), GFP_NOFS);
if (!root) if (!root)
return -ENOMEM; return ERR_PTR(-ENOMEM);
__setup_root(tree_root->nodesize, tree_root->leafsize, __setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize, tree_root->sectorsize, tree_root->stripesize,
...@@ -951,12 +963,23 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, ...@@ -951,12 +963,23 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
root->root_key.objectid = BTRFS_TREE_LOG_OBJECTID; root->root_key.objectid = BTRFS_TREE_LOG_OBJECTID;
root->root_key.type = BTRFS_ROOT_ITEM_KEY; root->root_key.type = BTRFS_ROOT_ITEM_KEY;
root->root_key.offset = BTRFS_TREE_LOG_OBJECTID; root->root_key.offset = BTRFS_TREE_LOG_OBJECTID;
/*
* log trees do not get reference counted because they go away
* before a real commit is actually done. They do store pointers
* to file data extents, and those reference counts still get
* updated (along with back refs to the log tree).
*/
root->ref_cows = 0; root->ref_cows = 0;
root->node = btrfs_alloc_free_block(trans, root, root->leafsize, leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
0, BTRFS_TREE_LOG_OBJECTID, 0, BTRFS_TREE_LOG_OBJECTID,
trans->transid, 0, 0, 0); trans->transid, 0, 0, 0);
if (IS_ERR(leaf)) {
kfree(root);
return ERR_CAST(leaf);
}
root->node = leaf;
btrfs_set_header_nritems(root->node, 0); btrfs_set_header_nritems(root->node, 0);
btrfs_set_header_level(root->node, 0); btrfs_set_header_level(root->node, 0);
btrfs_set_header_bytenr(root->node, root->node->start); btrfs_set_header_bytenr(root->node, root->node->start);
...@@ -968,7 +991,48 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, ...@@ -968,7 +991,48 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
BTRFS_FSID_SIZE); BTRFS_FSID_SIZE);
btrfs_mark_buffer_dirty(root->node); btrfs_mark_buffer_dirty(root->node);
btrfs_tree_unlock(root->node); btrfs_tree_unlock(root->node);
fs_info->log_root_tree = root; return root;
}
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info)
{
struct btrfs_root *log_root;
log_root = alloc_log_tree(trans, fs_info);
if (IS_ERR(log_root))
return PTR_ERR(log_root);
WARN_ON(fs_info->log_root_tree);
fs_info->log_root_tree = log_root;
return 0;
}
int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
struct btrfs_root *log_root;
struct btrfs_inode_item *inode_item;
log_root = alloc_log_tree(trans, root->fs_info);
if (IS_ERR(log_root))
return PTR_ERR(log_root);
log_root->last_trans = trans->transid;
log_root->root_key.offset = root->root_key.objectid;
inode_item = &log_root->root_item.inode;
inode_item->generation = cpu_to_le64(1);
inode_item->size = cpu_to_le64(3);
inode_item->nlink = cpu_to_le32(1);
inode_item->nbytes = cpu_to_le64(root->leafsize);
inode_item->mode = cpu_to_le32(S_IFDIR | 0755);
btrfs_set_root_bytenr(&log_root->root_item, log_root->node->start);
btrfs_set_root_generation(&log_root->root_item, trans->transid);
WARN_ON(root->log_root);
root->log_root = log_root;
root->log_transid = 0;
return 0; return 0;
} }
...@@ -1136,7 +1200,6 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits) ...@@ -1136,7 +1200,6 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
{ {
struct btrfs_fs_info *info = (struct btrfs_fs_info *)congested_data; struct btrfs_fs_info *info = (struct btrfs_fs_info *)congested_data;
int ret = 0; int ret = 0;
struct list_head *cur;
struct btrfs_device *device; struct btrfs_device *device;
struct backing_dev_info *bdi; struct backing_dev_info *bdi;
#if 0 #if 0
...@@ -1144,8 +1207,7 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits) ...@@ -1144,8 +1207,7 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
btrfs_congested_async(info, 0)) btrfs_congested_async(info, 0))
return 1; return 1;
#endif #endif
list_for_each(cur, &info->fs_devices->devices) { list_for_each_entry(device, &info->fs_devices->devices, dev_list) {
device = list_entry(cur, struct btrfs_device, dev_list);
if (!device->bdev) if (!device->bdev)
continue; continue;
bdi = blk_get_backing_dev_info(device->bdev); bdi = blk_get_backing_dev_info(device->bdev);
...@@ -1163,13 +1225,11 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits) ...@@ -1163,13 +1225,11 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
*/ */
static void __unplug_io_fn(struct backing_dev_info *bdi, struct page *page) static void __unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
{ {
struct list_head *cur;
struct btrfs_device *device; struct btrfs_device *device;
struct btrfs_fs_info *info; struct btrfs_fs_info *info;
info = (struct btrfs_fs_info *)bdi->unplug_io_data; info = (struct btrfs_fs_info *)bdi->unplug_io_data;
list_for_each(cur, &info->fs_devices->devices) { list_for_each_entry(device, &info->fs_devices->devices, dev_list) {
device = list_entry(cur, struct btrfs_device, dev_list);
if (!device->bdev) if (!device->bdev)
continue; continue;
...@@ -1447,7 +1507,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1447,7 +1507,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
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);
spin_lock_init(&fs_info->hash_lock);
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);
...@@ -1535,10 +1594,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1535,10 +1594,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
init_waitqueue_head(&fs_info->transaction_throttle); init_waitqueue_head(&fs_info->transaction_throttle);
init_waitqueue_head(&fs_info->transaction_wait); init_waitqueue_head(&fs_info->transaction_wait);
init_waitqueue_head(&fs_info->async_submit_wait); init_waitqueue_head(&fs_info->async_submit_wait);
init_waitqueue_head(&fs_info->tree_log_wait);
atomic_set(&fs_info->tree_log_commit, 0);
atomic_set(&fs_info->tree_log_writers, 0);
fs_info->tree_log_transid = 0;
__setup_root(4096, 4096, 4096, 4096, tree_root, __setup_root(4096, 4096, 4096, 4096, tree_root,
fs_info, BTRFS_ROOT_TREE_OBJECTID); fs_info, BTRFS_ROOT_TREE_OBJECTID);
...@@ -1627,6 +1682,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1627,6 +1682,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
* low idle thresh * low idle thresh
*/ */
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_write_workers.idle_thresh = 64; fs_info->endio_write_workers.idle_thresh = 64;
fs_info->endio_meta_write_workers.idle_thresh = 64; fs_info->endio_meta_write_workers.idle_thresh = 64;
...@@ -1740,13 +1797,13 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1740,13 +1797,13 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root,
"btrfs-cleaner"); "btrfs-cleaner");
if (!fs_info->cleaner_kthread) if (IS_ERR(fs_info->cleaner_kthread))
goto fail_csum_root; goto fail_csum_root;
fs_info->transaction_kthread = kthread_run(transaction_kthread, fs_info->transaction_kthread = kthread_run(transaction_kthread,
tree_root, tree_root,
"btrfs-transaction"); "btrfs-transaction");
if (!fs_info->transaction_kthread) if (IS_ERR(fs_info->transaction_kthread))
goto fail_cleaner; goto fail_cleaner;
if (btrfs_super_log_root(disk_super) != 0) { if (btrfs_super_log_root(disk_super) != 0) {
...@@ -1828,13 +1885,14 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1828,13 +1885,14 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fail_iput: fail_iput:
invalidate_inode_pages2(fs_info->btree_inode->i_mapping); invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
iput(fs_info->btree_inode); iput(fs_info->btree_inode);
fail:
btrfs_close_devices(fs_info->fs_devices); btrfs_close_devices(fs_info->fs_devices);
btrfs_mapping_tree_free(&fs_info->mapping_tree); btrfs_mapping_tree_free(&fs_info->mapping_tree);
bdi_destroy(&fs_info->bdi);
fail:
kfree(extent_root); kfree(extent_root);
kfree(tree_root); kfree(tree_root);
bdi_destroy(&fs_info->bdi);
kfree(fs_info); kfree(fs_info);
kfree(chunk_root); kfree(chunk_root);
kfree(dev_root); kfree(dev_root);
...@@ -1995,7 +2053,6 @@ static int write_dev_supers(struct btrfs_device *device, ...@@ -1995,7 +2053,6 @@ static int write_dev_supers(struct btrfs_device *device,
int write_all_supers(struct btrfs_root *root, int max_mirrors) int write_all_supers(struct btrfs_root *root, int max_mirrors)
{ {
struct list_head *cur;
struct list_head *head = &root->fs_info->fs_devices->devices; struct list_head *head = &root->fs_info->fs_devices->devices;
struct btrfs_device *dev; struct btrfs_device *dev;
struct btrfs_super_block *sb; struct btrfs_super_block *sb;
...@@ -2011,8 +2068,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) ...@@ -2011,8 +2068,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
sb = &root->fs_info->super_for_commit; sb = &root->fs_info->super_for_commit;
dev_item = &sb->dev_item; dev_item = &sb->dev_item;
list_for_each(cur, head) { list_for_each_entry(dev, head, dev_list) {
dev = list_entry(cur, struct btrfs_device, dev_list);
if (!dev->bdev) { if (!dev->bdev) {
total_errors++; total_errors++;
continue; continue;
...@@ -2045,8 +2101,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) ...@@ -2045,8 +2101,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
} }
total_errors = 0; total_errors = 0;
list_for_each(cur, head) { list_for_each_entry(dev, head, dev_list) {
dev = list_entry(cur, struct btrfs_device, dev_list);
if (!dev->bdev) if (!dev->bdev)
continue; continue;
if (!dev->in_fs_metadata || !dev->writeable) if (!dev->in_fs_metadata || !dev->writeable)
...@@ -2260,6 +2315,8 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) ...@@ -2260,6 +2315,8 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
u64 transid = btrfs_header_generation(buf); u64 transid = btrfs_header_generation(buf);
struct inode *btree_inode = root->fs_info->btree_inode; struct inode *btree_inode = root->fs_info->btree_inode;
btrfs_set_lock_blocking(buf);
WARN_ON(!btrfs_tree_locked(buf)); WARN_ON(!btrfs_tree_locked(buf));
if (transid != root->fs_info->generation) { if (transid != root->fs_info->generation) {
printk(KERN_CRIT "btrfs transid mismatch buffer %llu, " printk(KERN_CRIT "btrfs transid mismatch buffer %llu, "
...@@ -2302,14 +2359,13 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) ...@@ -2302,14 +2359,13 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
int ret; int ret;
ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid); ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
if (ret == 0) if (ret == 0)
buf->flags |= EXTENT_UPTODATE; set_bit(EXTENT_BUFFER_UPTODATE, &buf->bflags);
return ret; return ret;
} }
int btree_lock_page_hook(struct page *page) int btree_lock_page_hook(struct page *page)
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct extent_buffer *eb; struct extent_buffer *eb;
unsigned long len; unsigned long len;
...@@ -2324,9 +2380,7 @@ int btree_lock_page_hook(struct page *page) ...@@ -2324,9 +2380,7 @@ int btree_lock_page_hook(struct page *page)
goto out; goto out;
btrfs_tree_lock(eb); btrfs_tree_lock(eb);
spin_lock(&root->fs_info->hash_lock);
btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
spin_unlock(&root->fs_info->hash_lock);
btrfs_tree_unlock(eb); btrfs_tree_unlock(eb);
free_extent_buffer(eb); free_extent_buffer(eb);
out: out:
......
...@@ -98,5 +98,7 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, ...@@ -98,5 +98,7 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info); struct btrfs_fs_info *fs_info);
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, 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,
struct btrfs_root *root);
int btree_lock_page_hook(struct page *page); int btree_lock_page_hook(struct page *page);
#endif #endif
This diff is collapsed.
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/version.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/pagevec.h> #include <linux/pagevec.h>
#include "extent_io.h" #include "extent_io.h"
...@@ -31,7 +30,7 @@ static LIST_HEAD(buffers); ...@@ -31,7 +30,7 @@ static LIST_HEAD(buffers);
static LIST_HEAD(states); static LIST_HEAD(states);
#define LEAK_DEBUG 0 #define LEAK_DEBUG 0
#ifdef LEAK_DEBUG #if LEAK_DEBUG
static DEFINE_SPINLOCK(leak_lock); static DEFINE_SPINLOCK(leak_lock);
#endif #endif
...@@ -120,7 +119,7 @@ void extent_io_tree_init(struct extent_io_tree *tree, ...@@ -120,7 +119,7 @@ void extent_io_tree_init(struct extent_io_tree *tree,
static struct extent_state *alloc_extent_state(gfp_t mask) static struct extent_state *alloc_extent_state(gfp_t mask)
{ {
struct extent_state *state; struct extent_state *state;
#ifdef LEAK_DEBUG #if LEAK_DEBUG
unsigned long flags; unsigned long flags;
#endif #endif
...@@ -130,7 +129,7 @@ static struct extent_state *alloc_extent_state(gfp_t mask) ...@@ -130,7 +129,7 @@ static struct extent_state *alloc_extent_state(gfp_t mask)
state->state = 0; state->state = 0;
state->private = 0; state->private = 0;
state->tree = NULL; state->tree = NULL;
#ifdef LEAK_DEBUG #if LEAK_DEBUG
spin_lock_irqsave(&leak_lock, flags); spin_lock_irqsave(&leak_lock, flags);
list_add(&state->leak_list, &states); list_add(&state->leak_list, &states);
spin_unlock_irqrestore(&leak_lock, flags); spin_unlock_irqrestore(&leak_lock, flags);
...@@ -145,11 +144,11 @@ static void free_extent_state(struct extent_state *state) ...@@ -145,11 +144,11 @@ static void free_extent_state(struct extent_state *state)
if (!state) if (!state)
return; return;
if (atomic_dec_and_test(&state->refs)) { if (atomic_dec_and_test(&state->refs)) {
#ifdef LEAK_DEBUG #if LEAK_DEBUG
unsigned long flags; unsigned long flags;
#endif #endif
WARN_ON(state->tree); WARN_ON(state->tree);
#ifdef LEAK_DEBUG #if LEAK_DEBUG
spin_lock_irqsave(&leak_lock, flags); spin_lock_irqsave(&leak_lock, flags);
list_del(&state->leak_list); list_del(&state->leak_list);
spin_unlock_irqrestore(&leak_lock, flags); spin_unlock_irqrestore(&leak_lock, flags);
...@@ -2378,11 +2377,6 @@ static int extent_write_cache_pages(struct extent_io_tree *tree, ...@@ -2378,11 +2377,6 @@ static int extent_write_cache_pages(struct extent_io_tree *tree,
int scanned = 0; int scanned = 0;
int range_whole = 0; int range_whole = 0;
if (wbc->nonblocking && bdi_write_congested(bdi)) {
wbc->encountered_congestion = 1;
return 0;
}
pagevec_init(&pvec, 0); pagevec_init(&pvec, 0);
if (wbc->range_cyclic) { if (wbc->range_cyclic) {
index = mapping->writeback_index; /* Start from prev offset */ index = mapping->writeback_index; /* Start from prev offset */
...@@ -2855,6 +2849,98 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock, ...@@ -2855,6 +2849,98 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
return sector; return sector;
} }
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len, get_extent_t *get_extent)
{
int ret;
u64 off = start;
u64 max = start + len;
u32 flags = 0;
u64 disko = 0;
struct extent_map *em = NULL;
int end = 0;
u64 em_start = 0, em_len = 0;
unsigned long emflags;
ret = 0;
if (len == 0)
return -EINVAL;
lock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
GFP_NOFS);
em = get_extent(inode, NULL, 0, off, max - off, 0);
if (!em)
goto out;
if (IS_ERR(em)) {
ret = PTR_ERR(em);
goto out;
}
while (!end) {
off = em->start + em->len;
if (off >= max)
end = 1;
em_start = em->start;
em_len = em->len;
disko = 0;
flags = 0;
switch (em->block_start) {
case EXTENT_MAP_LAST_BYTE:
end = 1;
flags |= FIEMAP_EXTENT_LAST;
break;
case EXTENT_MAP_HOLE:
flags |= FIEMAP_EXTENT_UNWRITTEN;
break;
case EXTENT_MAP_INLINE:
flags |= (FIEMAP_EXTENT_DATA_INLINE |
FIEMAP_EXTENT_NOT_ALIGNED);
break;
case EXTENT_MAP_DELALLOC:
flags |= (FIEMAP_EXTENT_DELALLOC |
FIEMAP_EXTENT_UNKNOWN);
break;
default:
disko = em->block_start;
break;
}
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
flags |= FIEMAP_EXTENT_ENCODED;
emflags = em->flags;
free_extent_map(em);
em = NULL;
if (!end) {
em = get_extent(inode, NULL, 0, off, max - off, 0);
if (!em)
goto out;
if (IS_ERR(em)) {
ret = PTR_ERR(em);
goto out;
}
emflags = em->flags;
}
if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) {
flags |= FIEMAP_EXTENT_LAST;
end = 1;
}
ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
em_len, flags);
if (ret)
goto out_free;
}
out_free:
free_extent_map(em);
out:
unlock_extent(&BTRFS_I(inode)->io_tree, start, start + len,
GFP_NOFS);
return ret;
}
static inline struct page *extent_buffer_page(struct extent_buffer *eb, static inline struct page *extent_buffer_page(struct extent_buffer *eb,
unsigned long i) unsigned long i)
{ {
...@@ -2892,15 +2978,17 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, ...@@ -2892,15 +2978,17 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
gfp_t mask) gfp_t mask)
{ {
struct extent_buffer *eb = NULL; struct extent_buffer *eb = NULL;
#ifdef LEAK_DEBUG #if LEAK_DEBUG
unsigned long flags; unsigned long flags;
#endif #endif
eb = kmem_cache_zalloc(extent_buffer_cache, mask); eb = kmem_cache_zalloc(extent_buffer_cache, mask);
eb->start = start; eb->start = start;
eb->len = len; eb->len = len;
mutex_init(&eb->mutex); spin_lock_init(&eb->lock);
#ifdef LEAK_DEBUG init_waitqueue_head(&eb->lock_wq);
#if LEAK_DEBUG
spin_lock_irqsave(&leak_lock, flags); spin_lock_irqsave(&leak_lock, flags);
list_add(&eb->leak_list, &buffers); list_add(&eb->leak_list, &buffers);
spin_unlock_irqrestore(&leak_lock, flags); spin_unlock_irqrestore(&leak_lock, flags);
...@@ -2912,7 +3000,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, ...@@ -2912,7 +3000,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
static void __free_extent_buffer(struct extent_buffer *eb) static void __free_extent_buffer(struct extent_buffer *eb)
{ {
#ifdef LEAK_DEBUG #if LEAK_DEBUG
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&leak_lock, flags); spin_lock_irqsave(&leak_lock, flags);
list_del(&eb->leak_list); list_del(&eb->leak_list);
...@@ -2980,8 +3068,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, ...@@ -2980,8 +3068,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
unlock_page(p); unlock_page(p);
} }
if (uptodate) if (uptodate)
eb->flags |= EXTENT_UPTODATE; set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
eb->flags |= EXTENT_BUFFER_FILLED;
spin_lock(&tree->buffer_lock); spin_lock(&tree->buffer_lock);
exists = buffer_tree_insert(tree, start, &eb->rb_node); exists = buffer_tree_insert(tree, start, &eb->rb_node);
...@@ -3135,7 +3222,7 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree, ...@@ -3135,7 +3222,7 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
unsigned long num_pages; unsigned long num_pages;
num_pages = num_extent_pages(eb->start, eb->len); num_pages = num_extent_pages(eb->start, eb->len);
eb->flags &= ~EXTENT_UPTODATE; clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1, clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
GFP_NOFS); GFP_NOFS);
...@@ -3206,7 +3293,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree, ...@@ -3206,7 +3293,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree,
struct page *page; struct page *page;
int pg_uptodate = 1; int pg_uptodate = 1;
if (eb->flags & EXTENT_UPTODATE) if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
return 1; return 1;
ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1, ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
...@@ -3242,7 +3329,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, ...@@ -3242,7 +3329,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
struct bio *bio = NULL; struct bio *bio = NULL;
unsigned long bio_flags = 0; unsigned long bio_flags = 0;
if (eb->flags & EXTENT_UPTODATE) if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
return 0; return 0;
if (test_range_bit(tree, eb->start, eb->start + eb->len - 1, if (test_range_bit(tree, eb->start, eb->start + eb->len - 1,
...@@ -3273,7 +3360,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, ...@@ -3273,7 +3360,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
} }
if (all_uptodate) { if (all_uptodate) {
if (start_i == 0) if (start_i == 0)
eb->flags |= EXTENT_UPTODATE; set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
goto unlock_exit; goto unlock_exit;
} }
...@@ -3309,7 +3396,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, ...@@ -3309,7 +3396,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
} }
if (!ret) if (!ret)
eb->flags |= EXTENT_UPTODATE; set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
return ret; return ret;
unlock_exit: unlock_exit:
...@@ -3406,7 +3493,6 @@ int map_extent_buffer(struct extent_buffer *eb, unsigned long start, ...@@ -3406,7 +3493,6 @@ int map_extent_buffer(struct extent_buffer *eb, unsigned long start,
unmap_extent_buffer(eb, eb->map_token, km); unmap_extent_buffer(eb, eb->map_token, km);
eb->map_token = NULL; eb->map_token = NULL;
save = 1; save = 1;
WARN_ON(!mutex_is_locked(&eb->mutex));
} }
err = map_private_extent_buffer(eb, start, min_len, token, map, err = map_private_extent_buffer(eb, start, min_len, token, map,
map_start, map_len, km); map_start, map_len, km);
......
...@@ -22,6 +22,10 @@ ...@@ -22,6 +22,10 @@
/* flags for bio submission */ /* flags for bio submission */
#define EXTENT_BIO_COMPRESSED 1 #define EXTENT_BIO_COMPRESSED 1
/* these are bit numbers for test/set bit */
#define EXTENT_BUFFER_UPTODATE 0
#define EXTENT_BUFFER_BLOCKING 1
/* /*
* page->private values. Every page that is controlled by the extent * page->private values. Every page that is controlled by the extent
* map has page->private set to one. * map has page->private set to one.
...@@ -95,11 +99,19 @@ struct extent_buffer { ...@@ -95,11 +99,19 @@ struct extent_buffer {
unsigned long map_start; unsigned long map_start;
unsigned long map_len; unsigned long map_len;
struct page *first_page; struct page *first_page;
unsigned long bflags;
atomic_t refs; atomic_t refs;
int flags;
struct list_head leak_list; struct list_head leak_list;
struct rb_node rb_node; struct rb_node rb_node;
struct mutex mutex;
/* the spinlock is used to protect most operations */
spinlock_t lock;
/*
* when we keep the lock held while blocking, waiters go onto
* the wq
*/
wait_queue_head_t lock_wq;
}; };
struct extent_map_tree; struct extent_map_tree;
...@@ -193,6 +205,8 @@ int extent_commit_write(struct extent_io_tree *tree, ...@@ -193,6 +205,8 @@ int extent_commit_write(struct extent_io_tree *tree,
unsigned from, unsigned to); unsigned from, unsigned to);
sector_t extent_bmap(struct address_space *mapping, sector_t iblock, sector_t extent_bmap(struct address_space *mapping, sector_t iblock,
get_extent_t *get_extent); get_extent_t *get_extent);
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len, get_extent_t *get_extent);
int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end); int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end);
int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/version.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include "extent_map.h" #include "extent_map.h"
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/statfs.h> #include <linux/statfs.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/version.h>
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
#include "transaction.h" #include "transaction.h"
...@@ -1215,10 +1214,10 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) ...@@ -1215,10 +1214,10 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
} }
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
root->fs_info->tree_log_batch++; root->log_batch++;
filemap_fdatawrite(inode->i_mapping); filemap_fdatawrite(inode->i_mapping);
btrfs_wait_ordered_range(inode, 0, (u64)-1); btrfs_wait_ordered_range(inode, 0, (u64)-1);
root->fs_info->tree_log_batch++; root->log_batch++;
/* /*
* ok we haven't committed the transaction yet, lets do a commit * ok we haven't committed the transaction yet, lets do a commit
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include <linux/statfs.h> #include <linux/statfs.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/bit_spinlock.h> #include <linux/bit_spinlock.h>
#include <linux/version.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/posix_acl.h> #include <linux/posix_acl.h>
#include <linux/falloc.h> #include <linux/falloc.h>
...@@ -51,6 +50,7 @@ ...@@ -51,6 +50,7 @@
#include "tree-log.h" #include "tree-log.h"
#include "ref-cache.h" #include "ref-cache.h"
#include "compression.h" #include "compression.h"
#include "locking.h"
struct btrfs_iget_args { struct btrfs_iget_args {
u64 ino; u64 ino;
...@@ -91,6 +91,16 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -91,6 +91,16 @@ static noinline int cow_file_range(struct inode *inode,
u64 start, u64 end, int *page_started, u64 start, u64 end, int *page_started,
unsigned long *nr_written, int unlock); unsigned long *nr_written, int unlock);
static int btrfs_init_inode_security(struct inode *inode, struct inode *dir)
{
int err;
err = btrfs_init_acl(inode, dir);
if (!err)
err = btrfs_xattr_security_init(inode, dir);
return err;
}
/* /*
* a very lame attempt at stopping writes when the FS is 85% full. There * a very lame attempt at stopping writes when the FS is 85% full. There
* are countless ways this is incorrect, but it is better than nothing. * are countless ways this is incorrect, but it is better than nothing.
...@@ -350,6 +360,19 @@ static noinline int compress_file_range(struct inode *inode, ...@@ -350,6 +360,19 @@ static noinline int compress_file_range(struct inode *inode,
nr_pages = (end >> PAGE_CACHE_SHIFT) - (start >> PAGE_CACHE_SHIFT) + 1; nr_pages = (end >> PAGE_CACHE_SHIFT) - (start >> PAGE_CACHE_SHIFT) + 1;
nr_pages = min(nr_pages, (128 * 1024UL) / PAGE_CACHE_SIZE); nr_pages = min(nr_pages, (128 * 1024UL) / PAGE_CACHE_SIZE);
/*
* we don't want to send crud past the end of i_size through
* compression, that's just a waste of CPU time. So, if the
* end of the file is before the start of our current
* requested range of bytes, we bail out to the uncompressed
* cleanup code that can deal with all of this.
*
* It isn't really the fastest way to fix things, but this is a
* very uncommon corner.
*/
if (actual_end <= start)
goto cleanup_and_bail_uncompressed;
total_compressed = actual_end - start; total_compressed = actual_end - start;
/* we want to make sure that amount of ram required to uncompress /* we want to make sure that amount of ram required to uncompress
...@@ -494,6 +517,7 @@ static noinline int compress_file_range(struct inode *inode, ...@@ -494,6 +517,7 @@ static noinline int compress_file_range(struct inode *inode,
goto again; goto again;
} }
} else { } else {
cleanup_and_bail_uncompressed:
/* /*
* No compression, but we still need to write the pages in * No compression, but we still need to write the pages in
* the file we've been given so far. redirty the locked * the file we've been given so far. redirty the locked
...@@ -1324,12 +1348,11 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, ...@@ -1324,12 +1348,11 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
struct inode *inode, u64 file_offset, struct inode *inode, u64 file_offset,
struct list_head *list) struct list_head *list)
{ {
struct list_head *cur;
struct btrfs_ordered_sum *sum; struct btrfs_ordered_sum *sum;
btrfs_set_trans_block_group(trans, inode); btrfs_set_trans_block_group(trans, inode);
list_for_each(cur, list) {
sum = list_entry(cur, struct btrfs_ordered_sum, list); list_for_each_entry(sum, list, list) {
btrfs_csum_file_blocks(trans, btrfs_csum_file_blocks(trans,
BTRFS_I(inode)->root->fs_info->csum_root, sum); BTRFS_I(inode)->root->fs_info->csum_root, sum);
} }
...@@ -2013,6 +2036,7 @@ void btrfs_read_locked_inode(struct inode *inode) ...@@ -2013,6 +2036,7 @@ void btrfs_read_locked_inode(struct inode *inode)
BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item); BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
alloc_group_block = btrfs_inode_block_group(leaf, inode_item); alloc_group_block = btrfs_inode_block_group(leaf, inode_item);
BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0, BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0,
alloc_group_block, 0); alloc_group_block, 0);
btrfs_free_path(path); btrfs_free_path(path);
...@@ -2039,6 +2063,7 @@ void btrfs_read_locked_inode(struct inode *inode) ...@@ -2039,6 +2063,7 @@ void btrfs_read_locked_inode(struct inode *inode)
inode->i_mapping->backing_dev_info = &root->fs_info->bdi; inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
break; break;
default: default:
inode->i_op = &btrfs_special_inode_operations;
init_special_inode(inode, inode->i_mode, rdev); init_special_inode(inode, inode->i_mode, rdev);
break; break;
} }
...@@ -2108,6 +2133,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, ...@@ -2108,6 +2133,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
goto failed; goto failed;
} }
btrfs_unlock_up_safe(path, 1);
leaf = path->nodes[0]; leaf = path->nodes[0];
inode_item = btrfs_item_ptr(leaf, path->slots[0], inode_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_inode_item); struct btrfs_inode_item);
...@@ -2429,6 +2455,8 @@ static noinline int drop_csum_leaves(struct btrfs_trans_handle *trans, ...@@ -2429,6 +2455,8 @@ static noinline int drop_csum_leaves(struct btrfs_trans_handle *trans,
ref->generation = leaf_gen; ref->generation = leaf_gen;
ref->nritems = 0; ref->nritems = 0;
btrfs_sort_leaf_ref(ref);
ret = btrfs_add_leaf_ref(root, ref, 0); ret = btrfs_add_leaf_ref(root, ref, 0);
WARN_ON(ret); WARN_ON(ret);
btrfs_free_leaf_ref(root, ref); btrfs_free_leaf_ref(root, ref);
...@@ -2476,7 +2504,7 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -2476,7 +2504,7 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_key key; struct btrfs_key key;
struct btrfs_key found_key; struct btrfs_key found_key;
u32 found_type; u32 found_type = (u8)-1;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_file_extent_item *fi; struct btrfs_file_extent_item *fi;
u64 extent_start = 0; u64 extent_start = 0;
...@@ -2663,6 +2691,8 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -2663,6 +2691,8 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
if (pending_del_nr) if (pending_del_nr)
goto del_pending; goto del_pending;
btrfs_release_path(root, path); btrfs_release_path(root, path);
if (found_type == BTRFS_INODE_ITEM_KEY)
break;
goto search_again; goto search_again;
} }
...@@ -2679,6 +2709,8 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -2679,6 +2709,8 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
BUG_ON(ret); BUG_ON(ret);
pending_del_nr = 0; pending_del_nr = 0;
btrfs_release_path(root, path); btrfs_release_path(root, path);
if (found_type == BTRFS_INODE_ITEM_KEY)
break;
goto search_again; goto search_again;
} }
} }
...@@ -3265,7 +3297,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, ...@@ -3265,7 +3297,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
/* Reached end of directory/root. Bump pos past the last item. */ /* Reached end of directory/root. Bump pos past the last item. */
if (key_type == BTRFS_DIR_INDEX_KEY) if (key_type == BTRFS_DIR_INDEX_KEY)
filp->f_pos = INT_LIMIT(typeof(filp->f_pos)); filp->f_pos = INT_LIMIT(off_t);
else else
filp->f_pos++; filp->f_pos++;
nopos: nopos:
...@@ -3458,7 +3490,14 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -3458,7 +3490,14 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
root->highest_inode = objectid; root->highest_inode = objectid;
inode->i_uid = current_fsuid(); inode->i_uid = current_fsuid();
if (dir && (dir->i_mode & S_ISGID)) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
inode->i_gid = current_fsgid(); inode->i_gid = current_fsgid();
inode->i_mode = mode; inode->i_mode = mode;
inode->i_ino = objectid; inode->i_ino = objectid;
inode_set_bytes(inode, 0); inode_set_bytes(inode, 0);
...@@ -3586,7 +3625,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -3586,7 +3625,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_unlock; goto out_unlock;
err = btrfs_init_acl(inode, dir); err = btrfs_init_inode_security(inode, dir);
if (err) { if (err) {
drop_inode = 1; drop_inode = 1;
goto out_unlock; goto out_unlock;
...@@ -3649,7 +3688,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, ...@@ -3649,7 +3688,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_unlock; goto out_unlock;
err = btrfs_init_acl(inode, dir); err = btrfs_init_inode_security(inode, dir);
if (err) { if (err) {
drop_inode = 1; drop_inode = 1;
goto out_unlock; goto out_unlock;
...@@ -3772,7 +3811,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -3772,7 +3811,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
drop_on_err = 1; drop_on_err = 1;
err = btrfs_init_acl(inode, dir); err = btrfs_init_inode_security(inode, dir);
if (err) if (err)
goto out_fail; goto out_fail;
...@@ -4158,9 +4197,10 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, ...@@ -4158,9 +4197,10 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
return -EINVAL; return -EINVAL;
} }
static sector_t btrfs_bmap(struct address_space *mapping, sector_t iblock) static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len)
{ {
return extent_bmap(mapping, iblock, btrfs_get_extent); return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent);
} }
int btrfs_readpage(struct file *file, struct page *page) int btrfs_readpage(struct file *file, struct page *page)
...@@ -4733,7 +4773,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -4733,7 +4773,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_unlock; goto out_unlock;
err = btrfs_init_acl(inode, dir); err = btrfs_init_inode_security(inode, dir);
if (err) { if (err) {
drop_inode = 1; drop_inode = 1;
goto out_unlock; goto out_unlock;
...@@ -4987,13 +5027,24 @@ static struct extent_io_ops btrfs_extent_io_ops = { ...@@ -4987,13 +5027,24 @@ static struct extent_io_ops btrfs_extent_io_ops = {
.clear_bit_hook = btrfs_clear_bit_hook, .clear_bit_hook = btrfs_clear_bit_hook,
}; };
/*
* btrfs doesn't support the bmap operation because swapfiles
* use bmap to make a mapping of extents in the file. They assume
* these extents won't change over the life of the file and they
* use the bmap result to do IO directly to the drive.
*
* the btrfs bmap call would return logical addresses that aren't
* suitable for IO and they also will change frequently as COW
* operations happen. So, swapfile + btrfs == corruption.
*
* For now we're avoiding this by dropping bmap.
*/
static struct address_space_operations btrfs_aops = { static struct address_space_operations btrfs_aops = {
.readpage = btrfs_readpage, .readpage = btrfs_readpage,
.writepage = btrfs_writepage, .writepage = btrfs_writepage,
.writepages = btrfs_writepages, .writepages = btrfs_writepages,
.readpages = btrfs_readpages, .readpages = btrfs_readpages,
.sync_page = block_sync_page, .sync_page = block_sync_page,
.bmap = btrfs_bmap,
.direct_IO = btrfs_direct_IO, .direct_IO = btrfs_direct_IO,
.invalidatepage = btrfs_invalidatepage, .invalidatepage = btrfs_invalidatepage,
.releasepage = btrfs_releasepage, .releasepage = btrfs_releasepage,
...@@ -5017,6 +5068,7 @@ static struct inode_operations btrfs_file_inode_operations = { ...@@ -5017,6 +5068,7 @@ static struct inode_operations btrfs_file_inode_operations = {
.removexattr = btrfs_removexattr, .removexattr = btrfs_removexattr,
.permission = btrfs_permission, .permission = btrfs_permission,
.fallocate = btrfs_fallocate, .fallocate = btrfs_fallocate,
.fiemap = btrfs_fiemap,
}; };
static struct inode_operations btrfs_special_inode_operations = { static struct inode_operations btrfs_special_inode_operations = {
.getattr = btrfs_getattr, .getattr = btrfs_getattr,
...@@ -5032,4 +5084,8 @@ static struct inode_operations btrfs_symlink_inode_operations = { ...@@ -5032,4 +5084,8 @@ static struct inode_operations btrfs_symlink_inode_operations = {
.follow_link = page_follow_link_light, .follow_link = page_follow_link_light,
.put_link = page_put_link, .put_link = page_put_link,
.permission = btrfs_permission, .permission = btrfs_permission,
.setxattr = btrfs_setxattr,
.getxattr = btrfs_getxattr,
.listxattr = btrfs_listxattr,
.removexattr = btrfs_removexattr,
}; };
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/bit_spinlock.h> #include <linux/bit_spinlock.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/version.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include "compat.h" #include "compat.h"
......
...@@ -26,45 +26,215 @@ ...@@ -26,45 +26,215 @@
#include "locking.h" #include "locking.h"
/* /*
* locks the per buffer mutex in an extent buffer. This uses adaptive locks * btrfs_header_level() isn't free, so don't call it when lockdep isn't
* and the spin is not tuned very extensively. The spinning does make a big * on
* difference in almost every workload, but spinning for the right amount of */
* time needs some help. #ifdef CONFIG_DEBUG_LOCK_ALLOC
static inline void spin_nested(struct extent_buffer *eb)
{
spin_lock_nested(&eb->lock, BTRFS_MAX_LEVEL - btrfs_header_level(eb));
}
#else
static inline void spin_nested(struct extent_buffer *eb)
{
spin_lock(&eb->lock);
}
#endif
/*
* Setting a lock to blocking will drop the spinlock and set the
* flag that forces other procs who want the lock to wait. After
* this you can safely schedule with the lock held.
*/
void btrfs_set_lock_blocking(struct extent_buffer *eb)
{
if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) {
set_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags);
spin_unlock(&eb->lock);
}
/* exit with the spin lock released and the bit set */
}
/*
* clearing the blocking flag will take the spinlock again.
* After this you can't safely schedule
*/
void btrfs_clear_lock_blocking(struct extent_buffer *eb)
{
if (test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) {
spin_nested(eb);
clear_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags);
smp_mb__after_clear_bit();
}
/* exit with the spin lock held */
}
/*
* unfortunately, many of the places that currently set a lock to blocking
* don't end up blocking for every long, and often they don't block
* at all. For a dbench 50 run, if we don't spin one the blocking bit
* at all, the context switch rate can jump up to 400,000/sec or more.
* *
* In general, we want to spin as long as the lock holder is doing btree * So, we're still stuck with this crummy spin on the blocking bit,
* searches, and we should give up if they are in more expensive code. * at least until the most common causes of the short blocks
* can be dealt with.
*/ */
static int btrfs_spin_on_block(struct extent_buffer *eb)
{
int i;
for (i = 0; i < 512; i++) {
cpu_relax();
if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
return 1;
if (need_resched())
break;
}
return 0;
}
int btrfs_tree_lock(struct extent_buffer *eb) /*
* This is somewhat different from trylock. It will take the
* spinlock but if it finds the lock is set to blocking, it will
* return without the lock held.
*
* returns 1 if it was able to take the lock and zero otherwise
*
* After this call, scheduling is not safe without first calling
* btrfs_set_lock_blocking()
*/
int btrfs_try_spin_lock(struct extent_buffer *eb)
{ {
int i; int i;
if (mutex_trylock(&eb->mutex)) spin_nested(eb);
if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
return 1;
spin_unlock(&eb->lock);
/* spin for a bit on the BLOCKING flag */
for (i = 0; i < 2; i++) {
if (!btrfs_spin_on_block(eb))
break;
spin_nested(eb);
if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
return 1;
spin_unlock(&eb->lock);
}
return 0; return 0;
for (i = 0; i < 512; i++) { }
cpu_relax();
if (mutex_trylock(&eb->mutex)) /*
* the autoremove wake function will return 0 if it tried to wake up
* a process that was already awake, which means that process won't
* count as an exclusive wakeup. The waitq code will continue waking
* procs until it finds one that was actually sleeping.
*
* For btrfs, this isn't quite what we want. We want a single proc
* to be notified that the lock is ready for taking. If that proc
* already happen to be awake, great, it will loop around and try for
* the lock.
*
* So, btrfs_wake_function always returns 1, even when the proc that we
* tried to wake up was already awake.
*/
static int btrfs_wake_function(wait_queue_t *wait, unsigned mode,
int sync, void *key)
{
autoremove_wake_function(wait, mode, sync, key);
return 1;
}
/*
* returns with the extent buffer spinlocked.
*
* This will spin and/or wait as required to take the lock, and then
* return with the spinlock held.
*
* After this call, scheduling is not safe without first calling
* btrfs_set_lock_blocking()
*/
int btrfs_tree_lock(struct extent_buffer *eb)
{
DEFINE_WAIT(wait);
wait.func = btrfs_wake_function;
while(1) {
spin_nested(eb);
/* nobody is blocking, exit with the spinlock held */
if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
return 0; return 0;
/*
* we have the spinlock, but the real owner is blocking.
* wait for them
*/
spin_unlock(&eb->lock);
/*
* spin for a bit, and if the blocking flag goes away,
* loop around
*/
if (btrfs_spin_on_block(eb))
continue;
prepare_to_wait_exclusive(&eb->lock_wq, &wait,
TASK_UNINTERRUPTIBLE);
if (test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
schedule();
finish_wait(&eb->lock_wq, &wait);
} }
cpu_relax();
mutex_lock_nested(&eb->mutex, BTRFS_MAX_LEVEL - btrfs_header_level(eb));
return 0; return 0;
} }
/*
* Very quick trylock, this does not spin or schedule. It returns
* 1 with the spinlock held if it was able to take the lock, or it
* returns zero if it was unable to take the lock.
*
* After this call, scheduling is not safe without first calling
* btrfs_set_lock_blocking()
*/
int btrfs_try_tree_lock(struct extent_buffer *eb) int btrfs_try_tree_lock(struct extent_buffer *eb)
{ {
return mutex_trylock(&eb->mutex); if (spin_trylock(&eb->lock)) {
if (test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) {
/*
* we've got the spinlock, but the real owner is
* blocking. Drop the spinlock and return failure
*/
spin_unlock(&eb->lock);
return 0;
}
return 1;
}
/* someone else has the spinlock giveup */
return 0;
} }
int btrfs_tree_unlock(struct extent_buffer *eb) int btrfs_tree_unlock(struct extent_buffer *eb)
{ {
mutex_unlock(&eb->mutex); /*
* if we were a blocking owner, we don't have the spinlock held
* just clear the bit and look for waiters
*/
if (test_and_clear_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
smp_mb__after_clear_bit();
else
spin_unlock(&eb->lock);
if (waitqueue_active(&eb->lock_wq))
wake_up(&eb->lock_wq);
return 0; return 0;
} }
int btrfs_tree_locked(struct extent_buffer *eb) int btrfs_tree_locked(struct extent_buffer *eb)
{ {
return mutex_is_locked(&eb->mutex); return test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags) ||
spin_is_locked(&eb->lock);
} }
/* /*
...@@ -75,12 +245,14 @@ int btrfs_path_lock_waiting(struct btrfs_path *path, int level) ...@@ -75,12 +245,14 @@ int btrfs_path_lock_waiting(struct btrfs_path *path, int level)
{ {
int i; int i;
struct extent_buffer *eb; struct extent_buffer *eb;
for (i = level; i <= level + 1 && i < BTRFS_MAX_LEVEL; i++) { for (i = level; i <= level + 1 && i < BTRFS_MAX_LEVEL; i++) {
eb = path->nodes[i]; eb = path->nodes[i];
if (!eb) if (!eb)
break; break;
smp_mb(); smp_mb();
if (!list_empty(&eb->mutex.wait_list)) if (spin_is_contended(&eb->lock) ||
waitqueue_active(&eb->lock_wq))
return 1; return 1;
} }
return 0; return 0;
......
...@@ -22,6 +22,12 @@ ...@@ -22,6 +22,12 @@
int btrfs_tree_lock(struct extent_buffer *eb); int btrfs_tree_lock(struct extent_buffer *eb);
int btrfs_tree_unlock(struct extent_buffer *eb); int btrfs_tree_unlock(struct extent_buffer *eb);
int btrfs_tree_locked(struct extent_buffer *eb); int btrfs_tree_locked(struct extent_buffer *eb);
int btrfs_try_tree_lock(struct extent_buffer *eb); int btrfs_try_tree_lock(struct extent_buffer *eb);
int btrfs_try_spin_lock(struct extent_buffer *eb);
int btrfs_path_lock_waiting(struct btrfs_path *path, int level); int btrfs_path_lock_waiting(struct btrfs_path *path, int level);
void btrfs_set_lock_blocking(struct extent_buffer *eb);
void btrfs_clear_lock_blocking(struct extent_buffer *eb);
#endif #endif
...@@ -613,7 +613,6 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, ...@@ -613,7 +613,6 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
struct btrfs_sector_sum *sector_sums; struct btrfs_sector_sum *sector_sums;
struct btrfs_ordered_extent *ordered; struct btrfs_ordered_extent *ordered;
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree; struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
struct list_head *cur;
unsigned long num_sectors; unsigned long num_sectors;
unsigned long i; unsigned long i;
u32 sectorsize = BTRFS_I(inode)->root->sectorsize; u32 sectorsize = BTRFS_I(inode)->root->sectorsize;
...@@ -624,8 +623,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, ...@@ -624,8 +623,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
return 1; return 1;
mutex_lock(&tree->mutex); mutex_lock(&tree->mutex);
list_for_each_prev(cur, &ordered->list) { list_for_each_entry_reverse(ordered_sum, &ordered->list, list) {
ordered_sum = list_entry(cur, struct btrfs_ordered_sum, list);
if (disk_bytenr >= ordered_sum->bytenr) { if (disk_bytenr >= ordered_sum->bytenr) {
num_sectors = ordered_sum->len / sectorsize; num_sectors = ordered_sum->len / sectorsize;
sector_sums = ordered_sum->sums; sector_sums = ordered_sum->sums;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
*/ */
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sort.h>
#include "ctree.h" #include "ctree.h"
#include "ref-cache.h" #include "ref-cache.h"
#include "transaction.h" #include "transaction.h"
......
...@@ -73,5 +73,4 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref, ...@@ -73,5 +73,4 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref,
int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen, int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen,
int shared); int shared);
int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
#endif #endif
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/version.h>
#include <linux/magic.h> #include <linux/magic.h>
#include "compat.h" #include "compat.h"
#include "ctree.h" #include "ctree.h"
...@@ -583,17 +582,18 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, ...@@ -583,17 +582,18 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
struct btrfs_ioctl_vol_args *vol; struct btrfs_ioctl_vol_args *vol;
struct btrfs_fs_devices *fs_devices; struct btrfs_fs_devices *fs_devices;
int ret = -ENOTTY; int ret = -ENOTTY;
int len;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
vol = kmalloc(sizeof(*vol), GFP_KERNEL); vol = kmalloc(sizeof(*vol), GFP_KERNEL);
if (!vol)
return -ENOMEM;
if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) { if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) {
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
} }
len = strnlen(vol->name, BTRFS_PATH_NAME_MAX);
switch (cmd) { switch (cmd) {
case BTRFS_IOC_SCAN_DEV: case BTRFS_IOC_SCAN_DEV:
......
...@@ -852,11 +852,9 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, ...@@ -852,11 +852,9 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
{ {
struct btrfs_pending_snapshot *pending; struct btrfs_pending_snapshot *pending;
struct list_head *head = &trans->transaction->pending_snapshots; struct list_head *head = &trans->transaction->pending_snapshots;
struct list_head *cur;
int ret; int ret;
list_for_each(cur, head) { list_for_each_entry(pending, head, list) {
pending = list_entry(cur, struct btrfs_pending_snapshot, list);
ret = create_pending_snapshot(trans, fs_info, pending); ret = create_pending_snapshot(trans, fs_info, pending);
BUG_ON(ret); BUG_ON(ret);
} }
......
...@@ -74,6 +74,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, ...@@ -74,6 +74,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
u32 nritems; u32 nritems;
root_node = btrfs_lock_root_node(root); root_node = btrfs_lock_root_node(root);
btrfs_set_lock_blocking(root_node);
nritems = btrfs_header_nritems(root_node); nritems = btrfs_header_nritems(root_node);
root->defrag_max.objectid = 0; root->defrag_max.objectid = 0;
/* from above we know this is not a leaf */ /* from above we know this is not a leaf */
......
This diff is collapsed.
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/version.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "compat.h" #include "compat.h"
#include "ctree.h" #include "ctree.h"
...@@ -104,10 +103,8 @@ static noinline struct btrfs_device *__find_device(struct list_head *head, ...@@ -104,10 +103,8 @@ static noinline struct btrfs_device *__find_device(struct list_head *head,
u64 devid, u8 *uuid) u64 devid, u8 *uuid)
{ {
struct btrfs_device *dev; struct btrfs_device *dev;
struct list_head *cur;
list_for_each(cur, head) { list_for_each_entry(dev, head, dev_list) {
dev = list_entry(cur, struct btrfs_device, dev_list);
if (dev->devid == devid && if (dev->devid == devid &&
(!uuid || !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE))) { (!uuid || !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE))) {
return dev; return dev;
...@@ -118,11 +115,9 @@ static noinline struct btrfs_device *__find_device(struct list_head *head, ...@@ -118,11 +115,9 @@ static noinline struct btrfs_device *__find_device(struct list_head *head,
static noinline struct btrfs_fs_devices *find_fsid(u8 *fsid) static noinline struct btrfs_fs_devices *find_fsid(u8 *fsid)
{ {
struct list_head *cur;
struct btrfs_fs_devices *fs_devices; struct btrfs_fs_devices *fs_devices;
list_for_each(cur, &fs_uuids) { list_for_each_entry(fs_devices, &fs_uuids, list) {
fs_devices = list_entry(cur, struct btrfs_fs_devices, list);
if (memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE) == 0) if (memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE) == 0)
return fs_devices; return fs_devices;
} }
...@@ -159,6 +154,7 @@ static noinline int run_scheduled_bios(struct btrfs_device *device) ...@@ -159,6 +154,7 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
loop: loop:
spin_lock(&device->io_lock); spin_lock(&device->io_lock);
loop_lock:
/* take all the bios off the list at once and process them /* take all the bios off the list at once and process them
* later on (without the lock held). But, remember the * later on (without the lock held). But, remember the
* tail and other pointers so the bios can be properly reinserted * tail and other pointers so the bios can be properly reinserted
...@@ -208,7 +204,7 @@ static noinline int run_scheduled_bios(struct btrfs_device *device) ...@@ -208,7 +204,7 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
* is now congested. Back off and let other work structs * is now congested. Back off and let other work structs
* run instead * run instead
*/ */
if (pending && bdi_write_congested(bdi) && if (pending && bdi_write_congested(bdi) && num_run > 16 &&
fs_info->fs_devices->open_devices > 1) { fs_info->fs_devices->open_devices > 1) {
struct bio *old_head; struct bio *old_head;
...@@ -220,7 +216,8 @@ static noinline int run_scheduled_bios(struct btrfs_device *device) ...@@ -220,7 +216,8 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
tail->bi_next = old_head; tail->bi_next = old_head;
else else
device->pending_bio_tail = tail; device->pending_bio_tail = tail;
device->running_pending = 0;
device->running_pending = 1;
spin_unlock(&device->io_lock); spin_unlock(&device->io_lock);
btrfs_requeue_work(&device->work); btrfs_requeue_work(&device->work);
...@@ -229,6 +226,11 @@ static noinline int run_scheduled_bios(struct btrfs_device *device) ...@@ -229,6 +226,11 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
} }
if (again) if (again)
goto loop; goto loop;
spin_lock(&device->io_lock);
if (device->pending_bios)
goto loop_lock;
spin_unlock(&device->io_lock);
done: done:
return 0; return 0;
} }
...@@ -345,14 +347,11 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig) ...@@ -345,14 +347,11 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices) int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
{ {
struct list_head *tmp; struct btrfs_device *device, *next;
struct list_head *cur;
struct btrfs_device *device;
mutex_lock(&uuid_mutex); mutex_lock(&uuid_mutex);
again: again:
list_for_each_safe(cur, tmp, &fs_devices->devices) { list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
device = list_entry(cur, struct btrfs_device, dev_list);
if (device->in_fs_metadata) if (device->in_fs_metadata)
continue; continue;
...@@ -383,14 +382,12 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices) ...@@ -383,14 +382,12 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
{ {
struct list_head *cur;
struct btrfs_device *device; struct btrfs_device *device;
if (--fs_devices->opened > 0) if (--fs_devices->opened > 0)
return 0; return 0;
list_for_each(cur, &fs_devices->devices) { list_for_each_entry(device, &fs_devices->devices, dev_list) {
device = list_entry(cur, struct btrfs_device, dev_list);
if (device->bdev) { if (device->bdev) {
close_bdev_exclusive(device->bdev, device->mode); close_bdev_exclusive(device->bdev, device->mode);
fs_devices->open_devices--; fs_devices->open_devices--;
...@@ -439,7 +436,6 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, ...@@ -439,7 +436,6 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
{ {
struct block_device *bdev; struct block_device *bdev;
struct list_head *head = &fs_devices->devices; struct list_head *head = &fs_devices->devices;
struct list_head *cur;
struct btrfs_device *device; struct btrfs_device *device;
struct block_device *latest_bdev = NULL; struct block_device *latest_bdev = NULL;
struct buffer_head *bh; struct buffer_head *bh;
...@@ -450,8 +446,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, ...@@ -450,8 +446,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
int seeding = 1; int seeding = 1;
int ret = 0; int ret = 0;
list_for_each(cur, head) { list_for_each_entry(device, head, dev_list) {
device = list_entry(cur, struct btrfs_device, dev_list);
if (device->bdev) if (device->bdev)
continue; continue;
if (!device->name) if (!device->name)
...@@ -578,7 +573,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, ...@@ -578,7 +573,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
*(unsigned long long *)disk_super->fsid, *(unsigned long long *)disk_super->fsid,
*(unsigned long long *)(disk_super->fsid + 8)); *(unsigned long long *)(disk_super->fsid + 8));
} }
printk(KERN_INFO "devid %llu transid %llu %s\n", printk(KERN_CONT "devid %llu transid %llu %s\n",
(unsigned long long)devid, (unsigned long long)transid, path); (unsigned long long)devid, (unsigned long long)transid, path);
ret = device_list_add(path, disk_super, devid, fs_devices_ret); ret = device_list_add(path, disk_super, devid, fs_devices_ret);
...@@ -1017,14 +1012,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) ...@@ -1017,14 +1012,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
} }
if (strcmp(device_path, "missing") == 0) { if (strcmp(device_path, "missing") == 0) {
struct list_head *cur;
struct list_head *devices; struct list_head *devices;
struct btrfs_device *tmp; struct btrfs_device *tmp;
device = NULL; device = NULL;
devices = &root->fs_info->fs_devices->devices; devices = &root->fs_info->fs_devices->devices;
list_for_each(cur, devices) { list_for_each_entry(tmp, devices, dev_list) {
tmp = list_entry(cur, struct btrfs_device, dev_list);
if (tmp->in_fs_metadata && !tmp->bdev) { if (tmp->in_fs_metadata && !tmp->bdev) {
device = tmp; device = tmp;
break; break;
...@@ -1280,7 +1273,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ...@@ -1280,7 +1273,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_device *device; struct btrfs_device *device;
struct block_device *bdev; struct block_device *bdev;
struct list_head *cur;
struct list_head *devices; struct list_head *devices;
struct super_block *sb = root->fs_info->sb; struct super_block *sb = root->fs_info->sb;
u64 total_bytes; u64 total_bytes;
...@@ -1304,8 +1296,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ...@@ -1304,8 +1296,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
mutex_lock(&root->fs_info->volume_mutex); mutex_lock(&root->fs_info->volume_mutex);
devices = &root->fs_info->fs_devices->devices; devices = &root->fs_info->fs_devices->devices;
list_for_each(cur, devices) { list_for_each_entry(device, devices, dev_list) {
device = list_entry(cur, struct btrfs_device, dev_list);
if (device->bdev == bdev) { if (device->bdev == bdev) {
ret = -EEXIST; ret = -EEXIST;
goto error; goto error;
...@@ -1704,7 +1695,6 @@ static u64 div_factor(u64 num, int factor) ...@@ -1704,7 +1695,6 @@ static u64 div_factor(u64 num, int factor)
int btrfs_balance(struct btrfs_root *dev_root) int btrfs_balance(struct btrfs_root *dev_root)
{ {
int ret; int ret;
struct list_head *cur;
struct list_head *devices = &dev_root->fs_info->fs_devices->devices; struct list_head *devices = &dev_root->fs_info->fs_devices->devices;
struct btrfs_device *device; struct btrfs_device *device;
u64 old_size; u64 old_size;
...@@ -1723,8 +1713,7 @@ int btrfs_balance(struct btrfs_root *dev_root) ...@@ -1723,8 +1713,7 @@ int btrfs_balance(struct btrfs_root *dev_root)
dev_root = dev_root->fs_info->dev_root; dev_root = dev_root->fs_info->dev_root;
/* step one make some room on all the devices */ /* step one make some room on all the devices */
list_for_each(cur, devices) { list_for_each_entry(device, devices, dev_list) {
device = list_entry(cur, struct btrfs_device, dev_list);
old_size = device->total_bytes; old_size = device->total_bytes;
size_to_free = div_factor(old_size, 1); size_to_free = div_factor(old_size, 1);
size_to_free = min(size_to_free, (u64)1 * 1024 * 1024); size_to_free = min(size_to_free, (u64)1 * 1024 * 1024);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/security.h>
#include "ctree.h" #include "ctree.h"
#include "btrfs_inode.h" #include "btrfs_inode.h"
#include "transaction.h" #include "transaction.h"
...@@ -45,9 +46,12 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name, ...@@ -45,9 +46,12 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
/* lookup the xattr by name */ /* lookup the xattr by name */
di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name, di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name,
strlen(name), 0); strlen(name), 0);
if (!di || IS_ERR(di)) { if (!di) {
ret = -ENODATA; ret = -ENODATA;
goto out; goto out;
} else if (IS_ERR(di)) {
ret = PTR_ERR(di);
goto out;
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
...@@ -62,6 +66,14 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name, ...@@ -62,6 +66,14 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
ret = -ERANGE; ret = -ERANGE;
goto out; goto out;
} }
/*
* The way things are packed into the leaf is like this
* |struct btrfs_dir_item|name|data|
* where name is the xattr name, so security.foo, and data is the
* content of the xattr. data_ptr points to the location in memory
* where the data starts in the in memory leaf
*/
data_ptr = (unsigned long)((char *)(di + 1) + data_ptr = (unsigned long)((char *)(di + 1) +
btrfs_dir_name_len(leaf, di)); btrfs_dir_name_len(leaf, di));
read_extent_buffer(leaf, buffer, data_ptr, read_extent_buffer(leaf, buffer, data_ptr,
...@@ -86,7 +98,7 @@ int __btrfs_setxattr(struct inode *inode, const char *name, ...@@ -86,7 +98,7 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
trans = btrfs_start_transaction(root, 1); trans = btrfs_join_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode); btrfs_set_trans_block_group(trans, inode);
/* first lets see if we already have this xattr */ /* first lets see if we already have this xattr */
...@@ -176,7 +188,6 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -176,7 +188,6 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
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)
goto err; goto err;
ret = 0;
advance = 0; advance = 0;
while (1) { while (1) {
leaf = path->nodes[0]; leaf = path->nodes[0];
...@@ -320,3 +331,34 @@ int btrfs_removexattr(struct dentry *dentry, const char *name) ...@@ -320,3 +331,34 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return __btrfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE); return __btrfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
} }
int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
{
int err;
size_t len;
void *value;
char *suffix;
char *name;
err = security_inode_init_security(inode, dir, &suffix, &value, &len);
if (err) {
if (err == -EOPNOTSUPP)
return 0;
return err;
}
name = kmalloc(XATTR_SECURITY_PREFIX_LEN + strlen(suffix) + 1,
GFP_NOFS);
if (!name) {
err = -ENOMEM;
} else {
strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
err = __btrfs_setxattr(inode, name, value, len, 0);
kfree(name);
}
kfree(suffix);
kfree(value);
return err;
}
...@@ -36,4 +36,6 @@ extern int btrfs_setxattr(struct dentry *dentry, const char *name, ...@@ -36,4 +36,6 @@ extern int btrfs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags); const void *value, size_t size, int flags);
extern int btrfs_removexattr(struct dentry *dentry, const char *name); extern int btrfs_removexattr(struct dentry *dentry, const char *name);
extern int btrfs_xattr_security_init(struct inode *inode, struct inode *dir);
#endif /* __XATTR__ */ #endif /* __XATTR__ */
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