aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/dquot.c77
-rw-r--r--fs/quota.c5
-rw-r--r--fs/super.c10
-rw-r--r--include/linux/quota.h14
-rw-r--r--include/linux/quotaops.h29
5 files changed, 113 insertions, 22 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
1459static inline void reset_enable_flags(struct quota_info *dqopt, int type) 1461static 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 */
1474int vfs_quota_off(struct super_block *sb, int type) 1486int 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 */
1666static 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() */
1636int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) 1691int 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:
608int do_remount_sb(struct super_block *sb, int flags, void *data, int force) 608int 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
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 48556b039b1c..52e49dce6584 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -202,6 +202,8 @@ struct quota_format_type;
202 202
203struct mem_dqinfo { 203struct mem_dqinfo {
204 struct quota_format_type *dqi_format; 204 struct quota_format_type *dqi_format;
205 int dqi_fmt_id; /* Id of the dqi_format - used when turning
206 * quotas on after remount RW */
205 struct list_head dqi_dirty_list; /* List of dirty dquots */ 207 struct list_head dqi_dirty_list; /* List of dirty dquots */
206 unsigned long dqi_flags; 208 unsigned long dqi_flags;
207 unsigned int dqi_bgrace; 209 unsigned int dqi_bgrace;
@@ -298,8 +300,8 @@ struct dquot_operations {
298 300
299/* Operations handling requests from userspace */ 301/* Operations handling requests from userspace */
300struct quotactl_ops { 302struct quotactl_ops {
301 int (*quota_on)(struct super_block *, int, int, char *); 303 int (*quota_on)(struct super_block *, int, int, char *, int);
302 int (*quota_off)(struct super_block *, int); 304 int (*quota_off)(struct super_block *, int, int);
303 int (*quota_sync)(struct super_block *, int); 305 int (*quota_sync)(struct super_block *, int);
304 int (*get_info)(struct super_block *, int, struct if_dqinfo *); 306 int (*get_info)(struct super_block *, int, struct if_dqinfo *);
305 int (*set_info)(struct super_block *, int, struct if_dqinfo *); 307 int (*set_info)(struct super_block *, int, struct if_dqinfo *);
@@ -320,6 +322,10 @@ struct quota_format_type {
320 322
321#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ 323#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
322#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ 324#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
325#define DQUOT_USR_SUSPENDED 0x04 /* User diskquotas are off, but
326 * we have necessary info in
327 * memory to turn them on */
328#define DQUOT_GRP_SUSPENDED 0x08 /* The same for group quotas */
323 329
324struct quota_info { 330struct quota_info {
325 unsigned int flags; /* Flags for diskquotas on this device */ 331 unsigned int flags; /* Flags for diskquotas on this device */
@@ -337,6 +343,10 @@ struct quota_info {
337#define sb_any_quota_enabled(sb) (sb_has_quota_enabled(sb, USRQUOTA) | \ 343#define sb_any_quota_enabled(sb) (sb_has_quota_enabled(sb, USRQUOTA) | \
338 sb_has_quota_enabled(sb, GRPQUOTA)) 344 sb_has_quota_enabled(sb, GRPQUOTA))
339 345
346#define sb_has_quota_suspended(sb, type) \
347 ((type) == USRQUOTA ? (sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED) : \
348 (sb_dqopt(sb)->flags & DQUOT_GRP_SUSPENDED))
349
340int register_quota_format(struct quota_format_type *fmt); 350int register_quota_format(struct quota_format_type *fmt);
341void unregister_quota_format(struct quota_format_type *fmt); 351void unregister_quota_format(struct quota_format_type *fmt);
342 352
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 1aac25511f07..c97c8f3fa6ee 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -37,10 +37,11 @@ extern int dquot_release(struct dquot *dquot);
37extern int dquot_commit_info(struct super_block *sb, int type); 37extern int dquot_commit_info(struct super_block *sb, int type);
38extern int dquot_mark_dquot_dirty(struct dquot *dquot); 38extern int dquot_mark_dquot_dirty(struct dquot *dquot);
39 39
40extern int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path); 40extern int vfs_quota_on(struct super_block *sb, int type, int format_id,
41 char *path, int remount);
41extern int vfs_quota_on_mount(struct super_block *sb, char *qf_name, 42extern int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
42 int format_id, int type); 43 int format_id, int type);
43extern int vfs_quota_off(struct super_block *sb, int type); 44extern int vfs_quota_off(struct super_block *sb, int type, int remount);
44extern int vfs_quota_sync(struct super_block *sb, int type); 45extern int vfs_quota_sync(struct super_block *sb, int type);
45extern int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); 46extern int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
46extern int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); 47extern int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
@@ -175,12 +176,27 @@ static inline void DQUOT_SYNC(struct super_block *sb)
175 sync_dquots(sb, -1); 176 sync_dquots(sb, -1);
176} 177}
177 178
178static inline int DQUOT_OFF(struct super_block *sb) 179static inline int DQUOT_OFF(struct super_block *sb, int remount)
179{ 180{
180 int ret = -ENOSYS; 181 int ret = -ENOSYS;
181 182
182 if (sb_any_quota_enabled(sb) && sb->s_qcop && sb->s_qcop->quota_off) 183 if (sb->s_qcop && sb->s_qcop->quota_off)
183 ret = sb->s_qcop->quota_off(sb, -1); 184 ret = sb->s_qcop->quota_off(sb, -1, remount);
185 return ret;
186}
187
188static inline int DQUOT_ON_REMOUNT(struct super_block *sb)
189{
190 int cnt;
191 int ret = 0, err;
192
193 if (!sb->s_qcop || !sb->s_qcop->quota_on)
194 return -ENOSYS;
195 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
196 err = sb->s_qcop->quota_on(sb, cnt, 0, NULL, 1);
197 if (err < 0 && !ret)
198 ret = err;
199 }
184 return ret; 200 return ret;
185} 201}
186 202
@@ -196,7 +212,8 @@ static inline int DQUOT_OFF(struct super_block *sb)
196#define DQUOT_ALLOC_INODE(inode) (0) 212#define DQUOT_ALLOC_INODE(inode) (0)
197#define DQUOT_FREE_INODE(inode) do { } while(0) 213#define DQUOT_FREE_INODE(inode) do { } while(0)
198#define DQUOT_SYNC(sb) do { } while(0) 214#define DQUOT_SYNC(sb) do { } while(0)
199#define DQUOT_OFF(sb) (0) 215#define DQUOT_OFF(sb, remount) (0)
216#define DQUOT_ON_REMOUNT(sb) (0)
200#define DQUOT_TRANSFER(inode, iattr) (0) 217#define DQUOT_TRANSFER(inode, iattr) (0)
201static inline int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) 218static inline int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
202{ 219{