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 { 460 struct module *mp; 461 timestruc_t now; 462 463 if ((mp = objfs_data_lock(vp)) == NULL) 464 return (EIO); 465 466 vap->va_type = VREG; 467 vap->va_mode = S_IRUSR | S_IRGRP | S_IROTH; 468 vap->va_nodeid = gfs_file_inode(vp); 469 vap->va_nlink = 1; 470 vap->va_size = data_size(mp); 471 gethrestime(&now); 472 vap->va_atime = vap->va_ctime = vap->va_mtime = now; 473 474 (void) objfs_common_getattr(vp, vap); 475 476 objfs_data_unlock(vp); 477 478 return (0); 479 } 480 481 /* ARGSUSED */ 482 static int 483 objfs_data_access(vnode_t *vp, int mode, int flags, cred_t *cr) 484 { 485 if (mode & (VWRITE|VEXEC)) 486 return (EACCES); 487 488 return (0); 489 } 490 491 /* ARGSUSED */ 492 int 493 objfs_data_open(vnode_t **cpp, int flag, cred_t *cr) 494 { 495 if (flag & FWRITE) 496 return (EINVAL); 497 498 return (0); 499 } 500 501 /* 502 * Iterate over all symbols in the table and output each one individually, 503 * converting st_shndx to SHN_ABS for each symbol. 504 */ 505 static int 506 read_symtab(void *addr, size_t size, off_t offset, uio_t *uio) 507 { 508 #ifdef _LP64 509 Elf64_Sym sym, *symtab; 510 #else 511 Elf32_Sym sym, *symtab; 512 #endif 513 off_t index; 514 int error; 515 516 symtab = addr; 517 518 if (offset % sizeof (sym) != 0) { 519 /* 520 * Be careful with the first symbol, as it is not 521 * symbol-aligned. 522 */ 523 off_t partial = offset % sizeof (sym); 524 525 index = offset / sizeof (sym); 526 527 sym = symtab[index]; 528 if (sym.st_shndx != SHN_UNDEF) 529 sym.st_shndx = SHN_ABS; 530 531 if ((error = uiomove((char *)&sym + partial, 532 sizeof (sym) - partial, UIO_READ, uio)) != 0 || 533 uio->uio_resid <= 0) 534 return (error); 535 536 offset = (index + 1) * sizeof (sym); 537 } 538 539 ASSERT(size % sizeof (sym) == 0); 540 541 for (index = offset / sizeof (sym); index < size / sizeof (sym); 542 index++) { 543 544 sym = symtab[index]; 545 if (sym.st_shndx != SHN_UNDEF) 546 sym.st_shndx = SHN_ABS; 547 548 if ((error = uiomove((char *)&sym, sizeof (sym), UIO_READ, 549 uio)) != 0 || uio->uio_resid <= 0) 550 return (error); 551 } 552 553 return (0); 554 } 555 556 /* ARGSUSED */ 557 static int 558 objfs_data_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, 559 caller_context_t *ct) 560 { 561 int error = 0; 562 objfs_datanode_t *dnode = vp->v_data; 563 struct module *mp; 564 off_t off; 565 #ifdef _LP64 566 Elf64_Shdr shdr; 567 #else 568 Elf32_Shdr shdr; 569 #endif 570 int i, j; 571 section_desc_t *sp; 572 void *addr; 573 int transidx[NSECTIONS]; 574 575 if ((mp = objfs_data_lock(vp)) == NULL) 576 return (ENOENT); 577 578 if (uio->uio_resid <= 0 || uio->uio_offset >= data_size(mp)) 579 goto error; 580 581 /* 582 * Construct an array to translate from a generic section header index 583 * to an index specific for this object. 584 */ 585 for (i = 0, j = 0; i < NSECTIONS; i++) { 586 transidx[i] = j; 587 if (sect_valid(&data_sections[i], mp)) 588 j++; 589 590 } 591 592 /* 593 * Check to see if we're in the Elf header 594 */ 595 if (uio->uio_loffset < SECTION_OFFSET(0)) { 596 #ifdef _LP64 597 Elf64_Ehdr ehdr; 598 #else 599 Elf32_Ehdr ehdr; 600 #endif 601 602 bzero(&ehdr, sizeof (ehdr)); 603 604 bcopy(ELFMAG, ehdr.e_ident, SELFMAG); 605 #ifdef _BIG_ENDIAN 606 ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 607 #else 608 ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 609 #endif 610 ehdr.e_ident[EI_VERSION] = EV_CURRENT; 611 612 #ifdef _LP64 613 ehdr.e_ident[EI_CLASS] = ELFCLASS64; 614 ehdr.e_type = ELFCLASS64; 615 ehdr.e_ehsize = sizeof (Elf64_Ehdr); 616 ehdr.e_phentsize = sizeof (Elf64_Phdr); 617 ehdr.e_shentsize = sizeof (Elf64_Shdr); 618 #else 619 ehdr.e_ident[EI_CLASS] = ELFCLASS32; 620 ehdr.e_type = ELFCLASS32; 621 ehdr.e_ehsize = sizeof (Elf32_Ehdr); 622 ehdr.e_phentsize = sizeof (Elf32_Phdr); 623 ehdr.e_shentsize = sizeof (Elf32_Shdr); 624 #endif 625 626 #ifdef __sparc 627 #ifdef __sparcv9 628 ehdr.e_machine = EM_SPARCV9; 629 #else 630 ehdr.e_machine = EM_SPARC; 631 #endif 632 #elif defined(__amd64) 633 ehdr.e_machine = EM_AMD64; 634 #else 635 ehdr.e_machine = EM_386; 636 #endif 637 638 ehdr.e_version = EV_CURRENT; 639 ehdr.e_type = ET_SUNWPSEUDO; 640 ehdr.e_shnum = 0; 641 ehdr.e_shoff = SECTION_OFFSET(0); 642 643 for (i = 0; i < NSECTIONS; i++) { 644 if (strcmp(data_sections[i].sect_name, 645 ".shstrtab") == 0) 646 ehdr.e_shstrndx = transidx[i]; 647 648 if (sect_valid(&data_sections[i], mp)) 649 ehdr.e_shnum++; 650 } 651 652 if ((error = uiomove((char *)&ehdr + uio->uio_loffset, 653 sizeof (ehdr) - uio->uio_loffset, UIO_READ, uio)) != 0 || 654 uio->uio_resid <= 0) 655 goto error; 656 } 657 658 /* 659 * Go through and construct section headers for each section. 660 */ 661 j = 0; 662 for (i = 0; i < NSECTIONS; i++) { 663 sp = &data_sections[i]; 664 665 if (!sect_valid(sp, mp)) 666 continue; 667 668 if (uio->uio_loffset < SECTION_OFFSET(j+1)) { 669 shdr.sh_link = transidx[sp->sect_link]; 670 shdr.sh_entsize = sp->sect_entsize; 671 shdr.sh_info = 0; 672 shdr.sh_name = sp->sect_str; 673 shdr.sh_type = sp->sect_type; 674 shdr.sh_flags = sp->sect_flags; 675 shdr.sh_addr = sect_addr(sp, mp); 676 shdr.sh_offset = data_offset(sp, mp); 677 shdr.sh_size = sect_size(sp, mp); 678 shdr.sh_addralign = sp->sect_align; 679 680 off = uio->uio_loffset - SECTION_OFFSET(j); 681 if ((error = uiomove((char *)&shdr + off, 682 sizeof (shdr) - off, UIO_READ, uio)) != 0 || 683 uio->uio_resid <= 0) 684 goto error; 685 } 686 687 j++; 688 } 689 690 /* 691 * Output the data for each section 692 */ 693 for (i = 0; i < NSECTIONS; i++) { 694 size_t nextoff; 695 sp = &data_sections[i]; 696 nextoff = next_offset(i, mp); 697 if (sect_valid(sp, mp) && sp->sect_type != SHT_NOBITS && 698 uio->uio_loffset < nextoff) { 699 700 if (sp->sect_id == SECT_TYPE_INFO) 701 addr = &dnode->objfs_data_info; 702 else 703 addr = (void *)sect_addr(sp, mp); 704 off = uio->uio_loffset - data_offset(sp, mp); 705 706 /* 707 * The symtab requires special processing to convert 708 * the st_shndx field to SHN_ABS. Otherwise, simply 709 * copy the data in bulk. 710 */ 711 if (sp->sect_id == SECT_TYPE_SYMTAB) 712 error = read_symtab(addr, sect_size(sp, mp), 713 off, uio); 714 else 715 error = uiomove((char *)addr + off, 716 sect_size(sp, mp) - off, UIO_READ, uio); 717 718 if (error != 0 || uio->uio_resid <= 0) 719 goto error; 720 721 /* 722 * If the next section needs to be aligned, pad out with 723 * zeroes. 724 */ 725 if (uio->uio_loffset < nextoff) { 726 uint64_t padding = 0; 727 728 ASSERT(nextoff - uio->uio_loffset < 729 sizeof (uint64_t)); 730 731 if ((error = uiomove(&padding, 732 nextoff - uio->uio_loffset, UIO_READ, 733 uio)) != 0 || uio->uio_resid <= 0) 734 goto error; 735 736 } 737 } 738 } 739 740 error: 741 objfs_data_unlock(vp); 742 743 return (error); 744 } 745 746 /* ARGSUSED */ 747 static int 748 objfs_data_seek(vnode_t *vp, offset_t off, offset_t *offp) 749 { 750 return (0); 751 } 752 753 const fs_operation_def_t objfs_tops_data[] = { 754 { VOPNAME_OPEN, { .vop_open = objfs_data_open } }, 755 { VOPNAME_CLOSE, { .vop_close = objfs_common_close } }, 756 { VOPNAME_IOCTL, { .error = fs_inval } }, 757 { VOPNAME_GETATTR, { .vop_getattr = objfs_data_getattr } }, 758 { VOPNAME_ACCESS, { .vop_access = objfs_data_access } }, 759 { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 760 { VOPNAME_READ, { .vop_read = objfs_data_read } }, 761 { VOPNAME_SEEK, { .vop_seek = objfs_data_seek } }, 762 { VOPNAME_MAP, { .vop_map = gfs_vop_map } }, 763 { NULL } 764 }; 765