aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorYan, Zheng <zheng.yan@oracle.com>2010-05-16 10:48:46 -0400
committerChris Mason <chris.mason@oracle.com>2010-05-25 10:34:50 -0400
commita22285a6a32390195235171b89d157ed1a1fe932 (patch)
tree3fabc88a029e1af4f2fdcc708e7b62ef3cf3703a /fs/btrfs/ioctl.c
parentf0486c68e4bd9a06a5904d3eeb3a0d73a83befb8 (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.c157
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
353static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, 347static 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;
407fail: 393fail:
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 }
1713next: 1726next:
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;
1718out: 1731out:
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);
1731out_unlock: 1734out_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);