xref: /netbsd/sys/ufs/ufs/ufs_vfsops.c (revision d51593aa)
1 /*	$NetBSD: ufs_vfsops.c,v 1.61 2023/02/22 21:49:45 riastradh Exp $	*/
2 
3 /*
4  * Copyright (c) 1991, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)ufs_vfsops.c	8.8 (Berkeley) 5/20/95
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: ufs_vfsops.c,v 1.61 2023/02/22 21:49:45 riastradh Exp $");
41 
42 #if defined(_KERNEL_OPT)
43 #include "opt_ffs.h"
44 #include "opt_quota.h"
45 #include "opt_wapbl.h"
46 #endif
47 
48 #include <sys/param.h>
49 #include <sys/mount.h>
50 #include <sys/proc.h>
51 #include <sys/buf.h>
52 #include <sys/module.h>
53 #include <sys/vnode.h>
54 #include <sys/kmem.h>
55 #include <sys/kauth.h>
56 
57 #include <miscfs/specfs/specdev.h>
58 
59 #include <sys/quotactl.h>
60 #include <ufs/ufs/quota.h>
61 #include <ufs/ufs/inode.h>
62 #include <ufs/ufs/ufsmount.h>
63 #include <ufs/ufs/ufs_extern.h>
64 #ifdef UFS_DIRHASH
65 #include <ufs/ufs/dirhash.h>
66 #endif
67 
68 /* how many times ufs_init() was called */
69 static int ufs_initcount = 0;
70 
71 pool_cache_t ufs_direct_cache;
72 
73 /*
74  * Make a filesystem operational.
75  * Nothing to do at the moment.
76  */
77 /* ARGSUSED */
78 int
ufs_start(struct mount * mp,int flags)79 ufs_start(struct mount *mp, int flags)
80 {
81 
82 	return (0);
83 }
84 
85 /*
86  * Return the root of a filesystem.
87  */
88 int
ufs_root(struct mount * mp,int lktype,struct vnode ** vpp)89 ufs_root(struct mount *mp, int lktype, struct vnode **vpp)
90 {
91 	struct vnode *nvp;
92 	int error;
93 
94 	if ((error = VFS_VGET(mp, (ino_t)UFS_ROOTINO, lktype, &nvp)) != 0)
95 		return (error);
96 	*vpp = nvp;
97 	return (0);
98 }
99 
100 /*
101  * Look up and return a vnode/inode pair by inode number.
102  */
103 int
ufs_vget(struct mount * mp,ino_t ino,int lktype,struct vnode ** vpp)104 ufs_vget(struct mount *mp, ino_t ino, int lktype, struct vnode **vpp)
105 {
106 	int error;
107 
108 	error = vcache_get(mp, &ino, sizeof(ino), vpp);
109 	if (error)
110 		return error;
111 	error = vn_lock(*vpp, lktype);
112 	if (error) {
113 		vrele(*vpp);
114 		*vpp = NULL;
115 		return error;
116 	}
117 	return 0;
118 }
119 
120 /*
121  * Do operations associated with quotas
122  */
123 int
ufs_quotactl(struct mount * mp,struct quotactl_args * args)124 ufs_quotactl(struct mount *mp, struct quotactl_args *args)
125 {
126 
127 #if !defined(QUOTA) && !defined(QUOTA2)
128 	(void) mp;
129 	(void) args;
130 	return (EOPNOTSUPP);
131 #else
132 	struct lwp *l = curlwp;
133 	int error;
134 
135 	/* Mark the mount busy, as we're passing it to kauth(9). */
136 	error = vfs_busy(mp);
137 	if (error) {
138 		return (error);
139 	}
140 	mutex_enter(mp->mnt_updating);
141 
142 	error = quota_handle_cmd(mp, l, args);
143 
144 	mutex_exit(mp->mnt_updating);
145 	vfs_unbusy(mp);
146 	return (error);
147 #endif
148 }
149 
150 #if 0
151 	switch (cmd) {
152 	case Q_SYNC:
153 		break;
154 
155 	case Q_GETQUOTA:
156 		/* The user can always query about his own quota. */
157 		if (uid == kauth_cred_getuid(l->l_cred))
158 			break;
159 
160 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
161 		    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(uid), NULL);
162 
163 		break;
164 
165 	case Q_QUOTAON:
166 	case Q_QUOTAOFF:
167 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
168 		    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
169 
170 		break;
171 
172 	case Q_SETQUOTA:
173 	case Q_SETUSE:
174 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
175 		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(uid), NULL);
176 
177 		break;
178 
179 	default:
180 		error = EINVAL;
181 		break;
182 	}
183 
184 	type = cmds & SUBCMDMASK;
185 	if (!error) {
186 		/* Only check if there was no error above. */
187 		if ((u_int)type >= MAXQUOTAS)
188 			error = EINVAL;
189 	}
190 
191 	if (error) {
192 		vfs_unbusy(mp);
193 		return (error);
194 	}
195 
196 	mutex_enter(mp->mnt_updating);
197 	switch (cmd) {
198 
199 	case Q_QUOTAON:
200 		error = quotaon(l, mp, type, arg);
201 		break;
202 
203 	case Q_QUOTAOFF:
204 		error = quotaoff(l, mp, type);
205 		break;
206 
207 	case Q_SETQUOTA:
208 		error = setquota(mp, uid, type, arg);
209 		break;
210 
211 	case Q_SETUSE:
212 		error = setuse(mp, uid, type, arg);
213 		break;
214 
215 	case Q_GETQUOTA:
216 		error = getquota(mp, uid, type, arg);
217 		break;
218 
219 	case Q_SYNC:
220 		error = qsync(mp);
221 		break;
222 
223 	default:
224 		error = EINVAL;
225 	}
226 	mutex_exit(mp->mnt_updating);
227 	vfs_unbusy(mp);
228 	return (error);
229 #endif
230 
231 /*
232  * This is the generic part of fhtovp called after the underlying
233  * filesystem has validated the file handle.
234  */
235 int
ufs_fhtovp(struct mount * mp,struct ufid * ufhp,int lktype,struct vnode ** vpp)236 ufs_fhtovp(struct mount *mp, struct ufid *ufhp, int lktype, struct vnode **vpp)
237 {
238 	struct vnode *nvp;
239 	struct inode *ip;
240 	int error;
241 
242 	if ((error = VFS_VGET(mp, ufhp->ufid_ino, lktype, &nvp)) != 0) {
243 		if (error == ENOENT)
244 			error = ESTALE;
245 		*vpp = NULLVP;
246 		return (error);
247 	}
248 	ip = VTOI(nvp);
249 	KASSERT(ip != NULL);
250 	if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen ||
251 	    ((ip->i_mode & IFMT) == IFDIR && ip->i_size == 0)) {
252 		vput(nvp);
253 		*vpp = NULLVP;
254 		return (ESTALE);
255 	}
256 	*vpp = nvp;
257 	return (0);
258 }
259 
260 /*
261  * Initialize UFS filesystems, done only once.
262  */
263 void
ufs_init(void)264 ufs_init(void)
265 {
266 	if (ufs_initcount++ > 0)
267 		return;
268 
269 	ufs_direct_cache = pool_cache_init(sizeof(struct direct), 0, 0, 0,
270 	    "ufsdir", NULL, IPL_NONE, NULL, NULL, NULL);
271 
272 #if defined(QUOTA) || defined(QUOTA2)
273 	dqinit();
274 #endif
275 #ifdef UFS_DIRHASH
276 	ufsdirhash_init();
277 #endif
278 #ifdef UFS_EXTATTR
279 	ufs_extattr_init();
280 #endif
281 }
282 
283 void
ufs_reinit(void)284 ufs_reinit(void)
285 {
286 #if defined(QUOTA) || defined(QUOTA2)
287 	dqreinit();
288 #endif
289 }
290 
291 /*
292  * Free UFS filesystem resources, done only once.
293  */
294 void
ufs_done(void)295 ufs_done(void)
296 {
297 	if (--ufs_initcount > 0)
298 		return;
299 
300 #if defined(QUOTA) || defined(QUOTA2)
301 	dqdone();
302 #endif
303 	pool_cache_destroy(ufs_direct_cache);
304 #ifdef UFS_DIRHASH
305 	ufsdirhash_done();
306 #endif
307 #ifdef UFS_EXTATTR
308 	ufs_extattr_done();
309 #endif
310 }
311 
312 /*
313  * module interface
314  */
315 
316 #ifdef WAPBL
317 MODULE(MODULE_CLASS_MISC, ufs, "wapbl");
318 #else
319 MODULE(MODULE_CLASS_MISC, ufs, NULL);
320 #endif
321 
322 static int
ufs_modcmd(modcmd_t cmd,void * arg)323 ufs_modcmd(modcmd_t cmd, void *arg)
324 {
325         int error;
326 
327         switch (cmd) {
328         case MODULE_CMD_INIT:
329 		ufs_init();
330 		error = 0;
331 		break;
332         case MODULE_CMD_FINI:
333 		ufs_done();
334 		error = 0;
335 		break;
336 	default:
337 		error = ENOTTY;
338 		break;
339 	}
340 
341 	return error;
342 }
343