diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:48:46 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:50 -0400 |
commit | a22285a6a32390195235171b89d157ed1a1fe932 (patch) | |
tree | 3fabc88a029e1af4f2fdcc708e7b62ef3cf3703a /fs/btrfs/ioctl.c | |
parent | f0486c68e4bd9a06a5904d3eeb3a0d73a83befb8 (diff) |
Btrfs: Integrate metadata reservation with start_transaction
Besides simplify the code, this change makes sure all metadata
reservation for normal metadata operations are released after
committing transaction.
Changes since V1:
Add code that check if unlink and rmdir will free space.
Add ENOSPC handling for clone ioctl.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 157 |
1 files changed, 80 insertions, 77 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 97a97839a867..3066da468c6d 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -239,23 +239,19 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
239 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; | 239 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; |
240 | u64 index = 0; | 240 | u64 index = 0; |
241 | 241 | ||
242 | ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root, | ||
243 | 0, &objectid); | ||
244 | if (ret) | ||
245 | return ret; | ||
242 | /* | 246 | /* |
243 | * 1 - inode item | 247 | * 1 - inode item |
244 | * 2 - refs | 248 | * 2 - refs |
245 | * 1 - root item | 249 | * 1 - root item |
246 | * 2 - dir items | 250 | * 2 - dir items |
247 | */ | 251 | */ |
248 | ret = btrfs_reserve_metadata_space(root, 6); | 252 | trans = btrfs_start_transaction(root, 6); |
249 | if (ret) | 253 | if (IS_ERR(trans)) |
250 | return ret; | 254 | return PTR_ERR(trans); |
251 | |||
252 | trans = btrfs_start_transaction(root, 1); | ||
253 | BUG_ON(!trans); | ||
254 | |||
255 | ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root, | ||
256 | 0, &objectid); | ||
257 | if (ret) | ||
258 | goto fail; | ||
259 | 255 | ||
260 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, | 256 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, |
261 | 0, objectid, NULL, 0, 0, 0); | 257 | 0, objectid, NULL, 0, 0, 0); |
@@ -345,13 +341,10 @@ fail: | |||
345 | err = btrfs_commit_transaction(trans, root); | 341 | err = btrfs_commit_transaction(trans, root); |
346 | if (err && !ret) | 342 | if (err && !ret) |
347 | ret = err; | 343 | ret = err; |
348 | |||
349 | btrfs_unreserve_metadata_space(root, 6); | ||
350 | return ret; | 344 | return ret; |
351 | } | 345 | } |
352 | 346 | ||
353 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | 347 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) |
354 | char *name, int namelen) | ||
355 | { | 348 | { |
356 | struct inode *inode; | 349 | struct inode *inode; |
357 | struct btrfs_pending_snapshot *pending_snapshot; | 350 | struct btrfs_pending_snapshot *pending_snapshot; |
@@ -361,40 +354,33 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
361 | if (!root->ref_cows) | 354 | if (!root->ref_cows) |
362 | return -EINVAL; | 355 | return -EINVAL; |
363 | 356 | ||
364 | /* | ||
365 | * 1 - inode item | ||
366 | * 2 - refs | ||
367 | * 1 - root item | ||
368 | * 2 - dir items | ||
369 | */ | ||
370 | ret = btrfs_reserve_metadata_space(root, 6); | ||
371 | if (ret) | ||
372 | goto fail; | ||
373 | |||
374 | pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); | 357 | pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); |
375 | if (!pending_snapshot) { | 358 | if (!pending_snapshot) |
376 | ret = -ENOMEM; | 359 | return -ENOMEM; |
377 | btrfs_unreserve_metadata_space(root, 6); | 360 | |
378 | goto fail; | 361 | btrfs_init_block_rsv(&pending_snapshot->block_rsv); |
379 | } | ||
380 | pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS); | ||
381 | if (!pending_snapshot->name) { | ||
382 | ret = -ENOMEM; | ||
383 | kfree(pending_snapshot); | ||
384 | btrfs_unreserve_metadata_space(root, 6); | ||
385 | goto fail; | ||
386 | } | ||
387 | memcpy(pending_snapshot->name, name, namelen); | ||
388 | pending_snapshot->name[namelen] = '\0'; | ||
389 | pending_snapshot->dentry = dentry; | 362 | pending_snapshot->dentry = dentry; |
390 | trans = btrfs_start_transaction(root, 1); | ||
391 | BUG_ON(!trans); | ||
392 | pending_snapshot->root = root; | 363 | pending_snapshot->root = root; |
364 | |||
365 | trans = btrfs_start_transaction(root->fs_info->extent_root, 5); | ||
366 | if (IS_ERR(trans)) { | ||
367 | ret = PTR_ERR(trans); | ||
368 | goto fail; | ||
369 | } | ||
370 | |||
371 | ret = btrfs_snap_reserve_metadata(trans, pending_snapshot); | ||
372 | BUG_ON(ret); | ||
373 | |||
393 | list_add(&pending_snapshot->list, | 374 | list_add(&pending_snapshot->list, |
394 | &trans->transaction->pending_snapshots); | 375 | &trans->transaction->pending_snapshots); |
395 | ret = btrfs_commit_transaction(trans, root); | 376 | ret = btrfs_commit_transaction(trans, root->fs_info->extent_root); |
396 | BUG_ON(ret); | 377 | BUG_ON(ret); |
397 | btrfs_unreserve_metadata_space(root, 6); | 378 | |
379 | ret = pending_snapshot->error; | ||
380 | if (ret) | ||
381 | goto fail; | ||
382 | |||
383 | btrfs_orphan_cleanup(pending_snapshot->snap); | ||
398 | 384 | ||
399 | inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); | 385 | inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); |
400 | if (IS_ERR(inode)) { | 386 | if (IS_ERR(inode)) { |
@@ -405,6 +391,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
405 | d_instantiate(dentry, inode); | 391 | d_instantiate(dentry, inode); |
406 | ret = 0; | 392 | ret = 0; |
407 | fail: | 393 | fail: |
394 | kfree(pending_snapshot); | ||
408 | return ret; | 395 | return ret; |
409 | } | 396 | } |
410 | 397 | ||
@@ -456,8 +443,7 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
456 | goto out_up_read; | 443 | goto out_up_read; |
457 | 444 | ||
458 | if (snap_src) { | 445 | if (snap_src) { |
459 | error = create_snapshot(snap_src, dentry, | 446 | error = create_snapshot(snap_src, dentry); |
460 | name, namelen); | ||
461 | } else { | 447 | } else { |
462 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 448 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
463 | name, namelen); | 449 | name, namelen); |
@@ -811,7 +797,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
811 | device->name, (unsigned long long)new_size); | 797 | device->name, (unsigned long long)new_size); |
812 | 798 | ||
813 | if (new_size > old_size) { | 799 | if (new_size > old_size) { |
814 | trans = btrfs_start_transaction(root, 1); | 800 | trans = btrfs_start_transaction(root, 0); |
815 | ret = btrfs_grow_device(trans, device, new_size); | 801 | ret = btrfs_grow_device(trans, device, new_size); |
816 | btrfs_commit_transaction(trans, root); | 802 | btrfs_commit_transaction(trans, root); |
817 | } else { | 803 | } else { |
@@ -1300,7 +1286,13 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
1300 | if (err) | 1286 | if (err) |
1301 | goto out_up_write; | 1287 | goto out_up_write; |
1302 | 1288 | ||
1303 | trans = btrfs_start_transaction(root, 1); | 1289 | trans = btrfs_start_transaction(root, 0); |
1290 | if (IS_ERR(trans)) { | ||
1291 | err = PTR_ERR(trans); | ||
1292 | goto out; | ||
1293 | } | ||
1294 | trans->block_rsv = &root->fs_info->global_block_rsv; | ||
1295 | |||
1304 | ret = btrfs_unlink_subvol(trans, root, dir, | 1296 | ret = btrfs_unlink_subvol(trans, root, dir, |
1305 | dest->root_key.objectid, | 1297 | dest->root_key.objectid, |
1306 | dentry->d_name.name, | 1298 | dentry->d_name.name, |
@@ -1550,12 +1542,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1550 | btrfs_wait_ordered_range(src, off, off+len); | 1542 | btrfs_wait_ordered_range(src, off, off+len); |
1551 | } | 1543 | } |
1552 | 1544 | ||
1553 | trans = btrfs_start_transaction(root, 1); | ||
1554 | BUG_ON(!trans); | ||
1555 | |||
1556 | /* punch hole in destination first */ | ||
1557 | btrfs_drop_extents(trans, inode, off, off + len, &hint_byte, 1); | ||
1558 | |||
1559 | /* clone data */ | 1545 | /* clone data */ |
1560 | key.objectid = src->i_ino; | 1546 | key.objectid = src->i_ino; |
1561 | key.type = BTRFS_EXTENT_DATA_KEY; | 1547 | key.type = BTRFS_EXTENT_DATA_KEY; |
@@ -1566,7 +1552,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1566 | * note the key will change type as we walk through the | 1552 | * note the key will change type as we walk through the |
1567 | * tree. | 1553 | * tree. |
1568 | */ | 1554 | */ |
1569 | ret = btrfs_search_slot(trans, root, &key, path, 0, 0); | 1555 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
1570 | if (ret < 0) | 1556 | if (ret < 0) |
1571 | goto out; | 1557 | goto out; |
1572 | 1558 | ||
@@ -1629,12 +1615,31 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1629 | new_key.objectid = inode->i_ino; | 1615 | new_key.objectid = inode->i_ino; |
1630 | new_key.offset = key.offset + destoff - off; | 1616 | new_key.offset = key.offset + destoff - off; |
1631 | 1617 | ||
1618 | trans = btrfs_start_transaction(root, 1); | ||
1619 | if (IS_ERR(trans)) { | ||
1620 | ret = PTR_ERR(trans); | ||
1621 | goto out; | ||
1622 | } | ||
1623 | |||
1632 | if (type == BTRFS_FILE_EXTENT_REG || | 1624 | if (type == BTRFS_FILE_EXTENT_REG || |
1633 | type == BTRFS_FILE_EXTENT_PREALLOC) { | 1625 | type == BTRFS_FILE_EXTENT_PREALLOC) { |
1626 | if (off > key.offset) { | ||
1627 | datao += off - key.offset; | ||
1628 | datal -= off - key.offset; | ||
1629 | } | ||
1630 | |||
1631 | if (key.offset + datal > off + len) | ||
1632 | datal = off + len - key.offset; | ||
1633 | |||
1634 | ret = btrfs_drop_extents(trans, inode, | ||
1635 | new_key.offset, | ||
1636 | new_key.offset + datal, | ||
1637 | &hint_byte, 1); | ||
1638 | BUG_ON(ret); | ||
1639 | |||
1634 | ret = btrfs_insert_empty_item(trans, root, path, | 1640 | ret = btrfs_insert_empty_item(trans, root, path, |
1635 | &new_key, size); | 1641 | &new_key, size); |
1636 | if (ret) | 1642 | BUG_ON(ret); |
1637 | goto out; | ||
1638 | 1643 | ||
1639 | leaf = path->nodes[0]; | 1644 | leaf = path->nodes[0]; |
1640 | slot = path->slots[0]; | 1645 | slot = path->slots[0]; |
@@ -1645,14 +1650,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1645 | extent = btrfs_item_ptr(leaf, slot, | 1650 | extent = btrfs_item_ptr(leaf, slot, |
1646 | struct btrfs_file_extent_item); | 1651 | struct btrfs_file_extent_item); |
1647 | 1652 | ||
1648 | if (off > key.offset) { | ||
1649 | datao += off - key.offset; | ||
1650 | datal -= off - key.offset; | ||
1651 | } | ||
1652 | |||
1653 | if (key.offset + datal > off + len) | ||
1654 | datal = off + len - key.offset; | ||
1655 | |||
1656 | /* disko == 0 means it's a hole */ | 1653 | /* disko == 0 means it's a hole */ |
1657 | if (!disko) | 1654 | if (!disko) |
1658 | datao = 0; | 1655 | datao = 0; |
@@ -1683,14 +1680,21 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1683 | 1680 | ||
1684 | if (comp && (skip || trim)) { | 1681 | if (comp && (skip || trim)) { |
1685 | ret = -EINVAL; | 1682 | ret = -EINVAL; |
1683 | btrfs_end_transaction(trans, root); | ||
1686 | goto out; | 1684 | goto out; |
1687 | } | 1685 | } |
1688 | size -= skip + trim; | 1686 | size -= skip + trim; |
1689 | datal -= skip + trim; | 1687 | datal -= skip + trim; |
1688 | |||
1689 | ret = btrfs_drop_extents(trans, inode, | ||
1690 | new_key.offset, | ||
1691 | new_key.offset + datal, | ||
1692 | &hint_byte, 1); | ||
1693 | BUG_ON(ret); | ||
1694 | |||
1690 | ret = btrfs_insert_empty_item(trans, root, path, | 1695 | ret = btrfs_insert_empty_item(trans, root, path, |
1691 | &new_key, size); | 1696 | &new_key, size); |
1692 | if (ret) | 1697 | BUG_ON(ret); |
1693 | goto out; | ||
1694 | 1698 | ||
1695 | if (skip) { | 1699 | if (skip) { |
1696 | u32 start = | 1700 | u32 start = |
@@ -1708,8 +1712,17 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1708 | } | 1712 | } |
1709 | 1713 | ||
1710 | btrfs_mark_buffer_dirty(leaf); | 1714 | btrfs_mark_buffer_dirty(leaf); |
1711 | } | 1715 | btrfs_release_path(root, path); |
1712 | 1716 | ||
1717 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
1718 | if (new_key.offset + datal > inode->i_size) | ||
1719 | btrfs_i_size_write(inode, | ||
1720 | new_key.offset + datal); | ||
1721 | BTRFS_I(inode)->flags = BTRFS_I(src)->flags; | ||
1722 | ret = btrfs_update_inode(trans, root, inode); | ||
1723 | BUG_ON(ret); | ||
1724 | btrfs_end_transaction(trans, root); | ||
1725 | } | ||
1713 | next: | 1726 | next: |
1714 | btrfs_release_path(root, path); | 1727 | btrfs_release_path(root, path); |
1715 | key.offset++; | 1728 | key.offset++; |
@@ -1717,17 +1730,7 @@ next: | |||
1717 | ret = 0; | 1730 | ret = 0; |
1718 | out: | 1731 | out: |
1719 | btrfs_release_path(root, path); | 1732 | btrfs_release_path(root, path); |
1720 | if (ret == 0) { | ||
1721 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
1722 | if (destoff + olen > inode->i_size) | ||
1723 | btrfs_i_size_write(inode, destoff + olen); | ||
1724 | BTRFS_I(inode)->flags = BTRFS_I(src)->flags; | ||
1725 | ret = btrfs_update_inode(trans, root, inode); | ||
1726 | } | ||
1727 | btrfs_end_transaction(trans, root); | ||
1728 | unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); | 1733 | unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); |
1729 | if (ret) | ||
1730 | vmtruncate(inode, 0); | ||
1731 | out_unlock: | 1734 | out_unlock: |
1732 | mutex_unlock(&src->i_mutex); | 1735 | mutex_unlock(&src->i_mutex); |
1733 | mutex_unlock(&inode->i_mutex); | 1736 | mutex_unlock(&inode->i_mutex); |