diff options
| author | Jan Kara <jack@suse.cz> | 2015-03-16 05:26:41 -0400 |
|---|---|---|
| committer | Jan Kara <jack@suse.cz> | 2015-03-16 05:26:41 -0400 |
| commit | 7dca0548a21e5efa445b68a73554ef863e09c623 (patch) | |
| tree | 816483928c6da02928a256fb64617071f98552ed | |
| parent | 1be440de2ac5181495a7295fa9a4c8ad0793f056 (diff) | |
| parent | c39fb53b48c851b185c22548153581d78f2acc11 (diff) | |
Merge branch 'quota_interface' into for_next_testing
| -rw-r--r-- | fs/ext3/super.c | 2 | ||||
| -rw-r--r-- | fs/ext4/super.c | 2 | ||||
| -rw-r--r-- | fs/gfs2/quota.c | 28 | ||||
| -rw-r--r-- | fs/quota/dquot.c | 68 | ||||
| -rw-r--r-- | fs/quota/quota.c | 217 | ||||
| -rw-r--r-- | fs/reiserfs/super.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_qm.h | 4 | ||||
| -rw-r--r-- | fs/xfs/xfs_qm_syscalls.c | 176 | ||||
| -rw-r--r-- | fs/xfs/xfs_quotaops.c | 117 | ||||
| -rw-r--r-- | include/linux/quota.h | 56 | ||||
| -rw-r--r-- | include/linux/quotaops.h | 4 |
11 files changed, 422 insertions, 254 deletions
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index d4dbf3c259b3..f037b4b27300 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
| @@ -789,7 +789,7 @@ static const struct quotactl_ops ext3_qctl_operations = { | |||
| 789 | .quota_on = ext3_quota_on, | 789 | .quota_on = ext3_quota_on, |
| 790 | .quota_off = dquot_quota_off, | 790 | .quota_off = dquot_quota_off, |
| 791 | .quota_sync = dquot_quota_sync, | 791 | .quota_sync = dquot_quota_sync, |
| 792 | .get_info = dquot_get_dqinfo, | 792 | .get_state = dquot_get_state, |
| 793 | .set_info = dquot_set_dqinfo, | 793 | .set_info = dquot_set_dqinfo, |
| 794 | .get_dqblk = dquot_get_dqblk, | 794 | .get_dqblk = dquot_get_dqblk, |
| 795 | .set_dqblk = dquot_set_dqblk | 795 | .set_dqblk = dquot_set_dqblk |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e061e66c8280..d348c7d29d80 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -1076,7 +1076,7 @@ static const struct quotactl_ops ext4_qctl_operations = { | |||
| 1076 | .quota_on = ext4_quota_on, | 1076 | .quota_on = ext4_quota_on, |
| 1077 | .quota_off = ext4_quota_off, | 1077 | .quota_off = ext4_quota_off, |
| 1078 | .quota_sync = dquot_quota_sync, | 1078 | .quota_sync = dquot_quota_sync, |
| 1079 | .get_info = dquot_get_dqinfo, | 1079 | .get_state = dquot_get_state, |
| 1080 | .set_info = dquot_set_dqinfo, | 1080 | .set_info = dquot_set_dqinfo, |
| 1081 | .get_dqblk = dquot_get_dqblk, | 1081 | .get_dqblk = dquot_get_dqblk, |
| 1082 | .set_dqblk = dquot_set_dqblk | 1082 | .set_dqblk = dquot_set_dqblk |
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 3aa17d4d1cfc..fa54cbf4c866 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
| @@ -1468,32 +1468,34 @@ int gfs2_quotad(void *data) | |||
| 1468 | return 0; | 1468 | return 0; |
| 1469 | } | 1469 | } |
| 1470 | 1470 | ||
| 1471 | static int gfs2_quota_get_xstate(struct super_block *sb, | 1471 | static int gfs2_quota_get_state(struct super_block *sb, struct qc_state *state) |
| 1472 | struct fs_quota_stat *fqs) | ||
| 1473 | { | 1472 | { |
| 1474 | struct gfs2_sbd *sdp = sb->s_fs_info; | 1473 | struct gfs2_sbd *sdp = sb->s_fs_info; |
| 1475 | 1474 | ||
| 1476 | memset(fqs, 0, sizeof(struct fs_quota_stat)); | 1475 | memset(state, 0, sizeof(*state)); |
| 1477 | fqs->qs_version = FS_QSTAT_VERSION; | ||
| 1478 | 1476 | ||
| 1479 | switch (sdp->sd_args.ar_quota) { | 1477 | switch (sdp->sd_args.ar_quota) { |
| 1480 | case GFS2_QUOTA_ON: | 1478 | case GFS2_QUOTA_ON: |
| 1481 | fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD); | 1479 | state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED; |
| 1480 | state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED; | ||
| 1482 | /*FALLTHRU*/ | 1481 | /*FALLTHRU*/ |
| 1483 | case GFS2_QUOTA_ACCOUNT: | 1482 | case GFS2_QUOTA_ACCOUNT: |
| 1484 | fqs->qs_flags |= (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT); | 1483 | state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED | |
| 1484 | QCI_SYSFILE; | ||
| 1485 | state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED | | ||
| 1486 | QCI_SYSFILE; | ||
| 1485 | break; | 1487 | break; |
| 1486 | case GFS2_QUOTA_OFF: | 1488 | case GFS2_QUOTA_OFF: |
| 1487 | break; | 1489 | break; |
| 1488 | } | 1490 | } |
| 1489 | |||
| 1490 | if (sdp->sd_quota_inode) { | 1491 | if (sdp->sd_quota_inode) { |
| 1491 | fqs->qs_uquota.qfs_ino = GFS2_I(sdp->sd_quota_inode)->i_no_addr; | 1492 | state->s_state[USRQUOTA].ino = |
| 1492 | fqs->qs_uquota.qfs_nblks = sdp->sd_quota_inode->i_blocks; | 1493 | GFS2_I(sdp->sd_quota_inode)->i_no_addr; |
| 1494 | state->s_state[USRQUOTA].blocks = sdp->sd_quota_inode->i_blocks; | ||
| 1493 | } | 1495 | } |
| 1494 | fqs->qs_uquota.qfs_nextents = 1; /* unsupported */ | 1496 | state->s_state[USRQUOTA].nextents = 1; /* unsupported */ |
| 1495 | fqs->qs_gquota = fqs->qs_uquota; /* its the same inode in both cases */ | 1497 | state->s_state[GRPQUOTA] = state->s_state[USRQUOTA]; |
| 1496 | fqs->qs_incoredqs = list_lru_count(&gfs2_qd_lru); | 1498 | state->s_incoredqs = list_lru_count(&gfs2_qd_lru); |
| 1497 | return 0; | 1499 | return 0; |
| 1498 | } | 1500 | } |
| 1499 | 1501 | ||
| @@ -1638,7 +1640,7 @@ out_put: | |||
| 1638 | 1640 | ||
| 1639 | const struct quotactl_ops gfs2_quotactl_ops = { | 1641 | const struct quotactl_ops gfs2_quotactl_ops = { |
| 1640 | .quota_sync = gfs2_quota_sync, | 1642 | .quota_sync = gfs2_quota_sync, |
| 1641 | .get_xstate = gfs2_quota_get_xstate, | 1643 | .get_state = gfs2_quota_get_state, |
| 1642 | .get_dqblk = gfs2_get_dqblk, | 1644 | .get_dqblk = gfs2_get_dqblk, |
| 1643 | .set_dqblk = gfs2_set_dqblk, | 1645 | .set_dqblk = gfs2_set_dqblk, |
| 1644 | }; | 1646 | }; |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 2112ed33de41..327a58448592 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
| @@ -2629,55 +2629,73 @@ out: | |||
| 2629 | EXPORT_SYMBOL(dquot_set_dqblk); | 2629 | EXPORT_SYMBOL(dquot_set_dqblk); |
| 2630 | 2630 | ||
| 2631 | /* Generic routine for getting common part of quota file information */ | 2631 | /* Generic routine for getting common part of quota file information */ |
| 2632 | int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) | 2632 | int dquot_get_state(struct super_block *sb, struct qc_state *state) |
| 2633 | { | 2633 | { |
| 2634 | struct mem_dqinfo *mi; | 2634 | struct mem_dqinfo *mi; |
| 2635 | struct qc_type_state *tstate; | ||
| 2636 | struct quota_info *dqopt = sb_dqopt(sb); | ||
| 2637 | int type; | ||
| 2635 | 2638 | ||
| 2636 | mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); | 2639 | mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); |
| 2637 | if (!sb_has_quota_active(sb, type)) { | 2640 | memset(state, 0, sizeof(*state)); |
| 2638 | mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); | 2641 | for (type = 0; type < MAXQUOTAS; type++) { |
| 2639 | return -ESRCH; | 2642 | if (!sb_has_quota_active(sb, type)) |
| 2643 | continue; | ||
| 2644 | tstate = state->s_state + type; | ||
| 2645 | mi = sb_dqopt(sb)->info + type; | ||
| 2646 | tstate->flags = QCI_ACCT_ENABLED; | ||
| 2647 | spin_lock(&dq_data_lock); | ||
| 2648 | if (mi->dqi_flags & DQF_SYS_FILE) | ||
| 2649 | tstate->flags |= QCI_SYSFILE; | ||
| 2650 | if (mi->dqi_flags & DQF_ROOT_SQUASH) | ||
| 2651 | tstate->flags |= QCI_ROOT_SQUASH; | ||
| 2652 | if (sb_has_quota_limits_enabled(sb, type)) | ||
| 2653 | tstate->flags |= QCI_LIMITS_ENFORCED; | ||
| 2654 | tstate->spc_timelimit = mi->dqi_bgrace; | ||
| 2655 | tstate->ino_timelimit = mi->dqi_igrace; | ||
| 2656 | tstate->ino = dqopt->files[type]->i_ino; | ||
| 2657 | tstate->blocks = dqopt->files[type]->i_blocks; | ||
| 2658 | tstate->nextents = 1; /* We don't know... */ | ||
| 2659 | spin_unlock(&dq_data_lock); | ||
| 2640 | } | 2660 | } |
| 2641 | mi = sb_dqopt(sb)->info + type; | ||
| 2642 | spin_lock(&dq_data_lock); | ||
| 2643 | ii->dqi_bgrace = mi->dqi_bgrace; | ||
| 2644 | ii->dqi_igrace = mi->dqi_igrace; | ||
| 2645 | ii->dqi_flags = mi->dqi_flags & DQF_GETINFO_MASK; | ||
| 2646 | ii->dqi_valid = IIF_ALL; | ||
| 2647 | spin_unlock(&dq_data_lock); | ||
| 2648 | mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); | 2661 | mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); |
| 2649 | return 0; | 2662 | return 0; |
| 2650 | } | 2663 | } |
| 2651 | EXPORT_SYMBOL(dquot_get_dqinfo); | 2664 | EXPORT_SYMBOL(dquot_get_state); |
| 2652 | 2665 | ||
| 2653 | /* Generic routine for setting common part of quota file information */ | 2666 | /* Generic routine for setting common part of quota file information */ |
| 2654 | int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) | 2667 | int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii) |
| 2655 | { | 2668 | { |
| 2656 | struct mem_dqinfo *mi; | 2669 | struct mem_dqinfo *mi; |
| 2657 | int err = 0; | 2670 | int err = 0; |
| 2658 | 2671 | ||
| 2672 | if ((ii->i_fieldmask & QC_WARNS_MASK) || | ||
| 2673 | (ii->i_fieldmask & QC_RT_SPC_TIMER)) | ||
| 2674 | return -EINVAL; | ||
| 2659 | mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); | 2675 | mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); |
| 2660 | if (!sb_has_quota_active(sb, type)) { | 2676 | if (!sb_has_quota_active(sb, type)) { |
| 2661 | err = -ESRCH; | 2677 | err = -ESRCH; |
| 2662 | goto out; | 2678 | goto out; |
| 2663 | } | 2679 | } |
| 2664 | mi = sb_dqopt(sb)->info + type; | 2680 | mi = sb_dqopt(sb)->info + type; |
| 2665 | if (ii->dqi_valid & IIF_FLAGS) { | 2681 | if (ii->i_fieldmask & QC_FLAGS) { |
| 2666 | if (ii->dqi_flags & ~DQF_SETINFO_MASK || | 2682 | if ((ii->i_flags & QCI_ROOT_SQUASH && |
| 2667 | (ii->dqi_flags & DQF_ROOT_SQUASH && | ||
| 2668 | mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) { | 2683 | mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) { |
| 2669 | err = -EINVAL; | 2684 | err = -EINVAL; |
| 2670 | goto out; | 2685 | goto out; |
| 2671 | } | 2686 | } |
| 2672 | } | 2687 | } |
| 2673 | spin_lock(&dq_data_lock); | 2688 | spin_lock(&dq_data_lock); |
| 2674 | if (ii->dqi_valid & IIF_BGRACE) | 2689 | if (ii->i_fieldmask & QC_SPC_TIMER) |
| 2675 | mi->dqi_bgrace = ii->dqi_bgrace; | 2690 | mi->dqi_bgrace = ii->i_spc_timelimit; |
| 2676 | if (ii->dqi_valid & IIF_IGRACE) | 2691 | if (ii->i_fieldmask & QC_INO_TIMER) |
| 2677 | mi->dqi_igrace = ii->dqi_igrace; | 2692 | mi->dqi_igrace = ii->i_ino_timelimit; |
| 2678 | if (ii->dqi_valid & IIF_FLAGS) | 2693 | if (ii->i_fieldmask & QC_FLAGS) { |
| 2679 | mi->dqi_flags = (mi->dqi_flags & ~DQF_SETINFO_MASK) | | 2694 | if (ii->i_flags & QCI_ROOT_SQUASH) |
| 2680 | (ii->dqi_flags & DQF_SETINFO_MASK); | 2695 | mi->dqi_flags |= DQF_ROOT_SQUASH; |
| 2696 | else | ||
| 2697 | mi->dqi_flags &= ~DQF_ROOT_SQUASH; | ||
| 2698 | } | ||
| 2681 | spin_unlock(&dq_data_lock); | 2699 | spin_unlock(&dq_data_lock); |
| 2682 | mark_info_dirty(sb, type); | 2700 | mark_info_dirty(sb, type); |
| 2683 | /* Force write to disk */ | 2701 | /* Force write to disk */ |
| @@ -2692,7 +2710,7 @@ const struct quotactl_ops dquot_quotactl_ops = { | |||
| 2692 | .quota_on = dquot_quota_on, | 2710 | .quota_on = dquot_quota_on, |
| 2693 | .quota_off = dquot_quota_off, | 2711 | .quota_off = dquot_quota_off, |
| 2694 | .quota_sync = dquot_quota_sync, | 2712 | .quota_sync = dquot_quota_sync, |
| 2695 | .get_info = dquot_get_dqinfo, | 2713 | .get_state = dquot_get_state, |
| 2696 | .set_info = dquot_set_dqinfo, | 2714 | .set_info = dquot_set_dqinfo, |
| 2697 | .get_dqblk = dquot_get_dqblk, | 2715 | .get_dqblk = dquot_get_dqblk, |
| 2698 | .set_dqblk = dquot_set_dqblk | 2716 | .set_dqblk = dquot_set_dqblk |
| @@ -2703,7 +2721,7 @@ const struct quotactl_ops dquot_quotactl_sysfile_ops = { | |||
| 2703 | .quota_enable = dquot_quota_enable, | 2721 | .quota_enable = dquot_quota_enable, |
| 2704 | .quota_disable = dquot_quota_disable, | 2722 | .quota_disable = dquot_quota_disable, |
| 2705 | .quota_sync = dquot_quota_sync, | 2723 | .quota_sync = dquot_quota_sync, |
| 2706 | .get_info = dquot_get_dqinfo, | 2724 | .get_state = dquot_get_state, |
| 2707 | .set_info = dquot_set_dqinfo, | 2725 | .set_info = dquot_set_dqinfo, |
| 2708 | .get_dqblk = dquot_get_dqblk, | 2726 | .get_dqblk = dquot_get_dqblk, |
| 2709 | .set_dqblk = dquot_set_dqblk | 2727 | .set_dqblk = dquot_set_dqblk |
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index d14a799c7785..86ded7375c21 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
| @@ -118,13 +118,30 @@ static int quota_getfmt(struct super_block *sb, int type, void __user *addr) | |||
| 118 | 118 | ||
| 119 | static int quota_getinfo(struct super_block *sb, int type, void __user *addr) | 119 | static int quota_getinfo(struct super_block *sb, int type, void __user *addr) |
| 120 | { | 120 | { |
| 121 | struct if_dqinfo info; | 121 | struct qc_state state; |
| 122 | struct qc_type_state *tstate; | ||
| 123 | struct if_dqinfo uinfo; | ||
| 122 | int ret; | 124 | int ret; |
| 123 | 125 | ||
| 124 | if (!sb->s_qcop->get_info) | 126 | /* This checks whether qc_state has enough entries... */ |
| 127 | BUILD_BUG_ON(MAXQUOTAS > XQM_MAXQUOTAS); | ||
| 128 | if (!sb->s_qcop->get_state) | ||
| 125 | return -ENOSYS; | 129 | return -ENOSYS; |
| 126 | ret = sb->s_qcop->get_info(sb, type, &info); | 130 | ret = sb->s_qcop->get_state(sb, &state); |
| 127 | if (!ret && copy_to_user(addr, &info, sizeof(info))) | 131 | if (ret) |
| 132 | return ret; | ||
| 133 | tstate = state.s_state + type; | ||
| 134 | if (!(tstate->flags & QCI_ACCT_ENABLED)) | ||
| 135 | return -ESRCH; | ||
| 136 | memset(&uinfo, 0, sizeof(uinfo)); | ||
| 137 | uinfo.dqi_bgrace = tstate->spc_timelimit; | ||
| 138 | uinfo.dqi_igrace = tstate->ino_timelimit; | ||
| 139 | if (tstate->flags & QCI_SYSFILE) | ||
| 140 | uinfo.dqi_flags |= DQF_SYS_FILE; | ||
| 141 | if (tstate->flags & QCI_ROOT_SQUASH) | ||
| 142 | uinfo.dqi_flags |= DQF_ROOT_SQUASH; | ||
| 143 | uinfo.dqi_valid = IIF_ALL; | ||
| 144 | if (!ret && copy_to_user(addr, &uinfo, sizeof(uinfo))) | ||
| 128 | return -EFAULT; | 145 | return -EFAULT; |
| 129 | return ret; | 146 | return ret; |
| 130 | } | 147 | } |
| @@ -132,12 +149,31 @@ static int quota_getinfo(struct super_block *sb, int type, void __user *addr) | |||
| 132 | static int quota_setinfo(struct super_block *sb, int type, void __user *addr) | 149 | static int quota_setinfo(struct super_block *sb, int type, void __user *addr) |
| 133 | { | 150 | { |
| 134 | struct if_dqinfo info; | 151 | struct if_dqinfo info; |
| 152 | struct qc_info qinfo; | ||
| 135 | 153 | ||
| 136 | if (copy_from_user(&info, addr, sizeof(info))) | 154 | if (copy_from_user(&info, addr, sizeof(info))) |
| 137 | return -EFAULT; | 155 | return -EFAULT; |
| 138 | if (!sb->s_qcop->set_info) | 156 | if (!sb->s_qcop->set_info) |
| 139 | return -ENOSYS; | 157 | return -ENOSYS; |
| 140 | return sb->s_qcop->set_info(sb, type, &info); | 158 | if (info.dqi_valid & ~(IIF_FLAGS | IIF_BGRACE | IIF_IGRACE)) |
| 159 | return -EINVAL; | ||
| 160 | memset(&qinfo, 0, sizeof(qinfo)); | ||
| 161 | if (info.dqi_valid & IIF_FLAGS) { | ||
| 162 | if (info.dqi_flags & ~DQF_SETINFO_MASK) | ||
| 163 | return -EINVAL; | ||
| 164 | if (info.dqi_flags & DQF_ROOT_SQUASH) | ||
| 165 | qinfo.i_flags |= QCI_ROOT_SQUASH; | ||
| 166 | qinfo.i_fieldmask |= QC_FLAGS; | ||
| 167 | } | ||
| 168 | if (info.dqi_valid & IIF_BGRACE) { | ||
| 169 | qinfo.i_spc_timelimit = info.dqi_bgrace; | ||
| 170 | qinfo.i_fieldmask |= QC_SPC_TIMER; | ||
| 171 | } | ||
| 172 | if (info.dqi_valid & IIF_IGRACE) { | ||
| 173 | qinfo.i_ino_timelimit = info.dqi_igrace; | ||
| 174 | qinfo.i_fieldmask |= QC_INO_TIMER; | ||
| 175 | } | ||
| 176 | return sb->s_qcop->set_info(sb, type, &qinfo); | ||
| 141 | } | 177 | } |
| 142 | 178 | ||
| 143 | static inline qsize_t qbtos(qsize_t blocks) | 179 | static inline qsize_t qbtos(qsize_t blocks) |
| @@ -252,25 +288,149 @@ static int quota_disable(struct super_block *sb, void __user *addr) | |||
| 252 | return sb->s_qcop->quota_disable(sb, flags); | 288 | return sb->s_qcop->quota_disable(sb, flags); |
| 253 | } | 289 | } |
| 254 | 290 | ||
| 291 | static int quota_state_to_flags(struct qc_state *state) | ||
| 292 | { | ||
| 293 | int flags = 0; | ||
| 294 | |||
| 295 | if (state->s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) | ||
| 296 | flags |= FS_QUOTA_UDQ_ACCT; | ||
| 297 | if (state->s_state[USRQUOTA].flags & QCI_LIMITS_ENFORCED) | ||
| 298 | flags |= FS_QUOTA_UDQ_ENFD; | ||
| 299 | if (state->s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) | ||
| 300 | flags |= FS_QUOTA_GDQ_ACCT; | ||
| 301 | if (state->s_state[GRPQUOTA].flags & QCI_LIMITS_ENFORCED) | ||
| 302 | flags |= FS_QUOTA_GDQ_ENFD; | ||
| 303 | if (state->s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) | ||
| 304 | flags |= FS_QUOTA_PDQ_ACCT; | ||
| 305 | if (state->s_state[PRJQUOTA].flags & QCI_LIMITS_ENFORCED) | ||
| 306 | flags |= FS_QUOTA_PDQ_ENFD; | ||
| 307 | return flags; | ||
| 308 | } | ||
| 309 | |||
| 310 | static int quota_getstate(struct super_block *sb, struct fs_quota_stat *fqs) | ||
| 311 | { | ||
| 312 | int type; | ||
| 313 | struct qc_state state; | ||
| 314 | int ret; | ||
| 315 | |||
| 316 | ret = sb->s_qcop->get_state(sb, &state); | ||
| 317 | if (ret < 0) | ||
| 318 | return ret; | ||
| 319 | |||
| 320 | memset(fqs, 0, sizeof(*fqs)); | ||
| 321 | fqs->qs_version = FS_QSTAT_VERSION; | ||
| 322 | fqs->qs_flags = quota_state_to_flags(&state); | ||
| 323 | /* No quota enabled? */ | ||
| 324 | if (!fqs->qs_flags) | ||
| 325 | return -ENOSYS; | ||
| 326 | fqs->qs_incoredqs = state.s_incoredqs; | ||
| 327 | /* | ||
| 328 | * GETXSTATE quotactl has space for just one set of time limits so | ||
| 329 | * report them for the first enabled quota type | ||
| 330 | */ | ||
| 331 | for (type = 0; type < XQM_MAXQUOTAS; type++) | ||
| 332 | if (state.s_state[type].flags & QCI_ACCT_ENABLED) | ||
| 333 | break; | ||
| 334 | BUG_ON(type == XQM_MAXQUOTAS); | ||
| 335 | fqs->qs_btimelimit = state.s_state[type].spc_timelimit; | ||
| 336 | fqs->qs_itimelimit = state.s_state[type].ino_timelimit; | ||
| 337 | fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; | ||
| 338 | fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; | ||
| 339 | fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; | ||
| 340 | if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 341 | fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; | ||
| 342 | fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; | ||
| 343 | fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; | ||
| 344 | } | ||
| 345 | if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 346 | fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; | ||
| 347 | fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; | ||
| 348 | fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; | ||
| 349 | } | ||
| 350 | if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 351 | /* | ||
| 352 | * Q_XGETQSTAT doesn't have room for both group and project | ||
| 353 | * quotas. So, allow the project quota values to be copied out | ||
| 354 | * only if there is no group quota information available. | ||
| 355 | */ | ||
| 356 | if (!(state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)) { | ||
| 357 | fqs->qs_gquota.qfs_ino = state.s_state[PRJQUOTA].ino; | ||
| 358 | fqs->qs_gquota.qfs_nblks = | ||
| 359 | state.s_state[PRJQUOTA].blocks; | ||
| 360 | fqs->qs_gquota.qfs_nextents = | ||
| 361 | state.s_state[PRJQUOTA].nextents; | ||
| 362 | } | ||
| 363 | } | ||
| 364 | return 0; | ||
| 365 | } | ||
| 366 | |||
| 255 | static int quota_getxstate(struct super_block *sb, void __user *addr) | 367 | static int quota_getxstate(struct super_block *sb, void __user *addr) |
| 256 | { | 368 | { |
| 257 | struct fs_quota_stat fqs; | 369 | struct fs_quota_stat fqs; |
| 258 | int ret; | 370 | int ret; |
| 259 | 371 | ||
| 260 | if (!sb->s_qcop->get_xstate) | 372 | if (!sb->s_qcop->get_state) |
| 261 | return -ENOSYS; | 373 | return -ENOSYS; |
| 262 | ret = sb->s_qcop->get_xstate(sb, &fqs); | 374 | ret = quota_getstate(sb, &fqs); |
| 263 | if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) | 375 | if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) |
| 264 | return -EFAULT; | 376 | return -EFAULT; |
| 265 | return ret; | 377 | return ret; |
| 266 | } | 378 | } |
| 267 | 379 | ||
| 380 | static int quota_getstatev(struct super_block *sb, struct fs_quota_statv *fqs) | ||
| 381 | { | ||
| 382 | int type; | ||
| 383 | struct qc_state state; | ||
| 384 | int ret; | ||
| 385 | |||
| 386 | ret = sb->s_qcop->get_state(sb, &state); | ||
| 387 | if (ret < 0) | ||
| 388 | return ret; | ||
| 389 | |||
| 390 | memset(fqs, 0, sizeof(*fqs)); | ||
| 391 | fqs->qs_version = FS_QSTAT_VERSION; | ||
| 392 | fqs->qs_flags = quota_state_to_flags(&state); | ||
| 393 | /* No quota enabled? */ | ||
| 394 | if (!fqs->qs_flags) | ||
| 395 | return -ENOSYS; | ||
| 396 | fqs->qs_incoredqs = state.s_incoredqs; | ||
| 397 | /* | ||
| 398 | * GETXSTATV quotactl has space for just one set of time limits so | ||
| 399 | * report them for the first enabled quota type | ||
| 400 | */ | ||
| 401 | for (type = 0; type < XQM_MAXQUOTAS; type++) | ||
| 402 | if (state.s_state[type].flags & QCI_ACCT_ENABLED) | ||
| 403 | break; | ||
| 404 | BUG_ON(type == XQM_MAXQUOTAS); | ||
| 405 | fqs->qs_btimelimit = state.s_state[type].spc_timelimit; | ||
| 406 | fqs->qs_itimelimit = state.s_state[type].ino_timelimit; | ||
| 407 | fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit; | ||
| 408 | fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit; | ||
| 409 | fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit; | ||
| 410 | if (state.s_state[USRQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 411 | fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino; | ||
| 412 | fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks; | ||
| 413 | fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents; | ||
| 414 | } | ||
| 415 | if (state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 416 | fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino; | ||
| 417 | fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks; | ||
| 418 | fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents; | ||
| 419 | } | ||
| 420 | if (state.s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED) { | ||
| 421 | fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino; | ||
| 422 | fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks; | ||
| 423 | fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents; | ||
| 424 | } | ||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | |||
| 268 | static int quota_getxstatev(struct super_block *sb, void __user *addr) | 428 | static int quota_getxstatev(struct super_block *sb, void __user *addr) |
| 269 | { | 429 | { |
| 270 | struct fs_quota_statv fqs; | 430 | struct fs_quota_statv fqs; |
| 271 | int ret; | 431 | int ret; |
| 272 | 432 | ||
| 273 | if (!sb->s_qcop->get_xstatev) | 433 | if (!sb->s_qcop->get_state) |
| 274 | return -ENOSYS; | 434 | return -ENOSYS; |
| 275 | 435 | ||
| 276 | memset(&fqs, 0, sizeof(fqs)); | 436 | memset(&fqs, 0, sizeof(fqs)); |
| @@ -284,7 +444,7 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr) | |||
| 284 | default: | 444 | default: |
| 285 | return -EINVAL; | 445 | return -EINVAL; |
| 286 | } | 446 | } |
| 287 | ret = sb->s_qcop->get_xstatev(sb, &fqs); | 447 | ret = quota_getstatev(sb, &fqs); |
| 288 | if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) | 448 | if (!ret && copy_to_user(addr, &fqs, sizeof(fqs))) |
| 289 | return -EFAULT; | 449 | return -EFAULT; |
| 290 | return ret; | 450 | return ret; |
| @@ -357,6 +517,30 @@ static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src) | |||
| 357 | dst->d_fieldmask |= QC_RT_SPACE; | 517 | dst->d_fieldmask |= QC_RT_SPACE; |
| 358 | } | 518 | } |
| 359 | 519 | ||
| 520 | static void copy_qcinfo_from_xfs_dqblk(struct qc_info *dst, | ||
| 521 | struct fs_disk_quota *src) | ||
| 522 | { | ||
| 523 | memset(dst, 0, sizeof(*dst)); | ||
| 524 | dst->i_spc_timelimit = src->d_btimer; | ||
| 525 | dst->i_ino_timelimit = src->d_itimer; | ||
| 526 | dst->i_rt_spc_timelimit = src->d_rtbtimer; | ||
| 527 | dst->i_ino_warnlimit = src->d_iwarns; | ||
| 528 | dst->i_spc_warnlimit = src->d_bwarns; | ||
| 529 | dst->i_rt_spc_warnlimit = src->d_rtbwarns; | ||
| 530 | if (src->d_fieldmask & FS_DQ_BWARNS) | ||
| 531 | dst->i_fieldmask |= QC_SPC_WARNS; | ||
| 532 | if (src->d_fieldmask & FS_DQ_IWARNS) | ||
| 533 | dst->i_fieldmask |= QC_INO_WARNS; | ||
| 534 | if (src->d_fieldmask & FS_DQ_RTBWARNS) | ||
| 535 | dst->i_fieldmask |= QC_RT_SPC_WARNS; | ||
| 536 | if (src->d_fieldmask & FS_DQ_BTIMER) | ||
| 537 | dst->i_fieldmask |= QC_SPC_TIMER; | ||
| 538 | if (src->d_fieldmask & FS_DQ_ITIMER) | ||
| 539 | dst->i_fieldmask |= QC_INO_TIMER; | ||
| 540 | if (src->d_fieldmask & FS_DQ_RTBTIMER) | ||
| 541 | dst->i_fieldmask |= QC_RT_SPC_TIMER; | ||
| 542 | } | ||
| 543 | |||
| 360 | static int quota_setxquota(struct super_block *sb, int type, qid_t id, | 544 | static int quota_setxquota(struct super_block *sb, int type, qid_t id, |
| 361 | void __user *addr) | 545 | void __user *addr) |
| 362 | { | 546 | { |
| @@ -371,6 +555,21 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id, | |||
| 371 | qid = make_kqid(current_user_ns(), type, id); | 555 | qid = make_kqid(current_user_ns(), type, id); |
| 372 | if (!qid_valid(qid)) | 556 | if (!qid_valid(qid)) |
| 373 | return -EINVAL; | 557 | return -EINVAL; |
| 558 | /* Are we actually setting timer / warning limits for all users? */ | ||
| 559 | if (from_kqid(&init_user_ns, qid) == 0 && | ||
| 560 | fdq.d_fieldmask & (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) { | ||
| 561 | struct qc_info qinfo; | ||
| 562 | int ret; | ||
| 563 | |||
| 564 | if (!sb->s_qcop->set_info) | ||
| 565 | return -EINVAL; | ||
| 566 | copy_qcinfo_from_xfs_dqblk(&qinfo, &fdq); | ||
| 567 | ret = sb->s_qcop->set_info(sb, type, &qinfo); | ||
| 568 | if (ret) | ||
| 569 | return ret; | ||
| 570 | /* These are already done */ | ||
| 571 | fdq.d_fieldmask &= ~(FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK); | ||
| 572 | } | ||
| 374 | copy_from_xfs_dqblk(&qdq, &fdq); | 573 | copy_from_xfs_dqblk(&qdq, &fdq); |
| 375 | return sb->s_qcop->set_dqblk(sb, qid, &qdq); | 574 | return sb->s_qcop->set_dqblk(sb, qid, &qdq); |
| 376 | } | 575 | } |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 71fbbe3e2dab..68b5f182984e 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
| @@ -805,7 +805,7 @@ static const struct quotactl_ops reiserfs_qctl_operations = { | |||
| 805 | .quota_on = reiserfs_quota_on, | 805 | .quota_on = reiserfs_quota_on, |
| 806 | .quota_off = dquot_quota_off, | 806 | .quota_off = dquot_quota_off, |
| 807 | .quota_sync = dquot_quota_sync, | 807 | .quota_sync = dquot_quota_sync, |
| 808 | .get_info = dquot_get_dqinfo, | 808 | .get_state = dquot_get_state, |
| 809 | .set_info = dquot_set_dqinfo, | 809 | .set_info = dquot_set_dqinfo, |
| 810 | .get_dqblk = dquot_get_dqblk, | 810 | .get_dqblk = dquot_get_dqblk, |
| 811 | .set_dqblk = dquot_set_dqblk, | 811 | .set_dqblk = dquot_set_dqblk, |
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h index 0d4d3590cf85..996a04064894 100644 --- a/fs/xfs/xfs_qm.h +++ b/fs/xfs/xfs_qm.h | |||
| @@ -168,10 +168,6 @@ extern int xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t, | |||
| 168 | uint, struct qc_dqblk *); | 168 | uint, struct qc_dqblk *); |
| 169 | extern int xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint, | 169 | extern int xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint, |
| 170 | struct qc_dqblk *); | 170 | struct qc_dqblk *); |
| 171 | extern int xfs_qm_scall_getqstat(struct xfs_mount *, | ||
| 172 | struct fs_quota_stat *); | ||
| 173 | extern int xfs_qm_scall_getqstatv(struct xfs_mount *, | ||
| 174 | struct fs_quota_statv *); | ||
| 175 | extern int xfs_qm_scall_quotaon(struct xfs_mount *, uint); | 171 | extern int xfs_qm_scall_quotaon(struct xfs_mount *, uint); |
| 176 | extern int xfs_qm_scall_quotaoff(struct xfs_mount *, uint); | 172 | extern int xfs_qm_scall_quotaoff(struct xfs_mount *, uint); |
| 177 | 173 | ||
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 9b965db45800..9a25c9275fb3 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c | |||
| @@ -38,7 +38,6 @@ | |||
| 38 | STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint); | 38 | STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint); |
| 39 | STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *, | 39 | STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *, |
| 40 | uint); | 40 | uint); |
| 41 | STATIC uint xfs_qm_export_flags(uint); | ||
| 42 | 41 | ||
| 43 | /* | 42 | /* |
| 44 | * Turn off quota accounting and/or enforcement for all udquots and/or | 43 | * Turn off quota accounting and/or enforcement for all udquots and/or |
| @@ -389,159 +388,6 @@ xfs_qm_scall_quotaon( | |||
| 389 | return 0; | 388 | return 0; |
| 390 | } | 389 | } |
| 391 | 390 | ||
| 392 | |||
| 393 | /* | ||
| 394 | * Return quota status information, such as uquota-off, enforcements, etc. | ||
| 395 | * for Q_XGETQSTAT command. | ||
| 396 | */ | ||
| 397 | int | ||
| 398 | xfs_qm_scall_getqstat( | ||
| 399 | struct xfs_mount *mp, | ||
| 400 | struct fs_quota_stat *out) | ||
| 401 | { | ||
| 402 | struct xfs_quotainfo *q = mp->m_quotainfo; | ||
| 403 | struct xfs_inode *uip = NULL; | ||
| 404 | struct xfs_inode *gip = NULL; | ||
| 405 | struct xfs_inode *pip = NULL; | ||
| 406 | bool tempuqip = false; | ||
| 407 | bool tempgqip = false; | ||
| 408 | bool temppqip = false; | ||
| 409 | |||
| 410 | memset(out, 0, sizeof(fs_quota_stat_t)); | ||
| 411 | |||
| 412 | out->qs_version = FS_QSTAT_VERSION; | ||
| 413 | out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags & | ||
| 414 | (XFS_ALL_QUOTA_ACCT| | ||
| 415 | XFS_ALL_QUOTA_ENFD)); | ||
| 416 | uip = q->qi_uquotaip; | ||
| 417 | gip = q->qi_gquotaip; | ||
| 418 | pip = q->qi_pquotaip; | ||
| 419 | if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { | ||
| 420 | if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, | ||
| 421 | 0, 0, &uip) == 0) | ||
| 422 | tempuqip = true; | ||
| 423 | } | ||
| 424 | if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { | ||
| 425 | if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, | ||
| 426 | 0, 0, &gip) == 0) | ||
| 427 | tempgqip = true; | ||
| 428 | } | ||
| 429 | /* | ||
| 430 | * Q_XGETQSTAT doesn't have room for both group and project quotas. | ||
| 431 | * So, allow the project quota values to be copied out only if | ||
| 432 | * there is no group quota information available. | ||
| 433 | */ | ||
| 434 | if (!gip) { | ||
| 435 | if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) { | ||
| 436 | if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino, | ||
| 437 | 0, 0, &pip) == 0) | ||
| 438 | temppqip = true; | ||
| 439 | } | ||
| 440 | } else | ||
| 441 | pip = NULL; | ||
| 442 | if (uip) { | ||
| 443 | out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino; | ||
| 444 | out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks; | ||
| 445 | out->qs_uquota.qfs_nextents = uip->i_d.di_nextents; | ||
| 446 | if (tempuqip) | ||
| 447 | IRELE(uip); | ||
| 448 | } | ||
| 449 | |||
| 450 | if (gip) { | ||
| 451 | out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; | ||
| 452 | out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks; | ||
| 453 | out->qs_gquota.qfs_nextents = gip->i_d.di_nextents; | ||
| 454 | if (tempgqip) | ||
| 455 | IRELE(gip); | ||
| 456 | } | ||
| 457 | if (pip) { | ||
| 458 | out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; | ||
| 459 | out->qs_gquota.qfs_nblks = pip->i_d.di_nblocks; | ||
| 460 | out->qs_gquota.qfs_nextents = pip->i_d.di_nextents; | ||
| 461 | if (temppqip) | ||
| 462 | IRELE(pip); | ||
| 463 | } | ||
| 464 | out->qs_incoredqs = q->qi_dquots; | ||
| 465 | out->qs_btimelimit = q->qi_btimelimit; | ||
| 466 | out->qs_itimelimit = q->qi_itimelimit; | ||
| 467 | out->qs_rtbtimelimit = q->qi_rtbtimelimit; | ||
| 468 | out->qs_bwarnlimit = q->qi_bwarnlimit; | ||
| 469 | out->qs_iwarnlimit = q->qi_iwarnlimit; | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 474 | /* | ||
| 475 | * Return quota status information, such as uquota-off, enforcements, etc. | ||
| 476 | * for Q_XGETQSTATV command, to support separate project quota field. | ||
| 477 | */ | ||
| 478 | int | ||
| 479 | xfs_qm_scall_getqstatv( | ||
| 480 | struct xfs_mount *mp, | ||
| 481 | struct fs_quota_statv *out) | ||
| 482 | { | ||
| 483 | struct xfs_quotainfo *q = mp->m_quotainfo; | ||
| 484 | struct xfs_inode *uip = NULL; | ||
| 485 | struct xfs_inode *gip = NULL; | ||
| 486 | struct xfs_inode *pip = NULL; | ||
| 487 | bool tempuqip = false; | ||
| 488 | bool tempgqip = false; | ||
| 489 | bool temppqip = false; | ||
| 490 | |||
| 491 | out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags & | ||
| 492 | (XFS_ALL_QUOTA_ACCT| | ||
| 493 | XFS_ALL_QUOTA_ENFD)); | ||
| 494 | out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino; | ||
| 495 | out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; | ||
| 496 | out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino; | ||
| 497 | |||
| 498 | uip = q->qi_uquotaip; | ||
| 499 | gip = q->qi_gquotaip; | ||
| 500 | pip = q->qi_pquotaip; | ||
| 501 | if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { | ||
| 502 | if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, | ||
| 503 | 0, 0, &uip) == 0) | ||
| 504 | tempuqip = true; | ||
| 505 | } | ||
| 506 | if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { | ||
| 507 | if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, | ||
| 508 | 0, 0, &gip) == 0) | ||
| 509 | tempgqip = true; | ||
| 510 | } | ||
| 511 | if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) { | ||
| 512 | if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino, | ||
| 513 | 0, 0, &pip) == 0) | ||
| 514 | temppqip = true; | ||
| 515 | } | ||
| 516 | if (uip) { | ||
| 517 | out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks; | ||
| 518 | out->qs_uquota.qfs_nextents = uip->i_d.di_nextents; | ||
| 519 | if (tempuqip) | ||
| 520 | IRELE(uip); | ||
| 521 | } | ||
| 522 | |||
| 523 | if (gip) { | ||
| 524 | out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks; | ||
| 525 | out->qs_gquota.qfs_nextents = gip->i_d.di_nextents; | ||
| 526 | if (tempgqip) | ||
| 527 | IRELE(gip); | ||
| 528 | } | ||
| 529 | if (pip) { | ||
| 530 | out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks; | ||
| 531 | out->qs_pquota.qfs_nextents = pip->i_d.di_nextents; | ||
| 532 | if (temppqip) | ||
| 533 | IRELE(pip); | ||
| 534 | } | ||
| 535 | out->qs_incoredqs = q->qi_dquots; | ||
| 536 | out->qs_btimelimit = q->qi_btimelimit; | ||
| 537 | out->qs_itimelimit = q->qi_itimelimit; | ||
| 538 | out->qs_rtbtimelimit = q->qi_rtbtimelimit; | ||
| 539 | out->qs_bwarnlimit = q->qi_bwarnlimit; | ||
| 540 | out->qs_iwarnlimit = q->qi_iwarnlimit; | ||
| 541 | |||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | |||
| 545 | #define XFS_QC_MASK \ | 391 | #define XFS_QC_MASK \ |
| 546 | (QC_LIMIT_MASK | QC_TIMER_MASK | QC_WARNS_MASK) | 392 | (QC_LIMIT_MASK | QC_TIMER_MASK | QC_WARNS_MASK) |
| 547 | 393 | ||
| @@ -873,28 +719,6 @@ out_put: | |||
| 873 | return error; | 719 | return error; |
| 874 | } | 720 | } |
| 875 | 721 | ||
| 876 | STATIC uint | ||
| 877 | xfs_qm_export_flags( | ||
| 878 | uint flags) | ||
| 879 | { | ||
| 880 | uint uflags; | ||
| 881 | |||
| 882 | uflags = 0; | ||
| 883 | if (flags & XFS_UQUOTA_ACCT) | ||
| 884 | uflags |= FS_QUOTA_UDQ_ACCT; | ||
| 885 | if (flags & XFS_GQUOTA_ACCT) | ||
| 886 | uflags |= FS_QUOTA_GDQ_ACCT; | ||
| 887 | if (flags & XFS_PQUOTA_ACCT) | ||
| 888 | uflags |= FS_QUOTA_PDQ_ACCT; | ||
| 889 | if (flags & XFS_UQUOTA_ENFD) | ||
| 890 | uflags |= FS_QUOTA_UDQ_ENFD; | ||
| 891 | if (flags & XFS_GQUOTA_ENFD) | ||
| 892 | uflags |= FS_QUOTA_GDQ_ENFD; | ||
| 893 | if (flags & XFS_PQUOTA_ENFD) | ||
| 894 | uflags |= FS_QUOTA_PDQ_ENFD; | ||
| 895 | return uflags; | ||
| 896 | } | ||
| 897 | |||
| 898 | 722 | ||
| 899 | STATIC int | 723 | STATIC int |
| 900 | xfs_dqrele_inode( | 724 | xfs_dqrele_inode( |
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c index 6923905ab33d..7795e0d01382 100644 --- a/fs/xfs/xfs_quotaops.c +++ b/fs/xfs/xfs_quotaops.c | |||
| @@ -23,10 +23,81 @@ | |||
| 23 | #include "xfs_inode.h" | 23 | #include "xfs_inode.h" |
| 24 | #include "xfs_quota.h" | 24 | #include "xfs_quota.h" |
| 25 | #include "xfs_trans.h" | 25 | #include "xfs_trans.h" |
| 26 | #include "xfs_trace.h" | ||
| 27 | #include "xfs_icache.h" | ||
| 26 | #include "xfs_qm.h" | 28 | #include "xfs_qm.h" |
| 27 | #include <linux/quota.h> | 29 | #include <linux/quota.h> |
| 28 | 30 | ||
| 29 | 31 | ||
| 32 | static void | ||
| 33 | xfs_qm_fill_state( | ||
| 34 | struct qc_type_state *tstate, | ||
| 35 | struct xfs_mount *mp, | ||
| 36 | struct xfs_inode *ip, | ||
| 37 | xfs_ino_t ino) | ||
| 38 | { | ||
| 39 | struct xfs_quotainfo *q = mp->m_quotainfo; | ||
| 40 | bool tempqip = false; | ||
| 41 | |||
| 42 | tstate->ino = ino; | ||
| 43 | if (!ip && ino == NULLFSINO) | ||
| 44 | return; | ||
| 45 | if (!ip) { | ||
| 46 | if (xfs_iget(mp, NULL, ino, 0, 0, &ip)) | ||
| 47 | return; | ||
| 48 | tempqip = true; | ||
| 49 | } | ||
| 50 | tstate->flags |= QCI_SYSFILE; | ||
| 51 | tstate->blocks = ip->i_d.di_nblocks; | ||
| 52 | tstate->nextents = ip->i_d.di_nextents; | ||
| 53 | tstate->spc_timelimit = q->qi_btimelimit; | ||
| 54 | tstate->ino_timelimit = q->qi_itimelimit; | ||
| 55 | tstate->rt_spc_timelimit = q->qi_rtbtimelimit; | ||
| 56 | tstate->spc_warnlimit = q->qi_bwarnlimit; | ||
| 57 | tstate->ino_warnlimit = q->qi_iwarnlimit; | ||
| 58 | tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit; | ||
| 59 | if (tempqip) | ||
| 60 | IRELE(ip); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Return quota status information, such as enforcements, quota file inode | ||
| 65 | * numbers etc. | ||
| 66 | */ | ||
| 67 | static int | ||
| 68 | xfs_fs_get_quota_state( | ||
| 69 | struct super_block *sb, | ||
| 70 | struct qc_state *state) | ||
| 71 | { | ||
| 72 | struct xfs_mount *mp = XFS_M(sb); | ||
| 73 | struct xfs_quotainfo *q = mp->m_quotainfo; | ||
| 74 | |||
| 75 | memset(state, 0, sizeof(*state)); | ||
| 76 | if (!XFS_IS_QUOTA_RUNNING(mp)) | ||
| 77 | return 0; | ||
| 78 | state->s_incoredqs = q->qi_dquots; | ||
| 79 | if (XFS_IS_UQUOTA_RUNNING(mp)) | ||
| 80 | state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED; | ||
| 81 | if (XFS_IS_UQUOTA_ENFORCED(mp)) | ||
| 82 | state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED; | ||
| 83 | if (XFS_IS_GQUOTA_RUNNING(mp)) | ||
| 84 | state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED; | ||
| 85 | if (XFS_IS_GQUOTA_ENFORCED(mp)) | ||
| 86 | state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED; | ||
| 87 | if (XFS_IS_PQUOTA_RUNNING(mp)) | ||
| 88 | state->s_state[PRJQUOTA].flags |= QCI_ACCT_ENABLED; | ||
| 89 | if (XFS_IS_PQUOTA_ENFORCED(mp)) | ||
| 90 | state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED; | ||
| 91 | |||
| 92 | xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip, | ||
| 93 | mp->m_sb.sb_uquotino); | ||
| 94 | xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip, | ||
| 95 | mp->m_sb.sb_gquotino); | ||
| 96 | xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip, | ||
| 97 | mp->m_sb.sb_pquotino); | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 30 | STATIC int | 101 | STATIC int |
| 31 | xfs_quota_type(int type) | 102 | xfs_quota_type(int type) |
| 32 | { | 103 | { |
| @@ -40,28 +111,40 @@ xfs_quota_type(int type) | |||
| 40 | } | 111 | } |
| 41 | } | 112 | } |
| 42 | 113 | ||
| 43 | STATIC int | 114 | #define XFS_QC_SETINFO_MASK (QC_TIMER_MASK | QC_WARNS_MASK) |
| 44 | xfs_fs_get_xstate( | 115 | |
| 116 | /* | ||
| 117 | * Adjust quota timers & warnings | ||
| 118 | */ | ||
| 119 | static int | ||
| 120 | xfs_fs_set_info( | ||
| 45 | struct super_block *sb, | 121 | struct super_block *sb, |
| 46 | struct fs_quota_stat *fqs) | 122 | int type, |
| 123 | struct qc_info *info) | ||
| 47 | { | 124 | { |
| 48 | struct xfs_mount *mp = XFS_M(sb); | 125 | struct xfs_mount *mp = XFS_M(sb); |
| 126 | struct qc_dqblk newlim; | ||
| 49 | 127 | ||
| 128 | if (sb->s_flags & MS_RDONLY) | ||
| 129 | return -EROFS; | ||
| 50 | if (!XFS_IS_QUOTA_RUNNING(mp)) | 130 | if (!XFS_IS_QUOTA_RUNNING(mp)) |
| 51 | return -ENOSYS; | 131 | return -ENOSYS; |
| 52 | return xfs_qm_scall_getqstat(mp, fqs); | 132 | if (!XFS_IS_QUOTA_ON(mp)) |
| 53 | } | 133 | return -ESRCH; |
| 134 | if (info->i_fieldmask & ~XFS_QC_SETINFO_MASK) | ||
| 135 | return -EINVAL; | ||
| 136 | if ((info->i_fieldmask & XFS_QC_SETINFO_MASK) == 0) | ||
| 137 | return 0; | ||
| 54 | 138 | ||
| 55 | STATIC int | 139 | newlim.d_fieldmask = info->i_fieldmask; |
| 56 | xfs_fs_get_xstatev( | 140 | newlim.d_spc_timer = info->i_spc_timelimit; |
| 57 | struct super_block *sb, | 141 | newlim.d_ino_timer = info->i_ino_timelimit; |
| 58 | struct fs_quota_statv *fqs) | 142 | newlim.d_rt_spc_timer = info->i_rt_spc_timelimit; |
| 59 | { | 143 | newlim.d_ino_warns = info->i_ino_warnlimit; |
| 60 | struct xfs_mount *mp = XFS_M(sb); | 144 | newlim.d_spc_warns = info->i_spc_warnlimit; |
| 145 | newlim.d_rt_spc_warns = info->i_rt_spc_warnlimit; | ||
| 61 | 146 | ||
| 62 | if (!XFS_IS_QUOTA_RUNNING(mp)) | 147 | return xfs_qm_scall_setqlim(mp, 0, xfs_quota_type(type), &newlim); |
| 63 | return -ENOSYS; | ||
| 64 | return xfs_qm_scall_getqstatv(mp, fqs); | ||
| 65 | } | 148 | } |
| 66 | 149 | ||
| 67 | static unsigned int | 150 | static unsigned int |
| @@ -178,8 +261,8 @@ xfs_fs_set_dqblk( | |||
| 178 | } | 261 | } |
| 179 | 262 | ||
| 180 | const struct quotactl_ops xfs_quotactl_operations = { | 263 | const struct quotactl_ops xfs_quotactl_operations = { |
| 181 | .get_xstatev = xfs_fs_get_xstatev, | 264 | .get_state = xfs_fs_get_quota_state, |
| 182 | .get_xstate = xfs_fs_get_xstate, | 265 | .set_info = xfs_fs_set_info, |
| 183 | .quota_enable = xfs_quota_enable, | 266 | .quota_enable = xfs_quota_enable, |
| 184 | .quota_disable = xfs_quota_disable, | 267 | .quota_disable = xfs_quota_disable, |
| 185 | .rm_xquota = xfs_fs_rm_xquota, | 268 | .rm_xquota = xfs_fs_rm_xquota, |
diff --git a/include/linux/quota.h b/include/linux/quota.h index a3374dc3a91b..cf910d1f8efa 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h | |||
| @@ -344,7 +344,10 @@ struct qc_dqblk { | |||
| 344 | int d_rt_spc_warns; /* # warnings issued wrt RT space */ | 344 | int d_rt_spc_warns; /* # warnings issued wrt RT space */ |
| 345 | }; | 345 | }; |
| 346 | 346 | ||
| 347 | /* Field specifiers for ->set_dqblk() in struct qc_dqblk */ | 347 | /* |
| 348 | * Field specifiers for ->set_dqblk() in struct qc_dqblk and also for | ||
| 349 | * ->set_info() in struct qc_info | ||
| 350 | */ | ||
| 348 | #define QC_INO_SOFT (1<<0) | 351 | #define QC_INO_SOFT (1<<0) |
| 349 | #define QC_INO_HARD (1<<1) | 352 | #define QC_INO_HARD (1<<1) |
| 350 | #define QC_SPC_SOFT (1<<2) | 353 | #define QC_SPC_SOFT (1<<2) |
| @@ -365,6 +368,51 @@ struct qc_dqblk { | |||
| 365 | #define QC_INO_COUNT (1<<13) | 368 | #define QC_INO_COUNT (1<<13) |
| 366 | #define QC_RT_SPACE (1<<14) | 369 | #define QC_RT_SPACE (1<<14) |
| 367 | #define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE) | 370 | #define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE) |
| 371 | #define QC_FLAGS (1<<15) | ||
| 372 | |||
| 373 | #define QCI_SYSFILE (1 << 0) /* Quota file is hidden from userspace */ | ||
| 374 | #define QCI_ROOT_SQUASH (1 << 1) /* Root squash turned on */ | ||
| 375 | #define QCI_ACCT_ENABLED (1 << 2) /* Quota accounting enabled */ | ||
| 376 | #define QCI_LIMITS_ENFORCED (1 << 3) /* Quota limits enforced */ | ||
| 377 | |||
| 378 | /* Structures for communicating via ->get_state */ | ||
| 379 | struct qc_type_state { | ||
| 380 | unsigned int flags; /* Flags QCI_* */ | ||
| 381 | unsigned int spc_timelimit; /* Time after which space softlimit is | ||
| 382 | * enforced */ | ||
| 383 | unsigned int ino_timelimit; /* Ditto for inode softlimit */ | ||
| 384 | unsigned int rt_spc_timelimit; /* Ditto for real-time space */ | ||
| 385 | unsigned int spc_warnlimit; /* Limit for number of space warnings */ | ||
| 386 | unsigned int ino_warnlimit; /* Ditto for inodes */ | ||
| 387 | unsigned int rt_spc_warnlimit; /* Ditto for real-time space */ | ||
| 388 | unsigned long long ino; /* Inode number of quota file */ | ||
| 389 | blkcnt_t blocks; /* Number of 512-byte blocks in the file */ | ||
| 390 | blkcnt_t nextents; /* Number of extents in the file */ | ||
| 391 | }; | ||
| 392 | |||
| 393 | struct qc_state { | ||
| 394 | unsigned int s_incoredqs; /* Number of dquots in core */ | ||
| 395 | /* | ||
| 396 | * Per quota type information. The array should really have | ||
| 397 | * max(MAXQUOTAS, XQM_MAXQUOTAS) entries. BUILD_BUG_ON in | ||
| 398 | * quota_getinfo() makes sure XQM_MAXQUOTAS is large enough. Once VFS | ||
| 399 | * supports project quotas, this can be changed to MAXQUOTAS | ||
| 400 | */ | ||
| 401 | struct qc_type_state s_state[XQM_MAXQUOTAS]; | ||
| 402 | }; | ||
| 403 | |||
| 404 | /* Structure for communicating via ->set_info */ | ||
| 405 | struct qc_info { | ||
| 406 | int i_fieldmask; /* mask of fields to change in ->set_info() */ | ||
| 407 | unsigned int i_flags; /* Flags QCI_* */ | ||
| 408 | unsigned int i_spc_timelimit; /* Time after which space softlimit is | ||
| 409 | * enforced */ | ||
| 410 | unsigned int i_ino_timelimit; /* Ditto for inode softlimit */ | ||
| 411 | unsigned int i_rt_spc_timelimit;/* Ditto for real-time space */ | ||
| 412 | unsigned int i_spc_warnlimit; /* Limit for number of space warnings */ | ||
| 413 | unsigned int i_ino_warnlimit; /* Limit for number of inode warnings */ | ||
| 414 | unsigned int i_rt_spc_warnlimit; /* Ditto for real-time space */ | ||
| 415 | }; | ||
| 368 | 416 | ||
| 369 | /* Operations handling requests from userspace */ | 417 | /* Operations handling requests from userspace */ |
| 370 | struct quotactl_ops { | 418 | struct quotactl_ops { |
| @@ -373,12 +421,10 @@ struct quotactl_ops { | |||
| 373 | int (*quota_enable)(struct super_block *, unsigned int); | 421 | int (*quota_enable)(struct super_block *, unsigned int); |
| 374 | int (*quota_disable)(struct super_block *, unsigned int); | 422 | int (*quota_disable)(struct super_block *, unsigned int); |
| 375 | int (*quota_sync)(struct super_block *, int); | 423 | int (*quota_sync)(struct super_block *, int); |
| 376 | int (*get_info)(struct super_block *, int, struct if_dqinfo *); | 424 | int (*set_info)(struct super_block *, int, struct qc_info *); |
| 377 | int (*set_info)(struct super_block *, int, struct if_dqinfo *); | ||
| 378 | int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); | 425 | int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); |
| 379 | int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); | 426 | int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); |
| 380 | int (*get_xstate)(struct super_block *, struct fs_quota_stat *); | 427 | int (*get_state)(struct super_block *, struct qc_state *); |
| 381 | int (*get_xstatev)(struct super_block *, struct fs_quota_statv *); | ||
| 382 | int (*rm_xquota)(struct super_block *, unsigned int); | 428 | int (*rm_xquota)(struct super_block *, unsigned int); |
| 383 | }; | 429 | }; |
| 384 | 430 | ||
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 8778ec4775eb..77ca6601ff25 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h | |||
| @@ -95,8 +95,8 @@ int dquot_quota_on_mount(struct super_block *sb, char *qf_name, | |||
| 95 | int dquot_quota_off(struct super_block *sb, int type); | 95 | int dquot_quota_off(struct super_block *sb, int type); |
| 96 | int dquot_writeback_dquots(struct super_block *sb, int type); | 96 | int dquot_writeback_dquots(struct super_block *sb, int type); |
| 97 | int dquot_quota_sync(struct super_block *sb, int type); | 97 | int dquot_quota_sync(struct super_block *sb, int type); |
| 98 | int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); | 98 | int dquot_get_state(struct super_block *sb, struct qc_state *state); |
| 99 | int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); | 99 | int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii); |
| 100 | int dquot_get_dqblk(struct super_block *sb, struct kqid id, | 100 | int dquot_get_dqblk(struct super_block *sb, struct kqid id, |
| 101 | struct qc_dqblk *di); | 101 | struct qc_dqblk *di); |
| 102 | int dquot_set_dqblk(struct super_block *sb, struct kqid id, | 102 | int dquot_set_dqblk(struct super_block *sb, struct kqid id, |
