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