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 2006 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 <sys/types.h> 29 #include <sys/param.h> 30 #include <sys/vnode.h> 31 #include <sys/fs/ufs_fsdir.h> 32 #include <sys/fs/ufs_fs.h> 33 #include <sys/fs/ufs_inode.h> 34 #include <sys/sysmacros.h> 35 #include <sys/bootvfs.h> 36 #include <sys/filep.h> 37 38 #ifdef _BOOT 39 #include "../common/util.h" 40 #else 41 #include <sys/sunddi.h> 42 #endif 43 44 extern void *bkmem_alloc(size_t); 45 extern void bkmem_free(void *, size_t); 46 47 int bootrd_debug; 48 #ifdef _BOOT 49 #define dprintf if (bootrd_debug) printf 50 #else 51 #define printf kobj_printf 52 #define dprintf if (bootrd_debug) kobj_printf 53 54 /* PRINTLIKE */ 55 extern void kobj_printf(char *, ...); 56 #endif 57 58 /* 59 * This fd is used when talking to the device file itself. 60 */ 61 static fileid_t *head; 62 63 /* Only got one of these...ergo, only 1 fs open at once */ 64 /* static */ 65 devid_t *ufs_devp; 66 67 struct dirinfo { 68 int loc; 69 fileid_t *fi; 70 }; 71 72 static int bufs_close(int); 73 static void bufs_closeall(int); 74 static ino_t find(fileid_t *filep, char *path); 75 static ino_t dlook(fileid_t *filep, char *path); 76 static daddr32_t sbmap(fileid_t *filep, daddr32_t bn); 77 static struct direct *readdir(struct dirinfo *dstuff); 78 static void set_cache(int, void *, uint_t); 79 static void *get_cache(int); 80 static void free_cache(); 81 82 83 /* 84 * There is only 1 open (mounted) device at any given time. 85 * So we can keep a single, global devp file descriptor to 86 * use to index into the di[] array. This is not true for the 87 * fi[] array. We can have more than one file open at once, 88 * so there is no global fd for the fi[]. 89 * The user program must save the fd passed back from open() 90 * and use it to do subsequent read()'s. 91 */ 92 93 static int 94 openi(fileid_t *filep, ino_t inode) 95 { 96 struct dinode *dp; 97 devid_t *devp = filep->fi_devp; 98 99 filep->fi_inode = get_cache((int)inode); 100 if (filep->fi_inode != 0) 101 return (0); 102 103 filep->fi_offset = 0; 104 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, 105 itod(&devp->un_fs.di_fs, inode)); 106 107 /* never more than 1 disk block */ 108 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 109 filep->fi_memp = 0; /* cached read */ 110 if (diskread(filep) != 0) { 111 return (0); 112 } 113 114 dp = (struct dinode *)filep->fi_memp; 115 filep->fi_inode = (struct inode *) 116 bkmem_alloc(sizeof (struct inode)); 117 bzero((char *)filep->fi_inode, sizeof (struct inode)); 118 filep->fi_inode->i_ic = 119 dp[itoo(&devp->un_fs.di_fs, inode)].di_un.di_icom; 120 filep->fi_inode->i_number = inode; 121 set_cache((int)inode, (void *)filep->fi_inode, sizeof (struct inode)); 122 return (0); 123 } 124 125 static fileid_t * 126 find_fp(int fd) 127 { 128 fileid_t *filep = head; 129 130 if (fd >= 0) { 131 while ((filep = filep->fi_forw) != head) 132 if (fd == filep->fi_filedes) 133 return (filep->fi_taken ? filep : 0); 134 } 135 136 return (0); 137 } 138 139 static ino_t 140 find(fileid_t *filep, char *path) 141 { 142 char *q; 143 char c; 144 ino_t inode; 145 char lpath[MAXPATHLEN]; 146 char *lpathp = lpath; 147 int len, r; 148 devid_t *devp; 149 150 if (path == NULL || *path == '\0') { 151 printf("null path\n"); 152 return ((ino_t)0); 153 } 154 155 dprintf("openi: %s\n", path); 156 157 bzero(lpath, sizeof (lpath)); 158 bcopy(path, lpath, strlen(path)); 159 devp = filep->fi_devp; 160 while (*lpathp) { 161 /* if at the beginning of pathname get root inode */ 162 r = (lpathp == lpath); 163 if (r && openi(filep, (ino_t)UFSROOTINO)) 164 return ((ino_t)0); 165 while (*lpathp == '/') 166 lpathp++; /* skip leading slashes */ 167 q = lpathp; 168 while (*q != '/' && *q != '\0') 169 q++; /* find end of component */ 170 c = *q; 171 *q = '\0'; /* terminate component */ 172 173 /* Bail out early if opening root */ 174 if (r && (*lpathp == '\0')) 175 return ((ino_t)UFSROOTINO); 176 if ((inode = dlook(filep, lpathp)) != 0) { 177 if (openi(filep, inode)) 178 return ((ino_t)0); 179 if ((filep->fi_inode->i_smode & IFMT) == IFLNK) { 180 filep->fi_blocknum = 181 fsbtodb(&devp->un_fs.di_fs, 182 filep->fi_inode->i_db[0]); 183 filep->fi_count = DEV_BSIZE; 184 filep->fi_memp = 0; 185 if (diskread(filep) != 0) 186 return ((ino_t)0); 187 len = strlen(filep->fi_memp); 188 if (filep->fi_memp[0] == '/') 189 /* absolute link */ 190 lpathp = lpath; 191 /* copy rest of unprocessed path up */ 192 bcopy(q, lpathp + len, strlen(q + 1) + 2); 193 /* point to unprocessed path */ 194 *(lpathp + len) = c; 195 /* prepend link in before unprocessed path */ 196 bcopy(filep->fi_memp, lpathp, len); 197 lpathp = lpath; 198 continue; 199 } else 200 *q = c; 201 if (c == '\0') 202 break; 203 lpathp = q; 204 continue; 205 } else { 206 return ((ino_t)0); 207 } 208 } 209 return (inode); 210 } 211 212 static daddr32_t 213 sbmap(fileid_t *filep, daddr32_t bn) 214 { 215 struct inode *inodep; 216 int i, j, sh; 217 daddr32_t nb, *bap; 218 daddr32_t *db; 219 devid_t *devp; 220 221 /* These are the pools of buffers, etc. */ 222 /* Compilers like to play with alignment, so force the issue here */ 223 static union { 224 char *blk[NIADDR + 1]; 225 daddr32_t *dummy; 226 } b; 227 daddr32_t blknos[NIADDR + 1]; 228 229 devp = filep->fi_devp; 230 inodep = filep->fi_inode; 231 db = inodep->i_db; 232 233 /* 234 * blocks 0..NDADDR are direct blocks 235 */ 236 if (bn < NDADDR) { 237 nb = db[bn]; 238 return (nb); 239 } 240 241 /* 242 * addresses NIADDR have single and double indirect blocks. 243 * the first step is to determine how many levels of indirection. 244 */ 245 sh = 1; 246 bn -= NDADDR; 247 for (j = NIADDR; j > 0; j--) { 248 sh *= NINDIR(&devp->un_fs.di_fs); 249 if (bn < sh) 250 break; 251 bn -= sh; 252 } 253 if (j == 0) { 254 return ((daddr32_t)0); 255 } 256 257 /* 258 * fetch the first indirect block address from the inode 259 */ 260 nb = inodep->i_ib[NIADDR - j]; 261 if (nb == 0) { 262 return ((daddr32_t)0); 263 } 264 265 /* 266 * fetch through the indirect blocks 267 */ 268 for (; j <= NIADDR; j++) { 269 if (blknos[j] != nb) { 270 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, nb); 271 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 272 filep->fi_memp = 0; 273 if (diskread(filep) != 0) 274 return (0); 275 b.blk[j] = filep->fi_memp; 276 blknos[j] = nb; 277 } 278 bap = (daddr32_t *)b.blk[j]; 279 sh /= NINDIR(&devp->un_fs.di_fs); 280 i = (bn / sh) % NINDIR(&devp->un_fs.di_fs); 281 nb = bap[i]; 282 if (nb == 0) { 283 return ((daddr32_t)0); 284 } 285 } 286 return (nb); 287 } 288 289 static ino_t 290 dlook(fileid_t *filep, char *path) 291 { 292 struct direct *dp; 293 struct inode *ip; 294 struct dirinfo dirp; 295 int len; 296 297 ip = filep->fi_inode; 298 if (path == NULL || *path == '\0') 299 return (0); 300 301 dprintf("dlook: %s\n", path); 302 303 if ((ip->i_smode & IFMT) != IFDIR) { 304 return (0); 305 } 306 if (ip->i_size == 0) { 307 return (0); 308 } 309 len = strlen(path); 310 dirp.loc = 0; 311 dirp.fi = filep; 312 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { 313 if (dp->d_ino == 0) 314 continue; 315 if (dp->d_namlen == len && strcmp(path, dp->d_name) == 0) { 316 return (dp->d_ino); 317 } 318 /* Allow "*" to print all names at that level, w/out match */ 319 if (strcmp(path, "*") == 0) 320 dprintf("%s\n", dp->d_name); 321 } 322 return (0); 323 } 324 325 /* 326 * get next entry in a directory. 327 */ 328 struct direct * 329 readdir(struct dirinfo *dstuff) 330 { 331 struct direct *dp; 332 fileid_t *filep; 333 daddr32_t lbn, d; 334 int off; 335 devid_t *devp; 336 337 filep = dstuff->fi; 338 devp = filep->fi_devp; 339 for (;;) { 340 if (dstuff->loc >= filep->fi_inode->i_size) { 341 return (NULL); 342 } 343 off = blkoff(&devp->un_fs.di_fs, dstuff->loc); 344 dprintf("readdir: off = 0x%x\n", off); 345 if (off == 0) { 346 lbn = lblkno(&devp->un_fs.di_fs, dstuff->loc); 347 d = sbmap(filep, lbn); 348 349 if (d == 0) 350 return (NULL); 351 352 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, d); 353 filep->fi_count = 354 blksize(&devp->un_fs.di_fs, filep->fi_inode, lbn); 355 filep->fi_memp = 0; 356 if (diskread(filep) != 0) { 357 return (NULL); 358 } 359 } 360 dp = (struct direct *)(filep->fi_memp + off); 361 dstuff->loc += dp->d_reclen; 362 if (dp->d_ino == 0) 363 continue; 364 dprintf("readdir: name = %s\n", dp->d_name); 365 return (dp); 366 } 367 } 368 369 /* 370 * Get the next block of data from the file. If possible, dma right into 371 * user's buffer 372 */ 373 static int 374 getblock(fileid_t *filep, caddr_t buf, int count, int *rcount) 375 { 376 struct fs *fs; 377 caddr_t p; 378 int off, size, diff; 379 daddr32_t lbn; 380 devid_t *devp; 381 382 dprintf("getblock: buf 0x%p, count 0x%x\n", (void *)buf, count); 383 384 devp = filep->fi_devp; 385 p = filep->fi_memp; 386 if ((signed)filep->fi_count <= 0) { 387 388 /* find the amt left to be read in the file */ 389 diff = filep->fi_inode->i_size - filep->fi_offset; 390 if (diff <= 0) { 391 printf("Short read\n"); 392 return (-1); 393 } 394 395 fs = &devp->un_fs.di_fs; 396 /* which block (or frag) in the file do we read? */ 397 lbn = lblkno(fs, filep->fi_offset); 398 399 /* which physical block on the device do we read? */ 400 filep->fi_blocknum = fsbtodb(fs, sbmap(filep, lbn)); 401 402 off = blkoff(fs, filep->fi_offset); 403 404 /* either blksize or fragsize */ 405 size = blksize(fs, filep->fi_inode, lbn); 406 filep->fi_count = size; 407 filep->fi_memp = filep->fi_buf; 408 409 /* 410 * optimization if we are reading large blocks of data then 411 * we can go directly to user's buffer 412 */ 413 *rcount = 0; 414 if (off == 0 && count >= size) { 415 filep->fi_memp = buf; 416 if (diskread(filep)) { 417 return (-1); 418 } 419 *rcount = size; 420 filep->fi_count = 0; 421 return (0); 422 } else if (diskread(filep)) 423 return (-1); 424 425 if (filep->fi_offset - off + size >= filep->fi_inode->i_size) 426 filep->fi_count = diff + off; 427 filep->fi_count -= off; 428 p = &filep->fi_memp[off]; 429 } 430 filep->fi_memp = p; 431 return (0); 432 } 433 434 435 /* 436 * This is the high-level read function. It works like this. 437 * We assume that our IO device buffers up some amount of 438 * data and that we can get a ptr to it. Thus we need 439 * to actually call the device func about filesize/blocksize times 440 * and this greatly increases our IO speed. When we already 441 * have data in the buffer, we just return that data (with bcopy() ). 442 */ 443 444 static ssize_t 445 bufs_read(int fd, caddr_t buf, size_t count) 446 { 447 size_t i, j; 448 caddr_t n; 449 int rcount; 450 fileid_t *filep; 451 452 if (!(filep = find_fp(fd))) { 453 return (-1); 454 } 455 456 if (filep->fi_offset + count > filep->fi_inode->i_size) 457 count = filep->fi_inode->i_size - filep->fi_offset; 458 459 /* that was easy */ 460 if ((i = count) == 0) 461 return (0); 462 463 n = buf; 464 while (i > 0) { 465 /* If we need to reload the buffer, do so */ 466 if ((j = filep->fi_count) == 0) { 467 (void) getblock(filep, buf, i, &rcount); 468 i -= rcount; 469 buf += rcount; 470 filep->fi_offset += rcount; 471 } else { 472 /* else just bcopy from our buffer */ 473 j = MIN(i, j); 474 bcopy(filep->fi_memp, buf, (unsigned)j); 475 buf += j; 476 filep->fi_memp += j; 477 filep->fi_offset += j; 478 filep->fi_count -= j; 479 i -= j; 480 } 481 } 482 return (buf - n); 483 } 484 485 /* 486 * This routine will open a device as it is known by the V2 OBP. 487 * Interface Defn: 488 * err = mountroot(string); 489 * err = 0 on success 490 * err = -1 on failure 491 * string: char string describing the properties of the device. 492 * We must not dork with any fi[]'s here. Save that for later. 493 */ 494 495 static int 496 bufs_mountroot(char *str) 497 { 498 if (ufs_devp) /* already mounted */ 499 return (0); 500 501 ufs_devp = (devid_t *)bkmem_alloc(sizeof (devid_t)); 502 ufs_devp->di_taken = 1; 503 ufs_devp->di_dcookie = 0; 504 ufs_devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1); 505 (void) strcpy(ufs_devp->di_desc, str); 506 bzero(ufs_devp->un_fs.dummy, SBSIZE); 507 head = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 508 head->fi_back = head->fi_forw = head; 509 head->fi_filedes = 0; 510 head->fi_taken = 0; 511 512 /* Setup read of the superblock */ 513 head->fi_devp = ufs_devp; 514 head->fi_blocknum = SBLOCK; 515 head->fi_count = (uint_t)SBSIZE; 516 head->fi_memp = (caddr_t)&(ufs_devp->un_fs.di_fs); 517 head->fi_offset = 0; 518 519 if (diskread(head)) { 520 printf("failed to read superblock\n"); 521 (void) bufs_closeall(1); 522 return (-1); 523 } 524 525 if (ufs_devp->un_fs.di_fs.fs_magic != FS_MAGIC) { 526 dprintf("fs magic = 0x%x\n", ufs_devp->un_fs.di_fs.fs_magic); 527 (void) bufs_closeall(1); 528 return (-1); 529 } 530 dprintf("mountroot succeeded\n"); 531 return (0); 532 } 533 534 /* 535 * Unmount the currently mounted root fs. In practice, this means 536 * closing all open files and releasing resources. All of this 537 * is done by closeall(). 538 */ 539 540 static int 541 bufs_unmountroot(void) 542 { 543 if (ufs_devp == NULL) 544 return (-1); 545 546 (void) bufs_closeall(1); 547 548 return (0); 549 } 550 551 /* 552 * We allocate an fd here for use when talking 553 * to the file itself. 554 */ 555 556 /*ARGSUSED*/ 557 static int 558 bufs_open(char *filename, int flags) 559 { 560 fileid_t *filep; 561 ino_t inode; 562 static int filedes = 1; 563 564 dprintf("open: %s\n", filename); 565 566 /* build and link a new file descriptor */ 567 filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 568 filep->fi_back = head->fi_back; 569 filep->fi_forw = head; 570 head->fi_back->fi_forw = filep; 571 head->fi_back = filep; 572 filep->fi_filedes = filedes++; 573 filep->fi_taken = 1; 574 filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1); 575 (void) strcpy(filep->fi_path, filename); 576 filep->fi_devp = ufs_devp; /* dev is already "mounted" */ 577 filep->fi_inode = NULL; 578 bzero(filep->fi_buf, MAXBSIZE); 579 580 inode = find(filep, (char *)filename); 581 if (inode == (ino_t)0) { 582 dprintf("open: cannot find %s\n", filename); 583 (void) bufs_close(filep->fi_filedes); 584 return (-1); 585 } 586 if (openi(filep, inode)) { 587 printf("open: cannot open %s\n", filename); 588 (void) bufs_close(filep->fi_filedes); 589 return (-1); 590 } 591 592 filep->fi_offset = filep->fi_count = 0; 593 594 return (filep->fi_filedes); 595 } 596 597 /* 598 * We don't do any IO here. 599 * We just play games with the device pointers. 600 */ 601 602 static off_t 603 bufs_lseek(int fd, off_t addr, int whence) 604 { 605 fileid_t *filep; 606 607 /* Make sure user knows what file he is talking to */ 608 if (!(filep = find_fp(fd))) 609 return (-1); 610 611 switch (whence) { 612 case SEEK_CUR: 613 filep->fi_offset += addr; 614 break; 615 case SEEK_SET: 616 filep->fi_offset = addr; 617 break; 618 default: 619 case SEEK_END: 620 printf("lseek(): invalid whence value %d\n", whence); 621 break; 622 } 623 624 filep->fi_blocknum = addr / DEV_BSIZE; 625 filep->fi_count = 0; 626 627 return (0); 628 } 629 630 631 int 632 bufs_fstat(int fd, struct bootstat *stp) 633 { 634 fileid_t *filep; 635 struct inode *ip; 636 637 if (!(filep = find_fp(fd))) 638 return (-1); 639 640 ip = filep->fi_inode; 641 642 stp->st_mode = 0; 643 stp->st_size = 0; 644 645 if (ip == NULL) 646 return (0); 647 648 switch (ip->i_smode & IFMT) { 649 case IFLNK: 650 stp->st_mode = S_IFLNK; 651 break; 652 case IFREG: 653 stp->st_mode = S_IFREG; 654 break; 655 default: 656 break; 657 } 658 stp->st_size = ip->i_size; 659 stp->st_atim.tv_sec = ip->i_atime.tv_sec; 660 stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000; 661 stp->st_mtim.tv_sec = ip->i_mtime.tv_sec; 662 stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000; 663 stp->st_ctim.tv_sec = ip->i_ctime.tv_sec; 664 stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000; 665 666 return (0); 667 } 668 669 670 static int 671 bufs_close(int fd) 672 { 673 fileid_t *filep; 674 675 /* Make sure user knows what file he is talking to */ 676 if (!(filep = find_fp(fd))) 677 return (-1); 678 679 if (filep->fi_taken && (filep != head)) { 680 /* Clear the ranks */ 681 bkmem_free(filep->fi_path, strlen(filep->fi_path)+1); 682 filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0; 683 filep->fi_memp = (caddr_t)0; 684 filep->fi_devp = 0; 685 filep->fi_taken = 0; 686 687 /* unlink and deallocate node */ 688 filep->fi_forw->fi_back = filep->fi_back; 689 filep->fi_back->fi_forw = filep->fi_forw; 690 bkmem_free((char *)filep, sizeof (fileid_t)); 691 692 return (0); 693 } else { 694 /* Big problem */ 695 printf("\nFile descrip %d not allocated!", fd); 696 return (-1); 697 } 698 } 699 700 /*ARGSUSED*/ 701 static void 702 bufs_closeall(int flag) 703 { 704 fileid_t *filep = head; 705 706 while ((filep = filep->fi_forw) != head) 707 if (filep->fi_taken) 708 if (bufs_close(filep->fi_filedes)) 709 printf("Filesystem may be inconsistent.\n"); 710 711 ufs_devp->di_taken = 0; 712 bkmem_free((char *)ufs_devp, sizeof (devid_t)); 713 bkmem_free((char *)head, sizeof (fileid_t)); 714 ufs_devp = (devid_t *)NULL; 715 head = (fileid_t *)NULL; 716 free_cache(); 717 } 718 719 static struct cache { 720 struct cache *next; 721 void *data; 722 int key; 723 uint_t size; 724 } *icache; 725 726 void 727 set_cache(int key, void *data, uint_t size) 728 { 729 struct cache *entry = bkmem_alloc(sizeof (*entry)); 730 entry->key = key; 731 entry->data = data; 732 entry->size = size; 733 if (icache) { 734 entry->next = icache; 735 icache = entry; 736 } else { 737 icache = entry; 738 entry->next = 0; 739 } 740 } 741 742 void * 743 get_cache(int key) 744 { 745 struct cache *entry = icache; 746 while (entry) { 747 if (entry->key == key) 748 return (entry->data); 749 entry = entry->next; 750 } 751 return (NULL); 752 } 753 754 void 755 free_cache() 756 { 757 struct cache *next, *entry = icache; 758 while (entry) { 759 next = entry->next; 760 bkmem_free(entry->data, entry->size); 761 bkmem_free(entry, sizeof (*entry)); 762 entry = next; 763 } 764 icache = 0; 765 } 766 767 struct boot_fs_ops bufs_ops = { 768 "boot_ufs", 769 bufs_mountroot, 770 bufs_unmountroot, 771 bufs_open, 772 bufs_close, 773 bufs_read, 774 bufs_lseek, 775 bufs_fstat, 776 NULL 777 }; 778