2 * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
38 #include "xfs_trans.h"
42 #include "xfs_alloc.h"
43 #include "xfs_dmapi.h"
44 #include "xfs_quota.h"
45 #include "xfs_mount.h"
46 #include "xfs_alloc_btree.h"
47 #include "xfs_bmap_btree.h"
48 #include "xfs_ialloc_btree.h"
49 #include "xfs_btree.h"
50 #include "xfs_ialloc.h"
51 #include "xfs_attr_sf.h"
52 #include "xfs_dir_sf.h"
53 #include "xfs_dir2_sf.h"
54 #include "xfs_dinode.h"
55 #include "xfs_inode.h"
58 #include "xfs_rtalloc.h"
59 #include "xfs_error.h"
60 #include "xfs_itable.h"
66 #include "xfs_buf_item.h"
70 #define MNTOPT_QUOTA "quota" /* disk quotas (user) */
71 #define MNTOPT_NOQUOTA "noquota" /* no quotas */
72 #define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */
73 #define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */
74 #define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */
75 #define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */
76 #define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
77 #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
78 #define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */
84 struct xfs_mount_args
*args
,
88 char *local_options
= options
;
91 int referenced
= update
;
93 while ((this_char
= strsep(&local_options
, ",")) != NULL
) {
94 length
= strlen(this_char
);
98 if (!strcmp(this_char
, MNTOPT_NOQUOTA
)) {
99 args
->flags
&= ~(XFSMNT_UQUOTAENF
|XFSMNT_UQUOTA
);
100 args
->flags
&= ~(XFSMNT_GQUOTAENF
|XFSMNT_GQUOTA
);
102 } else if (!strcmp(this_char
, MNTOPT_QUOTA
) ||
103 !strcmp(this_char
, MNTOPT_UQUOTA
) ||
104 !strcmp(this_char
, MNTOPT_USRQUOTA
)) {
105 args
->flags
|= XFSMNT_UQUOTA
| XFSMNT_UQUOTAENF
;
107 } else if (!strcmp(this_char
, MNTOPT_QUOTANOENF
) ||
108 !strcmp(this_char
, MNTOPT_UQUOTANOENF
)) {
109 args
->flags
|= XFSMNT_UQUOTA
;
110 args
->flags
&= ~XFSMNT_UQUOTAENF
;
112 } else if (!strcmp(this_char
, MNTOPT_GQUOTA
) ||
113 !strcmp(this_char
, MNTOPT_GRPQUOTA
)) {
114 args
->flags
|= XFSMNT_GQUOTA
| XFSMNT_GQUOTAENF
;
116 } else if (!strcmp(this_char
, MNTOPT_GQUOTANOENF
)) {
117 args
->flags
|= XFSMNT_GQUOTA
;
118 args
->flags
&= ~XFSMNT_GQUOTAENF
;
122 *(local_options
-1) = ',';
130 PVFS_PARSEARGS(BHV_NEXT(bhv
), options
, args
, update
, error
);
131 if (!error
&& !referenced
)
132 bhv_remove_vfsops(bhvtovfs(bhv
), VFS_POSITION_QM
);
138 struct bhv_desc
*bhv
,
141 struct vfs
*vfsp
= bhvtovfs(bhv
);
142 struct xfs_mount
*mp
= XFS_VFSTOM(vfsp
);
145 if (mp
->m_qflags
& XFS_UQUOTA_ACCT
) {
146 (mp
->m_qflags
& XFS_UQUOTA_ENFD
) ?
147 seq_puts(m
, "," MNTOPT_USRQUOTA
) :
148 seq_puts(m
, "," MNTOPT_UQUOTANOENF
);
151 if (mp
->m_qflags
& XFS_GQUOTA_ACCT
) {
152 (mp
->m_qflags
& XFS_GQUOTA_ENFD
) ?
153 seq_puts(m
, "," MNTOPT_GRPQUOTA
) :
154 seq_puts(m
, "," MNTOPT_GQUOTANOENF
);
157 if (!(mp
->m_qflags
& (XFS_UQUOTA_ACCT
|XFS_GQUOTA_ACCT
)))
158 seq_puts(m
, "," MNTOPT_NOQUOTA
);
160 PVFS_SHOWARGS(BHV_NEXT(bhv
), m
, error
);
166 struct bhv_desc
*bhv
,
167 struct xfs_mount_args
*args
,
170 struct vfs
*vfsp
= bhvtovfs(bhv
);
171 struct xfs_mount
*mp
= XFS_VFSTOM(vfsp
);
174 if (args
->flags
& (XFSMNT_UQUOTA
| XFSMNT_GQUOTA
))
175 xfs_qm_mount_quotainit(mp
, args
->flags
);
176 PVFS_MOUNT(BHV_NEXT(bhv
), args
, cr
, error
);
182 struct bhv_desc
*bhv
,
186 struct vfs
*vfsp
= bhvtovfs(bhv
);
187 struct xfs_mount
*mp
= XFS_VFSTOM(vfsp
);
191 * Get the Quota Manager to flush the dquots.
193 if (XFS_IS_QUOTA_ON(mp
)) {
194 if ((error
= xfs_qm_sync(mp
, flags
))) {
196 * If we got an IO error, we will be shutting down.
197 * So, there's nothing more for us to do here.
199 ASSERT(error
!= EIO
|| XFS_FORCED_SHUTDOWN(mp
));
200 if (XFS_FORCED_SHUTDOWN(mp
)) {
201 return XFS_ERROR(error
);
205 PVFS_SYNC(BHV_NEXT(bhv
), flags
, credp
, error
);
210 * Clear the quotaflags in memory and in the superblock.
213 xfs_mount_reset_sbqflags(
221 * It is OK to look at sb_qflags here in mount path,
224 if (mp
->m_sb
.sb_qflags
== 0)
227 mp
->m_sb
.sb_qflags
= 0;
228 XFS_SB_UNLOCK(mp
, s
);
231 * if the fs is readonly, let the incore superblock run
232 * with quotas off but don't flush the update out to disk
234 if (XFS_MTOVFS(mp
)->vfs_flag
& VFS_RDONLY
)
237 xfs_fs_cmn_err(CE_NOTE
, mp
, "Writing superblock quota changes");
239 tp
= xfs_trans_alloc(mp
, XFS_TRANS_QM_SBCHANGE
);
240 if (xfs_trans_reserve(tp
, 0, mp
->m_sb
.sb_sectsize
+ 128, 0, 0,
241 XFS_DEFAULT_LOG_COUNT
)) {
242 xfs_trans_cancel(tp
, 0);
243 xfs_fs_cmn_err(CE_ALERT
, mp
,
244 "xfs_mount_reset_sbqflags: Superblock update failed!");
247 xfs_mod_sb(tp
, XFS_SB_QFLAGS
);
248 xfs_trans_commit(tp
, 0, NULL
);
254 uint
*needquotamount
,
258 uint uquotaondisk
= 0, gquotaondisk
= 0;
261 *needquotamount
= B_FALSE
;
263 quotaondisk
= XFS_SB_VERSION_HASQUOTA(&mp
->m_sb
) &&
264 mp
->m_sb
.sb_qflags
& (XFS_UQUOTA_ACCT
|XFS_GQUOTA_ACCT
);
267 uquotaondisk
= mp
->m_sb
.sb_qflags
& XFS_UQUOTA_ACCT
;
268 gquotaondisk
= mp
->m_sb
.sb_qflags
& XFS_GQUOTA_ACCT
;
272 * If the device itself is read-only, we can't allow
273 * the user to change the state of quota on the mount -
274 * this would generate a transaction on the ro device,
275 * which would lead to an I/O error and shutdown
278 if (((uquotaondisk
&& !XFS_IS_UQUOTA_ON(mp
)) ||
279 (!uquotaondisk
&& XFS_IS_UQUOTA_ON(mp
)) ||
280 (gquotaondisk
&& !XFS_IS_GQUOTA_ON(mp
)) ||
281 (!gquotaondisk
&& XFS_IS_GQUOTA_ON(mp
))) &&
282 xfs_dev_is_read_only(mp
, "changing quota state")) {
284 "XFS: please mount with%s%s%s.",
285 (!quotaondisk
? "out quota" : ""),
286 (uquotaondisk
? " usrquota" : ""),
287 (gquotaondisk
? " grpquota" : ""));
288 return XFS_ERROR(EPERM
);
291 if (XFS_IS_QUOTA_ON(mp
) || quotaondisk
) {
293 * Call mount_quotas at this point only if we won't have to do
296 if (quotaondisk
&& !XFS_QM_NEED_QUOTACHECK(mp
)) {
298 * If an error occured, qm_mount_quotas code
299 * has already disabled quotas. So, just finish
300 * mounting, and get on with the boring life
301 * without disk quotas.
303 xfs_qm_mount_quotas(mp
, 0);
306 * Clear the quota flags, but remember them. This
307 * is so that the quota code doesn't get invoked
308 * before we're ready. This can happen when an
309 * inode goes inactive and wants to free blocks,
310 * or via xfs_log_mount_finish.
312 *needquotamount
= B_TRUE
;
313 *quotaflags
= mp
->m_qflags
;
328 if (needquotamount
) {
329 ASSERT(mp
->m_qflags
== 0);
330 mp
->m_qflags
= quotaflags
;
331 xfs_qm_mount_quotas(mp
, mfsi_flags
);
334 #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
335 if (! (XFS_IS_QUOTA_ON(mp
)))
336 xfs_fs_cmn_err(CE_NOTE
, mp
, "Disk quotas not turned on");
338 xfs_fs_cmn_err(CE_NOTE
, mp
, "Disk quotas turned on");
342 if (XFS_IS_QUOTA_ON(mp
) && xfs_qm_internalqcheck(mp
))
343 cmn_err(CE_WARN
, "XFS: mount internalqcheck failed");
354 * Called from XFS, where we always check first for a NULL dquot.
362 struct xfs_qmops xfs_qmcore_xfs
= {
363 .xfs_qminit
= xfs_qm_newmount
,
364 .xfs_qmdone
= xfs_qm_unmount_quotadestroy
,
365 .xfs_qmmount
= xfs_qm_endmount
,
366 .xfs_qmunmount
= xfs_qm_unmount_quotas
,
367 .xfs_dqrele
= xfs_qm_dqrele_null
,
368 .xfs_dqattach
= xfs_qm_dqattach
,
369 .xfs_dqdetach
= xfs_qm_dqdetach
,
370 .xfs_dqpurgeall
= xfs_qm_dqpurge_all
,
371 .xfs_dqvopalloc
= xfs_qm_vop_dqalloc
,
372 .xfs_dqvopcreate
= xfs_qm_vop_dqattach_and_dqmod_newinode
,
373 .xfs_dqvoprename
= xfs_qm_vop_rename_dqattach
,
374 .xfs_dqvopchown
= xfs_qm_vop_chown
,
375 .xfs_dqvopchownresv
= xfs_qm_vop_chown_reserve
,
376 .xfs_dqtrxops
= &xfs_trans_dquot_ops
,
379 struct bhv_vfsops xfs_qmops
= { {
380 BHV_IDENTITY_INIT(VFS_BHV_QM
, VFS_POSITION_QM
),
381 .vfs_parseargs
= xfs_qm_parseargs
,
382 .vfs_showargs
= xfs_qm_showargs
,
383 .vfs_mount
= xfs_qm_mount
,
384 .vfs_sync
= xfs_qm_syncall
,
385 .vfs_quotactl
= xfs_qm_quotactl
, },
392 static char message
[] __initdata
=
393 KERN_INFO
"SGI XFS Quota Management subsystem\n";
396 mutex_init(&xfs_Gqm_lock
, MUTEX_DEFAULT
, "xfs_qmlock");
397 vfs_bhv_set_custom(&xfs_qmops
, &xfs_qmcore_xfs
);
398 xfs_qm_init_procfs();
404 vfs_bhv_clr_custom(&xfs_qmops
);
405 xfs_qm_cleanup_procfs();
407 kmem_cache_destroy(qm_dqzone
);
409 kmem_cache_destroy(qm_dqtrxzone
);