update name of code to labcodes
This commit is contained in:
116
labcodes/lab8/kern/fs/vfs/inode.c
Normal file
116
labcodes/lab8/kern/fs/vfs/inode.c
Normal file
@@ -0,0 +1,116 @@
|
||||
#include <defs.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <atomic.h>
|
||||
#include <vfs.h>
|
||||
#include <inode.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
#include <kmalloc.h>
|
||||
|
||||
/* *
|
||||
* __alloc_inode - alloc a inode structure and initialize in_type
|
||||
* */
|
||||
struct inode *
|
||||
__alloc_inode(int type) {
|
||||
struct inode *node;
|
||||
if ((node = kmalloc(sizeof(struct inode))) != NULL) {
|
||||
node->in_type = type;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/* *
|
||||
* inode_init - initialize a inode structure
|
||||
* invoked by vop_init
|
||||
* */
|
||||
void
|
||||
inode_init(struct inode *node, const struct inode_ops *ops, struct fs *fs) {
|
||||
node->ref_count = 0;
|
||||
node->open_count = 0;
|
||||
node->in_ops = ops, node->in_fs = fs;
|
||||
vop_ref_inc(node);
|
||||
}
|
||||
|
||||
/* *
|
||||
* inode_kill - kill a inode structure
|
||||
* invoked by vop_kill
|
||||
* */
|
||||
void
|
||||
inode_kill(struct inode *node) {
|
||||
assert(inode_ref_count(node) == 0);
|
||||
assert(inode_open_count(node) == 0);
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
/* *
|
||||
* inode_ref_inc - increment ref_count
|
||||
* invoked by vop_ref_inc
|
||||
* */
|
||||
int
|
||||
inode_ref_inc(struct inode *node) {
|
||||
node->ref_count += 1;
|
||||
return node->ref_count;
|
||||
}
|
||||
|
||||
/* *
|
||||
* inode_ref_dec - decrement ref_count
|
||||
* invoked by vop_ref_dec
|
||||
* calls vop_reclaim if the ref_count hits zero
|
||||
* */
|
||||
int
|
||||
inode_ref_dec(struct inode *node) {
|
||||
assert(inode_ref_count(node) > 0);
|
||||
int ref_count, ret;
|
||||
node->ref_count-= 1;
|
||||
ref_count = node->ref_count;
|
||||
if (ref_count == 0) {
|
||||
if ((ret = vop_reclaim(node)) != 0 && ret != -E_BUSY) {
|
||||
cprintf("vfs: warning: vop_reclaim: %e.\n", ret);
|
||||
}
|
||||
}
|
||||
return ref_count;
|
||||
}
|
||||
|
||||
/* *
|
||||
* inode_open_inc - increment the open_count
|
||||
* invoked by vop_open_inc
|
||||
* */
|
||||
int
|
||||
inode_open_inc(struct inode *node) {
|
||||
node->open_count += 1;
|
||||
return node->open_count;
|
||||
}
|
||||
|
||||
/* *
|
||||
* inode_open_dec - decrement the open_count
|
||||
* invoked by vop_open_dec
|
||||
* calls vop_close if the open_count hits zero
|
||||
* */
|
||||
int
|
||||
inode_open_dec(struct inode *node) {
|
||||
assert(inode_open_count(node) > 0);
|
||||
int open_count, ret;
|
||||
node->open_count -= 1;
|
||||
open_count = node->open_count;
|
||||
if (open_count == 0) {
|
||||
if ((ret = vop_close(node)) != 0) {
|
||||
cprintf("vfs: warning: vop_close: %e.\n", ret);
|
||||
}
|
||||
}
|
||||
return open_count;
|
||||
}
|
||||
|
||||
/* *
|
||||
* inode_check - check the various things being valid
|
||||
* called before all vop_* calls
|
||||
* */
|
||||
void
|
||||
inode_check(struct inode *node, const char *opstr) {
|
||||
assert(node != NULL && node->in_ops != NULL);
|
||||
assert(node->in_ops->vop_magic == VOP_MAGIC);
|
||||
int ref_count = inode_ref_count(node), open_count = inode_open_count(node);
|
||||
assert(ref_count >= open_count && open_count >= 0);
|
||||
assert(ref_count < MAX_INODE_COUNT && open_count < MAX_INODE_COUNT);
|
||||
}
|
||||
|
||||
248
labcodes/lab8/kern/fs/vfs/inode.h
Normal file
248
labcodes/lab8/kern/fs/vfs/inode.h
Normal file
@@ -0,0 +1,248 @@
|
||||
#ifndef __KERN_FS_VFS_INODE_H__
|
||||
#define __KERN_FS_VFS_INODE_H__
|
||||
|
||||
#include <defs.h>
|
||||
#include <dev.h>
|
||||
#include <sfs.h>
|
||||
#include <atomic.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct stat;
|
||||
struct iobuf;
|
||||
|
||||
/*
|
||||
* A struct inode is an abstract representation of a file.
|
||||
*
|
||||
* It is an interface that allows the kernel's filesystem-independent
|
||||
* code to interact usefully with multiple sets of filesystem code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstract low-level file.
|
||||
*
|
||||
* Note: in_info is Filesystem-specific data, in_type is the inode type
|
||||
*
|
||||
* open_count is managed using VOP_INCOPEN and VOP_DECOPEN by
|
||||
* vfs_open() and vfs_close(). Code above the VFS layer should not
|
||||
* need to worry about it.
|
||||
*/
|
||||
struct inode {
|
||||
union {
|
||||
struct device __device_info;
|
||||
struct sfs_inode __sfs_inode_info;
|
||||
} in_info;
|
||||
enum {
|
||||
inode_type_device_info = 0x1234,
|
||||
inode_type_sfs_inode_info,
|
||||
} in_type;
|
||||
int ref_count;
|
||||
int open_count;
|
||||
struct fs *in_fs;
|
||||
const struct inode_ops *in_ops;
|
||||
};
|
||||
|
||||
#define __in_type(type) inode_type_##type##_info
|
||||
|
||||
#define check_inode_type(node, type) ((node)->in_type == __in_type(type))
|
||||
|
||||
#define __vop_info(node, type) \
|
||||
({ \
|
||||
struct inode *__node = (node); \
|
||||
assert(__node != NULL && check_inode_type(__node, type)); \
|
||||
&(__node->in_info.__##type##_info); \
|
||||
})
|
||||
|
||||
#define vop_info(node, type) __vop_info(node, type)
|
||||
|
||||
#define info2node(info, type) \
|
||||
to_struct((info), struct inode, in_info.__##type##_info)
|
||||
|
||||
struct inode *__alloc_inode(int type);
|
||||
|
||||
#define alloc_inode(type) __alloc_inode(__in_type(type))
|
||||
|
||||
#define MAX_INODE_COUNT 0x10000
|
||||
|
||||
int inode_ref_inc(struct inode *node);
|
||||
int inode_ref_dec(struct inode *node);
|
||||
int inode_open_inc(struct inode *node);
|
||||
int inode_open_dec(struct inode *node);
|
||||
|
||||
void inode_init(struct inode *node, const struct inode_ops *ops, struct fs *fs);
|
||||
void inode_kill(struct inode *node);
|
||||
|
||||
#define VOP_MAGIC 0x8c4ba476
|
||||
|
||||
/*
|
||||
* Abstract operations on a inode.
|
||||
*
|
||||
* These are used in the form VOP_FOO(inode, args), which are macros
|
||||
* that expands to inode->inode_ops->vop_foo(inode, args). The operations
|
||||
* "foo" are:
|
||||
*
|
||||
* vop_open - Called on open() of a file. Can be used to
|
||||
* reject illegal or undesired open modes. Note that
|
||||
* various operations can be performed without the
|
||||
* file actually being opened.
|
||||
* The inode need not look at O_CREAT, O_EXCL, or
|
||||
* O_TRUNC, as these are handled in the VFS layer.
|
||||
*
|
||||
* VOP_EACHOPEN should not be called directly from
|
||||
* above the VFS layer - use vfs_open() to open inodes.
|
||||
* This maintains the open count so VOP_LASTCLOSE can
|
||||
* be called at the right time.
|
||||
*
|
||||
* vop_close - To be called on *last* close() of a file.
|
||||
*
|
||||
* VOP_LASTCLOSE should not be called directly from
|
||||
* above the VFS layer - use vfs_close() to close
|
||||
* inodes opened with vfs_open().
|
||||
*
|
||||
* vop_reclaim - Called when inode is no longer in use. Note that
|
||||
* this may be substantially after vop_lastclose is
|
||||
* called.
|
||||
*
|
||||
*****************************************
|
||||
*
|
||||
* vop_read - Read data from file to uio, at offset specified
|
||||
* in the uio, updating uio_resid to reflect the
|
||||
* amount read, and updating uio_offset to match.
|
||||
* Not allowed on directories or symlinks.
|
||||
*
|
||||
* vop_getdirentry - Read a single filename from a directory into a
|
||||
* uio, choosing what name based on the offset
|
||||
* field in the uio, and updating that field.
|
||||
* Unlike with I/O on regular files, the value of
|
||||
* the offset field is not interpreted outside
|
||||
* the filesystem and thus need not be a byte
|
||||
* count. However, the uio_resid field should be
|
||||
* handled in the normal fashion.
|
||||
* On non-directory objects, return ENOTDIR.
|
||||
*
|
||||
* vop_write - Write data from uio to file at offset specified
|
||||
* in the uio, updating uio_resid to reflect the
|
||||
* amount written, and updating uio_offset to match.
|
||||
* Not allowed on directories or symlinks.
|
||||
*
|
||||
* vop_ioctl - Perform ioctl operation OP on file using data
|
||||
* DATA. The interpretation of the data is specific
|
||||
* to each ioctl.
|
||||
*
|
||||
* vop_fstat -Return info about a file. The pointer is a
|
||||
* pointer to struct stat; see stat.h.
|
||||
*
|
||||
* vop_gettype - Return type of file. The values for file types
|
||||
* are in sfs.h.
|
||||
*
|
||||
* vop_tryseek - Check if seeking to the specified position within
|
||||
* the file is legal. (For instance, all seeks
|
||||
* are illegal on serial port devices, and seeks
|
||||
* past EOF on files whose sizes are fixed may be
|
||||
* as well.)
|
||||
*
|
||||
* vop_fsync - Force any dirty buffers associated with this file
|
||||
* to stable storage.
|
||||
*
|
||||
* vop_truncate - Forcibly set size of file to the length passed
|
||||
* in, discarding any excess blocks.
|
||||
*
|
||||
* vop_namefile - Compute pathname relative to filesystem root
|
||||
* of the file and copy to the specified io buffer.
|
||||
* Need not work on objects that are not
|
||||
* directories.
|
||||
*
|
||||
*****************************************
|
||||
*
|
||||
* vop_creat - Create a regular file named NAME in the passed
|
||||
* directory DIR. If boolean EXCL is true, fail if
|
||||
* the file already exists; otherwise, use the
|
||||
* existing file if there is one. Hand back the
|
||||
* inode for the file as per vop_lookup.
|
||||
*
|
||||
*****************************************
|
||||
*
|
||||
* vop_lookup - Parse PATHNAME relative to the passed directory
|
||||
* DIR, and hand back the inode for the file it
|
||||
* refers to. May destroy PATHNAME. Should increment
|
||||
* refcount on inode handed back.
|
||||
*/
|
||||
struct inode_ops {
|
||||
unsigned long vop_magic;
|
||||
int (*vop_open)(struct inode *node, uint32_t open_flags);
|
||||
int (*vop_close)(struct inode *node);
|
||||
int (*vop_read)(struct inode *node, struct iobuf *iob);
|
||||
int (*vop_write)(struct inode *node, struct iobuf *iob);
|
||||
int (*vop_fstat)(struct inode *node, struct stat *stat);
|
||||
int (*vop_fsync)(struct inode *node);
|
||||
int (*vop_namefile)(struct inode *node, struct iobuf *iob);
|
||||
int (*vop_getdirentry)(struct inode *node, struct iobuf *iob);
|
||||
int (*vop_reclaim)(struct inode *node);
|
||||
int (*vop_gettype)(struct inode *node, uint32_t *type_store);
|
||||
int (*vop_tryseek)(struct inode *node, off_t pos);
|
||||
int (*vop_truncate)(struct inode *node, off_t len);
|
||||
int (*vop_create)(struct inode *node, const char *name, bool excl, struct inode **node_store);
|
||||
int (*vop_lookup)(struct inode *node, char *path, struct inode **node_store);
|
||||
int (*vop_ioctl)(struct inode *node, int op, void *data);
|
||||
};
|
||||
|
||||
/*
|
||||
* Consistency check
|
||||
*/
|
||||
void inode_check(struct inode *node, const char *opstr);
|
||||
|
||||
#define __vop_op(node, sym) \
|
||||
({ \
|
||||
struct inode *__node = (node); \
|
||||
assert(__node != NULL && __node->in_ops != NULL && __node->in_ops->vop_##sym != NULL); \
|
||||
inode_check(__node, #sym); \
|
||||
__node->in_ops->vop_##sym; \
|
||||
})
|
||||
|
||||
#define vop_open(node, open_flags) (__vop_op(node, open)(node, open_flags))
|
||||
#define vop_close(node) (__vop_op(node, close)(node))
|
||||
#define vop_read(node, iob) (__vop_op(node, read)(node, iob))
|
||||
#define vop_write(node, iob) (__vop_op(node, write)(node, iob))
|
||||
#define vop_fstat(node, stat) (__vop_op(node, fstat)(node, stat))
|
||||
#define vop_fsync(node) (__vop_op(node, fsync)(node))
|
||||
#define vop_namefile(node, iob) (__vop_op(node, namefile)(node, iob))
|
||||
#define vop_getdirentry(node, iob) (__vop_op(node, getdirentry)(node, iob))
|
||||
#define vop_reclaim(node) (__vop_op(node, reclaim)(node))
|
||||
#define vop_ioctl(node, op, data) (__vop_op(node, ioctl)(node, op, data))
|
||||
#define vop_gettype(node, type_store) (__vop_op(node, gettype)(node, type_store))
|
||||
#define vop_tryseek(node, pos) (__vop_op(node, tryseek)(node, pos))
|
||||
#define vop_truncate(node, len) (__vop_op(node, truncate)(node, len))
|
||||
#define vop_create(node, name, excl, node_store) (__vop_op(node, create)(node, name, excl, node_store))
|
||||
#define vop_lookup(node, path, node_store) (__vop_op(node, lookup)(node, path, node_store))
|
||||
|
||||
|
||||
#define vop_fs(node) ((node)->in_fs)
|
||||
#define vop_init(node, ops, fs) inode_init(node, ops, fs)
|
||||
#define vop_kill(node) inode_kill(node)
|
||||
|
||||
/*
|
||||
* Reference count manipulation (handled above filesystem level)
|
||||
*/
|
||||
#define vop_ref_inc(node) inode_ref_inc(node)
|
||||
#define vop_ref_dec(node) inode_ref_dec(node)
|
||||
/*
|
||||
* Open count manipulation (handled above filesystem level)
|
||||
*
|
||||
* VOP_INCOPEN is called by vfs_open. VOP_DECOPEN is called by vfs_close.
|
||||
* Neither of these should need to be called from above the vfs layer.
|
||||
*/
|
||||
#define vop_open_inc(node) inode_open_inc(node)
|
||||
#define vop_open_dec(node) inode_open_dec(node)
|
||||
|
||||
|
||||
static inline int
|
||||
inode_ref_count(struct inode *node) {
|
||||
return node->ref_count;
|
||||
}
|
||||
|
||||
static inline int
|
||||
inode_open_count(struct inode *node) {
|
||||
return node->open_count;
|
||||
}
|
||||
|
||||
#endif /* !__KERN_FS_VFS_INODE_H__ */
|
||||
|
||||
97
labcodes/lab8/kern/fs/vfs/vfs.c
Normal file
97
labcodes/lab8/kern/fs/vfs/vfs.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <defs.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vfs.h>
|
||||
#include <inode.h>
|
||||
#include <sem.h>
|
||||
#include <kmalloc.h>
|
||||
#include <error.h>
|
||||
|
||||
static semaphore_t bootfs_sem;
|
||||
static struct inode *bootfs_node = NULL;
|
||||
|
||||
extern void vfs_devlist_init(void);
|
||||
|
||||
// __alloc_fs - allocate memory for fs, and set fs type
|
||||
struct fs *
|
||||
__alloc_fs(int type) {
|
||||
struct fs *fs;
|
||||
if ((fs = kmalloc(sizeof(struct fs))) != NULL) {
|
||||
fs->fs_type = type;
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
|
||||
// vfs_init - vfs initialize
|
||||
void
|
||||
vfs_init(void) {
|
||||
sem_init(&bootfs_sem, 1);
|
||||
vfs_devlist_init();
|
||||
}
|
||||
|
||||
// lock_bootfs - lock for bootfs
|
||||
static void
|
||||
lock_bootfs(void) {
|
||||
down(&bootfs_sem);
|
||||
}
|
||||
// ulock_bootfs - ulock for bootfs
|
||||
static void
|
||||
unlock_bootfs(void) {
|
||||
up(&bootfs_sem);
|
||||
}
|
||||
|
||||
// change_bootfs - set the new fs inode
|
||||
static void
|
||||
change_bootfs(struct inode *node) {
|
||||
struct inode *old;
|
||||
lock_bootfs();
|
||||
{
|
||||
old = bootfs_node, bootfs_node = node;
|
||||
}
|
||||
unlock_bootfs();
|
||||
if (old != NULL) {
|
||||
vop_ref_dec(old);
|
||||
}
|
||||
}
|
||||
|
||||
// vfs_set_bootfs - change the dir of file system
|
||||
int
|
||||
vfs_set_bootfs(char *fsname) {
|
||||
struct inode *node = NULL;
|
||||
if (fsname != NULL) {
|
||||
char *s;
|
||||
if ((s = strchr(fsname, ':')) == NULL || s[1] != '\0') {
|
||||
return -E_INVAL;
|
||||
}
|
||||
int ret;
|
||||
if ((ret = vfs_chdir(fsname)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = vfs_get_curdir(&node)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
change_bootfs(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// vfs_get_bootfs - get the inode of bootfs
|
||||
int
|
||||
vfs_get_bootfs(struct inode **node_store) {
|
||||
struct inode *node = NULL;
|
||||
if (bootfs_node != NULL) {
|
||||
lock_bootfs();
|
||||
{
|
||||
if ((node = bootfs_node) != NULL) {
|
||||
vop_ref_inc(bootfs_node);
|
||||
}
|
||||
}
|
||||
unlock_bootfs();
|
||||
}
|
||||
if (node == NULL) {
|
||||
return -E_NOENT;
|
||||
}
|
||||
*node_store = node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
191
labcodes/lab8/kern/fs/vfs/vfs.h
Normal file
191
labcodes/lab8/kern/fs/vfs/vfs.h
Normal file
@@ -0,0 +1,191 @@
|
||||
#ifndef __KERN_FS_VFS_VFS_H__
|
||||
#define __KERN_FS_VFS_VFS_H__
|
||||
|
||||
#include <defs.h>
|
||||
#include <fs.h>
|
||||
#include <sfs.h>
|
||||
|
||||
struct inode; // abstract structure for an on-disk file (inode.h)
|
||||
struct device; // abstract structure for a device (dev.h)
|
||||
struct iobuf; // kernel or userspace I/O buffer (iobuf.h)
|
||||
|
||||
/*
|
||||
* Abstract filesystem. (Or device accessible as a file.)
|
||||
*
|
||||
* Information:
|
||||
* fs_info : filesystem-specific data (sfs_fs)
|
||||
* fs_type : filesystem type
|
||||
* Operations:
|
||||
*
|
||||
* fs_sync - Flush all dirty buffers to disk.
|
||||
* fs_get_root - Return root inode of filesystem.
|
||||
* fs_unmount - Attempt unmount of filesystem.
|
||||
* fs_cleanup - Cleanup of filesystem.???
|
||||
*
|
||||
*
|
||||
* fs_get_root should increment the refcount of the inode returned.
|
||||
* It should not ever return NULL.
|
||||
*
|
||||
* If fs_unmount returns an error, the filesystem stays mounted, and
|
||||
* consequently the struct fs instance should remain valid. On success,
|
||||
* however, the filesystem object and all storage associated with the
|
||||
* filesystem should have been discarded/released.
|
||||
*
|
||||
*/
|
||||
struct fs {
|
||||
union {
|
||||
struct sfs_fs __sfs_info;
|
||||
} fs_info; // filesystem-specific data
|
||||
enum {
|
||||
fs_type_sfs_info,
|
||||
} fs_type; // filesystem type
|
||||
int (*fs_sync)(struct fs *fs); // Flush all dirty buffers to disk
|
||||
struct inode *(*fs_get_root)(struct fs *fs); // Return root inode of filesystem.
|
||||
int (*fs_unmount)(struct fs *fs); // Attempt unmount of filesystem.
|
||||
void (*fs_cleanup)(struct fs *fs); // Cleanup of filesystem.???
|
||||
};
|
||||
|
||||
#define __fs_type(type) fs_type_##type##_info
|
||||
|
||||
#define check_fs_type(fs, type) ((fs)->fs_type == __fs_type(type))
|
||||
|
||||
#define __fsop_info(_fs, type) ({ \
|
||||
struct fs *__fs = (_fs); \
|
||||
assert(__fs != NULL && check_fs_type(__fs, type)); \
|
||||
&(__fs->fs_info.__##type##_info); \
|
||||
})
|
||||
|
||||
#define fsop_info(fs, type) __fsop_info(fs, type)
|
||||
|
||||
#define info2fs(info, type) \
|
||||
to_struct((info), struct fs, fs_info.__##type##_info)
|
||||
|
||||
struct fs *__alloc_fs(int type);
|
||||
|
||||
#define alloc_fs(type) __alloc_fs(__fs_type(type))
|
||||
|
||||
// Macros to shorten the calling sequences.
|
||||
#define fsop_sync(fs) ((fs)->fs_sync(fs))
|
||||
#define fsop_get_root(fs) ((fs)->fs_get_root(fs))
|
||||
#define fsop_unmount(fs) ((fs)->fs_unmount(fs))
|
||||
#define fsop_cleanup(fs) ((fs)->fs_cleanup(fs))
|
||||
|
||||
/*
|
||||
* Virtual File System layer functions.
|
||||
*
|
||||
* The VFS layer translates operations on abstract on-disk files or
|
||||
* pathnames to operations on specific files on specific filesystems.
|
||||
*/
|
||||
void vfs_init(void);
|
||||
void vfs_cleanup(void);
|
||||
void vfs_devlist_init(void);
|
||||
|
||||
/*
|
||||
* VFS layer low-level operations.
|
||||
* See inode.h for direct operations on inodes.
|
||||
* See fs.h for direct operations on filesystems/devices.
|
||||
*
|
||||
* vfs_set_curdir - change current directory of current thread by inode
|
||||
* vfs_get_curdir - retrieve inode of current directory of current thread
|
||||
* vfs_get_root - get root inode for the filesystem named DEVNAME
|
||||
* vfs_get_devname - get mounted device name for the filesystem passed in
|
||||
*/
|
||||
int vfs_set_curdir(struct inode *dir);
|
||||
int vfs_get_curdir(struct inode **dir_store);
|
||||
int vfs_get_root(const char *devname, struct inode **root_store);
|
||||
const char *vfs_get_devname(struct fs *fs);
|
||||
|
||||
|
||||
/*
|
||||
* VFS layer high-level operations on pathnames
|
||||
* Because namei may destroy pathnames, these all may too.
|
||||
*
|
||||
* vfs_open - Open or create a file. FLAGS/MODE per the syscall.
|
||||
* vfs_close - Close a inode opened with vfs_open. Does not fail.
|
||||
* (See vfspath.c for a discussion of why.)
|
||||
* vfs_link - Create a hard link to a file.
|
||||
* vfs_symlink - Create a symlink PATH containing contents CONTENTS.
|
||||
* vfs_readlink - Read contents of a symlink into a uio.
|
||||
* vfs_mkdir - Create a directory. MODE per the syscall.
|
||||
* vfs_unlink - Delete a file/directory.
|
||||
* vfs_rename - rename a file.
|
||||
* vfs_chdir - Change current directory of current thread by name.
|
||||
* vfs_getcwd - Retrieve name of current directory of current thread.
|
||||
*
|
||||
*/
|
||||
int vfs_open(char *path, uint32_t open_flags, struct inode **inode_store);
|
||||
int vfs_close(struct inode *node);
|
||||
int vfs_link(char *old_path, char *new_path);
|
||||
int vfs_symlink(char *old_path, char *new_path);
|
||||
int vfs_readlink(char *path, struct iobuf *iob);
|
||||
int vfs_mkdir(char *path);
|
||||
int vfs_unlink(char *path);
|
||||
int vfs_rename(char *old_path, char *new_path);
|
||||
int vfs_chdir(char *path);
|
||||
int vfs_getcwd(struct iobuf *iob);
|
||||
|
||||
|
||||
/*
|
||||
* VFS layer mid-level operations.
|
||||
*
|
||||
* vfs_lookup - Like VOP_LOOKUP, but takes a full device:path name,
|
||||
* or a name relative to the current directory, and
|
||||
* goes to the correct filesystem.
|
||||
* vfs_lookparent - Likewise, for VOP_LOOKPARENT.
|
||||
*
|
||||
* Both of these may destroy the path passed in.
|
||||
*/
|
||||
int vfs_lookup(char *path, struct inode **node_store);
|
||||
int vfs_lookup_parent(char *path, struct inode **node_store, char **endp);
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*
|
||||
* vfs_set_bootfs - Set the filesystem that paths beginning with a
|
||||
* slash are sent to. If not set, these paths fail
|
||||
* with ENOENT. The argument should be the device
|
||||
* name or volume name for the filesystem (such as
|
||||
* "lhd0:") but need not have the trailing colon.
|
||||
*
|
||||
* vfs_get_bootfs - return the inode of the bootfs filesystem.
|
||||
*
|
||||
* vfs_add_fs - Add a hardwired filesystem to the VFS named device
|
||||
* list. It will be accessible as "devname:". This is
|
||||
* intended for filesystem-devices like emufs, and
|
||||
* gizmos like Linux procfs or BSD kernfs, not for
|
||||
* mounting filesystems on disk devices.
|
||||
*
|
||||
* vfs_add_dev - Add a device to the VFS named device list. If
|
||||
* MOUNTABLE is zero, the device will be accessible
|
||||
* as "DEVNAME:". If the mountable flag is set, the
|
||||
* device will be accessible as "DEVNAMEraw:" and
|
||||
* mountable under the name "DEVNAME". Thus, the
|
||||
* console, added with MOUNTABLE not set, would be
|
||||
* accessed by pathname as "con:", and lhd0, added
|
||||
* with mountable set, would be accessed by
|
||||
* pathname as "lhd0raw:" and mounted by passing
|
||||
* "lhd0" to vfs_mount.
|
||||
*
|
||||
* vfs_mount - Attempt to mount a filesystem on a device. The
|
||||
* device named by DEVNAME will be looked up and
|
||||
* passed, along with DATA, to the supplied function
|
||||
* MOUNTFUNC, which should create a struct fs and
|
||||
* return it in RESULT.
|
||||
*
|
||||
* vfs_unmount - Unmount the filesystem presently mounted on the
|
||||
* specified device.
|
||||
*
|
||||
* vfs_unmountall - Unmount all mounted filesystems.
|
||||
*/
|
||||
int vfs_set_bootfs(char *fsname);
|
||||
int vfs_get_bootfs(struct inode **node_store);
|
||||
|
||||
int vfs_add_fs(const char *devname, struct fs *fs);
|
||||
int vfs_add_dev(const char *devname, struct inode *devnode, bool mountable);
|
||||
|
||||
int vfs_mount(const char *devname, int (*mountfunc)(struct device *dev, struct fs **fs_store));
|
||||
int vfs_unmount(const char *devname);
|
||||
int vfs_unmount_all(void);
|
||||
|
||||
#endif /* !__KERN_FS_VFS_VFS_H__ */
|
||||
|
||||
309
labcodes/lab8/kern/fs/vfs/vfsdev.c
Normal file
309
labcodes/lab8/kern/fs/vfs/vfsdev.c
Normal file
@@ -0,0 +1,309 @@
|
||||
#include <defs.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vfs.h>
|
||||
#include <dev.h>
|
||||
#include <inode.h>
|
||||
#include <sem.h>
|
||||
#include <list.h>
|
||||
#include <kmalloc.h>
|
||||
#include <unistd.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
|
||||
// device info entry in vdev_list
|
||||
typedef struct {
|
||||
const char *devname;
|
||||
struct inode *devnode;
|
||||
struct fs *fs;
|
||||
bool mountable;
|
||||
list_entry_t vdev_link;
|
||||
} vfs_dev_t;
|
||||
|
||||
#define le2vdev(le, member) \
|
||||
to_struct((le), vfs_dev_t, member)
|
||||
|
||||
static list_entry_t vdev_list; // device info list in vfs layer
|
||||
static semaphore_t vdev_list_sem;
|
||||
|
||||
static void
|
||||
lock_vdev_list(void) {
|
||||
down(&vdev_list_sem);
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_vdev_list(void) {
|
||||
up(&vdev_list_sem);
|
||||
}
|
||||
|
||||
void
|
||||
vfs_devlist_init(void) {
|
||||
list_init(&vdev_list);
|
||||
sem_init(&vdev_list_sem, 1);
|
||||
}
|
||||
|
||||
// vfs_cleanup - finally clean (or sync) fs
|
||||
void
|
||||
vfs_cleanup(void) {
|
||||
if (!list_empty(&vdev_list)) {
|
||||
lock_vdev_list();
|
||||
{
|
||||
list_entry_t *list = &vdev_list, *le = list;
|
||||
while ((le = list_next(le)) != list) {
|
||||
vfs_dev_t *vdev = le2vdev(le, vdev_link);
|
||||
if (vdev->fs != NULL) {
|
||||
fsop_cleanup(vdev->fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
unlock_vdev_list();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_get_root - Given a device name (stdin, stdout, etc.), hand
|
||||
* back an appropriate inode.
|
||||
*/
|
||||
int
|
||||
vfs_get_root(const char *devname, struct inode **node_store) {
|
||||
assert(devname != NULL);
|
||||
int ret = -E_NO_DEV;
|
||||
if (!list_empty(&vdev_list)) {
|
||||
lock_vdev_list();
|
||||
{
|
||||
list_entry_t *list = &vdev_list, *le = list;
|
||||
while ((le = list_next(le)) != list) {
|
||||
vfs_dev_t *vdev = le2vdev(le, vdev_link);
|
||||
if (strcmp(devname, vdev->devname) == 0) {
|
||||
struct inode *found = NULL;
|
||||
if (vdev->fs != NULL) {
|
||||
found = fsop_get_root(vdev->fs);
|
||||
}
|
||||
else if (!vdev->mountable) {
|
||||
vop_ref_inc(vdev->devnode);
|
||||
found = vdev->devnode;
|
||||
}
|
||||
if (found != NULL) {
|
||||
ret = 0, *node_store = found;
|
||||
}
|
||||
else {
|
||||
ret = -E_NA_DEV;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
unlock_vdev_list();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_get_devname - Given a filesystem, hand back the name of the device it's mounted on.
|
||||
*/
|
||||
const char *
|
||||
vfs_get_devname(struct fs *fs) {
|
||||
assert(fs != NULL);
|
||||
list_entry_t *list = &vdev_list, *le = list;
|
||||
while ((le = list_next(le)) != list) {
|
||||
vfs_dev_t *vdev = le2vdev(le, vdev_link);
|
||||
if (vdev->fs == fs) {
|
||||
return vdev->devname;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* check_devname_confilct - Is there alreadily device which has the same name?
|
||||
*/
|
||||
static bool
|
||||
check_devname_conflict(const char *devname) {
|
||||
list_entry_t *list = &vdev_list, *le = list;
|
||||
while ((le = list_next(le)) != list) {
|
||||
vfs_dev_t *vdev = le2vdev(le, vdev_link);
|
||||
if (strcmp(vdev->devname, devname) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vfs_do_add - Add a new device to the VFS layer's device table.
|
||||
*
|
||||
* If "mountable" is set, the device will be treated as one that expects
|
||||
* to have a filesystem mounted on it, and a raw device will be created
|
||||
* for direct access.
|
||||
*/
|
||||
static int
|
||||
vfs_do_add(const char *devname, struct inode *devnode, struct fs *fs, bool mountable) {
|
||||
assert(devname != NULL);
|
||||
assert((devnode == NULL && !mountable) || (devnode != NULL && check_inode_type(devnode, device)));
|
||||
if (strlen(devname) > FS_MAX_DNAME_LEN) {
|
||||
return -E_TOO_BIG;
|
||||
}
|
||||
|
||||
int ret = -E_NO_MEM;
|
||||
char *s_devname;
|
||||
if ((s_devname = strdup(devname)) == NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
vfs_dev_t *vdev;
|
||||
if ((vdev = kmalloc(sizeof(vfs_dev_t))) == NULL) {
|
||||
goto failed_cleanup_name;
|
||||
}
|
||||
|
||||
ret = -E_EXISTS;
|
||||
lock_vdev_list();
|
||||
if (!check_devname_conflict(s_devname)) {
|
||||
unlock_vdev_list();
|
||||
goto failed_cleanup_vdev;
|
||||
}
|
||||
vdev->devname = s_devname;
|
||||
vdev->devnode = devnode;
|
||||
vdev->mountable = mountable;
|
||||
vdev->fs = fs;
|
||||
|
||||
list_add(&vdev_list, &(vdev->vdev_link));
|
||||
unlock_vdev_list();
|
||||
return 0;
|
||||
|
||||
failed_cleanup_vdev:
|
||||
kfree(vdev);
|
||||
failed_cleanup_name:
|
||||
kfree(s_devname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_add_fs - Add a new fs, by name. See vfs_do_add information for the description of
|
||||
* mountable.
|
||||
*/
|
||||
int
|
||||
vfs_add_fs(const char *devname, struct fs *fs) {
|
||||
return vfs_do_add(devname, NULL, fs, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_add_dev - Add a new device, by name. See vfs_do_add information for the description of
|
||||
* mountable.
|
||||
*/
|
||||
int
|
||||
vfs_add_dev(const char *devname, struct inode *devnode, bool mountable) {
|
||||
return vfs_do_add(devname, devnode, NULL, mountable);
|
||||
}
|
||||
|
||||
/*
|
||||
* find_mount - Look for a mountable device named DEVNAME.
|
||||
* Should already hold vdev_list lock.
|
||||
*/
|
||||
static int
|
||||
find_mount(const char *devname, vfs_dev_t **vdev_store) {
|
||||
assert(devname != NULL);
|
||||
list_entry_t *list = &vdev_list, *le = list;
|
||||
while ((le = list_next(le)) != list) {
|
||||
vfs_dev_t *vdev = le2vdev(le, vdev_link);
|
||||
if (vdev->mountable && strcmp(vdev->devname, devname) == 0) {
|
||||
*vdev_store = vdev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -E_NO_DEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_mount - Mount a filesystem. Once we've found the device, call MOUNTFUNC to
|
||||
* set up the filesystem and hand back a struct fs.
|
||||
*
|
||||
* The DATA argument is passed through unchanged to MOUNTFUNC.
|
||||
*/
|
||||
int
|
||||
vfs_mount(const char *devname, int (*mountfunc)(struct device *dev, struct fs **fs_store)) {
|
||||
int ret;
|
||||
lock_vdev_list();
|
||||
vfs_dev_t *vdev;
|
||||
if ((ret = find_mount(devname, &vdev)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
if (vdev->fs != NULL) {
|
||||
ret = -E_BUSY;
|
||||
goto out;
|
||||
}
|
||||
assert(vdev->devname != NULL && vdev->mountable);
|
||||
|
||||
struct device *dev = vop_info(vdev->devnode, device);
|
||||
if ((ret = mountfunc(dev, &(vdev->fs))) == 0) {
|
||||
assert(vdev->fs != NULL);
|
||||
cprintf("vfs: mount %s.\n", vdev->devname);
|
||||
}
|
||||
|
||||
out:
|
||||
unlock_vdev_list();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_unmount - Unmount a filesystem/device by name.
|
||||
* First calls FSOP_SYNC on the filesystem; then calls FSOP_UNMOUNT.
|
||||
*/
|
||||
int
|
||||
vfs_unmount(const char *devname) {
|
||||
int ret;
|
||||
lock_vdev_list();
|
||||
vfs_dev_t *vdev;
|
||||
if ((ret = find_mount(devname, &vdev)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
if (vdev->fs == NULL) {
|
||||
ret = -E_INVAL;
|
||||
goto out;
|
||||
}
|
||||
assert(vdev->devname != NULL && vdev->mountable);
|
||||
|
||||
if ((ret = fsop_sync(vdev->fs)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
if ((ret = fsop_unmount(vdev->fs)) == 0) {
|
||||
vdev->fs = NULL;
|
||||
cprintf("vfs: unmount %s.\n", vdev->devname);
|
||||
}
|
||||
|
||||
out:
|
||||
unlock_vdev_list();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_unmount_all - Global unmount function.
|
||||
*/
|
||||
int
|
||||
vfs_unmount_all(void) {
|
||||
if (!list_empty(&vdev_list)) {
|
||||
lock_vdev_list();
|
||||
{
|
||||
list_entry_t *list = &vdev_list, *le = list;
|
||||
while ((le = list_next(le)) != list) {
|
||||
vfs_dev_t *vdev = le2vdev(le, vdev_link);
|
||||
if (vdev->mountable && vdev->fs != NULL) {
|
||||
int ret;
|
||||
if ((ret = fsop_sync(vdev->fs)) != 0) {
|
||||
cprintf("vfs: warning: sync failed for %s: %e.\n", vdev->devname, ret);
|
||||
continue ;
|
||||
}
|
||||
if ((ret = fsop_unmount(vdev->fs)) != 0) {
|
||||
cprintf("vfs: warning: unmount failed for %s: %e.\n", vdev->devname, ret);
|
||||
continue ;
|
||||
}
|
||||
vdev->fs = NULL;
|
||||
cprintf("vfs: unmount %s.\n", vdev->devname);
|
||||
}
|
||||
}
|
||||
}
|
||||
unlock_vdev_list();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
110
labcodes/lab8/kern/fs/vfs/vfsfile.c
Normal file
110
labcodes/lab8/kern/fs/vfs/vfsfile.c
Normal file
@@ -0,0 +1,110 @@
|
||||
#include <defs.h>
|
||||
#include <string.h>
|
||||
#include <vfs.h>
|
||||
#include <inode.h>
|
||||
#include <unistd.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// open file in vfs, get/create inode for file with filename path.
|
||||
int
|
||||
vfs_open(char *path, uint32_t open_flags, struct inode **node_store) {
|
||||
bool can_write = 0;
|
||||
switch (open_flags & O_ACCMODE) {
|
||||
case O_RDONLY:
|
||||
break;
|
||||
case O_WRONLY:
|
||||
case O_RDWR:
|
||||
can_write = 1;
|
||||
break;
|
||||
default:
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
if (open_flags & O_TRUNC) {
|
||||
if (!can_write) {
|
||||
return -E_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int ret;
|
||||
struct inode *node;
|
||||
bool excl = (open_flags & O_EXCL) != 0;
|
||||
bool create = (open_flags & O_CREAT) != 0;
|
||||
ret = vfs_lookup(path, &node);
|
||||
|
||||
if (ret != 0) {
|
||||
if (ret == -16 && (create)) {
|
||||
char *name;
|
||||
struct inode *dir;
|
||||
if ((ret = vfs_lookup_parent(path, &dir, &name)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = vop_create(dir, name, excl, &node);
|
||||
} else return ret;
|
||||
} else if (excl && create) {
|
||||
return -E_EXISTS;
|
||||
}
|
||||
assert(node != NULL);
|
||||
|
||||
if ((ret = vop_open(node, open_flags)) != 0) {
|
||||
vop_ref_dec(node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
vop_open_inc(node);
|
||||
if (open_flags & O_TRUNC || create) {
|
||||
if ((ret = vop_truncate(node, 0)) != 0) {
|
||||
vop_open_dec(node);
|
||||
vop_ref_dec(node);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
*node_store = node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// close file in vfs
|
||||
int
|
||||
vfs_close(struct inode *node) {
|
||||
vop_open_dec(node);
|
||||
vop_ref_dec(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// unimplement
|
||||
int
|
||||
vfs_unlink(char *path) {
|
||||
return -E_UNIMP;
|
||||
}
|
||||
|
||||
// unimplement
|
||||
int
|
||||
vfs_rename(char *old_path, char *new_path) {
|
||||
return -E_UNIMP;
|
||||
}
|
||||
|
||||
// unimplement
|
||||
int
|
||||
vfs_link(char *old_path, char *new_path) {
|
||||
return -E_UNIMP;
|
||||
}
|
||||
|
||||
// unimplement
|
||||
int
|
||||
vfs_symlink(char *old_path, char *new_path) {
|
||||
return -E_UNIMP;
|
||||
}
|
||||
|
||||
// unimplement
|
||||
int
|
||||
vfs_readlink(char *path, struct iobuf *iob) {
|
||||
return -E_UNIMP;
|
||||
}
|
||||
|
||||
// unimplement
|
||||
int
|
||||
vfs_mkdir(char *path){
|
||||
return -E_UNIMP;
|
||||
}
|
||||
101
labcodes/lab8/kern/fs/vfs/vfslookup.c
Normal file
101
labcodes/lab8/kern/fs/vfs/vfslookup.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <defs.h>
|
||||
#include <string.h>
|
||||
#include <vfs.h>
|
||||
#include <inode.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* get_device- Common code to pull the device name, if any, off the front of a
|
||||
* path and choose the inode to begin the name lookup relative to.
|
||||
*/
|
||||
|
||||
static int
|
||||
get_device(char *path, char **subpath, struct inode **node_store) {
|
||||
int i, slash = -1, colon = -1;
|
||||
for (i = 0; path[i] != '\0'; i ++) {
|
||||
if (path[i] == ':') { colon = i; break; }
|
||||
if (path[i] == '/') { slash = i; break; }
|
||||
}
|
||||
if (colon < 0 && slash != 0) {
|
||||
/* *
|
||||
* No colon before a slash, so no device name specified, and the slash isn't leading
|
||||
* or is also absent, so this is a relative path or just a bare filename. Start from
|
||||
* the current directory, and use the whole thing as the subpath.
|
||||
* */
|
||||
*subpath = path;
|
||||
return vfs_get_curdir(node_store);
|
||||
}
|
||||
if (colon > 0) {
|
||||
/* device:path - get root of device's filesystem */
|
||||
path[colon] = '\0';
|
||||
|
||||
/* device:/path - skip slash, treat as device:path */
|
||||
while (path[++ colon] == '/');
|
||||
*subpath = path + colon;
|
||||
return vfs_get_root(path, node_store);
|
||||
}
|
||||
|
||||
/* *
|
||||
* we have either /path or :path
|
||||
* /path is a path relative to the root of the "boot filesystem"
|
||||
* :path is a path relative to the root of the current filesystem
|
||||
* */
|
||||
int ret;
|
||||
if (*path == '/') {
|
||||
if ((ret = vfs_get_bootfs(node_store)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(*path == ':');
|
||||
struct inode *node;
|
||||
if ((ret = vfs_get_curdir(&node)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
/* The current directory may not be a device, so it must have a fs. */
|
||||
assert(node->in_fs != NULL);
|
||||
*node_store = fsop_get_root(node->in_fs);
|
||||
vop_ref_dec(node);
|
||||
}
|
||||
|
||||
/* ///... or :/... */
|
||||
while (*(++ path) == '/');
|
||||
*subpath = path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_lookup - get the inode according to the path filename
|
||||
*/
|
||||
int
|
||||
vfs_lookup(char *path, struct inode **node_store) {
|
||||
int ret;
|
||||
struct inode *node;
|
||||
if ((ret = get_device(path, &path, &node)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
if (*path != '\0') {
|
||||
ret = vop_lookup(node, path, node_store);
|
||||
vop_ref_dec(node);
|
||||
return ret;
|
||||
}
|
||||
*node_store = node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_lookup_parent - Name-to-vnode translation.
|
||||
* (In BSD, both of these are subsumed by namei().)
|
||||
*/
|
||||
int
|
||||
vfs_lookup_parent(char *path, struct inode **node_store, char **endp){
|
||||
int ret;
|
||||
struct inode *node;
|
||||
if ((ret = get_device(path, &path, &node)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
*endp = path;
|
||||
*node_store = node;
|
||||
return 0;
|
||||
}
|
||||
126
labcodes/lab8/kern/fs/vfs/vfspath.c
Normal file
126
labcodes/lab8/kern/fs/vfs/vfspath.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include <defs.h>
|
||||
#include <string.h>
|
||||
#include <vfs.h>
|
||||
#include <inode.h>
|
||||
#include <iobuf.h>
|
||||
#include <stat.h>
|
||||
#include <proc.h>
|
||||
#include <error.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* get_cwd_nolock - retrieve current process's working directory. without lock protect
|
||||
*/
|
||||
static struct inode *
|
||||
get_cwd_nolock(void) {
|
||||
return current->filesp->pwd;
|
||||
}
|
||||
/*
|
||||
* set_cwd_nolock - set current working directory.
|
||||
*/
|
||||
static void
|
||||
set_cwd_nolock(struct inode *pwd) {
|
||||
current->filesp->pwd = pwd;
|
||||
}
|
||||
|
||||
/*
|
||||
* lock_cfs - lock the fs related process on current process
|
||||
*/
|
||||
static void
|
||||
lock_cfs(void) {
|
||||
lock_files(current->filesp);
|
||||
}
|
||||
/*
|
||||
* unlock_cfs - unlock the fs related process on current process
|
||||
*/
|
||||
static void
|
||||
unlock_cfs(void) {
|
||||
unlock_files(current->filesp);
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_get_curdir - Get current directory as a inode.
|
||||
*/
|
||||
int
|
||||
vfs_get_curdir(struct inode **dir_store) {
|
||||
struct inode *node;
|
||||
if ((node = get_cwd_nolock()) != NULL) {
|
||||
vop_ref_inc(node);
|
||||
*dir_store = node;
|
||||
return 0;
|
||||
}
|
||||
return -E_NOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_set_curdir - Set current directory as a inode.
|
||||
* The passed inode must in fact be a directory.
|
||||
*/
|
||||
int
|
||||
vfs_set_curdir(struct inode *dir) {
|
||||
int ret = 0;
|
||||
lock_cfs();
|
||||
struct inode *old_dir;
|
||||
if ((old_dir = get_cwd_nolock()) != dir) {
|
||||
if (dir != NULL) {
|
||||
uint32_t type;
|
||||
if ((ret = vop_gettype(dir, &type)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
if (!S_ISDIR(type)) {
|
||||
ret = -E_NOTDIR;
|
||||
goto out;
|
||||
}
|
||||
vop_ref_inc(dir);
|
||||
}
|
||||
set_cwd_nolock(dir);
|
||||
if (old_dir != NULL) {
|
||||
vop_ref_dec(old_dir);
|
||||
}
|
||||
}
|
||||
out:
|
||||
unlock_cfs();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs_chdir - Set current directory, as a pathname. Use vfs_lookup to translate
|
||||
* it to a inode.
|
||||
*/
|
||||
int
|
||||
vfs_chdir(char *path) {
|
||||
int ret;
|
||||
struct inode *node;
|
||||
if ((ret = vfs_lookup(path, &node)) == 0) {
|
||||
ret = vfs_set_curdir(node);
|
||||
vop_ref_dec(node);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* vfs_getcwd - retrieve current working directory(cwd).
|
||||
*/
|
||||
int
|
||||
vfs_getcwd(struct iobuf *iob) {
|
||||
int ret;
|
||||
struct inode *node;
|
||||
if ((ret = vfs_get_curdir(&node)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
assert(node->in_fs != NULL);
|
||||
|
||||
const char *devname = vfs_get_devname(node->in_fs);
|
||||
if ((ret = iobuf_move(iob, (char *)devname, strlen(devname), 1, NULL)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
char colon = ':';
|
||||
if ((ret = iobuf_move(iob, &colon, sizeof(colon), 1, NULL)) != 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = vop_namefile(node, iob);
|
||||
|
||||
out:
|
||||
vop_ref_dec(node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user