summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/inode.c
diff options
context:
space:
mode:
authorBenjamin Marzinski <bmarzins@redhat.com>2015-05-05 13:12:19 -0400
committerBob Peterson <rpeterso@redhat.com>2015-05-05 13:12:19 -0400
commita63b7bbc2175901d79fa36ba734499655c077f0d (patch)
treeb9c550aaa1887a13f3e2442e488c614116159305 /fs/gfs2/inode.c
parent959b6717175713259664950f3bba2418b038f69a (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.c205
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
1318static 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
1570static 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
1685out_end_trans:
1686 gfs2_trans_end(sdp);
1687out_gunlock:
1688 while (x--) {
1689 gfs2_glock_dq(ghs + x);
1690 gfs2_holder_uninit(ghs + x);
1691 }
1692out_gunlock_r:
1693 if (r_gh.gh_gl)
1694 gfs2_glock_dq_uninit(&r_gh);
1695out:
1696 return error;
1697}
1698
1699static 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,