aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/root-tree.c
diff options
context:
space:
mode:
authorAlexander Block <ablock84@googlemail.com>2012-07-25 11:35:53 -0400
committerAlexander Block <ablock84@googlemail.com>2012-07-25 17:28:38 -0400
commit8ea05e3a4262b9e6871c349fa3486bcfc72ffd1a (patch)
tree893a8ff635b31caf920aaa97948e612640cbac6a /fs/btrfs/root-tree.c
parent91cb916ca26feb99c78c131a1643af3d10fefd96 (diff)
Btrfs: introduce subvol uuids and times
This patch introduces uuids for subvolumes. Each subvolume has it's own uuid. In case it was snapshotted, it also contains parent_uuid. In case it was received, it also contains received_uuid. It also introduces subvolume ctime/otime/stime/rtime. The first two are comparable to the times found in inodes. otime is the origin/creation time and ctime is the change time. stime/rtime are only valid on received subvolumes. stime is the time of the subvolume when it was sent. rtime is the time of the subvolume when it was received. Additionally to the times, we have a transid for each time. They are updated at the same place as the times. btrfs receive uses stransid and rtransid to find out if a received subvolume changed in the meantime. If an older kernel mounts a filesystem with the extented fields, all fields become invalid. The next mount with a new kernel will detect this and reset the fields. Signed-off-by: Alexander Block <ablock84@googlemail.com> Reviewed-by: David Sterba <dave@jikos.cz> Reviewed-by: Arne Jansen <sensille@gmx.net> Reviewed-by: Jan Schmidt <list.btrfs@jan-o-sch.net> Reviewed-by: Alex Lyakas <alex.bolshoy.btrfs@gmail.com>
Diffstat (limited to 'fs/btrfs/root-tree.c')
-rw-r--r--fs/btrfs/root-tree.c107
1 files changed, 101 insertions, 6 deletions
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index 24fb8ce4e071..6bb465cca20f 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -16,12 +16,55 @@
16 * Boston, MA 021110-1307, USA. 16 * Boston, MA 021110-1307, USA.
17 */ 17 */
18 18
19#include <linux/uuid.h>
19#include "ctree.h" 20#include "ctree.h"
20#include "transaction.h" 21#include "transaction.h"
21#include "disk-io.h" 22#include "disk-io.h"
22#include "print-tree.h" 23#include "print-tree.h"
23 24
24/* 25/*
26 * Read a root item from the tree. In case we detect a root item smaller then
27 * sizeof(root_item), we know it's an old version of the root structure and
28 * initialize all new fields to zero. The same happens if we detect mismatching
29 * generation numbers as then we know the root was once mounted with an older
30 * kernel that was not aware of the root item structure change.
31 */
32void btrfs_read_root_item(struct btrfs_root *root,
33 struct extent_buffer *eb, int slot,
34 struct btrfs_root_item *item)
35{
36 uuid_le uuid;
37 int len;
38 int need_reset = 0;
39
40 len = btrfs_item_size_nr(eb, slot);
41 read_extent_buffer(eb, item, btrfs_item_ptr_offset(eb, slot),
42 min_t(int, len, (int)sizeof(*item)));
43 if (len < sizeof(*item))
44 need_reset = 1;
45 if (!need_reset && btrfs_root_generation(item)
46 != btrfs_root_generation_v2(item)) {
47 if (btrfs_root_generation_v2(item) != 0) {
48 printk(KERN_WARNING "btrfs: mismatching "
49 "generation and generation_v2 "
50 "found in root item. This root "
51 "was probably mounted with an "
52 "older kernel. Resetting all "
53 "new fields.\n");
54 }
55 need_reset = 1;
56 }
57 if (need_reset) {
58 memset(&item->generation_v2, 0,
59 sizeof(*item) - offsetof(struct btrfs_root_item,
60 generation_v2));
61
62 uuid_le_gen(&uuid);
63 memcpy(item->uuid, uuid.b, BTRFS_UUID_SIZE);
64 }
65}
66
67/*
25 * lookup the root with the highest offset for a given objectid. The key we do 68 * lookup the root with the highest offset for a given objectid. The key we do
26 * find is copied into 'key'. If we find something return 0, otherwise 1, < 0 69 * find is copied into 'key'. If we find something return 0, otherwise 1, < 0
27 * on error. 70 * on error.
@@ -61,10 +104,10 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
61 goto out; 104 goto out;
62 } 105 }
63 if (item) 106 if (item)
64 read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot), 107 btrfs_read_root_item(root, l, slot, item);
65 sizeof(*item));
66 if (key) 108 if (key)
67 memcpy(key, &found_key, sizeof(found_key)); 109 memcpy(key, &found_key, sizeof(found_key));
110
68 ret = 0; 111 ret = 0;
69out: 112out:
70 btrfs_free_path(path); 113 btrfs_free_path(path);
@@ -91,16 +134,15 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
91 int ret; 134 int ret;
92 int slot; 135 int slot;
93 unsigned long ptr; 136 unsigned long ptr;
137 int old_len;
94 138
95 path = btrfs_alloc_path(); 139 path = btrfs_alloc_path();
96 if (!path) 140 if (!path)
97 return -ENOMEM; 141 return -ENOMEM;
98 142
99 ret = btrfs_search_slot(trans, root, key, path, 0, 1); 143 ret = btrfs_search_slot(trans, root, key, path, 0, 1);
100 if (ret < 0) { 144 if (ret < 0)
101 btrfs_abort_transaction(trans, root, ret); 145 goto out_abort;
102 goto out;
103 }
104 146
105 if (ret != 0) { 147 if (ret != 0) {
106 btrfs_print_leaf(root, path->nodes[0]); 148 btrfs_print_leaf(root, path->nodes[0]);
@@ -113,16 +155,56 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
113 l = path->nodes[0]; 155 l = path->nodes[0];
114 slot = path->slots[0]; 156 slot = path->slots[0];
115 ptr = btrfs_item_ptr_offset(l, slot); 157 ptr = btrfs_item_ptr_offset(l, slot);
158 old_len = btrfs_item_size_nr(l, slot);
159
160 /*
161 * If this is the first time we update the root item which originated
162 * from an older kernel, we need to enlarge the item size to make room
163 * for the added fields.
164 */
165 if (old_len < sizeof(*item)) {
166 btrfs_release_path(path);
167 ret = btrfs_search_slot(trans, root, key, path,
168 -1, 1);
169 if (ret < 0)
170 goto out_abort;
171 ret = btrfs_del_item(trans, root, path);
172 if (ret < 0)
173 goto out_abort;
174 btrfs_release_path(path);
175 ret = btrfs_insert_empty_item(trans, root, path,
176 key, sizeof(*item));
177 if (ret < 0)
178 goto out_abort;
179 l = path->nodes[0];
180 slot = path->slots[0];
181 ptr = btrfs_item_ptr_offset(l, slot);
182 }
183
184 /*
185 * Update generation_v2 so at the next mount we know the new root
186 * fields are valid.
187 */
188 btrfs_set_root_generation_v2(item, btrfs_root_generation(item));
189
116 write_extent_buffer(l, item, ptr, sizeof(*item)); 190 write_extent_buffer(l, item, ptr, sizeof(*item));
117 btrfs_mark_buffer_dirty(path->nodes[0]); 191 btrfs_mark_buffer_dirty(path->nodes[0]);
118out: 192out:
119 btrfs_free_path(path); 193 btrfs_free_path(path);
120 return ret; 194 return ret;
195
196out_abort:
197 btrfs_abort_transaction(trans, root, ret);
198 goto out;
121} 199}
122 200
123int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, 201int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
124 struct btrfs_key *key, struct btrfs_root_item *item) 202 struct btrfs_key *key, struct btrfs_root_item *item)
125{ 203{
204 /*
205 * Make sure generation v1 and v2 match. See update_root for details.
206 */
207 btrfs_set_root_generation_v2(item, btrfs_root_generation(item));
126 return btrfs_insert_item(trans, root, key, item, sizeof(*item)); 208 return btrfs_insert_item(trans, root, key, item, sizeof(*item));
127} 209}
128 210
@@ -454,3 +536,16 @@ void btrfs_check_and_init_root_item(struct btrfs_root_item *root_item)
454 root_item->byte_limit = 0; 536 root_item->byte_limit = 0;
455 } 537 }
456} 538}
539
540void btrfs_update_root_times(struct btrfs_trans_handle *trans,
541 struct btrfs_root *root)
542{
543 struct btrfs_root_item *item = &root->root_item;
544 struct timespec ct = CURRENT_TIME;
545
546 spin_lock(&root->root_times_lock);
547 item->ctransid = trans->transid;
548 item->ctime.sec = cpu_to_le64(ct.tv_sec);
549 item->ctime.nsec = cpu_to_le64(ct.tv_nsec);
550 spin_unlock(&root->root_times_lock);
551}