]> err.no Git - linux-2.6/blob - fs/xfs/quota/xfs_qm_bhv.c
[XFS] Resolve a namespace collision on remaining vtypes for FreeBSD
[linux-2.6] / fs / xfs / quota / xfs_qm_bhv.c
1 /*
2  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include "xfs.h"
19 #include "xfs_fs.h"
20 #include "xfs_bit.h"
21 #include "xfs_log.h"
22 #include "xfs_inum.h"
23 #include "xfs_clnt.h"
24 #include "xfs_trans.h"
25 #include "xfs_sb.h"
26 #include "xfs_ag.h"
27 #include "xfs_dir.h"
28 #include "xfs_dir2.h"
29 #include "xfs_alloc.h"
30 #include "xfs_dmapi.h"
31 #include "xfs_quota.h"
32 #include "xfs_mount.h"
33 #include "xfs_bmap_btree.h"
34 #include "xfs_alloc_btree.h"
35 #include "xfs_ialloc_btree.h"
36 #include "xfs_dir_sf.h"
37 #include "xfs_dir2_sf.h"
38 #include "xfs_attr_sf.h"
39 #include "xfs_dinode.h"
40 #include "xfs_inode.h"
41 #include "xfs_ialloc.h"
42 #include "xfs_itable.h"
43 #include "xfs_btree.h"
44 #include "xfs_bmap.h"
45 #include "xfs_rtalloc.h"
46 #include "xfs_error.h"
47 #include "xfs_rw.h"
48 #include "xfs_acl.h"
49 #include "xfs_cap.h"
50 #include "xfs_mac.h"
51 #include "xfs_attr.h"
52 #include "xfs_buf_item.h"
53 #include "xfs_qm.h"
54
55 #define MNTOPT_QUOTA    "quota"         /* disk quotas (user) */
56 #define MNTOPT_NOQUOTA  "noquota"       /* no quotas */
57 #define MNTOPT_USRQUOTA "usrquota"      /* user quota enabled */
58 #define MNTOPT_GRPQUOTA "grpquota"      /* group quota enabled */
59 #define MNTOPT_PRJQUOTA "prjquota"      /* project quota enabled */
60 #define MNTOPT_UQUOTA   "uquota"        /* user quota (IRIX variant) */
61 #define MNTOPT_GQUOTA   "gquota"        /* group quota (IRIX variant) */
62 #define MNTOPT_PQUOTA   "pquota"        /* project quota (IRIX variant) */
63 #define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
64 #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
65 #define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */
66 #define MNTOPT_QUOTANOENF  "qnoenforce" /* same as uqnoenforce */
67
68 STATIC int
69 xfs_qm_parseargs(
70         struct bhv_desc         *bhv,
71         char                    *options,
72         struct xfs_mount_args   *args,
73         int                     update)
74 {
75         size_t                  length;
76         char                    *local_options = options;
77         char                    *this_char;
78         int                     error;
79         int                     referenced = update;
80
81         while ((this_char = strsep(&local_options, ",")) != NULL) {
82                 length = strlen(this_char);
83                 if (local_options)
84                         length++;
85
86                 if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
87                         args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA);
88                         args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA);
89                         referenced = update;
90                 } else if (!strcmp(this_char, MNTOPT_QUOTA) ||
91                            !strcmp(this_char, MNTOPT_UQUOTA) ||
92                            !strcmp(this_char, MNTOPT_USRQUOTA)) {
93                         args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
94                         referenced = 1;
95                 } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) ||
96                            !strcmp(this_char, MNTOPT_UQUOTANOENF)) {
97                         args->flags |= XFSMNT_UQUOTA;
98                         args->flags &= ~XFSMNT_UQUOTAENF;
99                         referenced = 1;
100                 } else if (!strcmp(this_char, MNTOPT_PQUOTA) ||
101                            !strcmp(this_char, MNTOPT_PRJQUOTA)) {
102                         args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF;
103                         referenced = 1;
104                 } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
105                         args->flags |= XFSMNT_PQUOTA;
106                         args->flags &= ~XFSMNT_PQUOTAENF;
107                         referenced = 1;
108                 } else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
109                            !strcmp(this_char, MNTOPT_GRPQUOTA)) {
110                         args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
111                         referenced = 1;
112                 } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
113                         args->flags |= XFSMNT_GQUOTA;
114                         args->flags &= ~XFSMNT_GQUOTAENF;
115                         referenced = 1;
116                 } else {
117                         if (local_options)
118                                 *(local_options-1) = ',';
119                         continue;
120                 }
121
122                 while (length--)
123                         *this_char++ = ',';
124         }
125
126         if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) {
127                 cmn_err(CE_WARN,
128                         "XFS: cannot mount with both project and group quota");
129                 return XFS_ERROR(EINVAL);
130         }
131
132         error = bhv_next_vfs_parseargs(BHV_NEXT(bhv), options, args, update);
133         if (!error && !referenced)
134                 bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM);
135         return error;
136 }
137
138 STATIC int
139 xfs_qm_showargs(
140         struct bhv_desc         *bhv,
141         struct seq_file         *m)
142 {
143         struct bhv_vfs          *vfsp = bhvtovfs(bhv);
144         struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
145
146         if (mp->m_qflags & XFS_UQUOTA_ACCT) {
147                 (mp->m_qflags & XFS_UQUOTA_ENFD) ?
148                         seq_puts(m, "," MNTOPT_USRQUOTA) :
149                         seq_puts(m, "," MNTOPT_UQUOTANOENF);
150         }
151
152         if (mp->m_qflags & XFS_PQUOTA_ACCT) {
153                 (mp->m_qflags & XFS_OQUOTA_ENFD) ?
154                         seq_puts(m, "," MNTOPT_PRJQUOTA) :
155                         seq_puts(m, "," MNTOPT_PQUOTANOENF);
156         }
157
158         if (mp->m_qflags & XFS_GQUOTA_ACCT) {
159                 (mp->m_qflags & XFS_OQUOTA_ENFD) ?
160                         seq_puts(m, "," MNTOPT_GRPQUOTA) :
161                         seq_puts(m, "," MNTOPT_GQUOTANOENF);
162         }
163
164         if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT))
165                 seq_puts(m, "," MNTOPT_NOQUOTA);
166
167         return bhv_next_vfs_showargs(BHV_NEXT(bhv), m);
168 }
169
170 STATIC int
171 xfs_qm_mount(
172         struct bhv_desc         *bhv,
173         struct xfs_mount_args   *args,
174         struct cred             *cr)
175 {
176         struct bhv_vfs          *vfsp = bhvtovfs(bhv);
177         struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
178
179         if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA))
180                 xfs_qm_mount_quotainit(mp, args->flags);
181         return bhv_next_vfs_mount(BHV_NEXT(bhv), args, cr);
182 }
183
184 /*
185  * Directory tree accounting is implemented using project quotas, where
186  * the project identifier is inherited from parent directories.
187  * A statvfs (df, etc.) of a directory that is using project quota should
188  * return a statvfs of the project, not the entire filesystem.
189  * This makes such trees appear as if they are filesystems in themselves.
190  */
191 STATIC int
192 xfs_qm_statvfs(
193         struct bhv_desc         *bhv,
194         bhv_statvfs_t           *statp,
195         struct bhv_vnode        *vnode)
196 {
197         xfs_mount_t             *mp;
198         xfs_inode_t             *ip;
199         xfs_dquot_t             *dqp;
200         xfs_disk_dquot_t        *dp;
201         __uint64_t              limit;
202         int                     error;
203
204         error = bhv_next_vfs_statvfs(BHV_NEXT(bhv), statp, vnode);
205         if (error || !vnode)
206                 return error;
207
208         mp = XFS_BHVTOM(bhv);
209         ip = xfs_vtoi(vnode);
210
211         if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT))
212                 return 0;
213         if (!(mp->m_qflags & XFS_PQUOTA_ACCT))
214                 return 0;
215         if (!(mp->m_qflags & XFS_OQUOTA_ENFD))
216                 return 0;
217
218         if (xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp))
219                 return 0;
220         dp = &dqp->q_core;
221
222         limit = dp->d_blk_softlimit ? dp->d_blk_softlimit : dp->d_blk_hardlimit;
223         if (limit && statp->f_blocks > limit) {
224                 statp->f_blocks = limit;
225                 statp->f_bfree = (statp->f_blocks > dp->d_bcount) ?
226                                         (statp->f_blocks - dp->d_bcount) : 0;
227         }
228         limit = dp->d_ino_softlimit ? dp->d_ino_softlimit : dp->d_ino_hardlimit;
229         if (limit && statp->f_files > limit) {
230                 statp->f_files = limit;
231                 statp->f_ffree = (statp->f_files > dp->d_icount) ?
232                                         (statp->f_ffree - dp->d_icount) : 0;
233         }
234
235         xfs_qm_dqput(dqp);
236         return 0;
237 }
238
239 STATIC int
240 xfs_qm_syncall(
241         struct bhv_desc         *bhv,
242         int                     flags,
243         cred_t                  *credp)
244 {
245         struct bhv_vfs          *vfsp = bhvtovfs(bhv);
246         struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
247         int                     error;
248
249         /*
250          * Get the Quota Manager to flush the dquots.
251          */
252         if (XFS_IS_QUOTA_ON(mp)) {
253                 if ((error = xfs_qm_sync(mp, flags))) {
254                         /*
255                          * If we got an IO error, we will be shutting down.
256                          * So, there's nothing more for us to do here.
257                          */
258                         ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp));
259                         if (XFS_FORCED_SHUTDOWN(mp)) {
260                                 return XFS_ERROR(error);
261                         }
262                 }
263         }
264         return bhv_next_vfs_sync(BHV_NEXT(bhv), flags, credp);
265 }
266
267 STATIC int
268 xfs_qm_newmount(
269         xfs_mount_t     *mp,
270         uint            *needquotamount,
271         uint            *quotaflags)
272 {
273         uint            quotaondisk;
274         uint            uquotaondisk = 0, gquotaondisk = 0, pquotaondisk = 0;
275
276         *quotaflags = 0;
277         *needquotamount = B_FALSE;
278
279         quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
280                                 (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT);
281
282         if (quotaondisk) {
283                 uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
284                 pquotaondisk = mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT;
285                 gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
286         }
287
288         /*
289          * If the device itself is read-only, we can't allow
290          * the user to change the state of quota on the mount -
291          * this would generate a transaction on the ro device,
292          * which would lead to an I/O error and shutdown
293          */
294
295         if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
296             (!uquotaondisk &&  XFS_IS_UQUOTA_ON(mp)) ||
297              (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
298             (!pquotaondisk &&  XFS_IS_PQUOTA_ON(mp)) ||
299              (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
300             (!gquotaondisk &&  XFS_IS_OQUOTA_ON(mp)))  &&
301             xfs_dev_is_read_only(mp, "changing quota state")) {
302                 cmn_err(CE_WARN,
303                         "XFS: please mount with%s%s%s%s.",
304                         (!quotaondisk ? "out quota" : ""),
305                         (uquotaondisk ? " usrquota" : ""),
306                         (pquotaondisk ? " prjquota" : ""),
307                         (gquotaondisk ? " grpquota" : ""));
308                 return XFS_ERROR(EPERM);
309         }
310
311         if (XFS_IS_QUOTA_ON(mp) || quotaondisk) {
312                 /*
313                  * Call mount_quotas at this point only if we won't have to do
314                  * a quotacheck.
315                  */
316                 if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) {
317                         /*
318                          * If an error occured, qm_mount_quotas code
319                          * has already disabled quotas. So, just finish
320                          * mounting, and get on with the boring life
321                          * without disk quotas.
322                          */
323                         xfs_qm_mount_quotas(mp, 0);
324                 } else {
325                         /*
326                          * Clear the quota flags, but remember them. This
327                          * is so that the quota code doesn't get invoked
328                          * before we're ready. This can happen when an
329                          * inode goes inactive and wants to free blocks,
330                          * or via xfs_log_mount_finish.
331                          */
332                         *needquotamount = B_TRUE;
333                         *quotaflags = mp->m_qflags;
334                         mp->m_qflags = 0;
335                 }
336         }
337
338         return 0;
339 }
340
341 STATIC int
342 xfs_qm_endmount(
343         xfs_mount_t     *mp,
344         uint            needquotamount,
345         uint            quotaflags,
346         int             mfsi_flags)
347 {
348         if (needquotamount) {
349                 ASSERT(mp->m_qflags == 0);
350                 mp->m_qflags = quotaflags;
351                 xfs_qm_mount_quotas(mp, mfsi_flags);
352         }
353
354 #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
355         if (! (XFS_IS_QUOTA_ON(mp)))
356                 xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
357         else
358                 xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
359 #endif
360
361 #ifdef QUOTADEBUG
362         if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp))
363                 cmn_err(CE_WARN, "XFS: mount internalqcheck failed");
364 #endif
365
366         return 0;
367 }
368
369 STATIC void
370 xfs_qm_dqrele_null(
371         xfs_dquot_t     *dq)
372 {
373         /*
374          * Called from XFS, where we always check first for a NULL dquot.
375          */
376         if (!dq)
377                 return;
378         xfs_qm_dqrele(dq);
379 }
380
381
382 STATIC struct xfs_qmops xfs_qmcore_xfs = {
383         .xfs_qminit             = xfs_qm_newmount,
384         .xfs_qmdone             = xfs_qm_unmount_quotadestroy,
385         .xfs_qmmount            = xfs_qm_endmount,
386         .xfs_qmunmount          = xfs_qm_unmount_quotas,
387         .xfs_dqrele             = xfs_qm_dqrele_null,
388         .xfs_dqattach           = xfs_qm_dqattach,
389         .xfs_dqdetach           = xfs_qm_dqdetach,
390         .xfs_dqpurgeall         = xfs_qm_dqpurge_all,
391         .xfs_dqvopalloc         = xfs_qm_vop_dqalloc,
392         .xfs_dqvopcreate        = xfs_qm_vop_dqattach_and_dqmod_newinode,
393         .xfs_dqvoprename        = xfs_qm_vop_rename_dqattach,
394         .xfs_dqvopchown         = xfs_qm_vop_chown,
395         .xfs_dqvopchownresv     = xfs_qm_vop_chown_reserve,
396         .xfs_dqtrxops           = &xfs_trans_dquot_ops,
397 };
398
399 struct bhv_module_vfsops xfs_qmops = { {
400         BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM),
401         .vfs_parseargs          = xfs_qm_parseargs,
402         .vfs_showargs           = xfs_qm_showargs,
403         .vfs_mount              = xfs_qm_mount,
404         .vfs_statvfs            = xfs_qm_statvfs,
405         .vfs_sync               = xfs_qm_syncall,
406         .vfs_quotactl           = xfs_qm_quotactl, },
407 };
408
409
410 void __init
411 xfs_qm_init(void)
412 {
413         static char     message[] __initdata =
414                 KERN_INFO "SGI XFS Quota Management subsystem\n";
415
416         printk(message);
417         mutex_init(&xfs_Gqm_lock);
418         vfs_bhv_set_custom(&xfs_qmops, &xfs_qmcore_xfs);
419         xfs_qm_init_procfs();
420 }
421
422 void __exit
423 xfs_qm_exit(void)
424 {
425         vfs_bhv_clr_custom(&xfs_qmops);
426         xfs_qm_cleanup_procfs();
427         if (qm_dqzone)
428                 kmem_zone_destroy(qm_dqzone);
429         if (qm_dqtrxzone)
430                 kmem_zone_destroy(qm_dqtrxzone);
431 }