diff options
Diffstat (limited to 'fs/xfs/quota/xfs_qm_bhv.c')
-rw-r--r-- | fs/xfs/quota/xfs_qm_bhv.c | 239 |
1 files changed, 33 insertions, 206 deletions
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index d2cdb8a2aad..97bb3293758 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c | |||
@@ -48,172 +48,13 @@ | |||
48 | #include "xfs_buf_item.h" | 48 | #include "xfs_buf_item.h" |
49 | #include "xfs_qm.h" | 49 | #include "xfs_qm.h" |
50 | 50 | ||
51 | #define MNTOPT_QUOTA "quota" /* disk quotas (user) */ | ||
52 | #define MNTOPT_NOQUOTA "noquota" /* no quotas */ | ||
53 | #define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ | ||
54 | #define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ | ||
55 | #define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */ | ||
56 | #define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ | ||
57 | #define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ | ||
58 | #define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */ | ||
59 | #define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ | ||
60 | #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ | ||
61 | #define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ | ||
62 | #define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ | ||
63 | 51 | ||
64 | STATIC int | 52 | STATIC void |
65 | xfs_qm_parseargs( | 53 | xfs_fill_statvfs_from_dquot( |
66 | struct bhv_desc *bhv, | ||
67 | char *options, | ||
68 | struct xfs_mount_args *args, | ||
69 | int update) | ||
70 | { | ||
71 | size_t length; | ||
72 | char *local_options = options; | ||
73 | char *this_char; | ||
74 | int error; | ||
75 | int referenced = update; | ||
76 | |||
77 | while ((this_char = strsep(&local_options, ",")) != NULL) { | ||
78 | length = strlen(this_char); | ||
79 | if (local_options) | ||
80 | length++; | ||
81 | |||
82 | if (!strcmp(this_char, MNTOPT_NOQUOTA)) { | ||
83 | args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA); | ||
84 | args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA); | ||
85 | referenced = update; | ||
86 | } else if (!strcmp(this_char, MNTOPT_QUOTA) || | ||
87 | !strcmp(this_char, MNTOPT_UQUOTA) || | ||
88 | !strcmp(this_char, MNTOPT_USRQUOTA)) { | ||
89 | args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; | ||
90 | referenced = 1; | ||
91 | } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) || | ||
92 | !strcmp(this_char, MNTOPT_UQUOTANOENF)) { | ||
93 | args->flags |= XFSMNT_UQUOTA; | ||
94 | args->flags &= ~XFSMNT_UQUOTAENF; | ||
95 | referenced = 1; | ||
96 | } else if (!strcmp(this_char, MNTOPT_PQUOTA) || | ||
97 | !strcmp(this_char, MNTOPT_PRJQUOTA)) { | ||
98 | args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF; | ||
99 | referenced = 1; | ||
100 | } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) { | ||
101 | args->flags |= XFSMNT_PQUOTA; | ||
102 | args->flags &= ~XFSMNT_PQUOTAENF; | ||
103 | referenced = 1; | ||
104 | } else if (!strcmp(this_char, MNTOPT_GQUOTA) || | ||
105 | !strcmp(this_char, MNTOPT_GRPQUOTA)) { | ||
106 | args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; | ||
107 | referenced = 1; | ||
108 | } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) { | ||
109 | args->flags |= XFSMNT_GQUOTA; | ||
110 | args->flags &= ~XFSMNT_GQUOTAENF; | ||
111 | referenced = 1; | ||
112 | } else { | ||
113 | if (local_options) | ||
114 | *(local_options-1) = ','; | ||
115 | continue; | ||
116 | } | ||
117 | |||
118 | while (length--) | ||
119 | *this_char++ = ','; | ||
120 | } | ||
121 | |||
122 | if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) { | ||
123 | cmn_err(CE_WARN, | ||
124 | "XFS: cannot mount with both project and group quota"); | ||
125 | return XFS_ERROR(EINVAL); | ||
126 | } | ||
127 | |||
128 | error = bhv_next_vfs_parseargs(BHV_NEXT(bhv), options, args, update); | ||
129 | if (!error && !referenced) | ||
130 | bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM); | ||
131 | return error; | ||
132 | } | ||
133 | |||
134 | STATIC int | ||
135 | xfs_qm_showargs( | ||
136 | struct bhv_desc *bhv, | ||
137 | struct seq_file *m) | ||
138 | { | ||
139 | struct bhv_vfs *vfsp = bhvtovfs(bhv); | ||
140 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); | ||
141 | |||
142 | if (mp->m_qflags & XFS_UQUOTA_ACCT) { | ||
143 | (mp->m_qflags & XFS_UQUOTA_ENFD) ? | ||
144 | seq_puts(m, "," MNTOPT_USRQUOTA) : | ||
145 | seq_puts(m, "," MNTOPT_UQUOTANOENF); | ||
146 | } | ||
147 | |||
148 | if (mp->m_qflags & XFS_PQUOTA_ACCT) { | ||
149 | (mp->m_qflags & XFS_OQUOTA_ENFD) ? | ||
150 | seq_puts(m, "," MNTOPT_PRJQUOTA) : | ||
151 | seq_puts(m, "," MNTOPT_PQUOTANOENF); | ||
152 | } | ||
153 | |||
154 | if (mp->m_qflags & XFS_GQUOTA_ACCT) { | ||
155 | (mp->m_qflags & XFS_OQUOTA_ENFD) ? | ||
156 | seq_puts(m, "," MNTOPT_GRPQUOTA) : | ||
157 | seq_puts(m, "," MNTOPT_GQUOTANOENF); | ||
158 | } | ||
159 | |||
160 | if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) | ||
161 | seq_puts(m, "," MNTOPT_NOQUOTA); | ||
162 | |||
163 | return bhv_next_vfs_showargs(BHV_NEXT(bhv), m); | ||
164 | } | ||
165 | |||
166 | STATIC int | ||
167 | xfs_qm_mount( | ||
168 | struct bhv_desc *bhv, | ||
169 | struct xfs_mount_args *args, | ||
170 | struct cred *cr) | ||
171 | { | ||
172 | struct bhv_vfs *vfsp = bhvtovfs(bhv); | ||
173 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); | ||
174 | |||
175 | if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA)) | ||
176 | xfs_qm_mount_quotainit(mp, args->flags); | ||
177 | return bhv_next_vfs_mount(BHV_NEXT(bhv), args, cr); | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Directory tree accounting is implemented using project quotas, where | ||
182 | * the project identifier is inherited from parent directories. | ||
183 | * A statvfs (df, etc.) of a directory that is using project quota should | ||
184 | * return a statvfs of the project, not the entire filesystem. | ||
185 | * This makes such trees appear as if they are filesystems in themselves. | ||
186 | */ | ||
187 | STATIC int | ||
188 | xfs_qm_statvfs( | ||
189 | struct bhv_desc *bhv, | ||
190 | bhv_statvfs_t *statp, | 54 | bhv_statvfs_t *statp, |
191 | struct bhv_vnode *vnode) | 55 | xfs_disk_dquot_t *dp) |
192 | { | 56 | { |
193 | xfs_mount_t *mp; | ||
194 | xfs_inode_t *ip; | ||
195 | xfs_dquot_t *dqp; | ||
196 | xfs_disk_dquot_t *dp; | ||
197 | __uint64_t limit; | 57 | __uint64_t limit; |
198 | int error; | ||
199 | |||
200 | error = bhv_next_vfs_statvfs(BHV_NEXT(bhv), statp, vnode); | ||
201 | if (error || !vnode) | ||
202 | return error; | ||
203 | |||
204 | mp = xfs_vfstom(bhvtovfs(bhv)); | ||
205 | ip = xfs_vtoi(vnode); | ||
206 | |||
207 | if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)) | ||
208 | return 0; | ||
209 | if (!(mp->m_qflags & XFS_PQUOTA_ACCT)) | ||
210 | return 0; | ||
211 | if (!(mp->m_qflags & XFS_OQUOTA_ENFD)) | ||
212 | return 0; | ||
213 | |||
214 | if (xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp)) | ||
215 | return 0; | ||
216 | dp = &dqp->q_core; | ||
217 | 58 | ||
218 | limit = dp->d_blk_softlimit ? | 59 | limit = dp->d_blk_softlimit ? |
219 | be64_to_cpu(dp->d_blk_softlimit) : | 60 | be64_to_cpu(dp->d_blk_softlimit) : |
@@ -234,37 +75,35 @@ xfs_qm_statvfs( | |||
234 | (statp->f_files > be64_to_cpu(dp->d_icount)) ? | 75 | (statp->f_files > be64_to_cpu(dp->d_icount)) ? |
235 | (statp->f_ffree - be64_to_cpu(dp->d_icount)) : 0; | 76 | (statp->f_ffree - be64_to_cpu(dp->d_icount)) : 0; |
236 | } | 77 | } |
237 | |||
238 | xfs_qm_dqput(dqp); | ||
239 | return 0; | ||
240 | } | 78 | } |
241 | 79 | ||
242 | STATIC int | 80 | |
243 | xfs_qm_syncall( | 81 | /* |
244 | struct bhv_desc *bhv, | 82 | * Directory tree accounting is implemented using project quotas, where |
245 | int flags, | 83 | * the project identifier is inherited from parent directories. |
246 | cred_t *credp) | 84 | * A statvfs (df, etc.) of a directory that is using project quota should |
85 | * return a statvfs of the project, not the entire filesystem. | ||
86 | * This makes such trees appear as if they are filesystems in themselves. | ||
87 | */ | ||
88 | STATIC void | ||
89 | xfs_qm_statvfs( | ||
90 | xfs_inode_t *ip, | ||
91 | bhv_statvfs_t *statp) | ||
247 | { | 92 | { |
248 | struct bhv_vfs *vfsp = bhvtovfs(bhv); | 93 | xfs_mount_t *mp = ip->i_mount; |
249 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); | 94 | xfs_dquot_t *dqp; |
250 | int error; | ||
251 | 95 | ||
252 | /* | 96 | if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) || |
253 | * Get the Quota Manager to flush the dquots. | 97 | !((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) == |
254 | */ | 98 | (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD)) |
255 | if (XFS_IS_QUOTA_ON(mp)) { | 99 | return; |
256 | if ((error = xfs_qm_sync(mp, flags))) { | 100 | |
257 | /* | 101 | if (!xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp)) { |
258 | * If we got an IO error, we will be shutting down. | 102 | xfs_disk_dquot_t *dp = &dqp->q_core; |
259 | * So, there's nothing more for us to do here. | 103 | |
260 | */ | 104 | xfs_fill_statvfs_from_dquot(statp, dp); |
261 | ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp)); | 105 | xfs_qm_dqput(dqp); |
262 | if (XFS_FORCED_SHUTDOWN(mp)) { | ||
263 | return XFS_ERROR(error); | ||
264 | } | ||
265 | } | ||
266 | } | 106 | } |
267 | return bhv_next_vfs_sync(BHV_NEXT(bhv), flags, credp); | ||
268 | } | 107 | } |
269 | 108 | ||
270 | STATIC int | 109 | STATIC int |
@@ -382,7 +221,7 @@ xfs_qm_dqrele_null( | |||
382 | } | 221 | } |
383 | 222 | ||
384 | 223 | ||
385 | static struct xfs_qmops xfs_qmcore_xfs = { | 224 | struct xfs_qmops xfs_qmcore_xfs = { |
386 | .xfs_qminit = xfs_qm_newmount, | 225 | .xfs_qminit = xfs_qm_newmount, |
387 | .xfs_qmdone = xfs_qm_unmount_quotadestroy, | 226 | .xfs_qmdone = xfs_qm_unmount_quotadestroy, |
388 | .xfs_qmmount = xfs_qm_endmount, | 227 | .xfs_qmmount = xfs_qm_endmount, |
@@ -396,36 +235,24 @@ static struct xfs_qmops xfs_qmcore_xfs = { | |||
396 | .xfs_dqvoprename = xfs_qm_vop_rename_dqattach, | 235 | .xfs_dqvoprename = xfs_qm_vop_rename_dqattach, |
397 | .xfs_dqvopchown = xfs_qm_vop_chown, | 236 | .xfs_dqvopchown = xfs_qm_vop_chown, |
398 | .xfs_dqvopchownresv = xfs_qm_vop_chown_reserve, | 237 | .xfs_dqvopchownresv = xfs_qm_vop_chown_reserve, |
238 | .xfs_dqstatvfs = xfs_qm_statvfs, | ||
239 | .xfs_dqsync = xfs_qm_sync, | ||
240 | .xfs_quotactl = xfs_qm_quotactl, | ||
399 | .xfs_dqtrxops = &xfs_trans_dquot_ops, | 241 | .xfs_dqtrxops = &xfs_trans_dquot_ops, |
400 | }; | 242 | }; |
401 | 243 | EXPORT_SYMBOL(xfs_qmcore_xfs); | |
402 | struct bhv_module_vfsops xfs_qmops = { { | ||
403 | BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM), | ||
404 | .vfs_parseargs = xfs_qm_parseargs, | ||
405 | .vfs_showargs = xfs_qm_showargs, | ||
406 | .vfs_mount = xfs_qm_mount, | ||
407 | .vfs_statvfs = xfs_qm_statvfs, | ||
408 | .vfs_sync = xfs_qm_syncall, | ||
409 | .vfs_quotactl = xfs_qm_quotactl, }, | ||
410 | }; | ||
411 | |||
412 | 244 | ||
413 | void __init | 245 | void __init |
414 | xfs_qm_init(void) | 246 | xfs_qm_init(void) |
415 | { | 247 | { |
416 | static char message[] __initdata = | 248 | printk(KERN_INFO "SGI XFS Quota Management subsystem\n"); |
417 | KERN_INFO "SGI XFS Quota Management subsystem\n"; | ||
418 | |||
419 | printk(message); | ||
420 | mutex_init(&xfs_Gqm_lock); | 249 | mutex_init(&xfs_Gqm_lock); |
421 | vfs_bhv_set_custom(&xfs_qmops, &xfs_qmcore_xfs); | ||
422 | xfs_qm_init_procfs(); | 250 | xfs_qm_init_procfs(); |
423 | } | 251 | } |
424 | 252 | ||
425 | void __exit | 253 | void __exit |
426 | xfs_qm_exit(void) | 254 | xfs_qm_exit(void) |
427 | { | 255 | { |
428 | vfs_bhv_clr_custom(&xfs_qmops); | ||
429 | xfs_qm_cleanup_procfs(); | 256 | xfs_qm_cleanup_procfs(); |
430 | if (qm_dqzone) | 257 | if (qm_dqzone) |
431 | kmem_zone_destroy(qm_dqzone); | 258 | kmem_zone_destroy(qm_dqzone); |