2 * This Cplant(TM) source code is the property of Sandia National
5 * This Cplant(TM) source code is copyrighted by Sandia National
8 * The redistribution of this Cplant(TM) source code is subject to the
9 * terms of the GNU Lesser General Public License
10 * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
12 * Cplant(TM) Copyright 1998-2004 Sandia Corporation.
13 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14 * license for use of this work by or on behalf of the US Government.
15 * Export of this program may require a license from the United States
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * Questions or comments about this library should be sent to:
37 * Sandia National Laboratories, New Mexico
39 * Albuquerque, NM 87185-1110
48 #include <sys/types.h>
50 #ifdef AUTOMOUNT_FILE_NAME
54 #include <sys/queue.h>
63 * File system and volume mount support.
66 #ifdef AUTOMOUNT_FILE_NAME
68 * Name of autmount specification file in a directory with
71 struct qstr _sysio_mount_file_name = { "", 0, 0 };
77 static LIST_HEAD(, mount) mounts;
79 static int _sysio_sub_fsswop_mount(const char *source,
82 struct pnode *tocover,
85 static struct fssw_ops _sysio_sub_fssw_ops = {
86 _sysio_sub_fsswop_mount
90 * Initialization. Must be called before any other routine in this module.
98 #ifdef AUTOMOUNT_FILE_NAME
99 _sysio_next_component(AUTOMOUNT_FILE_NAME, &_sysio_mount_file_name);
103 * Register the sub-trees "file system" driver.
105 err = _sysio_fssw_register("sub", &_sysio_sub_fssw_ops);
113 * Mount rooted sub-tree somewhere in the existing name space.
116 _sysio_do_mount(struct filesys *fs,
117 struct pnode_base *rootpb,
119 struct pnode *tocover,
126 * It's really poor form to allow the new root to be a
127 * descendant of the pnode being covered.
130 struct pnode_base *pb;
133 pb && pb != tocover->p_base;
136 if (pb == tocover->p_base)
143 mnt = malloc(sizeof(struct mount));
148 * Init enough to make the mount record usable to the path node
149 * generation routines.
152 if (fs->fs_flags & FS_F_RO) {
154 * Propagate the read-only flag -- Whether they set it or not.
158 mnt->mnt_flags = flags;
160 * Get alias for the new root.
163 _sysio_p_new_alias(tocover ? tocover->p_parent : NULL, rootpb, mnt);
164 if (!mnt->mnt_root) {
169 * It may have been a while since the root inode was validated;
170 * better validate again. And it better be a directory!
172 err = _sysio_p_validate(mnt->mnt_root, NULL, NULL);
176 if (!S_ISDIR(mnt->mnt_root->p_base->pb_ino->i_stbuf.st_mode)) {
181 * Cover up the mount point.
183 mnt->mnt_covers = tocover;
184 if (!mnt->mnt_covers) {
186 * New graph; It covers itself.
188 mnt->mnt_covers = tocover = mnt->mnt_root;
190 assert(!tocover->p_cover);
191 tocover->p_cover = mnt->mnt_root;
193 LIST_INSERT_HEAD(&mounts, mnt, mnt_link);
200 P_RELE(mnt->mnt_root);
201 _sysio_p_prune(mnt->mnt_root);
208 * Remove mounted sub-tree from the system.
211 _sysio_do_unmount(struct mount *mnt)
216 root = mnt->mnt_root;
217 if (root->p_cover && root->p_cover != root) {
223 assert(mnt->mnt_covers->p_cover == root);
224 if (_sysio_p_prune(root) != 1) {
233 * Drop ref of covered pnode and break linkage in name space.
235 if (root->p_cover != root)
236 P_RELE(mnt->mnt_covers);
237 mnt->mnt_covers->p_cover = NULL;
238 LIST_REMOVE(mnt, mnt_link);
243 root->p_cover = NULL;
246 * Release mount record resource.
256 * Establish the system name space.
259 _sysio_mount_root(const char *source,
264 struct fsswent *fssw;
271 fssw = _sysio_fssw_lookup(fstype);
275 err = (*fssw->fssw_ops.fsswop_mount)(source, flags, data, NULL, &mnt);
279 _sysio_root = mnt->mnt_root;
282 * It is very annoying to have to set the current working directory.
283 * So... If it isn't set, make it the root now.
286 _sysio_cwd = _sysio_root;
295 _sysio_mount(struct pnode *cwd,
298 const char *filesystemtype,
299 unsigned long mountflags,
303 struct fsswent *fssw;
304 struct intent intent;
309 * Find the file system switch entry specified.
311 fssw = _sysio_fssw_lookup(filesystemtype);
316 * Look up the target path node.
318 INTENT_INIT(&intent, INT_GETATTR, NULL, NULL);
319 err = _sysio_namei(cwd, target, 0, &intent, &tgt);
323 if (tgt == _sysio_root) {
325 * Attempting to mount over root.
333 (*fssw->fssw_ops.fsswop_mount)(source,
345 SYSIO_INTERFACE_NAME(mount)(const char *source,
347 const char *filesystemtype,
348 unsigned long mountflags,
352 SYSIO_INTERFACE_DISPLAY_BLOCK;
354 SYSIO_INTERFACE_ENTER;
356 _sysio_mount(_sysio_cwd,
362 SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
366 SYSIO_INTERFACE_NAME(umount)(const char *target)
370 SYSIO_INTERFACE_DISPLAY_BLOCK;
372 SYSIO_INTERFACE_ENTER;
374 * Look up the target path node.
376 err = _sysio_namei(_sysio_cwd, target, 0, NULL, &pno);
379 P_RELE(pno); /* was ref'd */
390 assert(pno->p_mount);
391 err = _sysio_do_unmount(pno->p_mount);
394 SYSIO_INTERFACE_RETURN(err ? -1 : 0, err);
398 * Unmount all file systems -- Usually as part of shutting everything down.
404 struct mount *mnt, *nxt;
408 nxt = mounts.lh_first;
409 while ((mnt = nxt)) {
410 nxt = mnt->mnt_link.le_next;
413 * If this is an automount generated mount, the root
414 * has no reference. We can cause the dismount with a
417 if (!_sysio_p_prune(pno))
421 * Need a ref but only if this is not the root of a
422 * disconnected graph. If it is, then it is covered by itself
423 * and, so, already referenced.
425 if (pno->p_cover != pno)
428 err = _sysio_do_unmount(mnt);
431 if (pno->p_cover != pno)
436 if (pno == _sysio_root)
444 _sysio_sub_fsswop_mount(const char *source,
446 const void *data __IS_UNUSED,
447 struct pnode *tocover,
451 struct nameidata nameidata;
455 * How can we make a sub-mount from nothing?
463 ND_INIT(&nameidata, 0, source, _sysio_root, NULL);
464 err = _sysio_path_walk(_sysio_root, &nameidata);
469 * Mount the rooted sub-tree at the given position.
472 _sysio_do_mount(nameidata.nd_pno->p_mount->mnt_fs,
473 nameidata.nd_pno->p_base,
474 nameidata.nd_pno->p_mount->mnt_flags & flags,
479 * Clean up and return.
482 FS_REF(nameidata.nd_pno->p_mount->mnt_fs);
485 P_RELE(nameidata.nd_pno);
489 #ifdef AUTOMOUNT_FILE_NAME
491 * Parse automount specification formatted as:
493 * <fstype>:<source>[[ \t]+<comma-separated-mount-options>]
496 * The buffer sent is (almost) always modified.
499 parse_automount_spec(char *s, char **fstyp, char **srcp, char **optsp)
503 char *fsty, *src, *opts;
510 while (*s && *s == ' ' && *s == '\t')
523 if (fsty == cp || *cp != ':')
531 while (*s && *s == ' ' && *s == '\t')
552 while (*s && *s == ' ' && *s == '\t')
582 * Parse (and strip) system mount options.
585 parse_opts(char *opts, unsigned *flagsp)
595 while (*cp && *cp != ',')
597 if (src + 2 == cp && strncmp(src, "rw", 2) == 0) {
599 * Do nothing. This is the default.
602 } else if (src + 2 == cp && strncmp(src, "ro", 2) == 0) {
609 else if (src + 4 == cp && strncmp(src, "auto", 4) == 0) {
613 flags |= MOUNT_F_AUTO;
618 * Copy what we didn't consume.
629 src++; /* skip comma */
638 * Attempt automount over the given directory.
641 _sysio_automount(struct pnode *mntpno)
646 struct ioctx iocontext;
647 struct intnl_xtvec xtvec;
649 char *fstype, *source, *opts;
651 struct fsswent *fssw;
655 * Revalidate -- Paranoia.
657 err = _sysio_p_validate(mntpno, NULL, NULL);
664 ino = mntpno->p_base->pb_ino;
665 if (ino->i_stbuf.st_size > 64 * 1024) {
667 * Let's be reasonable.
671 iovec.iov_base = malloc(ino->i_stbuf.st_size + 1);
674 iovec.iov_len = ino->i_stbuf.st_size;
675 err = _sysio_open(mntpno, O_RDONLY, 0);
679 xtvec.xtv_len = ino->i_stbuf.st_size;
680 IOCTX_INIT(&iocontext,
686 _sysio_ioctx_enter(&iocontext);
687 err = (*ino->i_ops.inop_read)(ino, &iocontext);
689 _sysio_ioctx_complete(&iocontext);
690 (void )(*ino->i_ops.inop_close)(ino);
693 cc = _sysio_ioctx_wait(&iocontext);
694 err = (*ino->i_ops.inop_close)(ino);
701 ((char *)iovec.iov_base)[cc] = '\0';
706 err = parse_automount_spec(iovec.iov_base, &fstype, &source, &opts);
711 opts = parse_opts(opts, &flags);
714 * Find the file system switch entry specified.
716 fssw = _sysio_fssw_lookup(fstype);
725 P_REF(mntpno->p_parent);
727 (*fssw->fssw_ops.fsswop_mount)(source,
733 P_RELE(mntpno->p_parent);
737 free(iovec.iov_base);