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