1 /* This file performs the MOUNT and UMOUNT system calls. 2 * 3 * The entry points into this file are 4 * do_mount: perform the MOUNT system call 5 * do_umount: perform the UMOUNT system call 6 * unmount: unmount a file system 7 */ 8 9 #include "fs.h" 10 #include <fcntl.h> 11 #include <string.h> 12 #include <minix/callnr.h> 13 #include <minix/com.h> 14 #include <minix/const.h> 15 #include <minix/endpoint.h> 16 #include <minix/syslib.h> 17 #include <minix/bitmap.h> 18 #include <minix/ds.h> 19 #include <unistd.h> 20 #include <sys/stat.h> 21 #include <sys/mount.h> 22 #include <sys/dirent.h> 23 #include <assert.h> 24 #include "file.h" 25 #include <minix/vfsif.h> 26 #include "vnode.h" 27 #include "vmnt.h" 28 #include "path.h" 29 30 /* Allow the root to be replaced before the first 'real' mount. */ 31 static int have_root = 0; 32 33 /* Bitmap of in-use "none" pseudo devices. */ 34 static bitchunk_t nonedev[BITMAP_CHUNKS(NR_NONEDEVS)] = { 0 }; 35 36 #define alloc_nonedev(dev) SET_BIT(nonedev, minor(dev) - 1) 37 #define free_nonedev(dev) UNSET_BIT(nonedev, minor(dev) - 1) 38 39 static dev_t name_to_dev(int allow_mountpt, char path[PATH_MAX]); 40 static dev_t find_free_nonedev(void); 41 static void update_bspec(dev_t dev, endpoint_t fs_e, int send_drv_e); 42 43 /*===========================================================================* 44 * update_bspec * 45 *===========================================================================*/ 46 static void update_bspec(dev_t dev, endpoint_t fs_e, int send_drv_e) 47 { 48 /* Update all block special files for a certain device, to use a new FS endpt 49 * to route raw block I/O requests through. 50 */ 51 struct vnode *vp; 52 struct dmap *dp; 53 devmajor_t major; 54 int r; 55 56 for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) 57 if (vp->v_ref_count > 0 && S_ISBLK(vp->v_mode) && vp->v_sdev == dev) { 58 vp->v_bfs_e = fs_e; 59 if (send_drv_e) { 60 major = major(dev); 61 if (major < 0 || major >= NR_DEVICES) { 62 /* Can't update for out-of-range major */ 63 continue; 64 } 65 dp = &dmap[major(dev)]; 66 if (dp->dmap_driver == NONE) { 67 /* Can't update for vanished driver */ 68 printf("VFS: can't send new driver label\n"); 69 continue; 70 } 71 72 if ((r = req_newdriver(fs_e, vp->v_sdev, 73 dp->dmap_label)) != OK) { 74 printf("VFS: Failed to send new driver label" 75 " for moved block special file to %d\n", 76 fs_e); 77 } 78 } 79 } 80 } 81 82 /*===========================================================================* 83 * do_mount * 84 *===========================================================================*/ 85 int do_mount(void) 86 { 87 /* Perform the mount(name, mfile, mount_flags) system call. */ 88 endpoint_t fs_e; 89 int r, slot, nodev; 90 char mount_path[PATH_MAX], mount_dev[PATH_MAX]; 91 char mount_label[LABEL_MAX], mount_type[FSTYPE_MAX]; 92 dev_t dev; 93 int mflags; 94 vir_bytes label, type, vname1, vname2; 95 size_t vname1_length, vname2_length, label_len, type_len; 96 97 mflags = job_m_in.m_lc_vfs_mount.flags; 98 label = job_m_in.m_lc_vfs_mount.label; 99 label_len = job_m_in.m_lc_vfs_mount.labellen; 100 vname1 = job_m_in.m_lc_vfs_mount.dev; 101 vname1_length = job_m_in.m_lc_vfs_mount.devlen; 102 vname2 = job_m_in.m_lc_vfs_mount.path; 103 vname2_length = job_m_in.m_lc_vfs_mount.pathlen; 104 type = job_m_in.m_lc_vfs_mount.type; 105 type_len = job_m_in.m_lc_vfs_mount.typelen; 106 107 /* Only the super-user may do MOUNT. */ 108 if (!super_user) return(EPERM); 109 110 /* Get the label from the caller, and ask DS for the endpoint of the FS. */ 111 if (label_len > sizeof(mount_label)) 112 return EINVAL; 113 r = sys_datacopy_wrapper(who_e, label, SELF, (vir_bytes) mount_label, 114 sizeof(mount_label)); 115 if (r != OK) return(r); 116 117 mount_label[sizeof(mount_label)-1] = 0; 118 119 r = ds_retrieve_label_endpt(mount_label, &fs_e); 120 if (r != OK) return(r); 121 122 /* Sanity check on process number. */ 123 if (isokendpt(fs_e, &slot) != OK) return(EINVAL); 124 125 /* A null string for block special device means don't use a device at all. */ 126 nodev = (vname1_length == 0); 127 if (!nodev) { 128 /* If 'name' is not for a block special file, return error. */ 129 if (fetch_name(vname1, vname1_length, mount_dev) != OK) 130 return(err_code); 131 if ((dev = name_to_dev(FALSE /*allow_mountpt*/, mount_dev)) == NO_DEV) 132 return(err_code); 133 } else { 134 /* Find a free pseudo-device as substitute for an actual device. */ 135 if ((dev = find_free_nonedev()) == NO_DEV) 136 return(err_code); 137 strlcpy(mount_dev, "none", sizeof(mount_dev)); 138 } 139 140 /* Fetch the name of the mountpoint */ 141 if (fetch_name(vname2, vname2_length, mount_path) != OK) return(err_code); 142 143 /* Fetch the type of the file system. */ 144 if (type_len > sizeof(mount_type)) return(ENAMETOOLONG); 145 if (fetch_name(type, type_len, mount_type) != OK) return(err_code); 146 147 /* Do the actual job */ 148 return mount_fs(dev, mount_dev, mount_path, fs_e, mflags, mount_type, 149 mount_label); 150 } 151 152 153 /*===========================================================================* 154 * mount_fs * 155 *===========================================================================*/ 156 int mount_fs( 157 dev_t dev, 158 char mount_dev[PATH_MAX], 159 char mount_path[PATH_MAX], 160 endpoint_t fs_e, 161 int flags, 162 char mount_type[FSTYPE_MAX], 163 char mount_label[LABEL_MAX] ) 164 { 165 int i, r = OK, found, isroot, mount_root, slot; 166 struct fproc *tfp, *rfp; 167 struct dmap *dp; 168 struct vnode *root_node, *vp = NULL; 169 struct vmnt *new_vmp, *parent_vmp; 170 char *label; 171 struct node_details res; 172 struct lookup resolve; 173 struct statvfs statvfs_buf; 174 unsigned int fs_flags; 175 176 /* Look up block device driver label when dev is not a pseudo-device */ 177 label = ""; 178 if (!is_nonedev(dev)) { 179 /* Get driver process' endpoint */ 180 dp = &dmap[major(dev)]; 181 if (dp->dmap_driver == NONE) { 182 printf("VFS: no driver for dev %llx\n", dev); 183 return(EINVAL); 184 } 185 186 label = dp->dmap_label; 187 assert(strlen(label) > 0); 188 } 189 190 /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/ 191 found = FALSE; 192 for (i = 0; i < NR_MNTS; ++i) { 193 if (vmnt[i].m_dev == dev) found = TRUE; 194 } 195 if (found) { 196 return(EBUSY); 197 } else if ((new_vmp = get_free_vmnt()) == NULL) { 198 return(ENOMEM); 199 } 200 if ((r = lock_vmnt(new_vmp, VMNT_EXCL)) != OK) return(r); 201 202 strlcpy(new_vmp->m_mount_path, mount_path, PATH_MAX); 203 strlcpy(new_vmp->m_mount_dev, mount_dev, PATH_MAX); 204 strlcpy(new_vmp->m_fstype, mount_type, sizeof(new_vmp->m_fstype)); 205 isroot = (strcmp(mount_path, "/") == 0); 206 mount_root = (isroot && have_root < 2); /* Root can be mounted twice: 207 * 1: ramdisk 208 * 2: boot disk (e.g., harddisk) 209 */ 210 211 if (!mount_root) { 212 /* Get vnode of mountpoint */ 213 lookup_init(&resolve, mount_path, PATH_NOFLAGS, &parent_vmp, &vp); 214 resolve.l_vmnt_lock = VMNT_EXCL; 215 resolve.l_vnode_lock = VNODE_WRITE; 216 if ((vp = eat_path(&resolve, fp)) == NULL) 217 r = err_code; 218 else if (vp->v_ref_count == 1) { 219 /*Tell FS on which vnode it is mounted (glue into mount tree)*/ 220 r = req_mountpoint(vp->v_fs_e, vp->v_inode_nr); 221 } else 222 r = EBUSY; 223 224 if (vp != NULL) { 225 /* Quickly unlock to allow back calls (from e.g. FUSE) to 226 * relock */ 227 unlock_vmnt(parent_vmp); 228 } 229 230 if (r != OK) { 231 if (vp != NULL) { 232 unlock_vnode(vp); 233 put_vnode(vp); 234 } 235 unlock_vmnt(new_vmp); 236 return(r); 237 } 238 } 239 240 /* We'll need a vnode for the root inode */ 241 if ((root_node = get_free_vnode()) == NULL) { 242 if (vp != NULL) { 243 unlock_vnode(vp); 244 put_vnode(vp); 245 } 246 unlock_vmnt(new_vmp); 247 return(err_code); 248 } 249 lock_vnode(root_node, VNODE_OPCL); 250 251 /* Record process as a system process */ 252 if (isokendpt(fs_e, &slot) != OK) { 253 if (vp != NULL) { 254 unlock_vnode(vp); 255 put_vnode(vp); 256 } 257 unlock_vnode(root_node); 258 unlock_vmnt(new_vmp); 259 return(EINVAL); 260 } 261 rfp = &fproc[slot]; 262 rfp->fp_flags |= FP_SRV_PROC; /* File Servers are also services */ 263 264 /* Store some essential vmnt data first */ 265 new_vmp->m_fs_e = fs_e; 266 new_vmp->m_dev = dev; 267 if (flags & MNT_RDONLY) new_vmp->m_flags |= VMNT_READONLY; 268 else new_vmp->m_flags &= ~VMNT_READONLY; 269 270 /* Tell FS which device to mount */ 271 new_vmp->m_flags |= VMNT_MOUNTING; 272 r = req_readsuper(new_vmp, label, dev, !!(flags & MNT_RDONLY), isroot, &res, 273 &fs_flags); 274 new_vmp->m_flags &= ~VMNT_MOUNTING; 275 276 new_vmp->m_fs_flags = fs_flags; 277 278 /* Fill the statvfs cache with initial values. */ 279 if (r == OK) 280 r = update_statvfs(new_vmp, &statvfs_buf); 281 282 if (r != OK) { 283 mark_vmnt_free(new_vmp); 284 unlock_vnode(root_node); 285 if (vp != NULL) { 286 unlock_vnode(vp); 287 put_vnode(vp); 288 } 289 unlock_vmnt(new_vmp); 290 return(r); 291 } 292 293 lock_bsf(); 294 295 /* Fill in root node's fields */ 296 root_node->v_fs_e = res.fs_e; 297 root_node->v_inode_nr = res.inode_nr; 298 root_node->v_mode = res.fmode; 299 root_node->v_uid = res.uid; 300 root_node->v_gid = res.gid; 301 root_node->v_size = res.fsize; 302 root_node->v_sdev = NO_DEV; 303 root_node->v_fs_count = 1; 304 root_node->v_ref_count = 1; 305 306 /* Root node is indeed on the partition */ 307 root_node->v_vmnt = new_vmp; 308 root_node->v_dev = new_vmp->m_dev; 309 if (!(new_vmp->m_fs_flags & RES_THREADED)) 310 new_vmp->m_comm.c_max_reqs = 1; 311 else 312 new_vmp->m_comm.c_max_reqs = NR_WTHREADS; 313 new_vmp->m_comm.c_cur_reqs = 0; 314 315 /* No more blocking operations, so we can now report on this file system. */ 316 new_vmp->m_flags |= VMNT_CANSTAT; 317 318 if (mount_root) { 319 /* Superblock and root node already read. 320 * Nothing else can go wrong. Perform the mount. */ 321 new_vmp->m_root_node = root_node; 322 new_vmp->m_mounted_on = NULL; 323 strlcpy(new_vmp->m_label, mount_label, LABEL_MAX); 324 if (is_nonedev(dev)) alloc_nonedev(dev); 325 update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */); 326 327 ROOT_DEV = dev; 328 ROOT_FS_E = fs_e; 329 330 /* Replace all root and working directories */ 331 for (i = 0, tfp = fproc; i < NR_PROCS; i++, tfp++) { 332 if (tfp->fp_pid == PID_FREE) 333 continue; 334 335 #define MAKEROOT(what) { \ 336 if (what) put_vnode(what); \ 337 dup_vnode(root_node); \ 338 what = root_node; \ 339 } 340 341 MAKEROOT(tfp->fp_rd); 342 MAKEROOT(tfp->fp_wd); 343 } 344 345 unlock_vnode(root_node); 346 unlock_vmnt(new_vmp); 347 have_root++; /* We have a (new) root */ 348 unlock_bsf(); 349 return(OK); 350 } 351 352 /* File types may not conflict. */ 353 if (!S_ISDIR(vp->v_mode) && S_ISDIR(root_node->v_mode)) r = EISDIR; 354 355 /* If error, return the super block and both inodes; release the vmnt. */ 356 if (r != OK) { 357 unlock_vnode(vp); 358 unlock_vnode(root_node); 359 mark_vmnt_free(new_vmp); 360 unlock_vmnt(new_vmp); 361 put_vnode(vp); 362 put_vnode(root_node); 363 unlock_bsf(); 364 return(r); 365 } 366 367 /* Nothing else can go wrong. Perform the mount. */ 368 new_vmp->m_mounted_on = vp; 369 new_vmp->m_root_node = root_node; 370 strlcpy(new_vmp->m_label, mount_label, LABEL_MAX); 371 372 /* Allocate the pseudo device that was found, if not using a real device. */ 373 if (is_nonedev(dev)) alloc_nonedev(dev); 374 375 /* The new FS will handle block I/O requests for its device now. */ 376 if (!(new_vmp->m_flags & VMNT_FORCEROOTBSF)) 377 update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */); 378 379 unlock_vnode(vp); 380 unlock_vnode(root_node); 381 unlock_vmnt(new_vmp); 382 unlock_bsf(); 383 384 return(OK); 385 } 386 387 388 /*===========================================================================* 389 * mount_pfs * 390 *===========================================================================*/ 391 void mount_pfs(void) 392 { 393 /* Mount the Pipe File Server. We treat it as a regular file system to a 394 * certain extent, to prevent creating too many exceptions all over the place. 395 * For example, it has a vmnt entry to make locking easier, and it gets sent 396 * a mount request to keep the fsdriver library happy. 397 */ 398 dev_t dev; 399 struct vmnt *vmp; 400 struct node_details res; 401 unsigned int fs_flags; 402 int r; 403 404 if ((dev = find_free_nonedev()) == NO_DEV) 405 panic("VFS: no nonedev to initialize PFS"); 406 407 if ((vmp = get_free_vmnt()) == NULL) 408 panic("VFS: no vmnt to initialize PFS"); 409 410 alloc_nonedev(dev); 411 412 vmp->m_dev = dev; 413 vmp->m_fs_e = PFS_PROC_NR; 414 vmp->m_fs_flags = 0; 415 strlcpy(vmp->m_label, "pfs", LABEL_MAX); 416 strlcpy(vmp->m_mount_path, "pipe", PATH_MAX); 417 strlcpy(vmp->m_mount_dev, "none", PATH_MAX); 418 419 /* Ask PFS to acknowledge being mounted. Ignore the returned node details. */ 420 r = req_readsuper(vmp, "", dev, FALSE, FALSE, &res, &fs_flags); 421 if (r != OK) 422 printf("VFS: unable to mount PFS (%d)\n", r); 423 else 424 vmp->m_fs_flags = fs_flags; 425 } 426 427 /*===========================================================================* 428 * do_umount * 429 *===========================================================================*/ 430 int do_umount(void) 431 { 432 /* Perform the umount(name) system call. Return the label of the FS service. 433 */ 434 char label[LABEL_MAX]; 435 dev_t dev; 436 int r; 437 char fullpath[PATH_MAX]; 438 vir_bytes vname, label_addr; 439 size_t vname_length, label_len; 440 441 vname = job_m_in.m_lc_vfs_umount.name; 442 vname_length = job_m_in.m_lc_vfs_umount.namelen; 443 label_addr = job_m_in.m_lc_vfs_umount.label; 444 label_len = job_m_in.m_lc_vfs_umount.labellen; 445 446 /* Only the super-user may do umount. */ 447 if (!super_user) return(EPERM); 448 449 /* If 'name' is not for a block special file or mountpoint, return error. */ 450 if (fetch_name(vname, vname_length, fullpath) != OK) 451 return(err_code); 452 if ((dev = name_to_dev(TRUE /*allow_mountpt*/, fullpath)) == NO_DEV) 453 return(err_code); 454 455 if ((r = unmount(dev, label)) != OK) return(r); 456 457 /* Return the label of the mounted file system, so that the caller 458 * can shut down the corresponding server process. 459 */ 460 if (strlen(label) >= label_len) 461 label[label_len-1] = 0; 462 return sys_datacopy_wrapper(SELF, (vir_bytes) label, who_e, label_addr, 463 strlen(label) + 1); 464 } 465 466 467 /*===========================================================================* 468 * unmount * 469 *===========================================================================*/ 470 int unmount( 471 dev_t dev, /* block-special device */ 472 char label[LABEL_MAX] /* buffer to retrieve label, or NULL */ 473 ) 474 { 475 struct vnode *vp; 476 struct vmnt *vmp_i = NULL, *vmp = NULL; 477 int count, locks, r; 478 479 /* Find vmnt that is to be unmounted */ 480 for (vmp_i = &vmnt[0]; vmp_i < &vmnt[NR_MNTS]; ++vmp_i) { 481 if (vmp_i->m_dev == dev) { 482 if(vmp) panic("device mounted more than once: %llx", dev); 483 vmp = vmp_i; 484 } 485 } 486 487 /* Did we find the vmnt (i.e., was dev a mounted device)? */ 488 if(!vmp) return(EINVAL); 489 490 if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) return(r); 491 492 /* See if the mounted device is busy. Only 1 vnode using it should be 493 * open -- the root vnode -- and that inode only 1 time. */ 494 locks = count = 0; 495 for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) 496 if (vp->v_ref_count > 0 && vp->v_dev == dev) { 497 count += vp->v_ref_count; 498 if (is_vnode_locked(vp)) locks++; 499 } 500 501 if (count > 1 || locks > 1 || tll_haspendinglock(&vmp->m_lock)) { 502 unlock_vmnt(vmp); 503 return(EBUSY); /* can't umount a busy file system */ 504 } 505 506 /* This FS will now disappear, so stop listing it in statistics. */ 507 vmp->m_flags &= ~VMNT_CANSTAT; 508 509 /* Tell FS to drop all inode references for root inode except 1. */ 510 vnode_clean_refs(vmp->m_root_node); 511 512 if (vmp->m_mounted_on) { 513 put_vnode(vmp->m_mounted_on); 514 vmp->m_mounted_on = NULL; 515 } 516 517 vmp->m_comm.c_max_reqs = 1; /* Force max concurrent reqs to just one, so 518 * we won't send any messages after the 519 * unmount request */ 520 521 /* Tell FS to unmount */ 522 if ((r = req_unmount(vmp->m_fs_e)) != OK) /* Not recoverable. */ 523 printf("VFS: ignoring failed umount attempt FS endpoint: %d (%d)\n", 524 vmp->m_fs_e, r); 525 526 if (is_nonedev(vmp->m_dev)) free_nonedev(vmp->m_dev); 527 528 if (label != NULL) strlcpy(label, vmp->m_label, LABEL_MAX); 529 530 if (vmp->m_root_node) { /* PFS lacks a root node */ 531 vmp->m_root_node->v_ref_count = 0; 532 vmp->m_root_node->v_fs_count = 0; 533 vmp->m_root_node->v_sdev = NO_DEV; 534 vmp->m_root_node = NULL; 535 } 536 mark_vmnt_free(vmp); 537 538 unlock_vmnt(vmp); 539 540 /* The root FS will handle block I/O requests for this device now. */ 541 lock_bsf(); 542 update_bspec(dev, ROOT_FS_E, 1 /* send new driver endpoint */); 543 unlock_bsf(); 544 545 return(OK); 546 } 547 548 549 /*===========================================================================* 550 * unmount_all * 551 *===========================================================================*/ 552 void unmount_all(int force) 553 { 554 /* Unmount all filesystems. File systems are mounted on other file systems, 555 * so you have to pull off the loose bits repeatedly to get it all undone. 556 */ 557 558 int i; 559 struct vmnt *vmp; 560 561 /* Now unmount the rest */ 562 for (i = 0; i < NR_MNTS; i++) { 563 /* Unmount at least one. */ 564 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { 565 if (vmp->m_dev != NO_DEV) 566 unmount(vmp->m_dev, NULL); 567 } 568 } 569 570 if (!force) return; 571 572 /* Verify nothing is locked anymore */ 573 check_vnode_locks(); 574 check_vmnt_locks(); 575 check_filp_locks(); 576 check_bsf_lock(); 577 578 /* Verify we succesfully unmounted all file systems */ 579 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { 580 if (vmp->m_dev != NO_DEV) { 581 panic("vmp still mounted: %s %d %llx\n", vmp->m_label, 582 vmp->m_fs_e, vmp->m_dev); 583 } 584 } 585 } 586 587 /*===========================================================================* 588 * name_to_dev * 589 *===========================================================================*/ 590 static dev_t name_to_dev(int allow_mountpt, char path[PATH_MAX]) 591 { 592 /* Convert the block special file in 'user_fullpath' to a device number. 593 * If the given path is not a block special file, but 'allow_mountpt' is set 594 * and the path is the root node of a mounted file system, return that device 595 * number. In all other cases, return NO_DEV and an error code in 'err_code'. 596 */ 597 dev_t dev; 598 struct vnode *vp; 599 struct vmnt *vmp; 600 struct lookup resolve; 601 602 lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp); 603 resolve.l_vmnt_lock = VMNT_READ; 604 resolve.l_vnode_lock = VNODE_READ; 605 606 /* Request lookup */ 607 if ((vp = eat_path(&resolve, fp)) == NULL) return(NO_DEV); 608 609 if (S_ISBLK(vp->v_mode)) { 610 dev = vp->v_sdev; 611 } else if (allow_mountpt && vp->v_vmnt->m_root_node == vp) { 612 dev = vp->v_dev; 613 } else { 614 err_code = ENOTBLK; 615 dev = NO_DEV; 616 } 617 618 unlock_vnode(vp); 619 unlock_vmnt(vmp); 620 put_vnode(vp); 621 return(dev); 622 } 623 624 625 /*===========================================================================* 626 * is_nonedev * 627 *===========================================================================*/ 628 int is_nonedev(dev_t dev) 629 { 630 /* Return whether the given device is a "none" pseudo device. 631 */ 632 633 return (major(dev) == NONE_MAJOR && 634 minor(dev) > 0 && minor(dev) <= NR_NONEDEVS); 635 } 636 637 638 /*===========================================================================* 639 * find_free_nonedev * 640 *===========================================================================*/ 641 static dev_t find_free_nonedev(void) 642 { 643 /* Find a free "none" pseudo device. Do not allocate it yet. 644 */ 645 int i; 646 647 for (i = 0; i < NR_NONEDEVS; i++) 648 if (!GET_BIT(nonedev, i)) 649 return makedev(NONE_MAJOR, i + 1); 650 651 err_code = EMFILE; 652 return NO_DEV; 653 } 654