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 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 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 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 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 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 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 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 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 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