📄 fs_native.c
字号:
/* * This Cplant(TM) source code is the property of Sandia National * Laboratories. * * This Cplant(TM) source code is copyrighted by Sandia National * Laboratories. * * The redistribution of this Cplant(TM) source code is subject to the * terms of the GNU Lesser General Public License * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) * * Cplant(TM) Copyright 1998-2004 Sandia Corporation. * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive * license for use of this work by or on behalf of the US Government. * Export of this program may require a license from the United States * Government. *//* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Questions or comments about this library should be sent to: * * Lee Ward * Sandia National Laboratories, New Mexico * P.O. Box 5800 * Albuquerque, NM 87185-1110 * * lee@sandia.gov */#ifdef __linux__#define _BSD_SOURCE#endif#include <stdio.h> /* for NULL */#include <stdlib.h>#ifdef __linux__#include <string.h>#endif#include <unistd.h>#if !(defined(REDSTORM) || defined(MAX_IOVEC))#include <limits.h>#endif#include <errno.h>#include <assert.h>#include <syscall.h>#include <sys/time.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/fcntl.h>#if 0#include <sys/vfs.h>#endif#ifdef _HAVE_STATVFS#include <sys/statvfs.h>#include <sys/statfs.h>#endif#include <utime.h>#include <sys/uio.h>#include <sys/queue.h>#include "sysio.h"#include "xtio.h"#include "native.h"#include "fs.h"#include "mount.h"#include "inode.h"#include "fs_native.h"#ifdef REDSTORM#include <sys/uio.h>#endif#if defined(SYSIO_SYS_getdirentries)#define DIR_CVT_64 0#elif defined(SYSIO_SYS_getdents64)#define DIR_CVT_64 0#elif defined(SYSIO_SYS_getdents)#if defined(_LARGEFILE64_SOURCE)#define DIR_CVT_64 1/* * Kernel version of directory entry. */struct linux_dirent { unsigned long ld_ino; unsigned long ld_off; unsigned short ld_reclen; char ld_name[1];};#include <dirent.h>#else /* !defined(_LARGEFILE64_SOURCE) */#define DIR_CVT_64 0#endif /* defined(_LARGEFILE64_SOURCE) */#else /* catch-none */#error No usable directory fill entries interface available#endif/* * Native file system information we keep per FS. */struct native_filesystem { time_t nfs_atimo; /* attr timeout (sec) */};/* * Given fs, return driver private part. */#define FS2NFS(fs) \ ((struct native_filesystem *)(fs)->fs_private)/* * Native file identifiers format. */struct native_inode_identifier { dev_t dev; /* device number */ ino_t ino; /* i-number */#ifdef HAVE_GENERATION unsigned int gen; /* generation number */#endif};/* * Driver-private i-node information we keep about local host file * system objects. */struct native_inode { unsigned ni_seekok : 1, /* can seek? */ ni_attrvalid : 1, /* cached attrs ok? */ ni_resetfpos : 1; /* reset fpos? */ struct native_inode_identifier ni_ident; /* unique identifier */ struct file_identifier ni_fileid; /* ditto */ int ni_fd; /* host fildes */ int ni_oflags; /* flags, from open */ unsigned ni_nopens; /* soft ref count */ _SYSIO_OFF_T ni_fpos; /* current pos */ time_t ni_attrtim; /* attrs expire time */};/* * Cached attributes usable? */#define NATIVE_ATTRS_VALID(nino, t) \ ((nino)->ni_attrtim && (t) < (nino)->ni_attrtim)/* * Native IO path arguments. */struct native_io { char nio_op; /* 'r' or 'w' */ struct native_inode *nio_nino; /* native ino */};static int native_inop_lookup(struct pnode *pno, struct inode **inop, struct intent *intnt, const char *path);static int native_inop_getattr(struct pnode *pno, struct inode *ino, struct intnl_stat *stbuf);static int native_inop_setattr(struct pnode *pno, struct inode *ino, unsigned mask, struct intnl_stat *stbuf);static ssize_t native_filldirentries(struct inode *ino, _SYSIO_OFF_T *posp, char *buf, size_t nbytes);static int native_inop_mkdir(struct pnode *pno, mode_t mode);static int native_inop_rmdir(struct pnode *pno);static int native_inop_symlink(struct pnode *pno, const char *data);static int native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz);static int native_inop_open(struct pnode *pno, int flags, mode_t mode);static int native_inop_close(struct inode *ino);static int native_inop_link(struct pnode *old, struct pnode *new);static int native_inop_unlink(struct pnode *pno);static int native_inop_rename(struct pnode *old, struct pnode *new);static int native_inop_read(struct inode *ino, struct ioctx *ioctx);static int native_inop_write(struct inode *ino, struct ioctx *ioctx);static _SYSIO_OFF_T native_inop_pos(struct inode *ino, _SYSIO_OFF_T off);static int native_inop_iodone(struct ioctx *ioctx);static int native_inop_fcntl(struct inode *ino, int cmd, va_list ap, int *rtn);static int native_inop_sync(struct inode *ino);static int native_inop_datasync(struct inode *ino);static int native_inop_ioctl(struct inode *ino, unsigned long int request, va_list ap);static int native_inop_mknod(struct pnode *pno, mode_t mode, dev_t dev);#ifdef _HAVE_STATVFSstatic int native_inop_statvfs(struct pnode *pno, struct inode *ino, struct intnl_statvfs *buf);#endifstatic void native_inop_gone(struct inode *ino);static struct inode_ops native_i_ops = { native_inop_lookup, native_inop_getattr, native_inop_setattr, native_filldirentries, native_inop_mkdir, native_inop_rmdir, native_inop_symlink, native_inop_readlink, native_inop_open, native_inop_close, native_inop_link, native_inop_unlink, native_inop_rename, native_inop_read, native_inop_write, native_inop_pos, native_inop_iodone, native_inop_fcntl, native_inop_sync, native_inop_datasync, native_inop_ioctl, native_inop_mknod,#ifdef _HAVE_STATVFS native_inop_statvfs,#endif native_inop_gone};static int native_fsswop_mount(const char *source, unsigned flags, const void *data, struct pnode *tocover, struct mount **mntp);static struct fssw_ops native_fssw_ops = { native_fsswop_mount};static void native_fsop_gone(struct filesys *fs);static struct filesys_ops native_inodesys_ops = { native_fsop_gone,};/* * This example driver plays a strange game. It maintains a private, * internal mount -- It's own separate, rooted, name space. The local * file system's entire name space is available via this tree. * * This simplifies the implementation. At mount time, we need to generate * a path-node to be used as a root. This allows us to look up the needed * node in the host name space and leverage a whole lot of support from * the system. */static struct mount *native_internal_mount = NULL;/* * Given i-node, return driver private part. */#define I2NI(ino) ((struct native_inode *)((ino)->i_private))/* * stat -- by path. */static intnative_stat(const char *path, struct inode *ino, time_t t, struct intnl_stat *buf){ struct native_inode *nino; int err; struct _sysio_native_stat stbuf; nino = ino ? I2NI(ino) : NULL; if (path) err = syscall(SYSIO_SYS_stat, path, &stbuf); else if (nino && nino->ni_fd >= 0) err = syscall(SYSIO_SYS_fstat, nino->ni_fd, &stbuf); else abort(); if (err) { if (nino) nino->ni_attrtim = 0; return -errno; } if (nino) { nino->ni_attrtim = t; SYSIO_COPY_STAT(&stbuf, &ino->i_stbuf); if (buf) *buf = ino->i_stbuf; return 0; } if (!buf) return 0; SYSIO_COPY_STAT(&stbuf, buf); return 0;}/* * Introduce an i-node to the system. */static struct inode *native_i_new(struct filesys *fs, time_t expiration, struct intnl_stat *buf){ struct native_inode *nino; struct inode *ino; nino = malloc(sizeof(struct native_inode)); if (!nino) return NULL; bzero(&nino->ni_ident, sizeof(nino->ni_ident)); nino->ni_seekok = 0; nino->ni_attrvalid = 0; nino->ni_resetfpos = 0; nino->ni_ident.dev = buf->st_dev; nino->ni_ident.ino = buf->st_ino;#ifdef HAVE_GENERATION nino->ni_ident.gen = buf->st_gen;#endif nino->ni_fileid.fid_data = &nino->ni_ident; nino->ni_fileid.fid_len = sizeof(nino->ni_ident); nino->ni_fd = -1; nino->ni_oflags = 0; nino->ni_nopens = 0; nino->ni_fpos = 0; nino->ni_attrtim = expiration; ino = _sysio_i_new(fs, &nino->ni_fileid, buf, 0, &native_i_ops, nino); if (!ino) free(nino); return ino;}/* * Initialize this driver. */int_sysio_native_init(){ /* * Capture current process umask and reset our process umask to * zero. All permission bits to open/creat/setattr are absolute -- * They've already had a umask applied, when appropriate. */#ifndef REDSTORM _sysio_umask = syscall(SYSIO_SYS_umask, 0); /* * For Red Storm, this functionality is handled in cstart. * The mask to be "captured" has been sent already. * This eliminates a system call from every node! */#endif /* REDSTORM */ return _sysio_fssw_register("native", &native_fssw_ops);}/* * Create private, internal, view of the hosts name space. */static intcreate_internal_namespace(const void *data){ char *opts; ssize_t len; char *cp; struct native_filesystem *nfs; int err; struct mount *mnt; struct inode *rootino; struct pnode_base *rootpb; static struct qstr noname = { NULL, 0, 0 }; struct filesys *fs; time_t t; struct intnl_stat stbuf; unsigned long ul; static struct option_value_info v[] = { { "atimo", "30" }, { NULL, NULL } }; if (native_internal_mount) { /* * Reentered! */ abort(); } /* * Get mount options. */ opts = NULL; if (data && (len = strlen((char *)data))) { opts = malloc(len + 1); if (!opts) return -ENOMEM; (void )strcpy(opts, data); if (_sysio_get_args(opts, v) - opts != (ssize_t )len) return -EINVAL; } ul = strtoul(v[0].ovi_value, &cp, 0); if (*cp != '\0' || ul >= UINT_MAX) return -EINVAL; if (opts) { free(opts); opts = NULL; } /* * We maintain an artificial, internal, name space in order to * have access to fully qualified path names in the various routines. * Initialize that name space now. */ fs = NULL; mnt = NULL; rootino = NULL; rootpb = NULL; /* * This really should be per-mount. Hmm, but that's best done * as proper sub-mounts in the core and not this driver. We reconcile * now, here, by putting the mount options on the file system. That * means they are global and only can be passed at the initial mount. * * Maybe do it right some day? */ nfs = malloc(sizeof(struct native_filesystem)); if (!nfs) { err = -ENOMEM; goto error; } nfs->nfs_atimo = ul; if ((unsigned long)nfs->nfs_atimo != ul) { err = -EINVAL; goto error; } fs = _sysio_fs_new(&native_inodesys_ops, 0, nfs); if (!fs) { err = -ENOMEM; goto error; } /* * Get root i-node. */ t = _SYSIO_LOCAL_TIME(); err = native_stat("/", NULL, 0, &stbuf); if (err) goto error; rootino = native_i_new(fs, t + FS2NFS(fs)->nfs_atimo, &stbuf); if (!rootino) { err = -ENOMEM; goto error; } /* * Generate base path-node for root. */ rootpb = _sysio_pb_new(&noname, NULL, rootino); if (!rootpb) { err = -ENOMEM; goto error; } /* * Mount it. This name space is disconnected from the * rest of the system -- Only available within this driver. */ err = _sysio_do_mount(fs, rootpb, 0, NULL, &mnt); if (err) goto error; native_internal_mount = mnt; return 0;error: if (mnt) { if (_sysio_do_unmount(mnt) != 0) abort(); nfs = NULL; fs = NULL; rootpb = NULL; rootino = NULL; } if (rootpb) _sysio_pb_gone(rootpb); if (fs) { FS_RELE(fs); nfs = NULL; } if (nfs) free(nfs); if (opts) free(opts); return err;}static intnative_fsswop_mount(const char *source, unsigned flags, const void *data, struct pnode *tocover, struct mount **mntp){ int err; struct nameidata nameidata; struct mount *mnt; /* * Caller must use fully qualified path names when specifying * the source. */ if (*source != '/') return -ENOENT; if (!native_internal_mount) { err = create_internal_namespace(data); if (err) return err; } else if (data && *(char *)data) return -EINVAL; /* * Lookup the source in the internally maintained name space. */ ND_INIT(&nameidata, 0, source, native_internal_mount->mnt_root, NULL); err = _sysio_path_walk(native_internal_mount->mnt_root, &nameidata); if (err) return err; /* * Have path-node specified by the given source argument. Let the * system finish the job, now. */ err = _sysio_do_mount(native_internal_mount->mnt_fs, nameidata.nd_pno->p_base, flags, tocover, &mnt); /* * Release the internal name space pnode and clean up any * aliases we might have generated. We really don't need to cache them * as they are only used at mount time.. */ P_RELE(nameidata.nd_pno); (void )_sysio_p_prune(native_internal_mount->mnt_root); if (!err) { FS_REF(native_internal_mount->mnt_fs); *mntp = mnt; } return err;}static intnative_i_invalid(struct inode *inop, struct intnl_stat *stat){ struct native_inode *nino; /* * Validate passed in inode against stat struct info */ nino = I2NI(inop); if (!nino->ni_attrtim || (nino->ni_ident.dev != stat->st_dev || nino->ni_ident.ino != stat->st_ino ||#ifdef HAVE_GENERATION nino->ni_ident.gen != stat->st_gen ||#endif ((inop)->i_stbuf.st_mode & S_IFMT) != (stat->st_mode & S_IFMT)) || (((inop)->i_stbuf.st_rdev != stat->st_rdev) && (S_ISCHR((inop)->i_stbuf.st_mode) || S_ISBLK((inop)->i_stbuf.st_mode)))) { nino->ni_attrtim = 0; /* invalidate attrs */ return 1; } return 0;}static struct inode *native_iget(struct filesys *fs, time_t expire, struct intnl_stat *stbp){ struct inode *ino; struct native_inode_identifier ident; struct file_identifier fileid; bzero(&ident, sizeof(ident));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -