⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mount.c

📁 微内核软实时操作系统
💻 C
字号:
/* * Copyright (c) 2005-2007, Kohsuke Ohtani * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors  *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * mount.c - mount operations */#include <prex/prex.h>#include <sys/stat.h>#include <sys/vnode.h>#include <sys/file.h>#include <sys/mount.h>#include <sys/dirent.h>#include <sys/list.h>#include <sys/buf.h>#include <limits.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include "vfs.h"/* * List for VFS mount points. */static struct list mount_list = LIST_INIT(mount_list);/* * Global lock to access mount point. */#if NR_FS_THREADS > 1static mutex_t mount_lock = MUTEX_INITIALIZER;#define MOUNT_LOCK()	mutex_lock(&mount_lock)#define MOUNT_UNLOCK()	mutex_unlock(&mount_lock)#else#define MOUNT_LOCK()#define MOUNT_UNLOCK()#endifstatic const struct vfssw *fs_lookup(char *name){	const struct vfssw *fs;	for (fs = vfssw_table; fs->vs_name; fs++) {		if (!strncmp(name, fs->vs_name, FSNAME_MAX))			break;	}	if (!fs->vs_name)		return NULL;	return fs;}int sys_mount(char *dev, char *dir, char *fsname, int flags, void *data){	const struct vfssw *fs;	mount_t mp;	list_t head, n;	device_t device;	vnode_t vp, vp_covered;	int err;	dprintf("Mounting fs=%s dir=%s dev=%s\n", fsname, dir, dev);	if (!dir || *dir == '\0')		return ENOENT;	/* Find a file system. */	if (!(fs = fs_lookup(fsname)))		return ENODEV;	/* No such file system */	/* Open device. NULL can be specified as a device. */	device = NULL;	if (*dev != '\0') {		if (strncmp(dev, "/dev/", 5))			return ENOTBLK;		if ((err = device_open(dev + 5, DO_RDWR, &device)) != 0)			return err;	}	MOUNT_LOCK();	/* Check if device or directory has already been mounted. */	head = &mount_list;	for (n = list_first(head); n != head; n = list_next(n)) {		mp = list_entry(n, struct mount, m_link);		if (!strcmp(mp->m_path, dir) ||		    (device && mp->m_dev == (dev_t)device)) {			err = EBUSY;	/* Already mounted */			goto err1;		}	}	/*	 * Create VFS mount entry	 */	if (!(mp = malloc(sizeof(struct mount)))) {		err = ENOMEM;		goto err1;	}	mp->m_count = 0;	mp->m_op = fs->vs_op;	mp->m_flags = flags;	mp->m_dev = (dev_t)device;	strlcpy(mp->m_path, dir, PATH_MAX);	mp->m_path[PATH_MAX - 1] = '\0';	/*	 * Get vnode to be covered in the upper file system.	 */	if (*dir == '/' && *(dir + 1) == '\0') {		/* Ignore if it mounts to global root directory. */		vp_covered = NULL;	} else {		if ((err = namei(dir, &vp_covered)) != 0) {			err = ENOENT;			goto err2;		}		if (vp_covered->v_type != VDIR) {			err = ENOTDIR;			goto err3;		}	}	mp->m_covered = vp_covered;	/*	 * Create a root vnode for this file system.	 */	if ((vp = vget(mp, "/")) == NULL) {		err = ENOMEM;		goto err3;	}	vp->v_type = VDIR;	vp->v_flags = VROOT;	vp->v_mode = (mode_t)(S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH);	mp->m_root = vp;	/*	 * Call a file system specific routine to mount.	 */	if ((err = VFS_MOUNT(mp, dev, flags, data)) != 0)		goto err4;	/*	 * Keep reference count for root/covered vnode.	 */	vn_unlock(vp);	if (vp_covered)		vn_unlock(vp_covered);	/*	 * Insert to mount list	 */	list_insert(&mount_list, &mp->m_link);	MOUNT_UNLOCK();	return 0; err4:	vput(vp); err3:	if (vp_covered)		vput(vp_covered); err2:	free(mp); err1:	device_close(device);	MOUNT_UNLOCK();	return err;}int sys_umount(char *path){	mount_t mp;	list_t head, n;	int err;	dprintf("sys_umount: path=%s\n", path);	MOUNT_LOCK();	/* Get mount entry */	head = &mount_list;	for (n = list_first(head); n != head; n = list_next(n)) {		mp = list_entry(n, struct mount, m_link);		if (!strcmp(path, mp->m_path))			break;	}	if (n == head) {		err = EINVAL;		goto out;	}	/*	 * Root fs can not be unmounted.	 */	if (mp->m_covered == NULL) {		err = EINVAL;		goto out;	}	if ((err = VFS_UNMOUNT(mp)) != 0)		goto out;	list_remove(&mp->m_link);	/* Decrement referece count of root vnode */	vrele(mp->m_covered);	if (mp->m_dev)		device_close((device_t)mp->m_dev);	free(mp); out:	MOUNT_UNLOCK();	return err;}int sys_sync(void){	mount_t mp;	list_t head, n;	/* Call each mounted file system. */	MOUNT_LOCK();	head = &mount_list;	for (n = list_first(head); n != head; n = list_next(n)) {		mp = list_entry(n, struct mount, m_link);		VFS_SYNC(mp);	}	MOUNT_UNLOCK();	return 0;}/* * Compare two path strings. Return matched length. * * @path: target path. * @root: vfs root path as mount point. */static size_t count_match(char *path, char *mount_root){	size_t len = 0;	while (*path && *mount_root) {		if (*path++ != *mount_root++)			break;		len++;	}	if (*mount_root != '\0')		return 0;	if (len == 1 && *(path - 1) == '/')		return 1;	if (*path == '\0' || *path == '/')		return len;	return 0;}/* * Get the root directory and mount point for specified path. * * @path: full path. * @mp: mount point to return. * @root: pointer to root directory in path. */int vfs_findroot(char *path, mount_t *mp, char **root){	mount_t m, tmp;	list_t head, n;	size_t len, max_len = 0;	if (!path)		return -1;	/* Find mount point from nearest path */	MOUNT_LOCK();	m = NULL;	head = &mount_list;	for (n = list_first(head); n != head; n = list_next(n)) {		tmp = list_entry(n, struct mount, m_link);		len = count_match(path, tmp->m_path);		if (len > max_len) {			max_len = len;			m = tmp;		}	}	MOUNT_UNLOCK();	if (m == NULL)		return -1;	*root = (char *)(path + max_len);	if (**root == '/')		(*root)++;	*mp = m;	return 0;}/* * Mark a mount point as busy. */void vfs_busy(mount_t mp){	MOUNT_LOCK();	mp->m_count++;	MOUNT_UNLOCK();}/* * Mark a mount point as busy. */void vfs_unbusy(mount_t mp){	MOUNT_LOCK();	mp->m_count--;	MOUNT_UNLOCK();}#ifdef DEBUGvoid mount_dump(void){	list_t head, n;	mount_t mp;	MOUNT_LOCK();	printf("mount_dump\n");	printf("dev      count root\n");	printf("-------- ----- --------\n");	head = &mount_list;	for (n = list_first(head); n != head; n = list_next(n)) {		mp = list_entry(n, struct mount, m_link);		printf("%8x %5d %s\n", mp->m_dev, mp->m_count, mp->m_path);	}	MOUNT_UNLOCK();}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -