Merge branch 'for-chris' of git://git.kernel.org/pub/scm/linux/kernel/git/arne/btrfs-unstable-arne into inode_numbers

Conflicts:
	fs/btrfs/Makefile
	fs/btrfs/ctree.h
	fs/btrfs/volumes.h

Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
Chris Mason 2011-05-23 06:30:52 -04:00
commit 712673339a
13 changed files with 1649 additions and 13 deletions

View File

@ -7,4 +7,4 @@ 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_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
compression.o delayed-ref.o relocation.o delayed-inode.o
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o

View File

@ -23,6 +23,7 @@
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/fs.h>
#include <linux/rwsem.h>
#include <linux/completion.h>
#include <linux/backing-dev.h>
#include <linux/wait.h>
@ -33,6 +34,7 @@
#include "extent_io.h"
#include "extent_map.h"
#include "async-thread.h"
#include "ioctl.h"
struct btrfs_trans_handle;
struct btrfs_transaction;
@ -193,7 +195,6 @@ struct btrfs_mapping_tree {
struct extent_map_tree map_tree;
};
#define BTRFS_UUID_SIZE 16
struct btrfs_dev_item {
/* the internal btrfs device id */
__le64 devid;
@ -300,7 +301,6 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
sizeof(struct btrfs_stripe) * (num_stripes - 1);
}
#define BTRFS_FSID_SIZE 16
#define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0)
#define BTRFS_HEADER_FLAG_RELOC (1ULL << 1)
@ -516,6 +516,12 @@ struct btrfs_extent_item_v0 {
/* use full backrefs for extent pointers in the block */
#define BTRFS_BLOCK_FLAG_FULL_BACKREF (1ULL << 8)
/*
* this flag is only used internally by scrub and may be changed at any time
* it is only declared here to avoid collisions
*/
#define BTRFS_EXTENT_FLAG_SUPER (1ULL << 48)
struct btrfs_tree_block_info {
struct btrfs_disk_key key;
u8 level;
@ -1083,6 +1089,17 @@ struct btrfs_fs_info {
void *bdev_holder;
/* private scrub information */
struct mutex scrub_lock;
atomic_t scrubs_running;
atomic_t scrub_pause_req;
atomic_t scrubs_paused;
atomic_t scrub_cancel_req;
wait_queue_head_t scrub_pause_wait;
struct rw_semaphore scrub_super_lock;
int scrub_workers_refcnt;
struct btrfs_workers scrub_workers;
/* filesystem state */
u64 fs_state;
@ -2422,8 +2439,11 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
u64 bytenr, int cow);
int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start,
u64 end, struct list_head *list);
int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
u64 isize);
int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
struct list_head *list, int search_commit);
/* inode.c */
/* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */
@ -2577,4 +2597,18 @@ void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
u64 *bytes_to_reserve);
void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending);
/* scrub.c */
int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
struct btrfs_scrub_progress *progress, int readonly);
int btrfs_scrub_pause(struct btrfs_root *root);
int btrfs_scrub_pause_super(struct btrfs_root *root);
int btrfs_scrub_continue(struct btrfs_root *root);
int btrfs_scrub_continue_super(struct btrfs_root *root);
int btrfs_scrub_cancel(struct btrfs_root *root);
int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev);
int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid);
int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
struct btrfs_scrub_progress *progress);
#endif

View File

