diff options
author | Jan Kara <jack@suse.cz> | 2008-04-28 05:14:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-28 11:58:33 -0400 |
commit | 0ff5af8340aa6be44220d7237ef4a654314cf795 (patch) | |
tree | a9536ea573725931cd4eb3139f4885887e3f8bf8 /fs | |
parent | 03f6e92bdd467aed9d7571a571868563ae6ad288 (diff) |
quota: quota core changes for quotaon on remount
Currently, we just turn quotas off on remount of filesystem to read-only
state. The patch below adds necessary framework so that we can turn quotas
off on remount RO but we are able to automatically reenable them again when
filesystem is remounted to RW state. All we need to do is to keep references
to inodes of quota files when remounting RO and using these references to
reenable quotas when remounting RW.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dquot.c | 77 | ||||
-rw-r--r-- | fs/quota.c | 5 | ||||
-rw-r--r-- | fs/super.c | 10 |
3 files changed, 78 insertions, 14 deletions
diff --git a/fs/dquot.c b/fs/dquot.c index fc26d1097d3c..dfba1623cccb 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
@@ -1449,31 +1449,43 @@ static inline void set_enable_flags(struct quota_info *dqopt, int type) | |||
1449 | switch (type) { | 1449 | switch (type) { |
1450 | case USRQUOTA: | 1450 | case USRQUOTA: |
1451 | dqopt->flags |= DQUOT_USR_ENABLED; | 1451 | dqopt->flags |= DQUOT_USR_ENABLED; |
1452 | dqopt->flags &= ~DQUOT_USR_SUSPENDED; | ||
1452 | break; | 1453 | break; |
1453 | case GRPQUOTA: | 1454 | case GRPQUOTA: |
1454 | dqopt->flags |= DQUOT_GRP_ENABLED; | 1455 | dqopt->flags |= DQUOT_GRP_ENABLED; |
1456 | dqopt->flags &= ~DQUOT_GRP_SUSPENDED; | ||
1455 | break; | 1457 | break; |
1456 | } | 1458 | } |
1457 | } | 1459 | } |
1458 | 1460 | ||
1459 | static inline void reset_enable_flags(struct quota_info *dqopt, int type) | 1461 | static inline void reset_enable_flags(struct quota_info *dqopt, int type, |
1462 | int remount) | ||
1460 | { | 1463 | { |
1461 | switch (type) { | 1464 | switch (type) { |
1462 | case USRQUOTA: | 1465 | case USRQUOTA: |
1463 | dqopt->flags &= ~DQUOT_USR_ENABLED; | 1466 | dqopt->flags &= ~DQUOT_USR_ENABLED; |
1467 | if (remount) | ||
1468 | dqopt->flags |= DQUOT_USR_SUSPENDED; | ||
1469 | else | ||
1470 | dqopt->flags &= ~DQUOT_USR_SUSPENDED; | ||
1464 | break; | 1471 | break; |
1465 | case GRPQUOTA: | 1472 | case GRPQUOTA: |
1466 | dqopt->flags &= ~DQUOT_GRP_ENABLED; | 1473 | dqopt->flags &= ~DQUOT_GRP_ENABLED; |
1474 | if (remount) | ||
1475 | dqopt->flags |= DQUOT_GRP_SUSPENDED; | ||
1476 | else | ||
1477 | dqopt->flags &= ~DQUOT_GRP_SUSPENDED; | ||
1467 | break; | 1478 | break; |
1468 | } | 1479 | } |
1469 | } | 1480 | } |
1470 | 1481 | ||
1482 | |||
1471 | /* | 1483 | /* |
1472 | * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) | 1484 | * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) |
1473 | */ | 1485 | */ |
1474 | int vfs_quota_off(struct super_block *sb, int type) | 1486 | int vfs_quota_off(struct super_block *sb, int type, int remount) |
1475 | { | 1487 | { |
1476 | int cnt; | 1488 | int cnt, ret = 0; |
1477 | struct quota_info *dqopt = sb_dqopt(sb); | 1489 | struct quota_info *dqopt = sb_dqopt(sb); |
1478 | struct inode *toputinode[MAXQUOTAS]; | 1490 | struct inode *toputinode[MAXQUOTAS]; |
1479 | 1491 | ||
@@ -1483,9 +1495,17 @@ int vfs_quota_off(struct super_block *sb, int type) | |||
1483 | toputinode[cnt] = NULL; | 1495 | toputinode[cnt] = NULL; |
1484 | if (type != -1 && cnt != type) | 1496 | if (type != -1 && cnt != type) |
1485 | continue; | 1497 | continue; |
1498 | /* If we keep inodes of quota files after remount and quotaoff | ||
1499 | * is called, drop kept inodes. */ | ||
1500 | if (!remount && sb_has_quota_suspended(sb, cnt)) { | ||
1501 | iput(dqopt->files[cnt]); | ||
1502 | dqopt->files[cnt] = NULL; | ||
1503 | reset_enable_flags(dqopt, cnt, 0); | ||
1504 | continue; | ||
1505 | } | ||
1486 | if (!sb_has_quota_enabled(sb, cnt)) | 1506 | if (!sb_has_quota_enabled(sb, cnt)) |
1487 | continue; | 1507 | continue; |
1488 | reset_enable_flags(dqopt, cnt); | 1508 | reset_enable_flags(dqopt, cnt, remount); |
1489 | 1509 | ||
1490 | /* Note: these are blocking operations */ | 1510 | /* Note: these are blocking operations */ |
1491 | drop_dquot_ref(sb, cnt); | 1511 | drop_dquot_ref(sb, cnt); |
@@ -1501,7 +1521,8 @@ int vfs_quota_off(struct super_block *sb, int type) | |||
1501 | put_quota_format(dqopt->info[cnt].dqi_format); | 1521 | put_quota_format(dqopt->info[cnt].dqi_format); |
1502 | 1522 | ||
1503 | toputinode[cnt] = dqopt->files[cnt]; | 1523 | toputinode[cnt] = dqopt->files[cnt]; |
1504 | dqopt->files[cnt] = NULL; | 1524 | if (!remount) |
1525 | dqopt->files[cnt] = NULL; | ||
1505 | dqopt->info[cnt].dqi_flags = 0; | 1526 | dqopt->info[cnt].dqi_flags = 0; |
1506 | dqopt->info[cnt].dqi_igrace = 0; | 1527 | dqopt->info[cnt].dqi_igrace = 0; |
1507 | dqopt->info[cnt].dqi_bgrace = 0; | 1528 | dqopt->info[cnt].dqi_bgrace = 0; |
@@ -1531,12 +1552,19 @@ int vfs_quota_off(struct super_block *sb, int type) | |||
1531 | mutex_unlock(&toputinode[cnt]->i_mutex); | 1552 | mutex_unlock(&toputinode[cnt]->i_mutex); |
1532 | mark_inode_dirty(toputinode[cnt]); | 1553 | mark_inode_dirty(toputinode[cnt]); |
1533 | } | 1554 | } |
1534 | iput(toputinode[cnt]); | ||
1535 | mutex_unlock(&dqopt->dqonoff_mutex); | 1555 | mutex_unlock(&dqopt->dqonoff_mutex); |
1556 | /* On remount RO, we keep the inode pointer so that we | ||
1557 | * can reenable quota on the subsequent remount RW. | ||
1558 | * But we have better not keep inode pointer when there | ||
1559 | * is pending delete on the quota file... */ | ||
1560 | if (!remount) | ||
1561 | iput(toputinode[cnt]); | ||
1562 | else if (!toputinode[cnt]->i_nlink) | ||
1563 | ret = -EBUSY; | ||
1536 | } | 1564 | } |
1537 | if (sb->s_bdev) | 1565 | if (sb->s_bdev) |
1538 | invalidate_bdev(sb->s_bdev); | 1566 | invalidate_bdev(sb->s_bdev); |
1539 | return 0; | 1567 | return ret; |
1540 | } | 1568 | } |
1541 | 1569 | ||
1542 | /* | 1570 | /* |
@@ -1574,7 +1602,8 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) | |||
1574 | invalidate_bdev(sb->s_bdev); | 1602 | invalidate_bdev(sb->s_bdev); |
1575 | mutex_lock(&inode->i_mutex); | 1603 | mutex_lock(&inode->i_mutex); |
1576 | mutex_lock(&dqopt->dqonoff_mutex); | 1604 | mutex_lock(&dqopt->dqonoff_mutex); |
1577 | if (sb_has_quota_enabled(sb, type)) { | 1605 | if (sb_has_quota_enabled(sb, type) || |
1606 | sb_has_quota_suspended(sb, type)) { | ||
1578 | error = -EBUSY; | 1607 | error = -EBUSY; |
1579 | goto out_lock; | 1608 | goto out_lock; |
1580 | } | 1609 | } |
@@ -1597,6 +1626,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) | |||
1597 | 1626 | ||
1598 | dqopt->ops[type] = fmt->qf_ops; | 1627 | dqopt->ops[type] = fmt->qf_ops; |
1599 | dqopt->info[type].dqi_format = fmt; | 1628 | dqopt->info[type].dqi_format = fmt; |
1629 | dqopt->info[type].dqi_fmt_id = format_id; | ||
1600 | INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list); | 1630 | INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list); |
1601 | mutex_lock(&dqopt->dqio_mutex); | 1631 | mutex_lock(&dqopt->dqio_mutex); |
1602 | if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) { | 1632 | if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) { |
@@ -1632,12 +1662,41 @@ out_fmt: | |||
1632 | return error; | 1662 | return error; |
1633 | } | 1663 | } |
1634 | 1664 | ||
1665 | /* Reenable quotas on remount RW */ | ||
1666 | static int vfs_quota_on_remount(struct super_block *sb, int type) | ||
1667 | { | ||
1668 | struct quota_info *dqopt = sb_dqopt(sb); | ||
1669 | struct inode *inode; | ||
1670 | int ret; | ||
1671 | |||
1672 | mutex_lock(&dqopt->dqonoff_mutex); | ||
1673 | if (!sb_has_quota_suspended(sb, type)) { | ||
1674 | mutex_unlock(&dqopt->dqonoff_mutex); | ||
1675 | return 0; | ||
1676 | } | ||
1677 | BUG_ON(sb_has_quota_enabled(sb, type)); | ||
1678 | |||
1679 | inode = dqopt->files[type]; | ||
1680 | dqopt->files[type] = NULL; | ||
1681 | reset_enable_flags(dqopt, type, 0); | ||
1682 | mutex_unlock(&dqopt->dqonoff_mutex); | ||
1683 | |||
1684 | ret = vfs_quota_on_inode(inode, type, dqopt->info[type].dqi_fmt_id); | ||
1685 | iput(inode); | ||
1686 | |||
1687 | return ret; | ||
1688 | } | ||
1689 | |||
1635 | /* Actual function called from quotactl() */ | 1690 | /* Actual function called from quotactl() */ |
1636 | int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) | 1691 | int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, |
1692 | int remount) | ||
1637 | { | 1693 | { |
1638 | struct nameidata nd; | 1694 | struct nameidata nd; |
1639 | int error; | 1695 | int error; |
1640 | 1696 | ||
1697 | if (remount) | ||
1698 | return vfs_quota_on_remount(sb, type); | ||
1699 | |||
1641 | error = path_lookup(path, LOOKUP_FOLLOW, &nd); | 1700 | error = path_lookup(path, LOOKUP_FOLLOW, &nd); |
1642 | if (error < 0) | 1701 | if (error < 0) |
1643 | return error; | 1702 | return error; |
diff --git a/fs/quota.c b/fs/quota.c index 84f28dd72116..db1cc9f3c7aa 100644 --- a/fs/quota.c +++ b/fs/quota.c | |||
@@ -69,7 +69,6 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid | |||
69 | switch (cmd) { | 69 | switch (cmd) { |
70 | case Q_GETFMT: | 70 | case Q_GETFMT: |
71 | case Q_GETINFO: | 71 | case Q_GETINFO: |
72 | case Q_QUOTAOFF: | ||
73 | case Q_SETINFO: | 72 | case Q_SETINFO: |
74 | case Q_SETQUOTA: | 73 | case Q_SETQUOTA: |
75 | case Q_GETQUOTA: | 74 | case Q_GETQUOTA: |
@@ -229,12 +228,12 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void | |||
229 | 228 | ||
230 | if (IS_ERR(pathname = getname(addr))) | 229 | if (IS_ERR(pathname = getname(addr))) |
231 | return PTR_ERR(pathname); | 230 | return PTR_ERR(pathname); |
232 | ret = sb->s_qcop->quota_on(sb, type, id, pathname); | 231 | ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0); |
233 | putname(pathname); | 232 | putname(pathname); |
234 | return ret; | 233 | return ret; |
235 | } | 234 | } |
236 | case Q_QUOTAOFF: | 235 | case Q_QUOTAOFF: |
237 | return sb->s_qcop->quota_off(sb, type); | 236 | return sb->s_qcop->quota_off(sb, type, 0); |
238 | 237 | ||
239 | case Q_GETFMT: { | 238 | case Q_GETFMT: { |
240 | __u32 fmt; | 239 | __u32 fmt; |
diff --git a/fs/super.c b/fs/super.c index 4798350b2bc9..a5a4aca7e22f 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -179,7 +179,7 @@ void deactivate_super(struct super_block *s) | |||
179 | if (atomic_dec_and_lock(&s->s_active, &sb_lock)) { | 179 | if (atomic_dec_and_lock(&s->s_active, &sb_lock)) { |
180 | s->s_count -= S_BIAS-1; | 180 | s->s_count -= S_BIAS-1; |
181 | spin_unlock(&sb_lock); | 181 | spin_unlock(&sb_lock); |
182 | DQUOT_OFF(s); | 182 | DQUOT_OFF(s, 0); |
183 | down_write(&s->s_umount); | 183 | down_write(&s->s_umount); |
184 | fs->kill_sb(s); | 184 | fs->kill_sb(s); |
185 | put_filesystem(fs); | 185 | put_filesystem(fs); |
@@ -608,6 +608,7 @@ retry: | |||
608 | int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | 608 | int do_remount_sb(struct super_block *sb, int flags, void *data, int force) |
609 | { | 609 | { |
610 | int retval; | 610 | int retval; |
611 | int remount_rw; | ||
611 | 612 | ||
612 | #ifdef CONFIG_BLOCK | 613 | #ifdef CONFIG_BLOCK |
613 | if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) | 614 | if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) |
@@ -625,8 +626,11 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
625 | mark_files_ro(sb); | 626 | mark_files_ro(sb); |
626 | else if (!fs_may_remount_ro(sb)) | 627 | else if (!fs_may_remount_ro(sb)) |
627 | return -EBUSY; | 628 | return -EBUSY; |
628 | DQUOT_OFF(sb); | 629 | retval = DQUOT_OFF(sb, 1); |
630 | if (retval < 0 && retval != -ENOSYS) | ||
631 | return -EBUSY; | ||
629 | } | 632 | } |
633 | remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY); | ||
630 | 634 | ||
631 | if (sb->s_op->remount_fs) { | 635 | if (sb->s_op->remount_fs) { |
632 | lock_super(sb); | 636 | lock_super(sb); |
@@ -636,6 +640,8 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
636 | return retval; | 640 | return retval; |
637 | } | 641 | } |
638 | sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); | 642 | sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); |
643 | if (remount_rw) | ||
644 | DQUOT_ON_REMOUNT(sb); | ||
639 | return 0; | 645 | return 0; |
640 | } | 646 | } |
641 | 647 | ||