diff options
author | Benjamin Marzinski <bmarzins@redhat.com> | 2015-05-05 13:12:19 -0400 |
---|---|---|
committer | Bob Peterson <rpeterso@redhat.com> | 2015-05-05 13:12:19 -0400 |
commit | a63b7bbc2175901d79fa36ba734499655c077f0d (patch) | |
tree | b9c550aaa1887a13f3e2442e488c614116159305 /fs/gfs2/inode.c | |
parent | 959b6717175713259664950f3bba2418b038f69a (diff) |
GFS2: add support for rename2 and RENAME_EXCHANGE
gfs2 now uses the rename2 directory iop, and supports the
RENAME_EXCHANGE flag (as well as RENAME_NOREPLACE, which the vfs
takes care of).
Signed-off-by: Benjamin Marzinski <bmarzins redhat com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r-- | fs/gfs2/inode.c | 205 |
1 files changed, 189 insertions, 16 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2cd385d151b5..4d809eb71b48 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -1307,6 +1307,35 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) | |||
1307 | } | 1307 | } |
1308 | 1308 | ||
1309 | /** | 1309 | /** |
1310 | * update_moved_ino - Update an inode that's being moved | ||
1311 | * @ip: The inode being moved | ||
1312 | * @ndip: The parent directory of the new filename | ||
1313 | * @dir_rename: True of ip is a directory | ||
1314 | * | ||
1315 | * Returns: errno | ||
1316 | */ | ||
1317 | |||
1318 | static int update_moved_ino(struct gfs2_inode *ip, struct gfs2_inode *ndip, | ||
1319 | int dir_rename) | ||
1320 | { | ||
1321 | int error; | ||
1322 | struct buffer_head *dibh; | ||
1323 | |||
1324 | if (dir_rename) | ||
1325 | return gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); | ||
1326 | |||
1327 | error = gfs2_meta_inode_buffer(ip, &dibh); | ||
1328 | if (error) | ||
1329 | return error; | ||
1330 | ip->i_inode.i_ctime = CURRENT_TIME; | ||
1331 | gfs2_trans_add_meta(ip->i_gl, dibh); | ||
1332 | gfs2_dinode_out(ip, dibh->b_data); | ||
1333 | brelse(dibh); | ||
1334 | return 0; | ||
1335 | } | ||
1336 | |||
1337 | |||
1338 | /** | ||
1310 | * gfs2_rename - Rename a file | 1339 | * gfs2_rename - Rename a file |
1311 | * @odir: Parent directory of old file name | 1340 | * @odir: Parent directory of old file name |
1312 | * @odentry: The old dentry of the file | 1341 | * @odentry: The old dentry of the file |
@@ -1354,7 +1383,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
1354 | 1383 | ||
1355 | if (S_ISDIR(ip->i_inode.i_mode)) { | 1384 | if (S_ISDIR(ip->i_inode.i_mode)) { |
1356 | dir_rename = 1; | 1385 | dir_rename = 1; |
1357 | /* don't move a dirctory into it's subdir */ | 1386 | /* don't move a directory into its subdir */ |
1358 | error = gfs2_ok_to_move(ip, ndip); | 1387 | error = gfs2_ok_to_move(ip, ndip); |
1359 | if (error) | 1388 | if (error) |
1360 | goto out_gunlock_r; | 1389 | goto out_gunlock_r; |
@@ -1494,20 +1523,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
1494 | if (nip) | 1523 | if (nip) |
1495 | error = gfs2_unlink_inode(ndip, ndentry); | 1524 | error = gfs2_unlink_inode(ndip, ndentry); |
1496 | 1525 | ||
1497 | if (dir_rename) { | 1526 | error = update_moved_ino(ip, ndip, dir_rename); |
1498 | error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); | 1527 | if (error) |
1499 | if (error) | 1528 | goto out_end_trans; |
1500 | goto out_end_trans; | ||
1501 | } else { | ||
1502 | struct buffer_head *dibh; | ||
1503 | error = gfs2_meta_inode_buffer(ip, &dibh); | ||
1504 | if (error) | ||
1505 | goto out_end_trans; | ||
1506 | ip->i_inode.i_ctime = CURRENT_TIME; | ||
1507 | gfs2_trans_add_meta(ip->i_gl, dibh); | ||
1508 | gfs2_dinode_out(ip, dibh->b_data); | ||
1509 | brelse(dibh); | ||
1510 | } | ||
1511 | 1529 | ||
1512 | error = gfs2_dir_del(odip, odentry); | 1530 | error = gfs2_dir_del(odip, odentry); |
1513 | if (error) | 1531 | if (error) |
@@ -1539,6 +1557,161 @@ out: | |||
1539 | } | 1557 | } |
1540 | 1558 | ||
1541 | /** | 1559 | /** |
1560 | * gfs2_exchange - exchange two files | ||
1561 | * @odir: Parent directory of old file name | ||
1562 | * @odentry: The old dentry of the file | ||
1563 | * @ndir: Parent directory of new file name | ||
1564 | * @ndentry: The new dentry of the file | ||
1565 | * @flags: The rename flags | ||
1566 | * | ||
1567 | * Returns: errno | ||
1568 | */ | ||
1569 | |||
1570 | static int gfs2_exchange(struct inode *odir, struct dentry *odentry, | ||
1571 | struct inode *ndir, struct dentry *ndentry, | ||
1572 | unsigned int flags) | ||
1573 | { | ||
1574 | struct gfs2_inode *odip = GFS2_I(odir); | ||
1575 | struct gfs2_inode *ndip = GFS2_I(ndir); | ||
1576 | struct gfs2_inode *oip = GFS2_I(odentry->d_inode); | ||
1577 | struct gfs2_inode *nip = GFS2_I(ndentry->d_inode); | ||
1578 | struct gfs2_sbd *sdp = GFS2_SB(odir); | ||
1579 | struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }; | ||
1580 | unsigned int num_gh; | ||
1581 | unsigned int x; | ||
1582 | umode_t old_mode = oip->i_inode.i_mode; | ||
1583 | umode_t new_mode = nip->i_inode.i_mode; | ||
1584 | int error; | ||
1585 | |||
1586 | error = gfs2_rindex_update(sdp); | ||
1587 | if (error) | ||
1588 | return error; | ||
1589 | |||
1590 | if (odip != ndip) { | ||
1591 | error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, | ||
1592 | 0, &r_gh); | ||
1593 | if (error) | ||
1594 | goto out; | ||
1595 | |||
1596 | if (S_ISDIR(old_mode)) { | ||
1597 | /* don't move a directory into its subdir */ | ||
1598 | error = gfs2_ok_to_move(oip, ndip); | ||
1599 | if (error) | ||
1600 | goto out_gunlock_r; | ||
1601 | } | ||
1602 | |||
1603 | if (S_ISDIR(new_mode)) { | ||
1604 | /* don't move a directory into its subdir */ | ||
1605 | error = gfs2_ok_to_move(nip, odip); | ||
1606 | if (error) | ||
1607 | goto out_gunlock_r; | ||
1608 | } | ||
1609 | } | ||
1610 | |||
1611 | num_gh = 1; | ||
1612 | gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); | ||
1613 | if (odip != ndip) { | ||
1614 | gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); | ||
1615 | num_gh++; | ||
1616 | } | ||
1617 | gfs2_holder_init(oip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); | ||
1618 | num_gh++; | ||
1619 | |||
1620 | gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); | ||
1621 | num_gh++; | ||
1622 | |||
1623 | for (x = 0; x < num_gh; x++) { | ||
1624 | error = gfs2_glock_nq(ghs + x); | ||
1625 | if (error) | ||
1626 | goto out_gunlock; | ||
1627 | } | ||
1628 | |||
1629 | error = -ENOENT; | ||
1630 | if (oip->i_inode.i_nlink == 0 || nip->i_inode.i_nlink == 0) | ||
1631 | goto out_gunlock; | ||
1632 | |||
1633 | error = gfs2_unlink_ok(odip, &odentry->d_name, oip); | ||
1634 | if (error) | ||
1635 | goto out_gunlock; | ||
1636 | error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip); | ||
1637 | if (error) | ||
1638 | goto out_gunlock; | ||
1639 | |||
1640 | if (S_ISDIR(old_mode)) { | ||
1641 | error = gfs2_permission(odentry->d_inode, MAY_WRITE); | ||
1642 | if (error) | ||
1643 | goto out_gunlock; | ||
1644 | } | ||
1645 | if (S_ISDIR(new_mode)) { | ||
1646 | error = gfs2_permission(ndentry->d_inode, MAY_WRITE); | ||
1647 | if (error) | ||
1648 | goto out_gunlock; | ||
1649 | } | ||
1650 | error = gfs2_trans_begin(sdp, 4 * RES_DINODE + 4 * RES_LEAF, 0); | ||
1651 | if (error) | ||
1652 | goto out_gunlock; | ||
1653 | |||
1654 | error = update_moved_ino(oip, ndip, S_ISDIR(old_mode)); | ||
1655 | if (error) | ||
1656 | goto out_end_trans; | ||
1657 | |||
1658 | error = update_moved_ino(nip, odip, S_ISDIR(new_mode)); | ||
1659 | if (error) | ||
1660 | goto out_end_trans; | ||
1661 | |||
1662 | error = gfs2_dir_mvino(ndip, &ndentry->d_name, oip, | ||
1663 | IF2DT(old_mode)); | ||
1664 | if (error) | ||
1665 | goto out_end_trans; | ||
1666 | |||
1667 | error = gfs2_dir_mvino(odip, &odentry->d_name, nip, | ||
1668 | IF2DT(new_mode)); | ||
1669 | if (error) | ||
1670 | goto out_end_trans; | ||
1671 | |||
1672 | if (odip != ndip) { | ||
1673 | if (S_ISDIR(new_mode) && !S_ISDIR(old_mode)) { | ||
1674 | inc_nlink(&odip->i_inode); | ||
1675 | drop_nlink(&ndip->i_inode); | ||
1676 | } else if (S_ISDIR(old_mode) && !S_ISDIR(new_mode)) { | ||
1677 | inc_nlink(&ndip->i_inode); | ||
1678 | drop_nlink(&odip->i_inode); | ||
1679 | } | ||
1680 | } | ||
1681 | mark_inode_dirty(&ndip->i_inode); | ||
1682 | if (odip != ndip) | ||
1683 | mark_inode_dirty(&odip->i_inode); | ||
1684 | |||
1685 | out_end_trans: | ||
1686 | gfs2_trans_end(sdp); | ||
1687 | out_gunlock: | ||
1688 | while (x--) { | ||
1689 | gfs2_glock_dq(ghs + x); | ||
1690 | gfs2_holder_uninit(ghs + x); | ||
1691 | } | ||
1692 | out_gunlock_r: | ||
1693 | if (r_gh.gh_gl) | ||
1694 | gfs2_glock_dq_uninit(&r_gh); | ||
1695 | out: | ||
1696 | return error; | ||
1697 | } | ||
1698 | |||
1699 | static int gfs2_rename2(struct inode *odir, struct dentry *odentry, | ||
1700 | struct inode *ndir, struct dentry *ndentry, | ||
1701 | unsigned int flags) | ||
1702 | { | ||
1703 | flags &= ~RENAME_NOREPLACE; | ||
1704 | |||
1705 | if (flags & ~RENAME_EXCHANGE) | ||
1706 | return -EINVAL; | ||
1707 | |||
1708 | if (flags & RENAME_EXCHANGE) | ||
1709 | return gfs2_exchange(odir, odentry, ndir, ndentry, flags); | ||
1710 | |||
1711 | return gfs2_rename(odir, odentry, ndir, ndentry); | ||
1712 | } | ||
1713 | |||
1714 | /** | ||
1542 | * gfs2_follow_link - Follow a symbolic link | 1715 | * gfs2_follow_link - Follow a symbolic link |
1543 | * @dentry: The dentry of the link | 1716 | * @dentry: The dentry of the link |
1544 | * @nd: Data that we pass to vfs_follow_link() | 1717 | * @nd: Data that we pass to vfs_follow_link() |
@@ -1943,7 +2116,7 @@ const struct inode_operations gfs2_dir_iops = { | |||
1943 | .mkdir = gfs2_mkdir, | 2116 | .mkdir = gfs2_mkdir, |
1944 | .rmdir = gfs2_unlink, | 2117 | .rmdir = gfs2_unlink, |
1945 | .mknod = gfs2_mknod, | 2118 | .mknod = gfs2_mknod, |
1946 | .rename = gfs2_rename, | 2119 | .rename2 = gfs2_rename2, |
1947 | .permission = gfs2_permission, | 2120 | .permission = gfs2_permission, |
1948 | .setattr = gfs2_setattr, | 2121 | .setattr = gfs2_setattr, |
1949 | .getattr = gfs2_getattr, | 2122 | .getattr = gfs2_getattr, |