Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 318891
b: refs/heads/master
c: 8ea05e3
h: refs/heads/master
i:
  318889: 87168ad
  318887: 3293b4f
v: v3
  • Loading branch information
Alexander Block committed Jul 25, 2012
1 parent d3d692a commit e2edd7d
Show file tree
Hide file tree
Showing 9 changed files with 293 additions and 16 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 91cb916ca26feb99c78c131a1643af3d10fefd96
refs/heads/master: 8ea05e3a4262b9e6871c349fa3486bcfc72ffd1a
7 changes: 4 additions & 3 deletions trunk/fs/btrfs/check-integrity.c
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,7 @@ static int btrfsic_process_metablock(
struct btrfs_disk_key *disk_key;
u8 type;
u32 item_offset;
u32 item_size;

if (disk_item_offset + sizeof(struct btrfs_item) >
sf->block_ctx->len) {
Expand All @@ -1047,6 +1048,7 @@ static int btrfsic_process_metablock(
disk_item_offset,
sizeof(struct btrfs_item));
item_offset = le32_to_cpu(disk_item.offset);
item_size = le32_to_cpu(disk_item.size);
disk_key = &disk_item.key;
type = disk_key->type;

Expand All @@ -1057,14 +1059,13 @@ static int btrfsic_process_metablock(

root_item_offset = item_offset +
offsetof(struct btrfs_leaf, items);
if (root_item_offset +
sizeof(struct btrfs_root_item) >
if (root_item_offset + item_size >
sf->block_ctx->len)
goto leaf_item_out_of_bounce_error;
btrfsic_read_from_block_data(
sf->block_ctx, &root_item,
root_item_offset,
sizeof(struct btrfs_root_item));
item_size);
next_bytenr = le64_to_cpu(root_item.bytenr);

sf->error =
Expand Down
47 changes: 47 additions & 0 deletions trunk/fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,36 @@ struct btrfs_root_item {
struct btrfs_disk_key drop_progress;
u8 drop_level;
u8 level;

/*
* The following fields appear after subvol_uuids+subvol_times
* were introduced.
*/

/*
* This generation number is used to test if the new fields are valid
* and up to date while reading the root item. Everytime the root item
* is written out, the "generation" field is copied into this field. If
* anyone ever mounted the fs with an older kernel, we will have
* mismatching generation values here and thus must invalidate the
* new fields. See btrfs_update_root and btrfs_find_last_root for
* details.
* the offset of generation_v2 is also used as the start for the memset
* when invalidating the fields.
*/
__le64 generation_v2;
u8 uuid[BTRFS_UUID_SIZE];
u8 parent_uuid[BTRFS_UUID_SIZE];
u8 received_uuid[BTRFS_UUID_SIZE];
__le64 ctransid; /* updated when an inode changes */
__le64 otransid; /* trans when created */
__le64 stransid; /* trans when sent. non-zero for received subvol */
__le64 rtransid; /* trans when received. non-zero for received subvol */
struct btrfs_timespec ctime;
struct btrfs_timespec otime;
struct btrfs_timespec stime;
struct btrfs_timespec rtime;
__le64 reserved[8]; /* for future */
} __attribute__ ((__packed__));

/*
Expand Down Expand Up @@ -1416,6 +1446,8 @@ struct btrfs_root {
dev_t anon_dev;

int force_cow;

spinlock_t root_times_lock;
};

struct btrfs_ioctl_defrag_range_args {
Expand Down Expand Up @@ -2189,6 +2221,16 @@ BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
last_snapshot, 64);
BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item,
generation_v2, 64);
BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item,
ctransid, 64);
BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item,
otransid, 64);
BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item,
stransid, 64);
BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
rtransid, 64);

static inline bool btrfs_root_readonly(struct btrfs_root *root)
{
Expand Down Expand Up @@ -2822,13 +2864,18 @@ int __must_check btrfs_update_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_key *key,
struct btrfs_root_item *item);
void btrfs_read_root_item(struct btrfs_root *root,
struct extent_buffer *eb, int slot,
struct btrfs_root_item *item);
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
btrfs_root_item *item, struct btrfs_key *key);
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid);
int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
void btrfs_set_root_node(struct btrfs_root_item *item,
struct extent_buffer *node);
void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
void btrfs_update_root_times(struct btrfs_trans_handle *trans,
struct btrfs_root *root);

/* dir-item.c */
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
Expand Down
8 changes: 5 additions & 3 deletions trunk/fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->defrag_running = 0;
root->root_key.objectid = objectid;
root->anon_dev = 0;

spin_lock_init(&root->root_times_lock);
}

static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
Expand Down Expand Up @@ -1326,6 +1328,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
u64 generation;
u32 blocksize;
int ret = 0;
int slot;

root = btrfs_alloc_root(fs_info);
if (!root)
Expand All @@ -1352,9 +1355,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
if (ret == 0) {
l = path->nodes[0];
read_extent_buffer(l, &root->root_item,
btrfs_item_ptr_offset(l, path->slots[0]),
sizeof(root->root_item));
slot = path->slots[0];
btrfs_read_root_item(tree_root, l, slot, &root->root_item);
memcpy(&root->root_key, location, sizeof(*location));
}
btrfs_free_path(path);
Expand Down
4 changes: 4 additions & 0 deletions trunk/fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2734,6 +2734,8 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
*/
if (!btrfs_is_free_space_inode(root, inode)
&& root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
btrfs_update_root_times(trans, root);

ret = btrfs_delayed_update_inode(trans, root, inode);
if (!ret)
btrfs_set_inode_last_trans(trans, inode);
Expand Down Expand Up @@ -4723,6 +4725,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
trace_btrfs_inode_new(inode);
btrfs_set_inode_last_trans(trans, inode);

btrfs_update_root_times(trans, root);

return inode;
fail:
if (dir)
Expand Down
100 changes: 97 additions & 3 deletions trunk/fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
#include <linux/uuid.h>
#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
Expand Down Expand Up @@ -346,11 +347,13 @@ static noinline int create_subvol(struct btrfs_root *root,
struct btrfs_root *new_root;
struct dentry *parent = dentry->d_parent;
struct inode *dir;
struct timespec cur_time = CURRENT_TIME;
int ret;
int err;
u64 objectid;
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
u64 index = 0;
uuid_le new_uuid;

ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
if (ret)
Expand Down Expand Up @@ -389,8 +392,9 @@ static noinline int create_subvol(struct btrfs_root *root,
BTRFS_UUID_SIZE);
btrfs_mark_buffer_dirty(leaf);

memset(&root_item, 0, sizeof(root_item));

inode_item = &root_item.inode;
memset(inode_item, 0, sizeof(*inode_item));
inode_item->generation = cpu_to_le64(1);
inode_item->size = cpu_to_le64(3);
inode_item->nlink = cpu_to_le32(1);
Expand All @@ -408,8 +412,15 @@ static noinline int create_subvol(struct btrfs_root *root,
btrfs_set_root_used(&root_item, leaf->len);
btrfs_set_root_last_snapshot(&root_item, 0);

memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
root_item.drop_level = 0;
btrfs_set_root_generation_v2(&root_item,
btrfs_root_generation(&root_item));
uuid_le_gen(&new_uuid);
memcpy(root_item.uuid, new_uuid.b, BTRFS_UUID_SIZE);
root_item.otime.sec = cpu_to_le64(cur_time.tv_sec);
root_item.otime.nsec = cpu_to_le64(cur_time.tv_nsec);
root_item.ctime = root_item.otime;
btrfs_set_root_ctransid(&root_item, trans->transid);
btrfs_set_root_otransid(&root_item, trans->transid);

btrfs_tree_unlock(leaf);
free_extent_buffer(leaf);
Expand Down Expand Up @@ -3395,6 +3406,87 @@ static long btrfs_ioctl_balance_progress(struct btrfs_root *root,
return ret;
}

static long btrfs_ioctl_set_received_subvol(struct file *file,
void __user *arg)
{
struct btrfs_ioctl_received_subvol_args *sa = NULL;
struct inode *inode = fdentry(file)->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_root_item *root_item = &root->root_item;
struct btrfs_trans_handle *trans;
struct timespec ct = CURRENT_TIME;
int ret = 0;

ret = mnt_want_write_file(file);
if (ret < 0)
return ret;

down_write(&root->fs_info->subvol_sem);

if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
ret = -EINVAL;
goto out;
}

if (btrfs_root_readonly(root)) {
ret = -EROFS;
goto out;
}

if (!inode_owner_or_capable(inode)) {
ret = -EACCES;
goto out;
}

sa = memdup_user(arg, sizeof(*sa));
if (IS_ERR(sa)) {
ret = PTR_ERR(sa);
sa = NULL;
goto out;
}

trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
trans = NULL;
goto out;
}

sa->rtransid = trans->transid;
sa->rtime.sec = ct.tv_sec;
sa->rtime.nsec = ct.tv_nsec;

memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
btrfs_set_root_stransid(root_item, sa->stransid);
btrfs_set_root_rtransid(root_item, sa->rtransid);
root_item->stime.sec = cpu_to_le64(sa->stime.sec);
root_item->stime.nsec = cpu_to_le32(sa->stime.nsec);
root_item->rtime.sec = cpu_to_le64(sa->rtime.sec);
root_item->rtime.nsec = cpu_to_le32(sa->rtime.nsec);

ret = btrfs_update_root(trans, root->fs_info->tree_root,
&root->root_key, &root->root_item);
if (ret < 0) {
btrfs_end_transaction(trans, root);
trans = NULL;
goto out;
} else {
ret = btrfs_commit_transaction(trans, root);
if (ret < 0)
goto out;
}

ret = copy_to_user(arg, sa, sizeof(*sa));
if (ret)
ret = -EFAULT;

out:
kfree(sa);
up_write(&root->fs_info->subvol_sem);
mnt_drop_write_file(file);
return ret;
}

long btrfs_ioctl(struct file *file, unsigned int
cmd, unsigned long arg)
{
Expand Down Expand Up @@ -3477,6 +3569,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_balance_ctl(root, arg);
case BTRFS_IOC_BALANCE_PROGRESS:
return btrfs_ioctl_balance_progress(root, argp);
case BTRFS_IOC_SET_RECEIVED_SUBVOL:
return btrfs_ioctl_set_received_subvol(file, argp);
case BTRFS_IOC_GET_DEV_STATS:
return btrfs_ioctl_get_dev_stats(root, argp, 0);
case BTRFS_IOC_GET_AND_RESET_DEV_STATS:
Expand Down
17 changes: 17 additions & 0 deletions trunk/fs/btrfs/ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,21 @@ struct btrfs_ioctl_get_dev_stats {
__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
};

struct btrfs_ioctl_timespec {
__u64 sec;
__u32 nsec;
};

struct btrfs_ioctl_received_subvol_args {
char uuid[BTRFS_UUID_SIZE]; /* in */
__u64 stransid; /* in */
__u64 rtransid; /* out */
struct btrfs_ioctl_timespec stime; /* in */
struct btrfs_ioctl_timespec rtime; /* out */
__u64 flags; /* in */
__u64 reserved[16]; /* in */
};

#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
Expand Down Expand Up @@ -359,6 +374,8 @@ struct btrfs_ioctl_get_dev_stats {
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \
struct btrfs_ioctl_received_subvol_args)
#define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
struct btrfs_ioctl_get_dev_stats)
#define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \
Expand Down
Loading

0 comments on commit e2edd7d

Please sign in to comment.