1 /* $NetBSD: ufs_vfsops.c,v 1.63 2026/01/22 03:24:19 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.63 2026/01/22 03:24:19 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/types.h> 50 51 #include <sys/buf.h> 52 #include <sys/kauth.h> 53 #include <sys/kmem.h> 54 #include <sys/module.h> 55 #include <sys/mount.h> 56 #include <sys/proc.h> 57 #include <sys/sdt.h> 58 #include <sys/vnode.h> 59 60 #include <miscfs/specfs/specdev.h> 61 62 #include <sys/quotactl.h> 63 #ifdef UFS_DIRHASH 64 #include <ufs/ufs/dirhash.h> 65 #endif 66 #include <ufs/ufs/inode.h> 67 #include <ufs/ufs/quota.h> 68 #include <ufs/ufs/ufs_extern.h> 69 #include <ufs/ufs/ufsmount.h> 70 71 /* how many times ufs_init() was called */ 72 static int ufs_initcount = 0; 73 74 pool_cache_t ufs_direct_cache; 75 76 /* 77 * Make a filesystem operational. 78 * Nothing to do at the moment. 79 */ 80 /* ARGSUSED */ 81 int 82 ufs_start(struct mount *mp, int flags) 83 { 84 85 return 0; 86 } 87 88 /* 89 * Return the root of a filesystem. 90 */ 91 int 92 ufs_root(struct mount *mp, int lktype, struct vnode **vpp) 93 { 94 struct vnode *nvp; 95 int error; 96 97 if ((error = VFS_VGET(mp, (ino_t)UFS_ROOTINO, lktype, &nvp)) != 0) 98 return error; 99 *vpp = nvp; 100 return 0; 101 } 102 103 /* 104 * Look up and return a vnode/inode pair by inode number. 105 */ 106 int 107 ufs_vget(struct mount *mp, ino_t ino, int lktype, struct vnode **vpp) 108 { 109 int error; 110 111 error = vcache_get(mp, &ino, sizeof(ino), vpp); 112 if (error) 113 return error; 114 error = vn_lock(*vpp, lktype); 115 if (error) { 116 vrele(*vpp); 117 *vpp = NULL; 118 return error; 119 } 120 return 0; 121 } 122 123 /* 124 * Do operations associated with quotas 125 */ 126 int 127 ufs_quotactl(struct mount *mp, struct quotactl_args *args) 128 { 129 130 #if !defined(QUOTA) && !defined(QUOTA2) 131 (void) mp; 132 (void) args; 133 return SET_ERROR(EOPNOTSUPP); 134 #else 135 struct lwp *l = curlwp; 136 int error; 137 138 /* Mark the mount busy, as we're passing it to kauth(9). */ 139 error = vfs_busy(mp); 140 if (error) { 141 return error; 142 } 143 mutex_enter(mp->mnt_updating); 144 145 error = quota_handle_cmd(mp, l, args); 146 147 mutex_exit(mp->mnt_updating); 148 vfs_unbusy(mp); 149 return error; 150 #endif 151 } 152 153 #if 0 154 switch (cmd) { 155 case Q_SYNC: 156 break; 157 158 case Q_GETQUOTA: 159 /* The user can always query about his own quota. */ 160 if (uid == kauth_cred_getuid(l->l_cred)) 161 break; 162 163 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 164 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(uid), NULL); 165 166 break; 167 168 case Q_QUOTAON: 169 case Q_QUOTAOFF: 170 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 171 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); 172 173 break; 174 175 case Q_SETQUOTA: 176 case Q_SETUSE: 177 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 178 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(uid), NULL); 179 180 break; 181 182 default: 183 error = SET_ERROR(EINVAL); 184 break; 185 } 186 187 type = cmds & SUBCMDMASK; 188 if (!error) { 189 /* Only check if there was no error above. */ 190 if ((u_int)type >= MAXQUOTAS) 191 error = SET_ERROR(EINVAL); 192 } 193 194 if (error) { 195 vfs_unbusy(mp); 196 return (error); 197 } 198 199 mutex_enter(mp->mnt_updating); 200 switch (cmd) { 201 202 case Q_QUOTAON: 203 error = quotaon(l, mp, type, arg); 204 break; 205 206 case Q_QUOTAOFF: 207 error = quotaoff(l, mp, type); 208 break; 209 210 case Q_SETQUOTA: 211 error = setquota(mp, uid, type, arg); 212 break; 213 214 case Q_SETUSE: 215 error = setuse(mp, uid, type, arg); 216 break; 217 218 case Q_GETQUOTA: 219 error = getquota(mp, uid, type, arg); 220 break; 221 222 case Q_SYNC: 223 error = qsync(mp); 224 break; 225 226 default: 227 error = SET_ERROR(EINVAL); 228 } 229 mutex_exit(mp->mnt_updating); 230 vfs_unbusy(mp); 231 return error; 232 #endif 233 234 /* 235 * This is the generic part of fhtovp called after the underlying 236 * filesystem has validated the file handle. 237 */ 238 int 239 ufs_fhtovp(struct mount *mp, struct ufid *ufhp, int lktype, struct vnode **vpp) 240 { 241 struct vnode *nvp; 242 struct inode *ip; 243 int error; 244 245 if ((error = VFS_VGET(mp, ufhp->ufid_ino, lktype, &nvp)) != 0) { 246 if (error == ENOENT) 247 error = SET_ERROR(ESTALE); 248 *vpp = NULLVP; 249 return error; 250 } 251 ip = VTOI(nvp); 252 KASSERT(ip != NULL); 253 if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen || 254 ((ip->i_mode & IFMT) == IFDIR && ip->i_size == 0)) { 255 vput(nvp); 256 *vpp = NULLVP; 257 return SET_ERROR(ESTALE); 258 } 259 *vpp = nvp; 260 return 0; 261 } 262 263 /* 264 * Initialize UFS filesystems, done only once. 265 */ 266 void 267 ufs_init(void) 268 { 269 if (ufs_initcount++ > 0) 270 return; 271 272 ufs_direct_cache = pool_cache_init(sizeof(struct direct), 0, 0, 0, 273 "ufsdir", NULL, IPL_NONE, NULL, NULL, NULL); 274 275 #if defined(QUOTA) || defined(QUOTA2) 276 dqinit(); 277 #endif 278 #ifdef UFS_DIRHASH 279 ufsdirhash_init(); 280 #endif 281 #ifdef UFS_EXTATTR 282 ufs_extattr_init(); 283 #endif 284 } 285 286 void 287 ufs_reinit(void) 288 { 289 #if defined(QUOTA) || defined(QUOTA2) 290 dqreinit(); 291 #endif 292 } 293 294 /* 295 * Free UFS filesystem resources, done only once. 296 */ 297 void 298 ufs_done(void) 299 { 300 if (--ufs_initcount > 0) 301 return; 302 303 #if defined(QUOTA) || defined(QUOTA2) 304 dqdone(); 305 #endif 306 pool_cache_destroy(ufs_direct_cache); 307 #ifdef UFS_DIRHASH 308 ufsdirhash_done(); 309 #endif 310 #ifdef UFS_EXTATTR 311 ufs_extattr_done(); 312 #endif 313 } 314 315 /* 316 * module interface 317 */ 318 319 #ifdef WAPBL 320 MODULE(MODULE_CLASS_MISC, ufs, "wapbl"); 321 #else 322 MODULE(MODULE_CLASS_MISC, ufs, NULL); 323 #endif 324 325 static int 326 ufs_modcmd(modcmd_t cmd, void *arg) 327 { 328 int error; 329 330 switch (cmd) { 331 case MODULE_CMD_INIT: 332 ufs_init(); 333 error = 0; 334 break; 335 case MODULE_CMD_FINI: 336 ufs_done(); 337 error = 0; 338 break; 339 default: 340 error = SET_ERROR(ENOTTY); 341 break; 342 } 343 344 return error; 345 } 346