@ -1654,6 +1654,17 @@ struct btrfs_root *open_ctree(struct super_block *sb,
}
btrfs_init_delayed_root(fs_info->delayed_root);
mutex_init(&fs_info->scrub_lock);
atomic_set(&fs_info->scrubs_running, 0);
atomic_set(&fs_info->scrub_pause_req, 0);
atomic_set(&fs_info->scrubs_paused, 0);
atomic_set(&fs_info->scrub_cancel_req, 0);
init_waitqueue_head(&fs_info->scrub_pause_wait);
init_rwsem(&fs_info->scrub_super_lock);
fs_info->scrub_workers_refcnt = 0;
btrfs_init_workers(&fs_info->scrub_workers, "scrub",
fs_info->thread_pool_size, &fs_info->generic_worker);
sb->s_blocksize = 4096;
sb->s_blocksize_bits = blksize_bits(4096);
sb->s_bdi = &fs_info->bdi;
@ -2488,6 +2499,7 @@ int close_ctree(struct btrfs_root *root)
fs_info->closing = 1;
smp_mb();
btrfs_scrub_cancel(root);
btrfs_put_block_group_cache(fs_info);
/*

View File

@ -267,7 +267,7 @@ int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
}
int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
struct list_head *list)
struct list_head *list, int search_commit)
{
struct btrfs_key key;
struct btrfs_path *path;
@ -284,6 +284,12 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
path = btrfs_alloc_path();
BUG_ON(!path);
if (search_commit) {
path->skip_locking = 1;
path->reada = 2;
path->search_commit_root = 1;
}
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
key.offset = start;
key.type = BTRFS_EXTENT_CSUM_KEY;

View File

@ -1019,7 +1019,7 @@ static noinline int csum_exist_in_range(struct btrfs_root *root,
LIST_HEAD(list);
ret = btrfs_lookup_csums_range(root->fs_info->csum_root, bytenr,
bytenr + num_bytes - 1, &list);
bytenr + num_bytes - 1, &list, 0);
if (ret == 0 && list_empty(&list))
return 0;

View File

@ -1809,6 +1809,75 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
return ret;
}
static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
{
struct btrfs_ioctl_fs_info_args fi_args;
struct btrfs_device *device;
struct btrfs_device *next;
struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
fi_args.num_devices = fs_devices->num_devices;
fi_args.max_id = 0;
memcpy(&fi_args.fsid, root->fs_info->fsid, sizeof(fi_args.fsid));
mutex_lock(&fs_devices->device_list_mutex);
list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
if (device->devid > fi_args.max_id)
fi_args.max_id = device->devid;
}
mutex_unlock(&fs_devices->device_list_mutex);
if (copy_to_user(arg, &fi_args, sizeof(fi_args)))
return -EFAULT;
return 0;
}
static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
{
struct btrfs_ioctl_dev_info_args *di_args;
struct btrfs_device *dev;
struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
int ret = 0;
char *s_uuid = NULL;
char empty_uuid[BTRFS_UUID_SIZE] = {0};
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
di_args = memdup_user(arg, sizeof(*di_args));
if (IS_ERR(di_args))
return PTR_ERR(di_args);
if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0)
s_uuid = di_args->uuid;
mutex_lock(&fs_devices->device_list_mutex);
dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL);
mutex_unlock(&fs_devices->device_list_mutex);
if (!dev) {
ret = -ENODEV;
goto out;
}
di_args->devid = dev->devid;
di_args->bytes_used = dev->bytes_used;
di_args->total_bytes = dev->total_bytes;
memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid));
strncpy(di_args->path, dev->name, sizeof(di_args->path));
out:
if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args)))
ret = -EFAULT;
kfree(di_args);
return ret;
}
static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
u64 off, u64 olen, u64 destoff)
{
@ -2471,6 +2540,58 @@ static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp)
return btrfs_wait_for_commit(root, transid);
}
static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
{
int ret;
struct btrfs_ioctl_scrub_args *sa;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
sa = memdup_user(arg, sizeof(*sa));
if (IS_ERR(sa))
return PTR_ERR(sa);
ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end,
&sa->progress, sa->flags & BTRFS_SCRUB_READONLY);
if (copy_to_user(arg, sa, sizeof(*sa)))
ret = -EFAULT;
kfree(sa);
return ret;
}
static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg)
{
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return btrfs_scrub_cancel(root);
}
static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
void __user *arg)
{
struct btrfs_ioctl_scrub_args *sa;
int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
sa = memdup_user(arg, sizeof(*sa));
if (IS_ERR(sa))
return PTR_ERR(sa);
ret = btrfs_scrub_progress(root, sa->devid, &sa->progress);
if (copy_to_user(arg, sa, sizeof(*sa)))
ret = -EFAULT;
kfree(sa);
return ret;
}
long btrfs_ioctl(struct file *file, unsigned int
cmd, unsigned long arg)
{
@ -2510,6 +2631,10 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_add_dev(root, argp);
case BTRFS_IOC_RM_DEV:
return btrfs_ioctl_rm_dev(root, argp);
case BTRFS_IOC_FS_INFO:
return btrfs_ioctl_fs_info(root, argp);
case BTRFS_IOC_DEV_INFO:
return btrfs_ioctl_dev_info(root, argp);
case BTRFS_IOC_BALANCE:
return btrfs_balance(root->fs_info->dev_root);
case BTRFS_IOC_CLONE:
@ -2533,6 +2658,12 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_start_sync(file, argp);
case BTRFS_IOC_WAIT_SYNC:
return btrfs_ioctl_wait_sync(file, argp);
case BTRFS_IOC_SCRUB:
return btrfs_ioctl_scrub(root, argp);
case BTRFS_IOC_SCRUB_CANCEL:
return btrfs_ioctl_scrub_cancel(root, argp);
case BTRFS_IOC_SCRUB_PROGRESS:
return btrfs_ioctl_scrub_progress(root, argp);
}
return -ENOTTY;

View File

@ -32,6 +32,8 @@ struct btrfs_ioctl_vol_args {
#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0)
#define BTRFS_SUBVOL_RDONLY (1ULL << 1)
#define BTRFS_FSID_SIZE 16
#define BTRFS_UUID_SIZE 16
#define BTRFS_SUBVOL_NAME_MAX 4039
struct btrfs_ioctl_vol_args_v2 {
@ -42,6 +44,71 @@ struct btrfs_ioctl_vol_args_v2 {
char name[BTRFS_SUBVOL_NAME_MAX + 1];
};
/*
* structure to report errors and progress to userspace, either as a
* result of a finished scrub, a canceled scrub or a progress inquiry
*/
struct btrfs_scrub_progress {
__u64 data_extents_scrubbed; /* # of data extents scrubbed */
__u64 tree_extents_scrubbed; /* # of tree extents scrubbed */
__u64 data_bytes_scrubbed; /* # of data bytes scrubbed */
__u64 tree_bytes_scrubbed; /* # of tree bytes scrubbed */
__u64 read_errors; /* # of read errors encountered (EIO) */
__u64 csum_errors; /* # of failed csum checks */
__u64 verify_errors; /* # of occurences, where the metadata
* of a tree block did not match the
* expected values, like generation or
* logical */
__u64 no_csum; /* # of 4k data block for which no csum
* is present, probably the result of
* data written with nodatasum */
__u64 csum_discards; /* # of csum for which no data was found
* in the extent tree. */
__u64 super_errors; /* # of bad super blocks encountered */
__u64 malloc_errors; /* # of internal kmalloc errors. These
* will likely cause an incomplete
* scrub */
__u64 uncorrectable_errors; /* # of errors where either no intact
* copy was found or the writeback
* failed */
__u64 corrected_errors; /* # of errors corrected */
__u64 last_physical; /* last physical address scrubbed. In
* case a scrub was aborted, this can
* be used to restart the scrub */
__u64 unverified_errors; /* # of occurences where a read for a
* full (64k) bio failed, but the re-
* check succeeded for each 4k piece.
* Intermittent error. */
};
#define BTRFS_SCRUB_READONLY 1
struct btrfs_ioctl_scrub_args {
__u64 devid; /* in */
__u64 start; /* in */
__u64 end; /* in */
__u64 flags; /* in */
struct btrfs_scrub_progress progress; /* out */
/* pad to 1k */
__u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8];
};
#define BTRFS_DEVICE_PATH_NAME_MAX 1024
struct btrfs_ioctl_dev_info_args {
__u64 devid; /* in/out */
__u8 uuid[BTRFS_UUID_SIZE]; /* in/out */
__u64 bytes_used; /* out */
__u64 total_bytes; /* out */
__u64 unused[379]; /* pad to 4k */
__u8 path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */
};
struct btrfs_ioctl_fs_info_args {
__u64 max_id; /* out */
__u64 num_devices; /* out */
__u8 fsid[BTRFS_FSID_SIZE]; /* out */
__u64 reserved[124]; /* pad to 1k */
};
#define BTRFS_INO_LOOKUP_PATH_MAX 4080
struct btrfs_ioctl_ino_lookup_args {
__u64 treeid;
@ -203,4 +270,13 @@ struct btrfs_ioctl_space_args {
struct btrfs_ioctl_vol_args_v2)
#define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64)
#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
#define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \
struct btrfs_ioctl_scrub_args)
#define BTRFS_IOC_SCRUB_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28)
#define BTRFS_IOC_SCRUB_PROGRESS _IOWR(BTRFS_IOCTL_MAGIC, 29, \
struct btrfs_ioctl_scrub_args)
#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \
struct btrfs_ioctl_dev_info_args)
#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
struct btrfs_ioctl_fs_info_args)
#endif

