diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-05-13 16:03:06 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:03 -0400 |
commit | a0af469b58944f6e8c5c8ecbebb42997baf0cb9e (patch) | |
tree | 1fa478aa49c24d60417a2e1239050c4c1435a0dc /fs/btrfs/volumes.c | |
parent | dfe25020689bb2d318782d2c9c7141203583fc70 (diff) |
Fix btrfs_open_devices to deal with changes since the scan ioctls
Devices can change after the scan ioctls are done, and btrfs_open_devices
needs to be able to verify them as they are opened and used by the FS.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 70 |
1 files changed, 59 insertions, 11 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 43f74d17bcea..501d23d3ebfd 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -71,6 +71,7 @@ int btrfs_cleanup_fs_uuids(void) | |||
71 | dev_list); | 71 | dev_list); |
72 | if (dev->bdev) { | 72 | if (dev->bdev) { |
73 | close_bdev_excl(dev->bdev); | 73 | close_bdev_excl(dev->bdev); |
74 | fs_devices->open_devices--; | ||
74 | } | 75 | } |
75 | list_del(&dev->dev_list); | 76 | list_del(&dev->dev_list); |
76 | kfree(dev->name); | 77 | kfree(dev->name); |
@@ -174,9 +175,10 @@ again: | |||
174 | list_for_each(cur, head) { | 175 | list_for_each(cur, head) { |
175 | device = list_entry(cur, struct btrfs_device, dev_list); | 176 | device = list_entry(cur, struct btrfs_device, dev_list); |
176 | if (!device->in_fs_metadata) { | 177 | if (!device->in_fs_metadata) { |
177 | printk("getting rid of extra dev %s\n", device->name); | 178 | if (device->bdev) { |
178 | if (device->bdev) | ||
179 | close_bdev_excl(device->bdev); | 179 | close_bdev_excl(device->bdev); |
180 | fs_devices->open_devices--; | ||
181 | } | ||
180 | list_del(&device->dev_list); | 182 | list_del(&device->dev_list); |
181 | list_del(&device->dev_alloc_list); | 183 | list_del(&device->dev_alloc_list); |
182 | fs_devices->num_devices--; | 184 | fs_devices->num_devices--; |
@@ -188,6 +190,7 @@ printk("getting rid of extra dev %s\n", device->name); | |||
188 | mutex_unlock(&uuid_mutex); | 190 | mutex_unlock(&uuid_mutex); |
189 | return 0; | 191 | return 0; |
190 | } | 192 | } |
193 | |||
191 | int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) | 194 | int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) |
192 | { | 195 | { |
193 | struct list_head *head = &fs_devices->devices; | 196 | struct list_head *head = &fs_devices->devices; |
@@ -199,10 +202,12 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) | |||
199 | device = list_entry(cur, struct btrfs_device, dev_list); | 202 | device = list_entry(cur, struct btrfs_device, dev_list); |
200 | if (device->bdev) { | 203 | if (device->bdev) { |
201 | close_bdev_excl(device->bdev); | 204 | close_bdev_excl(device->bdev); |
205 | fs_devices->open_devices--; | ||
202 | } | 206 | } |
203 | device->bdev = NULL; | 207 | device->bdev = NULL; |
204 | device->in_fs_metadata = 0; | 208 | device->in_fs_metadata = 0; |
205 | } | 209 | } |
210 | fs_devices->mounted = 0; | ||
206 | mutex_unlock(&uuid_mutex); | 211 | mutex_unlock(&uuid_mutex); |
207 | return 0; | 212 | return 0; |
208 | } | 213 | } |
@@ -214,9 +219,19 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | |||
214 | struct list_head *head = &fs_devices->devices; | 219 | struct list_head *head = &fs_devices->devices; |
215 | struct list_head *cur; | 220 | struct list_head *cur; |
216 | struct btrfs_device *device; | 221 | struct btrfs_device *device; |
217 | int ret; | 222 | struct block_device *latest_bdev = NULL; |
223 | struct buffer_head *bh; | ||
224 | struct btrfs_super_block *disk_super; | ||
225 | u64 latest_devid = 0; | ||
226 | u64 latest_transid = 0; | ||
227 | u64 transid; | ||
228 | u64 devid; | ||
229 | int ret = 0; | ||
218 | 230 | ||
219 | mutex_lock(&uuid_mutex); | 231 | mutex_lock(&uuid_mutex); |
232 | if (fs_devices->mounted) | ||
233 | goto out; | ||
234 | |||
220 | list_for_each(cur, head) { | 235 | list_for_each(cur, head) { |
221 | device = list_entry(cur, struct btrfs_device, dev_list); | 236 | device = list_entry(cur, struct btrfs_device, dev_list); |
222 | if (device->bdev) | 237 | if (device->bdev) |
@@ -229,21 +244,52 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | |||
229 | 244 | ||
230 | if (IS_ERR(bdev)) { | 245 | if (IS_ERR(bdev)) { |
231 | printk("open %s failed\n", device->name); | 246 | printk("open %s failed\n", device->name); |
232 | ret = PTR_ERR(bdev); | 247 | goto error; |
233 | goto fail; | ||
234 | } | 248 | } |
235 | set_blocksize(bdev, 4096); | 249 | set_blocksize(bdev, 4096); |
236 | if (device->devid == fs_devices->latest_devid) | 250 | |
237 | fs_devices->latest_bdev = bdev; | 251 | bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096); |
252 | if (!bh) | ||
253 | goto error_close; | ||
254 | |||
255 | disk_super = (struct btrfs_super_block *)bh->b_data; | ||
256 | if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC, | ||
257 | sizeof(disk_super->magic))) | ||
258 | goto error_brelse; | ||
259 | |||
260 | devid = le64_to_cpu(disk_super->dev_item.devid); | ||
261 | if (devid != device->devid) | ||
262 | goto error_brelse; | ||
263 | |||
264 | transid = btrfs_super_generation(disk_super); | ||
265 | if (transid > latest_transid) { | ||
266 | latest_devid = devid; | ||
267 | latest_transid = transid; | ||
268 | latest_bdev = bdev; | ||
269 | } | ||
270 | |||
238 | device->bdev = bdev; | 271 | device->bdev = bdev; |
239 | device->in_fs_metadata = 0; | 272 | device->in_fs_metadata = 0; |
273 | fs_devices->open_devices++; | ||
274 | continue; | ||
240 | 275 | ||
276 | error_brelse: | ||
277 | brelse(bh); | ||
278 | error_close: | ||
279 | close_bdev_excl(bdev); | ||
280 | error: | ||
281 | continue; | ||
241 | } | 282 | } |
283 | if (fs_devices->open_devices == 0) { | ||
284 | ret = -EIO; | ||
285 | goto out; | ||
286 | } | ||
287 | fs_devices->mounted = 1; | ||
288 | fs_devices->latest_bdev = latest_bdev; | ||
289 | fs_devices->latest_devid = latest_devid; | ||
290 | fs_devices->latest_trans = latest_transid; | ||
291 | out: | ||
242 | mutex_unlock(&uuid_mutex); | 292 | mutex_unlock(&uuid_mutex); |
243 | return 0; | ||
244 | fail: | ||
245 | mutex_unlock(&uuid_mutex); | ||
246 | btrfs_close_devices(fs_devices); | ||
247 | return ret; | 293 | return ret; |
248 | } | 294 | } |
249 | 295 | ||
@@ -828,6 +874,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
828 | if (device->bdev) { | 874 | if (device->bdev) { |
829 | /* one close for the device struct or super_block */ | 875 | /* one close for the device struct or super_block */ |
830 | close_bdev_excl(device->bdev); | 876 | close_bdev_excl(device->bdev); |
877 | root->fs_info->fs_devices->open_devices--; | ||
831 | } | 878 | } |
832 | if (bdev) { | 879 | if (bdev) { |
833 | /* one close for us */ | 880 | /* one close for us */ |
@@ -914,6 +961,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) | |||
914 | list_add(&device->dev_alloc_list, | 961 | list_add(&device->dev_alloc_list, |
915 | &root->fs_info->fs_devices->alloc_list); | 962 | &root->fs_info->fs_devices->alloc_list); |
916 | root->fs_info->fs_devices->num_devices++; | 963 | root->fs_info->fs_devices->num_devices++; |
964 | root->fs_info->fs_devices->open_devices++; | ||
917 | out: | 965 | out: |
918 | btrfs_end_transaction(trans, root); | 966 | btrfs_end_transaction(trans, root); |
919 | mutex_unlock(&root->fs_info->fs_mutex); | 967 | mutex_unlock(&root->fs_info->fs_mutex); |