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 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <fs/fs_subr.h> 29 30 #include <sys/elf.h> 31 #include <sys/errno.h> 32 #include <sys/file.h> 33 #include <sys/kmem.h> 34 #include <sys/kobj.h> 35 #include <sys/objfs.h> 36 #include <sys/objfs_impl.h> 37 #include <sys/stat.h> 38 #include <sys/systm.h> 39 #include <sys/sysmacros.h> 40 #include <sys/vfs_opreg.h> 41 42 /* 43 * /system/object/<obj>/object 44 * 45 * This is an ELF file that contains information about data stored in the 46 * kernel. We use a special ELF file type, ET_SUNWPSEUDO, so that we can 47 * control which fields and sections have meaning. The file contains the 48 * following sections: 49 * 50 * .shstrtab Section header string table 51 * .SUNW_ctf CTF data 52 * .symtab Symbol table 53 * .strtab String table 54 * .text Text 55 * .data Data 56 * .bss BSS 57 * .filename Filename of module 58 * .info Private module info structure 59 * 60 * The .text, .data, and .bss sections are all marked SHT_NOBITS, and the data 61 * is not actually exported in the file for security reasons. The section 62 * headers do contain the address and size of the sections, which is needed by 63 * DTrace. The CTF data, symbol table, and string table are present only if 64 * they exist in the kernel. 65 */ 66 67 typedef enum { 68 SECT_TYPE_DATA, 69 SECT_TYPE_SHSTRTAB, 70 SECT_TYPE_DUMMY, 71 SECT_TYPE_SYMTAB, 72 SECT_TYPE_STRTAB, 73 SECT_TYPE_FILENAME, 74 SECT_TYPE_INFO 75 } sect_type_t; 76 77 typedef struct section_desc { 78 sect_type_t sect_id; 79 const char *sect_name; 80 uintptr_t sect_addr; 81 size_t sect_size; 82 int sect_type; 83 int sect_flags; 84 size_t sect_str; 85 int sect_link; 86 int sect_entsize; 87 int sect_align; 88 } section_desc_t; 89 90 /* 91 * For data sections, 'addr' and 'size' refer to offsets within the module 92 * structure where we can find the address and size of the section. 93 */ 94 #define SECT_DATA(name, addr, size, type, flags, align) \ 95 { SECT_TYPE_DATA, name, offsetof(struct module, addr), \ 96 offsetof(struct module, size), type, flags, 0, 0, 0, align } 97 98 /* 99 * The dummy section is the initial section of the file. It is put into this 100 * array only for convenience when reading the file. 101 */ 102 #define SECT_DUMMY { SECT_TYPE_DUMMY, "", 0, 0, 0, 0, 0, 0, 0, 0 } 103 104 /* 105 * The size of the symbol table and string table are not immediately available 106 * as an offset into the module struct, so we have to create individual types 107 * for each. 108 */ 109 #ifdef _LP64 110 #define SECT_SYMTAB(name, type, flags) \ 111 { SECT_TYPE_SYMTAB, name, offsetof(struct module, symtbl), 0, type, \ 112 flags, 0, 0, sizeof (Elf64_Sym), sizeof (uint64_t) } 113 #else 114 #define SECT_SYMTAB(name, type, flags) \ 115 { SECT_TYPE_SYMTAB, name, offsetof(struct module, symtbl), 0, type, \ 116 flags, 0, 0, sizeof (Elf32_Sym), sizeof (uint32_t) } 117 #endif 118 #define SECT_STRTAB(name, type, flags) \ 119 { SECT_TYPE_STRTAB, name, offsetof(struct module, strings), 0, type, \ 120 flags, 0, 0, 0, 1 } 121 122 /* 123 * The .shstrtab section is constructed when the module is first loaded. 124 */ 125 #define SECT_SHSTRTAB(name, type, flags) \ 126 { SECT_TYPE_SHSTRTAB, name, 0, 0, type, flags, 0, 0, 0, 1 } 127 128 /* 129 * Generic module information (objfs_info_t) 130 */ 131 #define SECT_INFO \ 132 { SECT_TYPE_INFO, ".info", 0, 0, SHT_PROGBITS, 0, 0, 0, 0, \ 133 sizeof (uint32_t) } 134 135 /* 136 * Filename section. 137 */ 138 #define SECT_FILENAME \ 139 { SECT_TYPE_FILENAME, ".filename", 0, 0, SHT_PROGBITS, 0, 0, 0, 0, 1 } 140 141 static section_desc_t data_sections[] = { 142 SECT_DUMMY, 143 SECT_SHSTRTAB(".shstrtab", 144 SHT_STRTAB, SHF_STRINGS), 145 SECT_DATA(".SUNW_ctf", ctfdata, ctfsize, 146 SHT_PROGBITS, 0, sizeof (uint64_t)), 147 SECT_SYMTAB(".symtab", SHT_SYMTAB, 0), 148 SECT_STRTAB(".strtab", SHT_STRTAB, SHF_STRINGS), 149 SECT_DATA(".text", text, text_size, 150 SHT_NOBITS, SHF_ALLOC | SHF_EXECINSTR, 0), 151 SECT_DATA(".data", data, data_size, 152 SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0), 153 SECT_DATA(".bss", bss, bss_size, 154 SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0), 155 SECT_INFO, 156 SECT_FILENAME 157 }; 158 159 #define NSECTIONS \ 160 (sizeof (data_sections) / sizeof (section_desc_t)) 161 162 #ifdef _LP64 163 #define SECTION_OFFSET(section) \ 164 (sizeof (Elf64_Ehdr) + (section) * sizeof (Elf64_Shdr)) 165 #else 166 #define SECTION_OFFSET(section) \ 167 (sizeof (Elf32_Ehdr) + (section) * sizeof (Elf32_Shdr)) 168 #endif 169 170 /* 171 * Given a data node, returns the struct module appropriately locked. If the 172 * object has been unloaded, or re-loaded since the file was first opened, this 173 * function will return NULL. If successful, the caller must call 174 * objfs_data_unlock(). 175 */ 176 struct module * 177 objfs_data_lock(vnode_t *vp) 178 { 179 objfs_datanode_t *dnode = vp->v_data; 180 objfs_odirnode_t *odir = gfs_file_parent(vp)->v_data; 181 struct modctl *mp = odir->objfs_odir_modctl; 182 183 (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD); 184 185 if (mp->mod_mp == NULL || 186 dnode->objfs_data_gencount < mp->mod_gencount) { 187 mod_release_mod(mp); 188 return (NULL); 189 } 190 191 return (mp->mod_mp); 192 } 193 194 void 195 objfs_data_unlock(vnode_t *vp) 196 { 197 objfs_odirnode_t *odir = gfs_file_parent(vp)->v_data; 198 199 mod_release_mod(odir->objfs_odir_modctl); 200 } 201 202 203 /* 204 * Called when the filesystem is first loaded. Creates and initializes the 205 * section header string table, and fills in the sect_str members of the section 206 * descriptors. This information could be encoded at compile-time, but this 207 * way keeps the code more maintainable, as we don't have to worry about 208 * duplicating information. 209 */ 210 void 211 objfs_data_init(void) 212 { 213 int i, shstrtab, strtab, symtab; 214 size_t len = 0; 215 section_desc_t *sect; 216 char *strdata; 217 218 for (i = 0; i < NSECTIONS; i++) { 219 sect = &data_sections[i]; 220 221 ASSERT(sect->sect_align == 0 || ISP2(sect->sect_align)); 222 ASSERT(sect->sect_align <= sizeof (uint64_t)); 223 224 len += strlen(sect->sect_name) + 1; 225 if (strcmp(sect->sect_name, ".shstrtab") == 0) 226 shstrtab = i; 227 else if (strcmp(sect->sect_name, ".symtab") == 0) 228 symtab = i; 229 else if (strcmp(sect->sect_name, ".strtab") == 0) 230 strtab = i; 231 } 232 233 strdata = kmem_zalloc(len, KM_SLEEP); 234 sect = &data_sections[shstrtab]; 235 sect->sect_addr = (uintptr_t)strdata; 236 sect->sect_size = len; 237 238 len = 0; 239 for (i = 0; i < NSECTIONS; i++) { 240 sect = &data_sections[i]; 241 sect->sect_str = len; 242 bcopy(sect->sect_name, strdata + len, 243 strlen(sect->sect_name) + 1); 244 len += strlen(sect->sect_name) + 1; 245 246 if (strcmp(sect->sect_name, ".SUNW_ctf") == 0) 247 sect->sect_link = symtab; 248 else if (strcmp(sect->sect_name, ".symtab") == 0) 249 sect->sect_link = strtab; 250 } 251 } 252 253 /* 254 * Given a section descriptor and module pointer, return the address of the 255 * data. 256 */ 257 static uintptr_t 258 sect_addr(section_desc_t *sp, struct module *mp) 259 { 260 uintptr_t addr; 261 262 switch (sp->sect_id) { 263 case SECT_TYPE_DUMMY: 264 addr = 0; 265 break; 266 267 case SECT_TYPE_SHSTRTAB: 268 addr = sp->sect_addr; 269 break; 270 271 case SECT_TYPE_STRTAB: 272 case SECT_TYPE_SYMTAB: 273 case SECT_TYPE_DATA: 274 addr = *((uintptr_t *)((char *)mp + sp->sect_addr)); 275 break; 276 277 case SECT_TYPE_FILENAME: 278 addr = (uintptr_t)mp->filename; 279 break; 280 281 case SECT_TYPE_INFO: 282 addr = 1; /* This can be anything nonzero */ 283 break; 284 } 285 286 return (addr); 287 } 288 289 /* 290 * Given a section descriptor and module pointer, return the size of the data. 291 */ 292 static size_t 293 sect_size(section_desc_t *sp, struct module *mp) 294 { 295 size_t size; 296 297 switch (sp->sect_id) { 298 case SECT_TYPE_DUMMY: 299 size = 0; 300 break; 301 302 case SECT_TYPE_SHSTRTAB: 303 size = sp->sect_size; 304 break; 305 306 case SECT_TYPE_DATA: 307 size = *((size_t *)((char *)mp + sp->sect_size)); 308 break; 309 310 case SECT_TYPE_SYMTAB: 311 size = mp->symhdr->sh_size; 312 break; 313 314 case SECT_TYPE_STRTAB: 315 size = mp->strhdr->sh_size; 316 break; 317 318 case SECT_TYPE_INFO: 319 size = sizeof (objfs_info_t); 320 break; 321 322 case SECT_TYPE_FILENAME: 323 if (mp->filename == NULL) 324 size = 0; 325 else 326 size = strlen(mp->filename) + 1; 327 } 328 329 return (size); 330 } 331 332 /* 333 * Given a section descriptor and module pointer, return 1 if the section has 334 * valid data and should be included, 0 otherwise. 335 */ 336 static int 337 sect_valid(section_desc_t *sp, struct module *mp) 338 { 339 if (sp->sect_id == SECT_TYPE_DUMMY || 340 sect_addr(sp, mp) != 0) 341 return (1); 342 343 return (0); 344 } 345 346 /* 347 * Given a section descriptor and module pointer, return the offset into the 348 * file where the data should be placed. 349 */ 350 static size_t 351 data_offset(section_desc_t *sp, struct module *mp) 352 { 353 int i; 354 size_t len; 355 section_desc_t *cp; 356 357 if (sp != NULL && mp != NULL && !sect_valid(sp, mp)) 358 return (0); 359 360 #ifdef _LP64 361 len = sizeof (Elf64_Ehdr); 362 #else 363 len = sizeof (Elf32_Ehdr); 364 #endif 365 366 /* 367 * Do a first pass to account for all the section headers. 368 */ 369 for (i = 0; i < NSECTIONS; i++) { 370 if (sect_valid(&data_sections[i], mp)) { 371 #ifdef _LP64 372 len += sizeof (Elf64_Shdr); 373 #else 374 len += sizeof (Elf32_Shdr); 375 #endif 376 } 377 } 378 379 /* 380 * Add length of each section until we find the one we're looking for. 381 */ 382 for (i = 0; i < NSECTIONS; i++) { 383 cp = &data_sections[i]; 384 385 /* 386 * Align the section only if it's valid and contains data. When 387 * searching for a specific section, align the section before 388 * breaking out of the loop. 389 */ 390 if (sect_valid(cp, mp) && cp->sect_type != SHT_NOBITS) { 391 if (cp->sect_align > 1) 392 len = P2ROUNDUP(len, cp->sect_align); 393 394 if (sp != cp) 395 len += sect_size(cp, mp); 396 } 397 398 if (sp == cp) 399 break; 400 } 401 402 return (len); 403 } 404 405 /* 406 * Given an index into the section table and a module pointer, returns the 407 * data offset of the next section. 408 */ 409 static size_t 410 next_offset(int idx, struct module *mp) 411 { 412 int i; 413 414 for (i = idx + 1; i < NSECTIONS; i++) { 415 if (sect_valid(&data_sections[i], mp)) 416 return (data_offset(&data_sections[i], mp)); 417 } 418 419 return (data_offset(NULL, mp)); 420 } 421 422 /* 423 * Given a module pointer, return the total size needed for the file. 424 */ 425 static size_t 426 data_size(struct module *mp) 427 { 428 return (data_offset(NULL, mp)); 429 } 430 431 /* 432 * Returns the size needed for all the headers in the file. 433 */ 434 static size_t 435 header_size(void) 436 { 437 return (data_offset(&data_sections[0], NULL)); 438 } 439 440 /* ARGSUSED */ 441 vnode_t * 442 objfs_create_data(vnode_t *pvp) 443 { 444 objfs_odirnode_t *onode = pvp->v_data; 445 vnode_t *vp = gfs_file_create(sizeof (objfs_datanode_t), pvp, 446 objfs_ops_data); 447 objfs_datanode_t *dnode = vp->v_data; 448 449 dnode->objfs_data_gencount = onode->objfs_odir_modctl->mod_gencount; 450 dnode->objfs_data_info.objfs_info_primary = 451 onode->objfs_odir_modctl->mod_prim; 452 453 return (vp); 454 } 455 456 /* ARGSUSED */ 457 static int 458 objfs_data_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 459 caller_context_t *ct) 460 { 461 struct module *mp; 462 timestruc_t now; 463 464 if ((mp = objfs_data_lock(vp)) == NULL) 465 return (EIO); 466 467 vap->va_type = VREG; 468 vap->va_mode = S_IRUSR | S_IRGRP | S_IROTH; 469 vap->va_nodeid = gfs_file_inode(vp); 470 vap->va_nlink = 1; 471 vap->va_size = data_size(mp); 472 gethrestime(&now); 473 vap->va_atime = vap->va_ctime = vap->va_mtime = now; 474 475 (void) objfs_common_getattr(vp, vap); 476 477 objfs_data_unlock(vp); 478 479 return (0); 480 } 481 482 /* ARGSUSED */ 483 static int 484 objfs_data_access(vnode_t *vp, int mode, int flags, cred_t *cr, 485 caller_context_t *ct) 486 { 487 if (mode & (VWRITE|VEXEC)) 488 return (EACCES); 489 490 return (0); 491 } 492 493 /* ARGSUSED */ 494 int 495 objfs_data_open(vnode_t **cpp, int flag, cred_t *cr, 496 caller_context_t *ct) 497 { 498 if (flag & FWRITE) 499 return (EINVAL); 500 501 return (0); 502 } 503 504 /* 505 * Iterate over all symbols in the table and output each one individually, 506 * converting st_shndx to SHN_ABS for each symbol. 507 */ 508 static int 509 read_symtab(void *addr, size_t size, off_t offset, uio_t *uio) 510 { 511 #ifdef _LP64 512 Elf64_Sym sym, *symtab; 513 #else 514 Elf32_Sym sym, *symtab; 515 #endif 516 off_t index; 517 int error; 518 519 symtab = addr; 520 521 if (offset % sizeof (sym) != 0) { 522 /* 523 * Be careful with the first symbol, as it is not 524 * symbol-aligned. 525 */ 526 off_t partial = offset % sizeof (sym); 527 528 index = offset / sizeof (sym); 529 530 sym = symtab[index]; 531 if (sym.st_shndx != SHN_UNDEF) 532 sym.st_shndx = SHN_ABS; 533 534 if ((error = uiomove((char *)&sym + partial, 535 sizeof (sym) - partial, UIO_READ, uio)) != 0 || 536 uio->uio_resid <= 0) 537 return (error); 538 539 offset = (index + 1) * sizeof (sym); 540 } 541 542 ASSERT(size % sizeof (sym) == 0); 543 544 for (index = offset / sizeof (sym); index < size / sizeof (sym); 545 index++) { 546 547 sym = symtab[index]; 548 if (sym.st_shndx != SHN_UNDEF) 549 sym.st_shndx = SHN_ABS; 550 551 if ((error = uiomove((char *)&sym, sizeof (sym), UIO_READ, 552 uio)) != 0 || uio->uio_resid <= 0) 553 return (error); 554 } 555 556 return (0); 557 } 558 559 /* ARGSUSED */ 560 static int 561 objfs_data_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, 562 caller_context_t *ct) 563 { 564 int error = 0; 565 objfs_datanode_t *dnode = vp->v_data; 566 struct module *mp; 567 off_t off; 568 #ifdef _LP64 569 Elf64_Shdr shdr; 570 #else 571 Elf32_Shdr shdr; 572 #endif 573 int i, j; 574 section_desc_t *sp; 575 void *addr; 576 int transidx[NSECTIONS]; 577 578 if ((mp = objfs_data_lock(vp)) == NULL) 579 return (ENOENT); 580 581 if (uio->uio_resid <= 0 || uio->uio_offset >= data_size(mp)) 582 goto error; 583 584 /* 585 * Construct an array to translate from a generic section header index 586 * to an index specific for this object. 587 */ 588 for (i = 0, j = 0; i < NSECTIONS; i++) { 589 transidx[i] = j; 590 if (sect_valid(&data_sections[i], mp)) 591 j++; 592 593 } 594 595 /* 596 * Check to see if we're in the Elf header 597 */ 598 if (uio->uio_loffset < SECTION_OFFSET(0)) { 599 #ifdef _LP64 600 Elf64_Ehdr ehdr; 601 #else 602 Elf32_Ehdr ehdr; 603 #endif 604 605 bzero(&ehdr, sizeof (ehdr)); 606 607 bcopy(ELFMAG, ehdr.e_ident, SELFMAG); 608 #ifdef _BIG_ENDIAN 609 ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 610 #else 611 ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 612 #endif 613 ehdr.e_ident[EI_VERSION] = EV_CURRENT; 614 615 #ifdef _LP64 616 ehdr.e_ident[EI_CLASS] = ELFCLASS64; 617 ehdr.e_type = ELFCLASS64; 618 ehdr.e_ehsize = sizeof (Elf64_Ehdr); 619 ehdr.e_phentsize = sizeof (Elf64_Phdr); 620 ehdr.e_shentsize = sizeof (Elf64_Shdr); 621 #else 622 ehdr.e_ident[EI_CLASS] = ELFCLASS32; 623 ehdr.e_type = ELFCLASS32; 624 ehdr.e_ehsize = sizeof (Elf32_Ehdr); 625 ehdr.e_phentsize = sizeof (Elf32_Phdr); 626 ehdr.e_shentsize = sizeof (Elf32_Shdr); 627 #endif 628 629 #ifdef __sparc 630 #ifdef __sparcv9 631 ehdr.e_machine = EM_SPARCV9; 632 #else 633 ehdr.e_machine = EM_SPARC; 634 #endif 635 #elif defined(__amd64) 636 ehdr.e_machine = EM_AMD64; 637 #else 638 ehdr.e_machine = EM_386; 639 #endif 640 641 ehdr.e_version = EV_CURRENT; 642 ehdr.e_type = ET_SUNWPSEUDO; 643 ehdr.e_shnum = 0; 644 ehdr.e_shoff = SECTION_OFFSET(0); 645 646 for (i = 0; i < NSECTIONS; i++) { 647 if (strcmp(data_sections[i].sect_name, 648 ".shstrtab") == 0) 649 ehdr.e_shstrndx = transidx[i]; 650 651 if (sect_valid(&data_sections[i], mp)) 652 ehdr.e_shnum++; 653 } 654 655 if ((error = uiomove((char *)&ehdr + uio->uio_loffset, 656 sizeof (ehdr) - uio->uio_loffset, UIO_READ, uio)) != 0 || 657 uio->uio_resid <= 0) 658 goto error; 659 } 660 661 /* 662 * Go through and construct section headers for each section. 663 */ 664 j = 0; 665 for (i = 0; i < NSECTIONS; i++) { 666 sp = &data_sections[i]; 667 668 if (!sect_valid(sp, mp)) 669 continue; 670 671 if (uio->uio_loffset < SECTION_OFFSET(j+1)) { 672 shdr.sh_link = transidx[sp->sect_link]; 673 shdr.sh_entsize = sp->sect_entsize; 674 shdr.sh_info = 0; 675 shdr.sh_name = sp->sect_str; 676 shdr.sh_type = sp->sect_type; 677 shdr.sh_flags = sp->sect_flags; 678 shdr.sh_addr = sect_addr(sp, mp); 679 shdr.sh_offset = data_offset(sp, mp); 680 shdr.sh_size = sect_size(sp, mp); 681 shdr.sh_addralign = sp->sect_align; 682 683 off = uio->uio_loffset - SECTION_OFFSET(j); 684 if ((error = uiomove((char *)&shdr + off, 685 sizeof (shdr) - off, UIO_READ, uio)) != 0 || 686 uio->uio_resid <= 0) 687 goto error; 688 } 689 690 j++; 691 } 692 693 /* 694 * Output the data for each section 695 */ 696 for (i = 0; i < NSECTIONS; i++) { 697 size_t nextoff; 698 sp = &data_sections[i]; 699 nextoff = next_offset(i, mp); 700 if (sect_valid(sp, mp) && sp->sect_type != SHT_NOBITS && 701 uio->uio_loffset < nextoff) { 702 703 if (sp->sect_id == SECT_TYPE_INFO) 704 addr = &dnode->objfs_data_info; 705 else 706 addr = (void *)sect_addr(sp, mp); 707 off = uio->uio_loffset - data_offset(sp, mp); 708 709 /* 710 * The symtab requires special processing to convert 711 * the st_shndx field to SHN_ABS. Otherwise, simply 712 * copy the data in bulk. 713 */ 714 if (sp->sect_id == SECT_TYPE_SYMTAB) 715 error = read_symtab(addr, sect_size(sp, mp), 716 off, uio); 717 else 718 error = uiomove((char *)addr + off, 719 sect_size(sp, mp) - off, UIO_READ, uio); 720 721 if (error != 0 || uio->uio_resid <= 0) 722 goto error; 723 724 /* 725 * If the next section needs to be aligned, pad out with 726 * zeroes. 727 */ 728 if (uio->uio_loffset < nextoff) { 729 uint64_t padding = 0; 730 731 ASSERT(nextoff - uio->uio_loffset < 732 sizeof (uint64_t)); 733 734 if ((error = uiomove(&padding, 735 nextoff - uio->uio_loffset, UIO_READ, 736 uio)) != 0 || uio->uio_resid <= 0) 737 goto error; 738 739 } 740 } 741 } 742 743 error: 744 objfs_data_unlock(vp); 745 746 return (error); 747 } 748 749 /* ARGSUSED */ 750 static int 751 objfs_data_seek(vnode_t *vp, offset_t off, offset_t *offp, 752 caller_context_t *ct) 753 { 754 return (0); 755 } 756 757 const fs_operation_def_t objfs_tops_data[] = { 758 { VOPNAME_OPEN, { .vop_open = objfs_data_open } }, 759 { VOPNAME_CLOSE, { .vop_close = objfs_common_close } }, 760 { VOPNAME_IOCTL, { .error = fs_inval } }, 761 { VOPNAME_GETATTR, { .vop_getattr = objfs_data_getattr } }, 762 { VOPNAME_ACCESS, { .vop_access = objfs_data_access } }, 763 { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 764 { VOPNAME_READ, { .vop_read = objfs_data_read } }, 765 { VOPNAME_SEEK, { .vop_seek = objfs_data_seek } }, 766 { VOPNAME_MAP, { .vop_map = gfs_vop_map } }, 767 { NULL } 768 }; 769