View File

@ -4245,7 +4245,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt;
ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr,
disk_bytenr + len - 1, &list);
disk_bytenr + len - 1, &list, 0);
while (!list_empty(&list)) {
sums = list_entry(list.next, struct btrfs_ordered_sum, list);

1368
fs/btrfs/scrub.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1228,6 +1228,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
WARN_ON(cur_trans != trans->transaction);
btrfs_scrub_pause(root);
/* btrfs_commit_tree_roots is responsible for getting the
* various roots consistent with each other. Every pointer
* in the tree of tree roots has to point to the most up to date
@ -1312,6 +1313,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
mutex_unlock(&root->fs_info->trans_mutex);
btrfs_scrub_continue(root);
if (current->journal_info == trans)
current->journal_info = NULL;

View File

@ -614,7 +614,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
ret = btrfs_lookup_csums_range(root->log_root,
csum_start, csum_end - 1,
&ordered_sums);
&ordered_sums, 0);
BUG_ON(ret);
while (!list_empty(&ordered_sums)) {
struct btrfs_ordered_sum *sums;
@ -2094,7 +2094,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
* the running transaction open, so a full commit can't hop
* in and cause problems either.
*/
btrfs_scrub_pause_super(root);
write_ctree_super(trans, root->fs_info->tree_root, 1);
btrfs_scrub_continue_super(root);
ret = 0;
mutex_lock(&root->log_mutex);
@ -2689,7 +2691,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
ret = btrfs_lookup_csums_range(
log->fs_info->csum_root,
ds + cs, ds + cs + cl - 1,
&ordered_sums);
&ordered_sums, 0);
BUG_ON(ret);
}
}

View File

@ -38,9 +38,6 @@ static int init_first_rw_device(struct btrfs_trans_handle *trans,
struct btrfs_device *device);
static int btrfs_relocate_sys_chunks(struct btrfs_root *root);
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
static DEFINE_MUTEX(uuid_mutex);
static LIST_HEAD(fs_uuids);
@ -1287,6 +1284,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
goto error_undo;
device->in_fs_metadata = 0;
btrfs_scrub_cancel_dev(root, device);
/*
* the device list mutex makes sure that we don't change

View File

@ -85,6 +85,9 @@ struct btrfs_device {
/* physical drive uuid (or lvm uuid) */
u8 uuid[BTRFS_UUID_SIZE];
/* per-device scrub information */
struct scrub_dev *scrub_device;
struct btrfs_work work;
};
@ -158,6 +161,9 @@ struct map_lookup {
struct btrfs_bio_stripe stripes[];
};
#define map_lookup_size(n) (sizeof(struct map_lookup) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
u64 end, u64 *length);