diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-10 18:52:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-10 18:52:38 -0500 |
commit | c5452a58db9bbcb331ee92afa99a6f42e39085c7 (patch) | |
tree | 90d3749e9103b0582079b40f64743959767df268 /fs/quota | |
parent | 4b4f8580a4b77126733db8072862793d4deae66a (diff) | |
parent | 6981498d7956e3177b6f74926aa4a5c2a45b4edb (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull quota interface unification and misc cleanups from Jan Kara:
"The first part of the series unifying XFS and VFS quota interfaces.
This part unifies turning quotas on and off so quota-tools and
xfs_quota can be used to manage any filesystem. This is useful so
that userspace doesn't have to distinguish which filesystem it is
working with. As a result we can then easily reuse tests for project
quotas in XFS for ext4.
This also contains minor cleanups and fixes for udf, isofs, and ext3"
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: (23 commits)
udf: remove bool assignment to 0/1
udf: use bool for done
quota: Store maximum space limit in bytes
quota: Remove quota_on_meta callback
ocfs2: Use generic helpers for quotaon and quotaoff
ext4: Use generic helpers for quotaon and quotaoff
quota: Add ->quota_{enable,disable} callbacks for VFS quotas
quota: Wire up ->quota_{enable,disable} callbacks into Q_QUOTA{ON,OFF}
quota: Split ->set_xstate callback into two
xfs: Remove some pointless quota checks
xfs: Remove some useless flags tests
xfs: Remove useless test
quota: Verify flags passed to Q_SETINFO
quota: Cleanup flags definitions
ocfs2: Move OLQF_CLEAN flag out of generic quota flags
quota: Don't store flags for v2 quota format
jbd: drop jbd_ENOSYS debug
udf: destroy sbi mutex in put_super
udf: Check length of extended attributes and allocation descriptors
udf: Remove repeated loads blocksize
...
Diffstat (limited to 'fs/quota')
-rw-r--r-- | fs/quota/dquot.c | 107 | ||||
-rw-r--r-- | fs/quota/quota.c | 52 | ||||
-rw-r--r-- | fs/quota/quota_v1.c | 4 | ||||
-rw-r--r-- | fs/quota/quota_v2.c | 16 |
4 files changed, 151 insertions, 28 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 69df5b239844..0ccd4ba3a246 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -1248,7 +1248,7 @@ static int ignore_hardlimit(struct dquot *dquot) | |||
1248 | 1248 | ||
1249 | return capable(CAP_SYS_RESOURCE) && | 1249 | return capable(CAP_SYS_RESOURCE) && |
1250 | (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || | 1250 | (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || |
1251 | !(info->dqi_flags & V1_DQF_RSQUASH)); | 1251 | !(info->dqi_flags & DQF_ROOT_SQUASH)); |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | /* needs dq_data_lock */ | 1254 | /* needs dq_data_lock */ |
@@ -2385,14 +2385,84 @@ out: | |||
2385 | } | 2385 | } |
2386 | EXPORT_SYMBOL(dquot_quota_on_mount); | 2386 | EXPORT_SYMBOL(dquot_quota_on_mount); |
2387 | 2387 | ||
2388 | static inline qsize_t qbtos(qsize_t blocks) | 2388 | static int dquot_quota_enable(struct super_block *sb, unsigned int flags) |
2389 | { | 2389 | { |
2390 | return blocks << QIF_DQBLKSIZE_BITS; | 2390 | int ret; |
2391 | int type; | ||
2392 | struct quota_info *dqopt = sb_dqopt(sb); | ||
2393 | |||
2394 | if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) | ||
2395 | return -ENOSYS; | ||
2396 | /* Accounting cannot be turned on while fs is mounted */ | ||
2397 | flags &= ~(FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT | FS_QUOTA_PDQ_ACCT); | ||
2398 | if (!flags) | ||
2399 | return -EINVAL; | ||
2400 | for (type = 0; type < MAXQUOTAS; type++) { | ||
2401 | if (!(flags & qtype_enforce_flag(type))) | ||
2402 | continue; | ||
2403 | /* Can't enforce without accounting */ | ||
2404 | if (!sb_has_quota_usage_enabled(sb, type)) | ||
2405 | return -EINVAL; | ||
2406 | ret = dquot_enable(dqopt->files[type], type, | ||
2407 | dqopt->info[type].dqi_fmt_id, | ||
2408 | DQUOT_LIMITS_ENABLED); | ||
2409 | if (ret < 0) | ||
2410 | goto out_err; | ||
2411 | } | ||
2412 | return 0; | ||
2413 | out_err: | ||
2414 | /* Backout enforcement enablement we already did */ | ||
2415 | for (type--; type >= 0; type--) { | ||
2416 | if (flags & qtype_enforce_flag(type)) | ||
2417 | dquot_disable(sb, type, DQUOT_LIMITS_ENABLED); | ||
2418 | } | ||
2419 | /* Error code translation for better compatibility with XFS */ | ||
2420 | if (ret == -EBUSY) | ||
2421 | ret = -EEXIST; | ||
2422 | return ret; | ||
2391 | } | 2423 | } |
2392 | 2424 | ||
2393 | static inline qsize_t stoqb(qsize_t space) | 2425 | static int dquot_quota_disable(struct super_block *sb, unsigned int flags) |
2394 | { | 2426 | { |
2395 | return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS; | 2427 | int ret; |
2428 | int type; | ||
2429 | struct quota_info *dqopt = sb_dqopt(sb); | ||
2430 | |||
2431 | if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) | ||
2432 | return -ENOSYS; | ||
2433 | /* | ||
2434 | * We don't support turning off accounting via quotactl. In principle | ||
2435 | * quota infrastructure can do this but filesystems don't expect | ||
2436 | * userspace to be able to do it. | ||
2437 | */ | ||
2438 | if (flags & | ||
2439 | (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT | FS_QUOTA_PDQ_ACCT)) | ||
2440 | return -EOPNOTSUPP; | ||
2441 | |||
2442 | /* Filter out limits not enabled */ | ||
2443 | for (type = 0; type < MAXQUOTAS; type++) | ||
2444 | if (!sb_has_quota_limits_enabled(sb, type)) | ||
2445 | flags &= ~qtype_enforce_flag(type); | ||
2446 | /* Nothing left? */ | ||
2447 | if (!flags) | ||
2448 | return -EEXIST; | ||
2449 | for (type = 0; type < MAXQUOTAS; type++) { | ||
2450 | if (flags & qtype_enforce_flag(type)) { | ||
2451 | ret = dquot_disable(sb, type, DQUOT_LIMITS_ENABLED); | ||
2452 | if (ret < 0) | ||
2453 | goto out_err; | ||
2454 | } | ||
2455 | } | ||
2456 | return 0; | ||
2457 | out_err: | ||
2458 | /* Backout enforcement disabling we already did */ | ||
2459 | for (type--; type >= 0; type--) { | ||
2460 | if (flags & qtype_enforce_flag(type)) | ||
2461 | dquot_enable(dqopt->files[type], type, | ||
2462 | dqopt->info[type].dqi_fmt_id, | ||
2463 | DQUOT_LIMITS_ENABLED); | ||
2464 | } | ||
2465 | return ret; | ||
2396 | } | 2466 | } |
2397 | 2467 | ||
2398 | /* Generic routine for getting common part of quota structure */ | 2468 | /* Generic routine for getting common part of quota structure */ |
@@ -2444,13 +2514,13 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di) | |||
2444 | return -EINVAL; | 2514 | return -EINVAL; |
2445 | 2515 | ||
2446 | if (((di->d_fieldmask & QC_SPC_SOFT) && | 2516 | if (((di->d_fieldmask & QC_SPC_SOFT) && |
2447 | stoqb(di->d_spc_softlimit) > dqi->dqi_maxblimit) || | 2517 | di->d_spc_softlimit > dqi->dqi_max_spc_limit) || |
2448 | ((di->d_fieldmask & QC_SPC_HARD) && | 2518 | ((di->d_fieldmask & QC_SPC_HARD) && |
2449 | stoqb(di->d_spc_hardlimit) > dqi->dqi_maxblimit) || | 2519 | di->d_spc_hardlimit > dqi->dqi_max_spc_limit) || |
2450 | ((di->d_fieldmask & QC_INO_SOFT) && | 2520 | ((di->d_fieldmask & QC_INO_SOFT) && |
2451 | (di->d_ino_softlimit > dqi->dqi_maxilimit)) || | 2521 | (di->d_ino_softlimit > dqi->dqi_max_ino_limit)) || |
2452 | ((di->d_fieldmask & QC_INO_HARD) && | 2522 | ((di->d_fieldmask & QC_INO_HARD) && |
2453 | (di->d_ino_hardlimit > dqi->dqi_maxilimit))) | 2523 | (di->d_ino_hardlimit > dqi->dqi_max_ino_limit))) |
2454 | return -ERANGE; | 2524 | return -ERANGE; |
2455 | 2525 | ||
2456 | spin_lock(&dq_data_lock); | 2526 | spin_lock(&dq_data_lock); |
@@ -2577,6 +2647,14 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) | |||
2577 | goto out; | 2647 | goto out; |
2578 | } | 2648 | } |
2579 | mi = sb_dqopt(sb)->info + type; | 2649 | mi = sb_dqopt(sb)->info + type; |
2650 | if (ii->dqi_valid & IIF_FLAGS) { | ||
2651 | if (ii->dqi_flags & ~DQF_SETINFO_MASK || | ||
2652 | (ii->dqi_flags & DQF_ROOT_SQUASH && | ||
2653 | mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) { | ||
2654 | err = -EINVAL; | ||
2655 | goto out; | ||
2656 | } | ||
2657 | } | ||
2580 | spin_lock(&dq_data_lock); | 2658 | spin_lock(&dq_data_lock); |
2581 | if (ii->dqi_valid & IIF_BGRACE) | 2659 | if (ii->dqi_valid & IIF_BGRACE) |
2582 | mi->dqi_bgrace = ii->dqi_bgrace; | 2660 | mi->dqi_bgrace = ii->dqi_bgrace; |
@@ -2606,6 +2684,17 @@ const struct quotactl_ops dquot_quotactl_ops = { | |||
2606 | }; | 2684 | }; |
2607 | EXPORT_SYMBOL(dquot_quotactl_ops); | 2685 | EXPORT_SYMBOL(dquot_quotactl_ops); |
2608 | 2686 | ||
2687 | const struct quotactl_ops dquot_quotactl_sysfile_ops = { | ||
2688 | .quota_enable = dquot_quota_enable, | ||
2689 | .quota_disable = dquot_quota_disable, | ||
2690 | .quota_sync = dquot_quota_sync, | ||
2691 | .get_info = dquot_get_dqinfo, | ||
2692 | .set_info = dquot_set_dqinfo, | ||
2693 | .get_dqblk = dquot_get_dqblk, | ||
2694 | .set_dqblk = dquot_set_dqblk | ||
2695 | }; | ||
2696 | EXPORT_SYMBOL(dquot_quotactl_sysfile_ops); | ||
2697 | |||
2609 | static int do_proc_dqstats(struct ctl_table *table, int write, | 2698 | static int do_proc_dqstats(struct ctl_table *table, int write, |
2610 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2699 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2611 | { | 2700 | { |
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 6f3856328eea..d14a799c7785 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
@@ -66,18 +66,40 @@ static int quota_sync_all(int type) | |||
66 | return ret; | 66 | return ret; |
67 | } | 67 | } |
68 | 68 | ||
69 | unsigned int qtype_enforce_flag(int type) | ||
70 | { | ||
71 | switch (type) { | ||
72 | case USRQUOTA: | ||
73 | return FS_QUOTA_UDQ_ENFD; | ||
74 | case GRPQUOTA: | ||
75 | return FS_QUOTA_GDQ_ENFD; | ||
76 | case PRJQUOTA: | ||
77 | return FS_QUOTA_PDQ_ENFD; | ||
78 | } | ||
79 | return 0; | ||
80 | } | ||
81 | |||
69 | static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, | 82 | static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, |
70 | struct path *path) | 83 | struct path *path) |
71 | { | 84 | { |
72 | if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta) | 85 | if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_enable) |
73 | return -ENOSYS; | 86 | return -ENOSYS; |
74 | if (sb->s_qcop->quota_on_meta) | 87 | if (sb->s_qcop->quota_enable) |
75 | return sb->s_qcop->quota_on_meta(sb, type, id); | 88 | return sb->s_qcop->quota_enable(sb, qtype_enforce_flag(type)); |
76 | if (IS_ERR(path)) | 89 | if (IS_ERR(path)) |
77 | return PTR_ERR(path); | 90 | return PTR_ERR(path); |
78 | return sb->s_qcop->quota_on(sb, type, id, path); | 91 | return sb->s_qcop->quota_on(sb, type, id, path); |
79 | } | 92 | } |
80 | 93 | ||
94 | static int quota_quotaoff(struct super_block *sb, int type) | ||
95 | { | ||
96 | if (!sb->s_qcop->quota_off && !sb->s_qcop->quota_disable) | ||
97 | return -ENOSYS; | ||
98 | if (sb->s_qcop->quota_disable) | ||
99 | return sb->s_qcop->quota_disable(sb, qtype_enforce_flag(type)); | ||
100 | return sb->s_qcop->quota_off(sb, type); | ||
101 | } | ||
102 | |||
81 | static int quota_getfmt(struct super_block *sb, int type, void __user *addr) | 103 | static int quota_getfmt(struct super_block *sb, int type, void __user *addr) |
82 | { | 104 | { |
83 | __u32 fmt; | 105 | __u32 fmt; |
@@ -208,15 +230,26 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id, | |||
208 | return sb->s_qcop->set_dqblk(sb, qid, &fdq); | 230 | return sb->s_qcop->set_dqblk(sb, qid, &fdq); |
209 | } | 231 | } |
210 | 232 | ||
211 | static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr) | 233 | static int quota_enable(struct super_block *sb, void __user *addr) |
212 | { | 234 | { |
213 | __u32 flags; | 235 | __u32 flags; |
214 | 236 | ||
215 | if (copy_from_user(&flags, addr, sizeof(flags))) | 237 | if (copy_from_user(&flags, addr, sizeof(flags))) |
216 | return -EFAULT; | 238 | return -EFAULT; |
217 | if (!sb->s_qcop->set_xstate) | 239 | if (!sb->s_qcop->quota_enable) |
218 | return -ENOSYS; | 240 | return -ENOSYS; |
219 | return sb->s_qcop->set_xstate(sb, flags, cmd); | 241 | return sb->s_qcop->quota_enable(sb, flags); |
242 | } | ||
243 | |||
244 | static int quota_disable(struct super_block *sb, void __user *addr) | ||
245 | { | ||
246 | __u32 flags; | ||
247 | |||
248 | if (copy_from_user(&flags, addr, sizeof(flags))) | ||
249 | return -EFAULT; | ||
250 | if (!sb->s_qcop->quota_disable) | ||
251 | return -ENOSYS; | ||
252 | return sb->s_qcop->quota_disable(sb, flags); | ||
220 | } | 253 | } |
221 | 254 | ||
222 | static int quota_getxstate(struct super_block *sb, void __user *addr) | 255 | static int quota_getxstate(struct super_block *sb, void __user *addr) |
@@ -429,9 +462,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, | |||
429 | case Q_QUOTAON: | 462 | case Q_QUOTAON: |
430 | return quota_quotaon(sb, type, cmd, id, path); | 463 | return quota_quotaon(sb, type, cmd, id, path); |
431 | case Q_QUOTAOFF: | 464 | case Q_QUOTAOFF: |
432 | if (!sb->s_qcop->quota_off) | 465 | return quota_quotaoff(sb, type); |
433 | return -ENOSYS; | ||
434 | return sb->s_qcop->quota_off(sb, type); | ||
435 | case Q_GETFMT: | 466 | case Q_GETFMT: |
436 | return quota_getfmt(sb, type, addr); | 467 | return quota_getfmt(sb, type, addr); |
437 | case Q_GETINFO: | 468 | case Q_GETINFO: |
@@ -447,8 +478,9 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, | |||
447 | return -ENOSYS; | 478 | return -ENOSYS; |
448 | return sb->s_qcop->quota_sync(sb, type); | 479 | return sb->s_qcop->quota_sync(sb, type); |
449 | case Q_XQUOTAON: | 480 | case Q_XQUOTAON: |
481 | return quota_enable(sb, addr); | ||
450 | case Q_XQUOTAOFF: | 482 | case Q_XQUOTAOFF: |
451 | return quota_setxstate(sb, cmd, addr); | 483 | return quota_disable(sb, addr); |
452 | case Q_XQUOTARM: | 484 | case Q_XQUOTARM: |
453 | return quota_rmxquota(sb, addr); | 485 | return quota_rmxquota(sb, addr); |
454 | case Q_XGETQSTAT: | 486 | case Q_XGETQSTAT: |
diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c index 469c6848b322..8fe79beced5c 100644 --- a/fs/quota/quota_v1.c +++ b/fs/quota/quota_v1.c | |||
@@ -169,8 +169,8 @@ static int v1_read_file_info(struct super_block *sb, int type) | |||
169 | } | 169 | } |
170 | ret = 0; | 170 | ret = 0; |
171 | /* limits are stored as unsigned 32-bit data */ | 171 | /* limits are stored as unsigned 32-bit data */ |
172 | dqopt->info[type].dqi_maxblimit = 0xffffffff; | 172 | dqopt->info[type].dqi_max_spc_limit = 0xffffffffULL << QUOTABLOCK_BITS; |
173 | dqopt->info[type].dqi_maxilimit = 0xffffffff; | 173 | dqopt->info[type].dqi_max_ino_limit = 0xffffffff; |
174 | dqopt->info[type].dqi_igrace = | 174 | dqopt->info[type].dqi_igrace = |
175 | dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME; | 175 | dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME; |
176 | dqopt->info[type].dqi_bgrace = | 176 | dqopt->info[type].dqi_bgrace = |
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 02751ec695c5..9cb10d7197f7 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c | |||
@@ -117,16 +117,17 @@ static int v2_read_file_info(struct super_block *sb, int type) | |||
117 | qinfo = info->dqi_priv; | 117 | qinfo = info->dqi_priv; |
118 | if (version == 0) { | 118 | if (version == 0) { |
119 | /* limits are stored as unsigned 32-bit data */ | 119 | /* limits are stored as unsigned 32-bit data */ |
120 | info->dqi_maxblimit = 0xffffffff; | 120 | info->dqi_max_spc_limit = 0xffffffffULL << QUOTABLOCK_BITS; |
121 | info->dqi_maxilimit = 0xffffffff; | 121 | info->dqi_max_ino_limit = 0xffffffff; |
122 | } else { | 122 | } else { |
123 | /* used space is stored as unsigned 64-bit value */ | 123 | /* used space is stored as unsigned 64-bit value in bytes */ |
124 | info->dqi_maxblimit = 0xffffffffffffffffULL; /* 2^64-1 */ | 124 | info->dqi_max_spc_limit = 0xffffffffffffffffULL; /* 2^64-1 */ |
125 | info->dqi_maxilimit = 0xffffffffffffffffULL; | 125 | info->dqi_max_ino_limit = 0xffffffffffffffffULL; |
126 | } | 126 | } |
127 | info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); | 127 | info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); |
128 | info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); | 128 | info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); |
129 | info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); | 129 | /* No flags currently supported */ |
130 | info->dqi_flags = 0; | ||
130 | qinfo->dqi_sb = sb; | 131 | qinfo->dqi_sb = sb; |
131 | qinfo->dqi_type = type; | 132 | qinfo->dqi_type = type; |
132 | qinfo->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); | 133 | qinfo->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); |
@@ -157,7 +158,8 @@ static int v2_write_file_info(struct super_block *sb, int type) | |||
157 | info->dqi_flags &= ~DQF_INFO_DIRTY; | 158 | info->dqi_flags &= ~DQF_INFO_DIRTY; |
158 | dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace); | 159 | dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace); |
159 | dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); | 160 | dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); |
160 | dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); | 161 | /* No flags currently supported */ |
162 | dinfo.dqi_flags = cpu_to_le32(0); | ||
161 | spin_unlock(&dq_data_lock); | 163 | spin_unlock(&dq_data_lock); |
162 | dinfo.dqi_blocks = cpu_to_le32(qinfo->dqi_blocks); | 164 | dinfo.dqi_blocks = cpu_to_le32(qinfo->dqi_blocks); |
163 | dinfo.dqi_free_blk = cpu_to_le32(qinfo->dqi_free_blk); | 165 | dinfo.dqi_free_blk = cpu_to_le32(qinfo->dqi_free_blk); |