1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 3921 jk115741 * Common Development and Distribution License (the "License"). 6 3921 jk115741 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 3921 jk115741 /* Portions Copyright 2007 Shivakumar GN */ 22 0 stevel /* 23 6036 mec * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel #include <sys/types.h> 30 0 stevel #include <sys/cmn_err.h> 31 0 stevel #include <sys/debug.h> 32 0 stevel #include <sys/dirent.h> 33 0 stevel #include <sys/kmem.h> 34 0 stevel #include <sys/mman.h> 35 0 stevel #include <sys/mutex.h> 36 0 stevel #include <sys/sysmacros.h> 37 0 stevel #include <sys/systm.h> 38 6492 timh #include <sys/sunddi.h> 39 0 stevel #include <sys/uio.h> 40 0 stevel #include <sys/vmsystm.h> 41 0 stevel #include <sys/vfs.h> 42 0 stevel #include <sys/vnode.h> 43 0 stevel 44 0 stevel #include <vm/as.h> 45 0 stevel #include <vm/seg_vn.h> 46 0 stevel 47 0 stevel #include <sys/gfs.h> 48 0 stevel 49 0 stevel /* 50 0 stevel * Generic pseudo-filesystem routines. 51 0 stevel * 52 0 stevel * There are significant similarities between the implementation of certain file 53 0 stevel * system entry points across different filesystems. While one could attempt to 54 0 stevel * "choke up on the bat" and incorporate common functionality into a VOP 55 3921 jk115741 * preamble or postamble, such an approach is limited in the benefit it can 56 0 stevel * provide. In this file we instead define a toolkit of routines which can be 57 0 stevel * called from a filesystem (with in-kernel pseudo-filesystems being the focus 58 0 stevel * of the exercise) in a more component-like fashion. 59 0 stevel * 60 0 stevel * There are three basic classes of routines: 61 0 stevel * 62 0 stevel * 1) Lowlevel support routines 63 0 stevel * 64 0 stevel * These routines are designed to play a support role for existing 65 3921 jk115741 * pseudo-filesystems (such as procfs). They simplify common tasks, 66 5331 amw * without forcing the filesystem to hand over management to GFS. The 67 0 stevel * routines covered are: 68 0 stevel * 69 0 stevel * gfs_readdir_init() 70 0 stevel * gfs_readdir_emit() 71 0 stevel * gfs_readdir_emitn() 72 0 stevel * gfs_readdir_pred() 73 0 stevel * gfs_readdir_fini() 74 0 stevel * gfs_lookup_dot() 75 0 stevel * 76 0 stevel * 2) Complete GFS management 77 0 stevel * 78 0 stevel * These routines take a more active role in management of the 79 0 stevel * pseudo-filesystem. They handle the relationship between vnode private 80 0 stevel * data and VFS data, as well as the relationship between vnodes in the 81 3921 jk115741 * directory hierarchy. 82 0 stevel * 83 0 stevel * In order to use these interfaces, the first member of every private 84 0 stevel * v_data must be a gfs_file_t or a gfs_dir_t. This hands over all control 85 0 stevel * to GFS. 86 0 stevel * 87 0 stevel * gfs_file_create() 88 0 stevel * gfs_dir_create() 89 0 stevel * gfs_root_create() 90 0 stevel * 91 0 stevel * gfs_file_inactive() 92 0 stevel * gfs_dir_inactive() 93 0 stevel * gfs_dir_lookup() 94 0 stevel * gfs_dir_readdir() 95 0 stevel * 96 0 stevel * gfs_vop_inactive() 97 0 stevel * gfs_vop_lookup() 98 0 stevel * gfs_vop_readdir() 99 0 stevel * gfs_vop_map() 100 3957 th199096 * 101 3957 th199096 * 3) Single File pseudo-filesystems 102 3957 th199096 * 103 3957 th199096 * This routine creates a rooted file to be overlayed ontop of another 104 3957 th199096 * file in the physical filespace. 105 3957 th199096 * 106 3957 th199096 * Note that the parent is NULL (actually the vfs), but there is nothing 107 3957 th199096 * technically keeping such a file from utilizing the "Complete GFS 108 3957 th199096 * management" set of routines. 109 3957 th199096 * 110 3957 th199096 * gfs_root_create_file() 111 0 stevel */ 112 0 stevel 113 0 stevel /* 114 0 stevel * gfs_make_opsvec: take an array of vnode type definitions and create 115 0 stevel * their vnodeops_t structures 116 0 stevel * 117 0 stevel * This routine takes an array of gfs_opsvec_t's. It could 118 0 stevel * alternatively take an array of gfs_opsvec_t*'s, which would allow 119 0 stevel * vnode types to be completely defined in files external to the caller 120 0 stevel * of gfs_make_opsvec(). As it stands, much more sharing takes place -- 121 0 stevel * both the caller and the vnode type provider need to access gfsv_ops 122 0 stevel * and gfsv_template, and the caller also needs to know gfsv_name. 123 0 stevel */ 124 0 stevel int 125 0 stevel gfs_make_opsvec(gfs_opsvec_t *vec) 126 0 stevel { 127 0 stevel int error, i; 128 0 stevel 129 0 stevel for (i = 0; ; i++) { 130 0 stevel if (vec[i].gfsv_name == NULL) 131 0 stevel return (0); 132 0 stevel error = vn_make_ops(vec[i].gfsv_name, vec[i].gfsv_template, 133 0 stevel vec[i].gfsv_ops); 134 0 stevel if (error) 135 0 stevel break; 136 0 stevel } 137 0 stevel 138 0 stevel cmn_err(CE_WARN, "gfs_make_opsvec: bad vnode ops template for '%s'", 139 0 stevel vec[i].gfsv_name); 140 0 stevel for (i--; i >= 0; i--) { 141 0 stevel vn_freevnodeops(*vec[i].gfsv_ops); 142 0 stevel *vec[i].gfsv_ops = NULL; 143 0 stevel } 144 0 stevel return (error); 145 0 stevel } 146 0 stevel 147 0 stevel /* 148 0 stevel * Low level directory routines 149 0 stevel * 150 0 stevel * These routines provide some simple abstractions for reading directories. 151 0 stevel * They are designed to be used by existing pseudo filesystems (namely procfs) 152 0 stevel * that already have a complicated management infrastructure. 153 0 stevel */ 154 0 stevel 155 0 stevel /* 156 5663 ck153898 * gfs_get_parent_ino: used to obtain a parent inode number and the 157 5663 ck153898 * inode number of the given vnode in preparation for calling gfs_readdir_init. 158 5663 ck153898 */ 159 5663 ck153898 int 160 5663 ck153898 gfs_get_parent_ino(vnode_t *dvp, cred_t *cr, caller_context_t *ct, 161 5663 ck153898 ino64_t *pino, ino64_t *ino) 162 5663 ck153898 { 163 5663 ck153898 vnode_t *parent; 164 5663 ck153898 gfs_dir_t *dp = dvp->v_data; 165 5663 ck153898 int error; 166 5663 ck153898 167 5663 ck153898 *ino = dp->gfsd_file.gfs_ino; 168 5663 ck153898 parent = dp->gfsd_file.gfs_parent; 169 5663 ck153898 170 5663 ck153898 if (parent == NULL) { 171 5663 ck153898 *pino = *ino; /* root of filesystem */ 172 5663 ck153898 } else if (dvp->v_flag & V_XATTRDIR) { 173 5663 ck153898 vattr_t va; 174 5663 ck153898 175 5663 ck153898 va.va_mask = AT_NODEID; 176 5663 ck153898 error = VOP_GETATTR(parent, &va, 0, cr, ct); 177 5663 ck153898 if (error) 178 5663 ck153898 return (error); 179 5663 ck153898 *pino = va.va_nodeid; 180 5663 ck153898 } else { 181 5663 ck153898 *pino = ((gfs_file_t *)(parent->v_data))->gfs_ino; 182 5663 ck153898 } 183 5663 ck153898 184 5663 ck153898 return (0); 185 5663 ck153898 } 186 5663 ck153898 187 5663 ck153898 /* 188 0 stevel * gfs_readdir_init: initiate a generic readdir 189 0 stevel * st - a pointer to an uninitialized gfs_readdir_state_t structure 190 0 stevel * name_max - the directory's maximum file name length 191 0 stevel * ureclen - the exported file-space record length (1 for non-legacy FSs) 192 0 stevel * uiop - the uiop passed to readdir 193 0 stevel * parent - the parent directory's inode 194 0 stevel * self - this directory's inode 195 5663 ck153898 * flags - flags from VOP_READDIR 196 0 stevel * 197 0 stevel * Returns 0 or a non-zero errno. 198 0 stevel * 199 0 stevel * Typical VOP_READDIR usage of gfs_readdir_*: 200 0 stevel * 201 0 stevel * if ((error = gfs_readdir_init(...)) != 0) 202 0 stevel * return (error); 203 0 stevel * eof = 0; 204 0 stevel * while ((error = gfs_readdir_pred(..., &voffset)) != 0) { 205 0 stevel * if (!consumer_entry_at(voffset)) 206 0 stevel * voffset = consumer_next_entry(voffset); 207 0 stevel * if (consumer_eof(voffset)) { 208 0 stevel * eof = 1 209 0 stevel * break; 210 0 stevel * } 211 0 stevel * if ((error = gfs_readdir_emit(..., voffset, 212 0 stevel * consumer_ino(voffset), consumer_name(voffset))) != 0) 213 0 stevel * break; 214 0 stevel * } 215 0 stevel * return (gfs_readdir_fini(..., error, eofp, eof)); 216 0 stevel * 217 0 stevel * As you can see, a zero result from gfs_readdir_pred() or 218 0 stevel * gfs_readdir_emit() indicates that processing should continue, 219 0 stevel * whereas a non-zero result indicates that the loop should terminate. 220 0 stevel * Most consumers need do nothing more than let gfs_readdir_fini() 221 0 stevel * determine what the cause of failure was and return the appropriate 222 0 stevel * value. 223 0 stevel */ 224 0 stevel int 225 0 stevel gfs_readdir_init(gfs_readdir_state_t *st, int name_max, int ureclen, 226 5663 ck153898 uio_t *uiop, ino64_t parent, ino64_t self, int flags) 227 0 stevel { 228 5663 ck153898 size_t dirent_size; 229 5663 ck153898 230 0 stevel if (uiop->uio_loffset < 0 || uiop->uio_resid <= 0 || 231 0 stevel (uiop->uio_loffset % ureclen) != 0) 232 0 stevel return (EINVAL); 233 0 stevel 234 0 stevel st->grd_ureclen = ureclen; 235 0 stevel st->grd_oresid = uiop->uio_resid; 236 0 stevel st->grd_namlen = name_max; 237 5663 ck153898 if (flags & V_RDDIR_ENTFLAGS) 238 5663 ck153898 dirent_size = EDIRENT_RECLEN(st->grd_namlen); 239 5663 ck153898 else 240 5663 ck153898 dirent_size = DIRENT64_RECLEN(st->grd_namlen); 241 5663 ck153898 st->grd_dirent = kmem_zalloc(dirent_size, KM_SLEEP); 242 0 stevel st->grd_parent = parent; 243 0 stevel st->grd_self = self; 244 5663 ck153898 st->grd_flags = flags; 245 0 stevel 246 0 stevel return (0); 247 0 stevel } 248 0 stevel 249 0 stevel /* 250 0 stevel * gfs_readdir_emit_int: internal routine to emit directory entry 251 0 stevel * 252 5663 ck153898 * st - the current readdir state, which must have d_ino/ed_ino 253 5663 ck153898 * and d_name/ed_name set 254 0 stevel * uiop - caller-supplied uio pointer 255 0 stevel * next - the offset of the next entry 256 0 stevel */ 257 0 stevel static int 258 847 maybee gfs_readdir_emit_int(gfs_readdir_state_t *st, uio_t *uiop, offset_t next) 259 0 stevel { 260 0 stevel int reclen; 261 5663 ck153898 dirent64_t *dp; 262 5663 ck153898 edirent_t *edp; 263 0 stevel 264 5663 ck153898 if (st->grd_flags & V_RDDIR_ENTFLAGS) { 265 5663 ck153898 edp = st->grd_dirent; 266 5663 ck153898 reclen = EDIRENT_RECLEN(strlen(edp->ed_name)); 267 5663 ck153898 } else { 268 5663 ck153898 dp = st->grd_dirent; 269 5663 ck153898 reclen = DIRENT64_RECLEN(strlen(dp->d_name)); 270 5663 ck153898 } 271 0 stevel 272 0 stevel if (reclen > uiop->uio_resid) { 273 0 stevel /* 274 0 stevel * Error if no entries were returned yet 275 0 stevel */ 276 0 stevel if (uiop->uio_resid == st->grd_oresid) 277 0 stevel return (EINVAL); 278 0 stevel return (-1); 279 0 stevel } 280 0 stevel 281 5663 ck153898 if (st->grd_flags & V_RDDIR_ENTFLAGS) { 282 5663 ck153898 edp->ed_off = next; 283 5663 ck153898 edp->ed_reclen = (ushort_t)reclen; 284 5663 ck153898 } else { 285 5663 ck153898 dp->d_off = next; 286 5663 ck153898 dp->d_reclen = (ushort_t)reclen; 287 5663 ck153898 } 288 0 stevel 289 0 stevel if (uiomove((caddr_t)st->grd_dirent, reclen, UIO_READ, uiop)) 290 0 stevel return (EFAULT); 291 0 stevel 292 0 stevel uiop->uio_loffset = next; 293 0 stevel 294 0 stevel return (0); 295 0 stevel } 296 0 stevel 297 0 stevel /* 298 0 stevel * gfs_readdir_emit: emit a directory entry 299 0 stevel * voff - the virtual offset (obtained from gfs_readdir_pred) 300 0 stevel * ino - the entry's inode 301 0 stevel * name - the entry's name 302 5663 ck153898 * eflags - value for ed_eflags (if processing edirent_t) 303 0 stevel * 304 0 stevel * Returns a 0 on success, a non-zero errno on failure, or -1 if the 305 0 stevel * readdir loop should terminate. A non-zero result (either errno or 306 0 stevel * -1) from this function is typically passed directly to 307 0 stevel * gfs_readdir_fini(). 308 0 stevel */ 309 0 stevel int 310 0 stevel gfs_readdir_emit(gfs_readdir_state_t *st, uio_t *uiop, offset_t voff, 311 5663 ck153898 ino64_t ino, const char *name, int eflags) 312 0 stevel { 313 0 stevel offset_t off = (voff + 2) * st->grd_ureclen; 314 0 stevel 315 5663 ck153898 if (st->grd_flags & V_RDDIR_ENTFLAGS) { 316 5663 ck153898 edirent_t *edp = st->grd_dirent; 317 5663 ck153898 318 5663 ck153898 edp->ed_ino = ino; 319 5663 ck153898 (void) strncpy(edp->ed_name, name, st->grd_namlen); 320 5663 ck153898 edp->ed_eflags = eflags; 321 5663 ck153898 } else { 322 5663 ck153898 dirent64_t *dp = st->grd_dirent; 323 5663 ck153898 324 5663 ck153898 dp->d_ino = ino; 325 5663 ck153898 (void) strncpy(dp->d_name, name, st->grd_namlen); 326 5663 ck153898 } 327 0 stevel 328 0 stevel /* 329 0 stevel * Inter-entry offsets are invalid, so we assume a record size of 330 0 stevel * grd_ureclen and explicitly set the offset appropriately. 331 0 stevel */ 332 847 maybee return (gfs_readdir_emit_int(st, uiop, off + st->grd_ureclen)); 333 0 stevel } 334 0 stevel 335 0 stevel /* 336 0 stevel * gfs_readdir_emitn: like gfs_readdir_emit(), but takes an integer 337 0 stevel * instead of a string for the entry's name. 338 0 stevel */ 339 0 stevel int 340 0 stevel gfs_readdir_emitn(gfs_readdir_state_t *st, uio_t *uiop, offset_t voff, 341 0 stevel ino64_t ino, unsigned long num) 342 0 stevel { 343 0 stevel char buf[40]; 344 0 stevel 345 0 stevel numtos(num, buf); 346 5663 ck153898 return (gfs_readdir_emit(st, uiop, voff, ino, buf, 0)); 347 0 stevel } 348 0 stevel 349 0 stevel /* 350 0 stevel * gfs_readdir_pred: readdir loop predicate 351 0 stevel * voffp - a pointer in which the next virtual offset should be stored 352 0 stevel * 353 0 stevel * Returns a 0 on success, a non-zero errno on failure, or -1 if the 354 0 stevel * readdir loop should terminate. A non-zero result (either errno or 355 0 stevel * -1) from this function is typically passed directly to 356 0 stevel * gfs_readdir_fini(). 357 0 stevel */ 358 0 stevel int 359 0 stevel gfs_readdir_pred(gfs_readdir_state_t *st, uio_t *uiop, offset_t *voffp) 360 0 stevel { 361 0 stevel offset_t off, voff; 362 0 stevel int error; 363 0 stevel 364 0 stevel top: 365 0 stevel if (uiop->uio_resid <= 0) 366 0 stevel return (-1); 367 0 stevel 368 0 stevel off = uiop->uio_loffset / st->grd_ureclen; 369 0 stevel voff = off - 2; 370 0 stevel if (off == 0) { 371 0 stevel if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_self, 372 5663 ck153898 ".", 0)) == 0) 373 0 stevel goto top; 374 0 stevel } else if (off == 1) { 375 0 stevel if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_parent, 376 5663 ck153898 "..", 0)) == 0) 377 0 stevel goto top; 378 0 stevel } else { 379 0 stevel *voffp = voff; 380 0 stevel return (0); 381 0 stevel } 382 0 stevel 383 0 stevel return (error); 384 0 stevel } 385 0 stevel 386 0 stevel /* 387 0 stevel * gfs_readdir_fini: generic readdir cleanup 388 0 stevel * error - if positive, an error to return 389 0 stevel * eofp - the eofp passed to readdir 390 0 stevel * eof - the eof value 391 0 stevel * 392 0 stevel * Returns a 0 on success, a non-zero errno on failure. This result 393 0 stevel * should be returned from readdir. 394 0 stevel */ 395 0 stevel int 396 0 stevel gfs_readdir_fini(gfs_readdir_state_t *st, int error, int *eofp, int eof) 397 0 stevel { 398 5663 ck153898 size_t dirent_size; 399 5663 ck153898 400 5663 ck153898 if (st->grd_flags & V_RDDIR_ENTFLAGS) 401 5663 ck153898 dirent_size = EDIRENT_RECLEN(st->grd_namlen); 402 5663 ck153898 else 403 5663 ck153898 dirent_size = DIRENT64_RECLEN(st->grd_namlen); 404 5663 ck153898 kmem_free(st->grd_dirent, dirent_size); 405 0 stevel if (error > 0) 406 0 stevel return (error); 407 0 stevel if (eofp) 408 0 stevel *eofp = eof; 409 0 stevel return (0); 410 0 stevel } 411 0 stevel 412 0 stevel /* 413 0 stevel * gfs_lookup_dot 414 0 stevel * 415 0 stevel * Performs a basic check for "." and ".." directory entries. 416 0 stevel */ 417 0 stevel int 418 0 stevel gfs_lookup_dot(vnode_t **vpp, vnode_t *dvp, vnode_t *pvp, const char *nm) 419 0 stevel { 420 0 stevel if (*nm == '\0' || strcmp(nm, ".") == 0) { 421 0 stevel VN_HOLD(dvp); 422 0 stevel *vpp = dvp; 423 0 stevel return (0); 424 0 stevel } else if (strcmp(nm, "..") == 0) { 425 0 stevel if (pvp == NULL) { 426 0 stevel ASSERT(dvp->v_flag & VROOT); 427 0 stevel VN_HOLD(dvp); 428 0 stevel *vpp = dvp; 429 0 stevel } else { 430 0 stevel VN_HOLD(pvp); 431 0 stevel *vpp = pvp; 432 0 stevel } 433 0 stevel return (0); 434 0 stevel } 435 0 stevel 436 0 stevel return (-1); 437 0 stevel } 438 0 stevel 439 0 stevel /* 440 0 stevel * gfs_file_create(): create a new GFS file 441 0 stevel * 442 0 stevel * size - size of private data structure (v_data) 443 0 stevel * pvp - parent vnode (GFS directory) 444 0 stevel * ops - vnode operations vector 445 0 stevel * 446 0 stevel * In order to use this interface, the parent vnode must have been created by 447 0 stevel * gfs_dir_create(), and the private data stored in v_data must have a 448 0 stevel * 'gfs_file_t' as its first field. 449 0 stevel * 450 0 stevel * Given these constraints, this routine will automatically: 451 0 stevel * 452 0 stevel * - Allocate v_data for the vnode 453 0 stevel * - Initialize necessary fields in the vnode 454 0 stevel * - Hold the parent 455 0 stevel */ 456 0 stevel vnode_t * 457 0 stevel gfs_file_create(size_t size, vnode_t *pvp, vnodeops_t *ops) 458 0 stevel { 459 0 stevel gfs_file_t *fp; 460 0 stevel vnode_t *vp; 461 0 stevel 462 0 stevel /* 463 0 stevel * Allocate vnode and internal data structure 464 0 stevel */ 465 0 stevel fp = kmem_zalloc(size, KM_SLEEP); 466 0 stevel vp = vn_alloc(KM_SLEEP); 467 0 stevel 468 0 stevel /* 469 0 stevel * Set up various pointers 470 0 stevel */ 471 0 stevel fp->gfs_vnode = vp; 472 0 stevel fp->gfs_parent = pvp; 473 0 stevel vp->v_data = fp; 474 0 stevel fp->gfs_size = size; 475 0 stevel fp->gfs_type = GFS_FILE; 476 0 stevel 477 0 stevel /* 478 0 stevel * Initialize vnode and hold parent. 479 0 stevel */ 480 0 stevel vn_setops(vp, ops); 481 0 stevel if (pvp) { 482 0 stevel VN_SET_VFS_TYPE_DEV(vp, pvp->v_vfsp, VREG, 0); 483 0 stevel VN_HOLD(pvp); 484 0 stevel } 485 0 stevel 486 0 stevel return (vp); 487 0 stevel } 488 0 stevel 489 0 stevel /* 490 0 stevel * gfs_dir_create: creates a new directory in the parent 491 0 stevel * 492 0 stevel * size - size of private data structure (v_data) 493 0 stevel * pvp - parent vnode (GFS directory) 494 0 stevel * ops - vnode operations vector 495 0 stevel * entries - NULL-terminated list of static entries (if any) 496 0 stevel * maxlen - maximum length of a directory entry 497 0 stevel * readdir_cb - readdir callback (see gfs_dir_readdir) 498 0 stevel * inode_cb - inode callback (see gfs_dir_readdir) 499 0 stevel * lookup_cb - lookup callback (see gfs_dir_lookup) 500 0 stevel * 501 0 stevel * In order to use this function, the first member of the private vnode 502 0 stevel * structure (v_data) must be a gfs_dir_t. For each directory, there are 503 0 stevel * static entries, defined when the structure is initialized, and dynamic 504 0 stevel * entries, retrieved through callbacks. 505 0 stevel * 506 0 stevel * If a directory has static entries, then it must supply a inode callback, 507 0 stevel * which will compute the inode number based on the parent and the index. 508 0 stevel * For a directory with dynamic entries, the caller must supply a readdir 509 0 stevel * callback and a lookup callback. If a static lookup fails, we fall back to 510 0 stevel * the supplied lookup callback, if any. 511 0 stevel * 512 0 stevel * This function also performs the same initialization as gfs_file_create(). 513 0 stevel */ 514 0 stevel vnode_t * 515 0 stevel gfs_dir_create(size_t struct_size, vnode_t *pvp, vnodeops_t *ops, 516 0 stevel gfs_dirent_t *entries, gfs_inode_cb inode_cb, int maxlen, 517 0 stevel gfs_readdir_cb readdir_cb, gfs_lookup_cb lookup_cb) 518 0 stevel { 519 0 stevel vnode_t *vp; 520 0 stevel gfs_dir_t *dp; 521 0 stevel gfs_dirent_t *de; 522 0 stevel 523 0 stevel vp = gfs_file_create(struct_size, pvp, ops); 524 0 stevel vp->v_type = VDIR; 525 0 stevel 526 0 stevel dp = vp->v_data; 527 0 stevel dp->gfsd_file.gfs_type = GFS_DIR; 528 0 stevel dp->gfsd_maxlen = maxlen; 529 0 stevel 530 0 stevel if (entries != NULL) { 531 0 stevel for (de = entries; de->gfse_name != NULL; de++) 532 0 stevel dp->gfsd_nstatic++; 533 0 stevel 534 0 stevel dp->gfsd_static = kmem_alloc( 535 0 stevel dp->gfsd_nstatic * sizeof (gfs_dirent_t), KM_SLEEP); 536 0 stevel bcopy(entries, dp->gfsd_static, 537 0 stevel dp->gfsd_nstatic * sizeof (gfs_dirent_t)); 538 0 stevel } 539 0 stevel 540 0 stevel dp->gfsd_readdir = readdir_cb; 541 0 stevel dp->gfsd_lookup = lookup_cb; 542 0 stevel dp->gfsd_inode = inode_cb; 543 0 stevel 544 0 stevel mutex_init(&dp->gfsd_lock, NULL, MUTEX_DEFAULT, NULL); 545 0 stevel 546 0 stevel return (vp); 547 0 stevel } 548 0 stevel 549 0 stevel /* 550 0 stevel * gfs_root_create(): create a root vnode for a GFS filesystem 551 0 stevel * 552 0 stevel * Similar to gfs_dir_create(), this creates a root vnode for a filesystem. The 553 0 stevel * only difference is that it takes a vfs_t instead of a vnode_t as its parent. 554 0 stevel */ 555 0 stevel vnode_t * 556 0 stevel gfs_root_create(size_t size, vfs_t *vfsp, vnodeops_t *ops, ino64_t ino, 557 0 stevel gfs_dirent_t *entries, gfs_inode_cb inode_cb, int maxlen, 558 0 stevel gfs_readdir_cb readdir_cb, gfs_lookup_cb lookup_cb) 559 0 stevel { 560 0 stevel vnode_t *vp = gfs_dir_create(size, NULL, ops, entries, inode_cb, 561 0 stevel maxlen, readdir_cb, lookup_cb); 562 0 stevel 563 0 stevel /* Manually set the inode */ 564 0 stevel ((gfs_file_t *)vp->v_data)->gfs_ino = ino; 565 0 stevel 566 0 stevel VFS_HOLD(vfsp); 567 0 stevel VN_SET_VFS_TYPE_DEV(vp, vfsp, VDIR, 0); 568 0 stevel vp->v_flag |= VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT; 569 0 stevel 570 0 stevel return (vp); 571 0 stevel } 572 0 stevel 573 0 stevel /* 574 3957 th199096 * gfs_root_create_file(): create a root vnode for a GFS file as a filesystem 575 3957 th199096 * 576 3957 th199096 * Similar to gfs_root_create(), this creates a root vnode for a file to 577 3957 th199096 * be the pseudo-filesystem. 578 3957 th199096 */ 579 3957 th199096 vnode_t * 580 3957 th199096 gfs_root_create_file(size_t size, vfs_t *vfsp, vnodeops_t *ops, ino64_t ino) 581 3957 th199096 { 582 3957 th199096 vnode_t *vp = gfs_file_create(size, NULL, ops); 583 3957 th199096 584 3957 th199096 ((gfs_file_t *)vp->v_data)->gfs_ino = ino; 585 3957 th199096 586 3957 th199096 VFS_HOLD(vfsp); 587 3957 th199096 VN_SET_VFS_TYPE_DEV(vp, vfsp, VREG, 0); 588 3957 th199096 vp->v_flag |= VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT; 589 3957 th199096 590 3957 th199096 return (vp); 591 3957 th199096 } 592 3957 th199096 593 3957 th199096 /* 594 0 stevel * gfs_file_inactive() 595 0 stevel * 596 0 stevel * Called from the VOP_INACTIVE() routine. If necessary, this routine will 597 0 stevel * remove the given vnode from the parent directory and clean up any references 598 0 stevel * in the VFS layer. 599 0 stevel * 600 0 stevel * If the vnode was not removed (due to a race with vget), then NULL is 601 0 stevel * returned. Otherwise, a pointer to the private data is returned. 602 0 stevel */ 603 0 stevel void * 604 0 stevel gfs_file_inactive(vnode_t *vp) 605 0 stevel { 606 0 stevel int i; 607 0 stevel gfs_dirent_t *ge = NULL; 608 0 stevel gfs_file_t *fp = vp->v_data; 609 0 stevel gfs_dir_t *dp = NULL; 610 0 stevel void *data; 611 0 stevel 612 5331 amw if (fp->gfs_parent == NULL || (vp->v_flag & V_XATTRDIR)) 613 0 stevel goto found; 614 0 stevel 615 0 stevel dp = fp->gfs_parent->v_data; 616 0 stevel 617 0 stevel /* 618 0 stevel * First, see if this vnode is cached in the parent. 619 0 stevel */ 620 0 stevel gfs_dir_lock(dp); 621 0 stevel 622 0 stevel /* 623 0 stevel * Find it in the set of static entries. 624 0 stevel */ 625 0 stevel for (i = 0; i < dp->gfsd_nstatic; i++) { 626 0 stevel ge = &dp->gfsd_static[i]; 627 0 stevel 628 0 stevel if (ge->gfse_vnode == vp) 629 0 stevel goto found; 630 0 stevel } 631 0 stevel 632 0 stevel /* 633 0 stevel * If 'ge' is NULL, then it is a dynamic entry. 634 0 stevel */ 635 0 stevel ge = NULL; 636 0 stevel 637 0 stevel found: 638 5331 amw if (vp->v_flag & V_XATTRDIR) { 639 5331 amw mutex_enter(&fp->gfs_parent->v_lock); 640 5331 amw } 641 0 stevel mutex_enter(&vp->v_lock); 642 0 stevel if (vp->v_count == 1) { 643 0 stevel /* 644 0 stevel * Really remove this vnode 645 0 stevel */ 646 0 stevel data = vp->v_data; 647 0 stevel if (ge != NULL) { 648 0 stevel /* 649 0 stevel * If this was a statically cached entry, simply set the 650 0 stevel * cached vnode to NULL. 651 0 stevel */ 652 0 stevel ge->gfse_vnode = NULL; 653 0 stevel } 654 5331 amw if (vp->v_flag & V_XATTRDIR) { 655 5331 amw fp->gfs_parent->v_xattrdir = NULL; 656 5331 amw mutex_exit(&fp->gfs_parent->v_lock); 657 5331 amw } 658 0 stevel mutex_exit(&vp->v_lock); 659 0 stevel 660 0 stevel /* 661 0 stevel * Free vnode and release parent 662 0 stevel */ 663 0 stevel if (fp->gfs_parent) { 664 5331 amw if (dp) { 665 5331 amw gfs_dir_unlock(dp); 666 5331 amw } 667 0 stevel VN_RELE(fp->gfs_parent); 668 0 stevel } else { 669 0 stevel ASSERT(vp->v_vfsp != NULL); 670 0 stevel VFS_RELE(vp->v_vfsp); 671 0 stevel } 672 0 stevel vn_free(vp); 673 0 stevel } else { 674 0 stevel vp->v_count--; 675 0 stevel data = NULL; 676 0 stevel mutex_exit(&vp->v_lock); 677 5331 amw if (vp->v_flag & V_XATTRDIR) { 678 5331 amw mutex_exit(&fp->gfs_parent->v_lock); 679 5331 amw } 680 0 stevel if (dp) 681 0 stevel gfs_dir_unlock(dp); 682 0 stevel } 683 0 stevel 684 0 stevel return (data); 685 0 stevel } 686 0 stevel 687 0 stevel /* 688 0 stevel * gfs_dir_inactive() 689 0 stevel * 690 0 stevel * Same as above, but for directories. 691 0 stevel */ 692 0 stevel void * 693 0 stevel gfs_dir_inactive(vnode_t *vp) 694 0 stevel { 695 0 stevel gfs_dir_t *dp; 696 0 stevel 697 0 stevel ASSERT(vp->v_type == VDIR); 698 0 stevel 699 0 stevel if ((dp = gfs_file_inactive(vp)) != NULL) { 700 0 stevel mutex_destroy(&dp->gfsd_lock); 701 0 stevel if (dp->gfsd_nstatic) 702 0 stevel kmem_free(dp->gfsd_static, 703 0 stevel dp->gfsd_nstatic * sizeof (gfs_dirent_t)); 704 0 stevel } 705 0 stevel 706 0 stevel return (dp); 707 0 stevel } 708 0 stevel 709 0 stevel /* 710 6492 timh * gfs_dir_lookup_dynamic() 711 0 stevel * 712 6492 timh * This routine looks up the provided name amongst the dynamic entries 713 6492 timh * in the gfs directory and returns the corresponding vnode, if found. 714 0 stevel * 715 6492 timh * The gfs directory is expected to be locked by the caller prior to 716 6492 timh * calling this function. The directory will be unlocked during the 717 6492 timh * execution of this function, but will be locked upon return from the 718 6492 timh * function. This function returns 0 on success, non-zero on error. 719 0 stevel * 720 6492 timh * The dynamic lookups are performed by invoking the lookup 721 6492 timh * callback, which is passed to this function as the first argument. 722 6492 timh * The arguments to the callback are: 723 0 stevel * 724 6492 timh * int gfs_lookup_cb(vnode_t *pvp, const char *nm, vnode_t **vpp, cred_t *cr, 725 6492 timh * int flags, int *deflgs, pathname_t *rpnp); 726 0 stevel * 727 0 stevel * pvp - parent vnode 728 0 stevel * nm - name of entry 729 0 stevel * vpp - pointer to resulting vnode 730 5331 amw * cr - pointer to cred 731 6492 timh * flags - flags value from lookup request 732 6492 timh * ignored here; currently only used to request 733 6492 timh * insensitive lookups 734 6492 timh * direntflgs - output parameter, directory entry flags 735 6492 timh * ignored here; currently only used to indicate a lookup 736 6492 timh * has more than one possible match when case is not considered 737 6492 timh * realpnp - output parameter, real pathname 738 6492 timh * ignored here; when lookup was performed case-insensitively, 739 6492 timh * this field contains the "real" name of the file. 740 0 stevel * 741 0 stevel * Returns 0 on success, non-zero on error. 742 0 stevel */ 743 6492 timh static int 744 6492 timh gfs_dir_lookup_dynamic(gfs_lookup_cb callback, gfs_dir_t *dp, 745 6492 timh const char *nm, vnode_t *dvp, vnode_t **vpp, cred_t *cr, int flags, 746 6492 timh int *direntflags, pathname_t *realpnp) 747 0 stevel { 748 6492 timh gfs_file_t *fp; 749 6492 timh ino64_t ino; 750 6492 timh int ret; 751 6492 timh 752 6492 timh ASSERT(GFS_DIR_LOCKED(dp)); 753 6492 timh 754 6492 timh /* 755 6492 timh * Drop the directory lock, as the lookup routine 756 6492 timh * will need to allocate memory, or otherwise deadlock on this 757 6492 timh * directory. 758 6492 timh */ 759 6492 timh gfs_dir_unlock(dp); 760 6492 timh ret = callback(dvp, nm, vpp, &ino, cr, flags, direntflags, realpnp); 761 6492 timh gfs_dir_lock(dp); 762 6492 timh 763 6492 timh /* 764 6492 timh * The callback for extended attributes returns a vnode 765 6492 timh * with v_data from an underlying fs. 766 6492 timh */ 767 6492 timh if (ret == 0 && !IS_XATTRDIR(dvp)) { 768 6492 timh fp = (gfs_file_t *)((*vpp)->v_data); 769 6492 timh fp->gfs_index = -1; 770 6492 timh fp->gfs_ino = ino; 771 6492 timh } 772 6492 timh 773 6492 timh return (ret); 774 6492 timh } 775 6492 timh 776 6492 timh /* 777 6492 timh * gfs_dir_lookup_static() 778 6492 timh * 779 6492 timh * This routine looks up the provided name amongst the static entries 780 6492 timh * in the gfs directory and returns the corresponding vnode, if found. 781 6492 timh * The first argument to the function is a pointer to the comparison 782 6492 timh * function this function should use to decide if names are a match. 783 6492 timh * 784 6492 timh * If a match is found, and GFS_CACHE_VNODE is set and the vnode 785 6492 timh * exists, we simply return the existing vnode. Otherwise, we call 786 6492 timh * the static entry's callback routine, caching the result if 787 6492 timh * necessary. If the idx pointer argument is non-NULL, we use it to 788 6492 timh * return the index of the matching static entry. 789 6492 timh * 790 6492 timh * The gfs directory is expected to be locked by the caller prior to calling 791 6492 timh * this function. The directory may be unlocked during the execution of 792 6492 timh * this function, but will be locked upon return from the function. 793 6492 timh * 794 6492 timh * This function returns 0 if a match is found, ENOENT if not. 795 6492 timh */ 796 6492 timh static int 797 6492 timh gfs_dir_lookup_static(int (*compare)(const char *, const char *), 798 6492 timh gfs_dir_t *dp, const char *nm, vnode_t *dvp, int *idx, 799 6492 timh vnode_t **vpp, pathname_t *rpnp) 800 6492 timh { 801 6492 timh gfs_dirent_t *ge; 802 6492 timh vnode_t *vp = NULL; 803 0 stevel int i; 804 0 stevel 805 6492 timh ASSERT(GFS_DIR_LOCKED(dp)); 806 0 stevel 807 0 stevel /* 808 0 stevel * Search static entries. 809 0 stevel */ 810 0 stevel for (i = 0; i < dp->gfsd_nstatic; i++) { 811 0 stevel ge = &dp->gfsd_static[i]; 812 0 stevel 813 6492 timh if (compare(ge->gfse_name, nm) == 0) { 814 6492 timh if (rpnp) 815 6492 timh (void) strlcpy(rpnp->pn_buf, ge->gfse_name, 816 6492 timh rpnp->pn_bufsize); 817 6492 timh 818 0 stevel if (ge->gfse_vnode) { 819 0 stevel ASSERT(ge->gfse_flags & GFS_CACHE_VNODE); 820 0 stevel vp = ge->gfse_vnode; 821 0 stevel VN_HOLD(vp); 822 6492 timh break; 823 0 stevel } 824 0 stevel 825 0 stevel /* 826 3921 jk115741 * We drop the directory lock, as the constructor will 827 0 stevel * need to do KM_SLEEP allocations. If we return from 828 0 stevel * the constructor only to find that a parallel 829 0 stevel * operation has completed, and GFS_CACHE_VNODE is set 830 6492 timh * for this entry, we discard the result in favor of 831 6492 timh * the cached vnode. 832 0 stevel */ 833 0 stevel gfs_dir_unlock(dp); 834 0 stevel vp = ge->gfse_ctor(dvp); 835 0 stevel gfs_dir_lock(dp); 836 0 stevel 837 0 stevel ((gfs_file_t *)vp->v_data)->gfs_index = i; 838 0 stevel 839 0 stevel /* Set the inode according to the callback. */ 840 0 stevel ((gfs_file_t *)vp->v_data)->gfs_ino = 841 0 stevel dp->gfsd_inode(dvp, i); 842 0 stevel 843 0 stevel if (ge->gfse_flags & GFS_CACHE_VNODE) { 844 0 stevel if (ge->gfse_vnode == NULL) { 845 0 stevel ge->gfse_vnode = vp; 846 0 stevel } else { 847 0 stevel /* 848 0 stevel * A parallel constructor beat us to it; 849 0 stevel * return existing vnode. We have to be 850 0 stevel * careful because we can't release the 851 0 stevel * current vnode while holding the 852 0 stevel * directory lock; its inactive routine 853 0 stevel * will try to lock this directory. 854 0 stevel */ 855 0 stevel vnode_t *oldvp = vp; 856 0 stevel vp = ge->gfse_vnode; 857 0 stevel VN_HOLD(vp); 858 0 stevel 859 0 stevel gfs_dir_unlock(dp); 860 0 stevel VN_RELE(oldvp); 861 0 stevel gfs_dir_lock(dp); 862 0 stevel } 863 0 stevel } 864 6492 timh break; 865 0 stevel } 866 0 stevel } 867 0 stevel 868 6492 timh if (vp == NULL) 869 6492 timh return (ENOENT); 870 6492 timh else if (idx) 871 6492 timh *idx = i; 872 6492 timh *vpp = vp; 873 6492 timh return (0); 874 6492 timh } 875 0 stevel 876 6492 timh /* 877 6492 timh * gfs_dir_lookup() 878 6492 timh * 879 6492 timh * Looks up the given name in the directory and returns the corresponding 880 6492 timh * vnode, if found. 881 6492 timh * 882 6492 timh * First, we search statically defined entries, if any, with a call to 883 6492 timh * gfs_dir_lookup_static(). If no static entry is found, and we have 884 6492 timh * a callback function we try a dynamic lookup via gfs_dir_lookup_dynamic(). 885 6492 timh * 886 6492 timh * This function returns 0 on success, non-zero on error. 887 6492 timh */ 888 6492 timh int 889 6492 timh gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cred_t *cr, 890 6492 timh int flags, int *direntflags, pathname_t *realpnp) 891 6492 timh { 892 6492 timh gfs_dir_t *dp = dvp->v_data; 893 6492 timh boolean_t casecheck; 894 6492 timh vnode_t *dynvp = NULL; 895 6492 timh vnode_t *vp = NULL; 896 6492 timh int (*compare)(const char *, const char *); 897 6492 timh int error, idx; 898 0 stevel 899 6492 timh ASSERT(dvp->v_type == VDIR); 900 6492 timh 901 6492 timh if (gfs_lookup_dot(vpp, dvp, dp->gfsd_file.gfs_parent, nm) == 0) 902 6492 timh return (0); 903 6492 timh 904 6492 timh casecheck = (flags & FIGNORECASE) != 0 && direntflags != NULL; 905 6492 timh if (vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) || 906 6492 timh (flags & FIGNORECASE)) 907 6492 timh compare = strcasecmp; 908 6492 timh else 909 6492 timh compare = strcmp; 910 6492 timh 911 6492 timh gfs_dir_lock(dp); 912 6492 timh 913 6492 timh error = gfs_dir_lookup_static(compare, dp, nm, dvp, &idx, &vp, realpnp); 914 6492 timh 915 6492 timh if (vp && casecheck) { 916 6492 timh gfs_dirent_t *ge; 917 6492 timh int i; 918 6492 timh 919 6492 timh for (i = idx + 1; i < dp->gfsd_nstatic; i++) { 920 6492 timh ge = &dp->gfsd_static[i]; 921 6492 timh 922 6492 timh if (strcasecmp(ge->gfse_name, nm) == 0) { 923 6492 timh *direntflags |= ED_CASE_CONFLICT; 924 6492 timh goto out; 925 6492 timh } 926 5331 amw } 927 6492 timh } 928 6492 timh 929 6492 timh if ((error || casecheck) && dp->gfsd_lookup) 930 6492 timh error = gfs_dir_lookup_dynamic(dp->gfsd_lookup, dp, nm, dvp, 931 6492 timh &dynvp, cr, flags, direntflags, vp ? NULL : realpnp); 932 6492 timh 933 6492 timh if (vp && dynvp) { 934 6492 timh /* static and dynamic entries are case-insensitive conflict */ 935 6492 timh ASSERT(casecheck); 936 6492 timh *direntflags |= ED_CASE_CONFLICT; 937 6492 timh VN_RELE(dynvp); 938 6492 timh } else if (vp == NULL) { 939 6492 timh vp = dynvp; 940 6492 timh } else if (error == ENOENT) { 941 6492 timh error = 0; 942 6492 timh } else if (error) { 943 6492 timh VN_RELE(vp); 944 6492 timh vp = NULL; 945 0 stevel } 946 0 stevel 947 0 stevel out: 948 0 stevel gfs_dir_unlock(dp); 949 0 stevel 950 6492 timh *vpp = vp; 951 6492 timh return (error); 952 0 stevel } 953 0 stevel 954 0 stevel /* 955 0 stevel * gfs_dir_readdir: does a readdir() on the given directory 956 0 stevel * 957 0 stevel * dvp - directory vnode 958 0 stevel * uiop - uio structure 959 0 stevel * eofp - eof pointer 960 0 stevel * data - arbitrary data passed to readdir callback 961 0 stevel * 962 0 stevel * This routine does all the readdir() dirty work. Even so, the caller must 963 0 stevel * supply two callbacks in order to get full compatibility. 964 0 stevel * 965 0 stevel * If the directory contains static entries, an inode callback must be 966 0 stevel * specified. This avoids having to create every vnode and call VOP_GETATTR() 967 0 stevel * when reading the directory. This function has the following arguments: 968 0 stevel * 969 0 stevel * ino_t gfs_inode_cb(vnode_t *vp, int index); 970 0 stevel * 971 0 stevel * vp - vnode for the directory 972 0 stevel * index - index in original gfs_dirent_t array 973 0 stevel * 974 0 stevel * Returns the inode number for the given entry. 975 0 stevel * 976 0 stevel * For directories with dynamic entries, a readdir callback must be provided. 977 0 stevel * This is significantly more complex, thanks to the particulars of 978 0 stevel * VOP_READDIR(). 979 0 stevel * 980 5663 ck153898 * int gfs_readdir_cb(vnode_t *vp, void *dp, int *eofp, 981 5663 ck153898 * offset_t *off, offset_t *nextoff, void *data, int flags) 982 0 stevel * 983 0 stevel * vp - directory vnode 984 0 stevel * dp - directory entry, sized according to maxlen given to 985 0 stevel * gfs_dir_create(). callback must fill in d_name and 986 5663 ck153898 * d_ino (if a dirent64_t), or ed_name, ed_ino, and ed_eflags 987 5663 ck153898 * (if an edirent_t). edirent_t is used if V_RDDIR_ENTFLAGS 988 5663 ck153898 * is set in 'flags'. 989 0 stevel * eofp - callback must set to 1 when EOF has been reached 990 0 stevel * off - on entry, the last offset read from the directory. Callback 991 0 stevel * must set to the offset of the current entry, typically left 992 0 stevel * untouched. 993 0 stevel * nextoff - callback must set to offset of next entry. Typically 994 0 stevel * (off + 1) 995 0 stevel * data - caller-supplied data 996 5663 ck153898 * flags - VOP_READDIR flags 997 0 stevel * 998 0 stevel * Return 0 on success, or error on failure. 999 0 stevel */ 1000 0 stevel int 1001 5331 amw gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data, cred_t *cr, 1002 5663 ck153898 caller_context_t *ct, int flags) 1003 0 stevel { 1004 0 stevel gfs_readdir_state_t gstate; 1005 0 stevel int error, eof = 0; 1006 0 stevel ino64_t ino, pino; 1007 0 stevel offset_t off, next; 1008 0 stevel gfs_dir_t *dp = dvp->v_data; 1009 0 stevel 1010 5663 ck153898 error = gfs_get_parent_ino(dvp, cr, ct, &pino, &ino); 1011 5663 ck153898 if (error) 1012 5663 ck153898 return (error); 1013 0 stevel 1014 0 stevel if ((error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, uiop, 1015 5663 ck153898 pino, ino, flags)) != 0) 1016 0 stevel return (error); 1017 0 stevel 1018 0 stevel while ((error = gfs_readdir_pred(&gstate, uiop, &off)) == 0 && 1019 0 stevel !eof) { 1020 0 stevel 1021 0 stevel if (off >= 0 && off < dp->gfsd_nstatic) { 1022 0 stevel ino = dp->gfsd_inode(dvp, off); 1023 0 stevel 1024 0 stevel if ((error = gfs_readdir_emit(&gstate, uiop, 1025 5663 ck153898 off, ino, dp->gfsd_static[off].gfse_name, 0)) 1026 0 stevel != 0) 1027 0 stevel break; 1028 0 stevel 1029 0 stevel } else if (dp->gfsd_readdir) { 1030 0 stevel off -= dp->gfsd_nstatic; 1031 0 stevel 1032 0 stevel if ((error = dp->gfsd_readdir(dvp, 1033 0 stevel gstate.grd_dirent, &eof, &off, &next, 1034 5663 ck153898 data, flags)) != 0 || eof) 1035 0 stevel break; 1036 0 stevel 1037 0 stevel off += dp->gfsd_nstatic + 2; 1038 0 stevel next += dp->gfsd_nstatic + 2; 1039 0 stevel 1040 0 stevel if ((error = gfs_readdir_emit_int(&gstate, uiop, 1041 847 maybee next)) != 0) 1042 0 stevel break; 1043 0 stevel } else { 1044 0 stevel /* 1045 0 stevel * Offset is beyond the end of the static entries, and 1046 0 stevel * we have no dynamic entries. Set EOF. 1047 0 stevel */ 1048 0 stevel eof = 1; 1049 0 stevel } 1050 0 stevel } 1051 0 stevel 1052 0 stevel return (gfs_readdir_fini(&gstate, error, eofp, eof)); 1053 0 stevel } 1054 0 stevel 1055 0 stevel 1056 0 stevel /* 1057 0 stevel * gfs_vop_lookup: VOP_LOOKUP() entry point 1058 0 stevel * 1059 0 stevel * For use directly in vnode ops table. Given a GFS directory, calls 1060 0 stevel * gfs_dir_lookup() as necessary. 1061 0 stevel */ 1062 0 stevel /* ARGSUSED */ 1063 0 stevel int 1064 0 stevel gfs_vop_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 1065 5331 amw int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 1066 5331 amw int *direntflags, pathname_t *realpnp) 1067 0 stevel { 1068 6492 timh return (gfs_dir_lookup(dvp, nm, vpp, cr, flags, direntflags, realpnp)); 1069 0 stevel } 1070 0 stevel 1071 0 stevel /* 1072 0 stevel * gfs_vop_readdir: VOP_READDIR() entry point 1073 0 stevel * 1074 0 stevel * For use directly in vnode ops table. Given a GFS directory, calls 1075 0 stevel * gfs_dir_readdir() as necessary. 1076 0 stevel */ 1077 0 stevel /* ARGSUSED */ 1078 0 stevel int 1079 5331 amw gfs_vop_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, 1080 5331 amw caller_context_t *ct, int flags) 1081 0 stevel { 1082 5663 ck153898 return (gfs_dir_readdir(vp, uiop, eofp, NULL, cr, ct, flags)); 1083 0 stevel } 1084 0 stevel 1085 0 stevel 1086 0 stevel /* 1087 0 stevel * gfs_vop_map: VOP_MAP() entry point 1088 0 stevel * 1089 0 stevel * Convenient routine for handling pseudo-files that wish to allow mmap() calls. 1090 0 stevel * This function only works for readonly files, and uses the read function for 1091 0 stevel * the vnode to fill in the data. The mapped data is immediately faulted in and 1092 0 stevel * filled with the necessary data during this call; there are no getpage() or 1093 0 stevel * putpage() routines. 1094 0 stevel */ 1095 0 stevel /* ARGSUSED */ 1096 0 stevel int 1097 0 stevel gfs_vop_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp, 1098 5331 amw size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cred, 1099 5331 amw caller_context_t *ct) 1100 0 stevel { 1101 0 stevel int rv; 1102 0 stevel ssize_t resid = len; 1103 0 stevel 1104 0 stevel /* 1105 0 stevel * Check for bad parameters 1106 0 stevel */ 1107 0 stevel #ifdef _ILP32 1108 0 stevel if (len > MAXOFF_T) 1109 0 stevel return (ENOMEM); 1110 0 stevel #endif 1111 0 stevel if (vp->v_flag & VNOMAP) 1112 0 stevel return (ENOTSUP); 1113 0 stevel if (off > MAXOFF_T) 1114 0 stevel return (EFBIG); 1115 0 stevel if ((long)off < 0 || (long)(off + len) < 0) 1116 0 stevel return (EINVAL); 1117 0 stevel if (vp->v_type != VREG) 1118 0 stevel return (ENODEV); 1119 0 stevel if ((prot & (PROT_EXEC | PROT_WRITE)) != 0) 1120 0 stevel return (EACCES); 1121 0 stevel 1122 0 stevel /* 1123 0 stevel * Find appropriate address if needed, otherwise clear address range. 1124 0 stevel */ 1125 0 stevel as_rangelock(as); 1126 6036 mec rv = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags); 1127 6036 mec if (rv != 0) { 1128 6036 mec as_rangeunlock(as); 1129 6036 mec return (rv); 1130 0 stevel } 1131 0 stevel 1132 0 stevel /* 1133 0 stevel * Create mapping 1134 0 stevel */ 1135 0 stevel rv = as_map(as, *addrp, len, segvn_create, zfod_argsp); 1136 0 stevel as_rangeunlock(as); 1137 0 stevel if (rv != 0) 1138 0 stevel return (rv); 1139 0 stevel 1140 0 stevel /* 1141 0 stevel * Fill with data from read() 1142 0 stevel */ 1143 0 stevel rv = vn_rdwr(UIO_READ, vp, *addrp, len, off, UIO_USERSPACE, 1144 0 stevel 0, (rlim64_t)0, cred, &resid); 1145 0 stevel 1146 0 stevel if (rv == 0 && resid != 0) 1147 0 stevel rv = ENXIO; 1148 0 stevel 1149 0 stevel if (rv != 0) { 1150 0 stevel as_rangelock(as); 1151 0 stevel (void) as_unmap(as, *addrp, len); 1152 0 stevel as_rangeunlock(as); 1153 0 stevel } 1154 0 stevel 1155 0 stevel return (rv); 1156 0 stevel } 1157 0 stevel 1158 0 stevel /* 1159 0 stevel * gfs_vop_inactive: VOP_INACTIVE() entry point 1160 0 stevel * 1161 0 stevel * Given a vnode that is a GFS file or directory, call gfs_file_inactive() or 1162 0 stevel * gfs_dir_inactive() as necessary, and kmem_free()s associated private data. 1163 0 stevel */ 1164 0 stevel /* ARGSUSED */ 1165 0 stevel void 1166 5331 amw gfs_vop_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 1167 0 stevel { 1168 0 stevel gfs_file_t *fp = vp->v_data; 1169 0 stevel void *data; 1170 0 stevel 1171 0 stevel if (fp->gfs_type == GFS_DIR) 1172 0 stevel data = gfs_dir_inactive(vp); 1173 0 stevel else 1174 0 stevel data = gfs_file_inactive(vp); 1175 0 stevel 1176 0 stevel if (data != NULL) 1177 0 stevel kmem_free(data, fp->gfs_size); 1178 0 stevel } 1179