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