1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* 26 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 27 * Copyright 2017 Joyent, Inc. 28 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 29 */ 30 31 /* 32 * Generic vnode operations. 33 */ 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/errno.h> 38 #include <sys/fcntl.h> 39 #include <sys/flock.h> 40 #include <sys/statvfs.h> 41 #include <sys/vfs.h> 42 #include <sys/vnode.h> 43 #include <sys/cred.h> 44 #include <sys/poll.h> 45 #include <sys/debug.h> 46 #include <sys/cmn_err.h> 47 #include <sys/share.h> 48 #include <sys/file.h> 49 #include <sys/kmem.h> 50 #include <sys/nbmlock.h> 51 #include <sys/acl.h> 52 53 #include <acl/acl_common.h> 54 #include <fs/fs_subr.h> 55 56 /* 57 * Tunable to limit the number of retry to recover from STALE error. 58 */ 59 int fs_estale_retry = 5; 60 61 /* 62 * The associated operation is not supported by the file system. 63 */ 64 int 65 fs_nosys() 66 { 67 return (ENOSYS); 68 } 69 70 /* 71 * The associated operation is invalid (on this vnode). 72 */ 73 int 74 fs_inval() 75 { 76 return (EINVAL); 77 } 78 79 /* 80 * The associated operation is valid only for directories. 81 */ 82 int 83 fs_notdir() 84 { 85 return (ENOTDIR); 86 } 87 88 /* 89 * Free the file system specific resources. For the file systems that 90 * do not support the forced unmount, it will be a nop function. 91 */ 92 93 /*ARGSUSED*/ 94 void 95 fs_freevfs(vfs_t *vfsp) 96 { 97 } 98 99 /* ARGSUSED */ 100 int 101 fs_nosys_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp, 102 size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr, 103 caller_context_t *ct) 104 { 105 return (ENOSYS); 106 } 107 108 /* ARGSUSED */ 109 int 110 fs_nosys_addmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr, 111 size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr, 112 caller_context_t *ct) 113 { 114 return (ENOSYS); 115 } 116 117 /* ARGSUSED */ 118 int 119 fs_nosys_poll(vnode_t *vp, short events, int anyyet, short *reventsp, 120 struct pollhead **phpp, caller_context_t *ct) 121 { 122 return (ENOSYS); 123 } 124 125 126 /* 127 * The file system has nothing to sync to disk. However, the 128 * VFS_SYNC operation must not fail. 129 */ 130 /* ARGSUSED */ 131 int 132 fs_sync(struct vfs *vfspp, short flag, cred_t *cr) 133 { 134 return (0); 135 } 136 137 /* 138 * Does nothing but VOP_FSYNC must not fail. 139 */ 140 /* ARGSUSED */ 141 int 142 fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 143 { 144 return (0); 145 } 146 147 /* 148 * Does nothing but VOP_PUTPAGE must not fail. 149 */ 150 /* ARGSUSED */ 151 int 152 fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr, 153 caller_context_t *ctp) 154 { 155 return (0); 156 } 157 158 /* 159 * Does nothing but VOP_IOCTL must not fail. 160 */ 161 /* ARGSUSED */ 162 int 163 fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred, 164 int *rvalp) 165 { 166 return (0); 167 } 168 169 /* 170 * Read/write lock/unlock. Does nothing. 171 */ 172 /* ARGSUSED */ 173 int 174 fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 175 { 176 return (-1); 177 } 178 179 /* ARGSUSED */ 180 void 181 fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 182 { 183 } 184 185 /* 186 * Compare two vnodes. 187 */ 188 /*ARGSUSED2*/ 189 int 190 fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct) 191 { 192 return (vp1 == vp2); 193 } 194 195 /* 196 * No-op seek operation. 197 */ 198 /* ARGSUSED */ 199 int 200 fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 201 { 202 return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0); 203 } 204 205 /* 206 * File and record locking. 207 */ 208 /* ARGSUSED */ 209 int 210 fs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset, 211 flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct) 212 { 213 return (ENOSYS); 214 } 215 216 /* 217 * Allow any flags. 218 */ 219 /* ARGSUSED */ 220 int 221 fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct) 222 { 223 return (0); 224 } 225 226 /* 227 * Return the answer requested to poll() for non-device files. 228 * Only POLLIN, POLLRDNORM, and POLLOUT are recognized. 229 */ 230 struct pollhead fs_pollhd; 231 232 /* ARGSUSED */ 233 int 234 fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp, 235 struct pollhead **phpp, caller_context_t *ct) 236 { 237 if (events & POLLET) { 238 return (EPERM); 239 } 240 241 *reventsp = 0; 242 if (events & POLLIN) 243 *reventsp |= POLLIN; 244 if (events & POLLRDNORM) 245 *reventsp |= POLLRDNORM; 246 if (events & POLLRDBAND) 247 *reventsp |= POLLRDBAND; 248 if (events & POLLOUT) 249 *reventsp |= POLLOUT; 250 if (events & POLLWRBAND) 251 *reventsp |= POLLWRBAND; 252 if (*reventsp == 0 && !anyyet) { 253 *phpp = &fs_pollhd; 254 } 255 return (0); 256 } 257 258 /* 259 * POSIX pathconf() support. 260 */ 261 /* ARGSUSED */ 262 int 263 fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 264 caller_context_t *ct) 265 { 266 /* not called */ 267 return (EINVAL); 268 } 269 270 /* 271 * Dispose of a page. 272 */ 273 /* ARGSUSED */ 274 void 275 fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr, 276 caller_context_t *ct) 277 { 278 } 279 280 /* ARGSUSED */ 281 void 282 fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr, 283 caller_context_t *ct) 284 { 285 cmn_err(CE_PANIC, "fs_nodispose invoked"); 286 } 287 288 /* 289 * fabricate acls for file systems that do not support acls. 290 */ 291 /* ARGSUSED */ 292 int 293 fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr, 294 caller_context_t *ct) 295 { 296 struct vattr vattr; 297 int error; 298 299 vsecattr->vsa_aclcnt = 0; 300 vsecattr->vsa_aclentsz = 0; 301 vsecattr->vsa_aclentp = NULL; 302 vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */ 303 vsecattr->vsa_dfaclentp = NULL; 304 305 vattr.va_mask = AT_MODE | AT_UID | AT_GID; 306 if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct)) 307 return (error); 308 309 if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) { 310 return (ENOSYS); 311 } 312 313 if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) { 314 VERIFY(0 == acl_trivial_create(vattr.va_mode, 315 (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp, 316 &vsecattr->vsa_aclcnt)); 317 vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t); 318 } 319 320 return (error); 321 } 322 323 /* 324 * Common code for implementing DOS share reservations 325 */ 326 /* ARGSUSED */ 327 int 328 fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr, 329 caller_context_t *ct) 330 { 331 return (ENOSYS); 332 } 333 334 /*ARGSUSED1*/ 335 int 336 fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 337 caller_context_t *ct) 338 { 339 ASSERT(vp != NULL); 340 return (ENOTSUP); 341 } 342 343 /*ARGSUSED1*/ 344 int 345 fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 346 caller_context_t *ct) 347 { 348 ASSERT(vp != NULL); 349 return (0); 350 } 351 352 // fs_acl_nontrivial 353 354 /* 355 * Check whether we need a retry to recover from STALE error. 356 */ 357 int 358 fs_need_estale_retry(int retry_count) 359 { 360 if (retry_count < fs_estale_retry) 361 return (1); 362 else 363 return (0); 364 } 365 366 // fs_vscan... 367 // reparse... 368 369 /* 370 * A few things from os/flock.c 371 */ 372 373 /* ARGSUSED */ 374 void 375 cleanlocks(vnode_t *vp, pid_t pid, int sysid) 376 { 377 } 378 379 /* ARGSUSED */ 380 void 381 cleanshares(struct vnode *vp, pid_t pid) 382 { 383 } 384 385 /* 386 * convoff - converts the given data (start, whence) to the 387 * given whence. 388 */ 389 int 390 convoff(struct vnode *vp, struct flock64 *lckdat, int whence, offset_t offset) 391 { 392 int error; 393 struct vattr vattr; 394 395 if ((lckdat->l_whence == 2) || (whence == 2)) { 396 vattr.va_mask = AT_SIZE; 397 if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) 398 return (error); 399 } 400 401 switch (lckdat->l_whence) { 402 case 1: 403 lckdat->l_start += offset; 404 break; 405 case 2: 406 lckdat->l_start += vattr.va_size; 407 /* FALLTHRU */ 408 case 0: 409 break; 410 default: 411 return (EINVAL); 412 } 413 414 if (lckdat->l_start < 0) 415 return (EINVAL); 416 417 switch (whence) { 418 case 1: 419 lckdat->l_start -= offset; 420 break; 421 case 2: 422 lckdat->l_start -= vattr.va_size; 423 /* FALLTHRU */ 424 case 0: 425 break; 426 default: 427 return (EINVAL); 428 } 429 430 lckdat->l_whence = (short)whence; 431 return (0); 432 } 433