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 <stdio.h> /* for NULL */
54 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
60 #include <sys/types.h>
62 #include <sys/fcntl.h>
67 #include <sys/statvfs.h>
68 #include <sys/statfs.h>
72 #include <sys/queue.h>
80 #include "fs_native.h"
86 #if defined(SYS_getdirentries)
87 #define DIR_STREAMED 0
89 #elif defined(SYS_getdents64)
90 #define DIR_STREAMED 1
92 #elif defined(SYS_getdents)
93 #define DIR_STREAMED 1
94 #if defined(_LARGEFILE64_SOURCE)
97 * Kernel version of directory entry.
100 unsigned long ld_ino;
101 unsigned long ld_off;
102 unsigned short ld_reclen;
106 #else /* !defined(_LARGEFILE64_SOURCE) */
108 #endif /* defined(_LARGEFILE64_SOURCE) */
109 #else /* catch-none */
110 #error No usable directory fill entries interface available
114 * Local host file system driver.
117 #if defined(ALPHA_LINUX)
119 /* stat struct from asm/stat.h, as returned
120 * by alpha linux kernel
122 struct __native_stat {
125 unsigned int st_mode;
126 unsigned int st_nlink;
129 unsigned int st_rdev;
131 unsigned long st_atime;
132 unsigned long st_mtime;
133 unsigned long st_ctime;
134 unsigned int st_blksize;
136 unsigned int st_flags;
140 #define COPY_STAT(src, dest) \
142 memset((dest), 0, sizeof((*dest))); \
143 (dest)->st_dev = (src)->st_dev; \
144 (dest)->st_ino = (src)->st_ino; \
145 (dest)->st_mode = (src)->st_mode; \
146 (dest)->st_nlink = (src)->st_nlink; \
147 (dest)->st_uid = (src)->st_uid; \
148 (dest)->st_gid = (src)->st_gid; \
149 (dest)->st_rdev = (src)->st_rdev; \
150 (dest)->st_size = (src)->st_size; \
151 (dest)->st_atime = (src)->st_atime; \
152 (dest)->st_mtime = (src)->st_mtime; \
153 (dest)->st_ctime = (src)->st_ctime; \
154 (dest)->st_blksize = (src)->st_blksize; \
155 (dest)->st_blocks = (src)->st_blocks; \
156 (dest)->st_flags = (src)->st_flags; \
157 (dest)->st_gen = (src)->st_gen; \
161 #define __native_stat intnl_stat
162 #define COPY_STAT(src, dest) *(dest) = *(src)
165 #if defined(USE_NATIVE_STAT)
166 #define __SYS_STAT SYS_lstat
167 #define __SYS_FSTAT SYS_fstat
168 #define __SYS_TRUNCATE SYS_truncate
169 #define __SYS_FTRUNCATE SYS_ftruncate
171 #define __SYS_STAT SYS_lstat64
172 #define __SYS_FSTAT SYS_fstat64
173 #define __SYS_TRUNCATE SYS_truncate64
174 #define __SYS_FTRUNCATE SYS_ftruncate64
177 #if defined(USE_NATIVE_FDATASYNC)
178 #define __SYS_FDATASYNC SYS_osf_fdatasync
180 #define __SYS_FDATASYNC SYS_fdatasync
183 #if defined(USE_NATIVE_UTIME)
184 #define __SYS_UTIME SYS_utimes
186 #define __SYS_UTIME SYS_utime
190 * Native file identifiers format.
192 struct native_inode_identifier {
193 dev_t dev; /* device number */
194 ino_t ino; /* i-number */
195 #ifdef HAVE_GENERATION
196 unsigned int gen; /* generation number */
201 * Driver-private i-node information we keep about local host file
204 struct native_inode {
206 ni_seekok : 1; /* can seek? */
207 struct native_inode_identifier ni_ident; /* unique identifier */
208 struct file_identifier ni_fileid; /* ditto */
209 int ni_fd; /* host fildes */
210 int ni_oflags; /* flags, from open */
211 unsigned ni_nopens; /* soft ref count */
212 _SYSIO_OFF_T ni_fpos; /* current pos */
213 struct intnl_stat ni_stat; /* cached attrs */
217 * Native IO path arguments.
220 char nio_op; /* 'r' or 'w' */
221 struct native_inode *nio_nino; /* native ino */
224 static int native_inop_lookup(struct pnode *pno,
226 struct intent *intnt,
228 static int native_inop_getattr(struct pnode *pno,
230 struct intnl_stat *stbuf);
231 static int native_inop_setattr(struct pnode *pno,
234 struct intnl_stat *stbuf);
235 static ssize_t native_getdirentries(struct inode *ino,
238 _SYSIO_OFF_T *basep);
239 static int native_inop_mkdir(struct pnode *pno, mode_t mode);
240 static int native_inop_rmdir(struct pnode *pno);
241 static int native_inop_symlink(struct pnode *pno, const char *data);
242 static int native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz);
243 static int native_inop_open(struct pnode *pno, int flags, mode_t mode);
244 static int native_inop_close(struct inode *ino);
245 static int native_inop_link(struct pnode *old, struct pnode *new);
246 static int native_inop_unlink(struct pnode *pno);
247 static int native_inop_rename(struct pnode *old, struct pnode *new);
248 static int native_inop_read(struct inode *ino, struct ioctx *ioctx);
249 static int native_inop_write(struct inode *ino, struct ioctx *ioctx);
250 static _SYSIO_OFF_T native_inop_pos(struct inode *ino, _SYSIO_OFF_T off);
251 static int native_inop_iodone(struct ioctx *ioctx);
252 static int native_inop_fcntl(struct inode *ino, int cmd, va_list ap, int *rtn);
253 static int native_inop_sync(struct inode *ino);
254 static int native_inop_datasync(struct inode *ino);
255 static int native_inop_ioctl(struct inode *ino,
256 unsigned long int request,
258 static int native_inop_mknod(struct pnode *pno, mode_t mode, dev_t dev);
260 static int native_inop_statvfs(struct pnode *pno,
262 struct intnl_statvfs *buf);
264 static void native_inop_gone(struct inode *ino);
266 static struct inode_ops native_i_ops = {
270 native_getdirentries,
274 native_inop_readlink,
286 native_inop_datasync,
295 static int native_fsswop_mount(const char *source,
298 struct pnode *tocover,
299 struct mount **mntp);
301 static struct fssw_ops native_fssw_ops = {
305 static void native_fsop_gone(struct filesys *fs);
307 static struct filesys_ops native_inodesys_ops = {
312 * This example driver plays a strange game. It maintains a private,
313 * internal mount -- It's own separate, rooted, name space. The local
314 * file system's entire name space is available via this tree.
316 * This simplifies the implementation. At mount time, we need to generate
317 * a path-node to be used as a root. This allows us to look up the needed
318 * node in the host name space and leverage a whole lot of support from
321 static struct mount *native_internal_mount = NULL;
324 * Given i-node, return driver private part.
326 #define I2NI(ino) ((struct native_inode *)((ino)->i_private))
332 native_stat(const char *path, struct native_inode *nino, struct intnl_stat *buf)
335 struct __native_stat stbuf;
337 err = syscall(__SYS_STAT, path, &stbuf);
343 COPY_STAT(&stbuf, buf);
346 COPY_STAT(&stbuf, &nino->ni_stat);
347 if (&nino->ni_stat != buf)
348 (void )memcpy(buf, &nino->ni_stat, sizeof(struct intnl_stat));
358 native_fstat(int fd, struct native_inode *nino, struct intnl_stat *buf)
361 struct __native_stat stbuf;
363 err = syscall(__SYS_FSTAT, fd, &stbuf);
369 COPY_STAT(&stbuf, buf);
372 COPY_STAT(&stbuf, &nino->ni_stat);
373 if (&nino->ni_stat != buf)
374 (void )memcpy(buf, &nino->ni_stat, sizeof(struct intnl_stat));
381 * Introduce an i-node to the system.
383 static struct inode *
384 native_i_new(struct filesys *fs, struct intnl_stat *buf)
386 struct native_inode *nino;
389 nino = malloc(sizeof(struct native_inode));
392 bzero(&nino->ni_ident, sizeof(nino->ni_ident));
393 nino->ni_ident.dev = buf->st_dev;
394 nino->ni_ident.ino = buf->st_ino;
395 #ifdef HAVE_GENERATION
396 nino->ni_ident.gen = buf->st_gen;
398 nino->ni_fileid.fid_data = &nino->ni_ident;
399 nino->ni_fileid.fid_len = sizeof(nino->ni_ident);
404 (void )memcpy(&nino->ni_stat, buf, sizeof(struct intnl_stat));
408 #ifndef AUTOMOUNT_FILE_NAME
409 buf->st_mode & S_IFMT,
411 buf->st_mode, /* all of the bits! */
423 * Initialize this driver.
430 * Capture current process umask and reset our process umask to
431 * zero. All permission bits to open/creat/setattr are absolute --
432 * They've already had a umask applied, when appropriate.
434 _sysio_umask = syscall(SYS_umask, 0);
436 return _sysio_fssw_register("native", &native_fssw_ops);
440 * Create private, internal, view of the hosts name space.
443 create_internal_namespace()
447 struct inode *rootino;
448 struct pnode_base *rootpb;
449 static struct qstr noname = { NULL, 0, 0 };
451 struct intnl_stat stbuf;
453 if (native_internal_mount) {
461 * We maintain an artificial, internal, name space in order to
462 * have access to fully qualified path names in the various routines.
463 * Initialize that name space now.
468 fs = _sysio_fs_new(&native_inodesys_ops, 0, NULL);
477 err = native_stat("/", NULL, &stbuf);
480 rootino = native_i_new(fs, &stbuf);
487 * Generate base path-node for root.
489 rootpb = _sysio_pb_new(&noname, NULL, rootino);
496 * Mount it. This name space is disconnected from the
497 * rest of the system -- Only available within this driver.
499 err = _sysio_do_mount(fs, rootpb, 0, NULL, &mnt);
503 native_internal_mount = mnt;
507 if (_sysio_do_unmount(mnt) != 0)
514 _sysio_pb_gone(rootpb);
524 native_fsswop_mount(const char *source,
526 const void *data __IS_UNUSED,
527 struct pnode *tocover,
531 struct nameidata nameidata;
535 * Caller must use fully qualified path names when specifying
541 if (!native_internal_mount) {
542 err = create_internal_namespace();
548 * Lookup the source in the internally maintained name space.
550 ND_INIT(&nameidata, 0, source, native_internal_mount->mnt_root, NULL);
551 err = _sysio_path_walk(native_internal_mount->mnt_root, &nameidata);
556 * Have path-node specified by the given source argument. Let the
557 * system finish the job, now.
560 _sysio_do_mount(native_internal_mount->mnt_fs,
561 nameidata.nd_pno->p_base,
566 * Release the internal name space pnode and clean up any
567 * aliases we might have generated. We really don't need to cache them
568 * as they are only used at mount time..
570 P_RELE(nameidata.nd_pno);
571 (void )_sysio_p_prune(native_internal_mount->mnt_root);
574 FS_REF(native_internal_mount->mnt_fs);
581 native_i_invalid(struct inode *inop, struct intnl_stat stbuf)
584 * Validate passed in inode against stat struct info
586 struct native_inode *nino = I2NI(inop);
588 if ((nino->ni_ident.dev != stbuf.st_dev ||
589 nino->ni_ident.ino != stbuf.st_ino ||
590 #ifdef HAVE_GENERATION
591 nino->ni_ident.gen != stbuf.st_gen ||
593 ((inop)->i_mode & S_IFMT) != (stbuf.st_mode & S_IFMT)) ||
594 (((inop)->i_rdev != stbuf.st_rdev) &&
595 (S_ISCHR((inop)->i_mode) || S_ISBLK((inop)->i_mode))))
602 * Find, and validate, or create i-node by host-relative path. Returned i-node
606 native_iget(struct filesys *fs,
613 struct intnl_stat stbuf;
614 struct native_inode_identifier ident;
615 struct file_identifier fileid;
620 err = native_stat(path, *inop ? I2NI(*inop) : NULL, &stbuf);
630 if (!native_i_invalid(*inop, stbuf))
639 * I-node is not already known. Find or create it.
641 bzero(&ident, sizeof(ident));
642 ident.dev = stbuf.st_dev;
643 ident.ino = stbuf.st_ino;
644 #ifdef HAVE_GENERATION
645 ident.gen = stbuf.st_gen;
647 fileid.fid_data = &ident;
648 fileid.fid_len = sizeof(ident);
649 ino = _sysio_i_find(fs, &fileid);
651 (forced || (ino->i_mode & S_IFMT) != (stbuf.st_mode & S_IFMT))) {
653 * Insertion was forced or dup inum but it's already present!
655 if (native_i_invalid(ino, stbuf)) {
657 * Cached inode has stale attrs
658 * make way for the new one
664 * OK to reuse cached inode
670 ino = native_i_new(fs, &stbuf);
681 * Look up named object in host's name space by path.
684 native_path_lookup(struct filesys *fs, const char *path, struct inode **inop)
687 return native_iget(fs, path, inop, 0);
691 * Look up object by it's path node.
694 native_i_lookup(struct filesys *fs, struct pnode_base *pb, struct inode **inop)
699 path = _sysio_pb_path(pb, '/');
702 err = native_path_lookup(fs, path, inop);
708 native_inop_lookup(struct pnode *pno,
710 struct intent *intnt __IS_UNUSED,
711 const char *path __IS_UNUSED)
715 *inop = pno->p_base->pb_ino;
718 * Don't have an inode yet. Because we translate everything back to
719 * a single name space for the host, we will assume the object the
720 * caller is looking for has no existing alias in our internal
721 * name space. We don't see the same file on different mounts in the
722 * underlying host FS as the same file.
724 * The file identifier *will* be unique. It's got to have a different
727 err = native_i_lookup(pno->p_mount->mnt_fs, pno->p_base, inop);
734 native_inop_getattr(struct pnode *pno,
736 struct intnl_stat *stbuf)
739 struct native_inode *nino;
742 nino = ino ? I2NI(ino) : NULL;
743 err = 0; /* compiler cookie */
745 path = _sysio_pb_path(pno->p_base, '/');
748 err = native_stat(path, nino, stbuf);
750 } else if (nino->ni_fd >= 0)
751 err = native_fstat(nino->ni_fd, nino, stbuf);
754 * Dev inodes don't open in this driver. We won't have
755 * a file descriptor with which to do the deed then. Satisfy
756 * the request from the cached copy of the attributes.
760 sizeof(struct intnl_stat));
768 native_inop_setattr(struct pnode *pno,
771 struct intnl_stat *stbuf)
774 struct native_inode *nino;
776 struct intnl_stat *stbp, _stbuf;
780 nino = ino ? I2NI(ino) : NULL;
785 stbp = &nino->ni_stat;
787 if (fd < 0 || mask & (SETATTR_MTIME|SETATTR_ATIME)) {
790 path = _sysio_pb_path(pno->p_base, '/');
796 * Get current status for undo.
800 ? native_stat(path, nino, stbp)
801 : native_fstat(fd, nino, stbp);
805 if (mask & SETATTR_MODE) {
809 * Alter permissions attribute.
811 mode = stbuf->st_mode & 07777;
814 ? syscall(SYS_chmod, path, mode)
815 : syscall(SYS_fchmod, fd, mode);
820 mask &= ~SETATTR_MODE;
821 else if (mask & (SETATTR_MTIME|SETATTR_ATIME)) {
825 * Alter access and/or modify time attributes.
827 ut.actime = stbuf->st_atime;
828 ut.modtime = stbuf->st_mtime;
829 if (mask & SETATTR_MTIME)
830 ut.modtime = stbuf->st_mtime;
831 if (mask & SETATTR_ATIME)
832 ut.actime = stbuf->st_atime;
833 err = syscall(__SYS_UTIME, path, &ut);
838 mask &= ~(SETATTR_MTIME|SETATTR_ATIME);
839 else if (mask & (SETATTR_UID|SETATTR_GID)) {
842 * Alter owner and/or group identifiers.
854 : syscall(SYS_fchown,
866 mask &= ~(SETATTR_UID|SETATTR_GID);
867 else if (mask & SETATTR_LEN) {
869 * Do the truncate last. It can't be undone.
872 ? syscall(__SYS_TRUNCATE, path, stbuf->st_size)
873 : syscall(__SYS_FTRUNCATE, fd, stbuf->st_size));
878 * Undo after error. Some or all of this might not work... We
881 if (mask & (SETATTR_UID|SETATTR_GID)) {
891 : syscall(SYS_fchown,
900 if (mask & (SETATTR_MTIME|SETATTR_ATIME)) {
903 ut.actime = stbp->st_atime;
904 ut.modtime = stbp->st_mtime;
905 (void )syscall(__SYS_UTIME, path, &ut);
907 if (mask & SETATTR_MODE) {
909 ? syscall(SYS_chmod, path, stbp->st_mode & 07777)
910 : syscall(SYS_fchmod, stbp->st_mode & 07777);
914 * We must refresh the cached attributes on success.
917 ? native_stat(path, nino, stbp)
918 : native_fstat(fd, nino, stbp)) != 0)
926 native_pos(int fd, _SYSIO_OFF_T *offset, int whence)
931 assert(*offset >= 0);
934 #if _LARGEFILE64_SOURCE && defined(SYS__llseek)
940 (unsigned int)(off >> 32),
962 native_filldirentries(struct native_inode *nino,
975 * Stream-oriented access requires that we reposition prior to the
978 if ((err = native_pos(nino->ni_fd, basep, SEEK_SET)) != 0)
981 nino->ni_fpos = *basep;
984 #if defined(SYS_getdirentries)
985 syscall(SYS_getdirentries,
990 #elif defined(SYS_getdents64)
991 syscall(SYS_getdents64, nino->ni_fd, buf, nbytes);
992 #elif defined(SYS_getdents)
993 syscall(SYS_getdents, nino->ni_fd, buf, nbytes);
1000 * Stream-oriented access requires that we discover where we are
1004 if ((err = native_pos(nino->ni_fd, basep, SEEK_CUR)) != 0)
1007 nino->ni_fpos = *basep;
1012 native_getdirentries(struct inode *ino,
1015 _SYSIO_OFF_T *basep)
1017 struct native_inode *nino = I2NI(ino);
1021 struct linux_dirent *ldp;
1022 struct dirent64 *d64p;
1027 #define count nbytes
1031 assert(nino->ni_fd >= 0);
1035 while (!(bp = malloc(count))) {
1037 if (count < sizeof(struct dirent))
1041 cc = native_filldirentries(nino, bp, count, basep);
1049 ldp = (struct linux_dirent *)bp;
1050 d64p = (struct dirent64 *)buf;
1052 if (cc < 0 || (size_t )cc <= sizeof(*ldp))
1054 namlen = strlen(ldp->ld_name);
1055 reclen = sizeof(*d64p) - sizeof(d64p->d_name) + namlen + 1;
1056 if (nbytes < reclen)
1058 d64p->d_ino = ldp->ld_ino;
1059 d64p->d_off = ldp->ld_off;
1061 (((reclen + sizeof(long) - 1)) / sizeof(long)) *
1063 if (nbytes < d64p->d_reclen)
1064 d64p->d_reclen = reclen;
1065 d64p->d_type = DT_UNKNOWN; /* you lose -- sorry. */
1066 (void )strncpy(d64p->d_name, ldp->ld_name, namlen);
1067 *(d64p->d_name + namlen) = '\0';
1068 cc -= ldp->ld_reclen;
1069 ldp = (struct linux_dirent *)((char *)ldp + ldp->ld_reclen);
1070 nbytes -= d64p->d_reclen;
1071 d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen);
1074 if (d64p == (struct dirent64 *)buf && cc)
1075 cc = -EINVAL; /* buf too small */
1076 cc = (char *)d64p - buf;
1085 native_inop_mkdir(struct pnode *pno, mode_t mode)
1090 path = _sysio_pb_path(pno->p_base, '/');
1094 err = syscall(SYS_mkdir, path, mode);
1102 native_inop_rmdir(struct pnode *pno)
1107 path = _sysio_pb_path(pno->p_base, '/');
1111 err = syscall(SYS_rmdir, path);
1119 native_inop_symlink(struct pnode *pno, const char *data)
1124 path = _sysio_pb_path(pno->p_base, '/');
1128 err = syscall(SYS_symlink, data, path);
1136 native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz)
1141 path = _sysio_pb_path(pno->p_base, '/');
1144 i = syscall(SYS_readlink, path, buf, bufsiz);
1152 native_inop_open(struct pnode *pno, int flags, mode_t mode)
1154 struct native_inode *nino;
1158 path = _sysio_pb_path(pno->p_base, '/');
1163 * Whether the file is already open, or not, makes no difference.
1164 * Want to always give the host OS a chance to authorize in case
1165 * something has changed underneath us.
1167 if (flags & O_WRONLY) {
1169 * Promote write-only attempt to RW.
1175 flags |= O_LARGEFILE;
1177 fd = syscall(SYS_open, path, flags, mode);
1178 if (!pno->p_base->pb_ino && fd >= 0) {
1182 * Success but we need to return an i-node.
1185 native_iget(pno->p_mount->mnt_fs,
1187 &pno->p_base->pb_ino,
1190 (void )syscall(SYS_close, fd);
1201 * Remember this new open.
1203 nino = I2NI(pno->p_base->pb_ino);
1205 assert(nino->ni_nopens);
1207 if (nino->ni_fd >= 0) {
1208 if ((nino->ni_oflags & O_RDWR) ||
1209 (flags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_RDONLY) {
1213 (void )syscall(SYS_close, fd);
1216 (void )syscall(SYS_close, nino->ni_fd);
1219 * Invariant; First open. Must init.
1224 * Need to know whether we can seek on this
1228 native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_CUR) != 0 ? 0 : 1;
1234 native_inop_close(struct inode *ino)
1236 struct native_inode *nino = I2NI(ino);
1239 if (nino->ni_fd < 0)
1242 assert(nino->ni_nopens);
1243 if (--nino->ni_nopens) {
1245 * Hmmm. We really don't need anything else. However, some
1246 * filesystems try to implement a sync-on-close semantic.
1247 * As this appears now, that is lost. Might want to change
1248 * it somehow in the future?
1253 err = syscall(SYS_close, nino->ni_fd);
1263 native_inop_link(struct pnode *old, struct pnode *new)
1266 char *opath, *npath;
1270 opath = _sysio_pb_path(old->p_base, '/');
1271 npath = _sysio_pb_path(new->p_base, '/');
1272 if (!(opath && npath)) {
1277 err = syscall(SYS_link, opath, npath);
1291 native_inop_unlink(struct pnode *pno)
1296 path = _sysio_pb_path(pno->p_base, '/');
1301 * For this driver, unlink is easy with open files. Since the
1302 * file remains open to the system, too, the descriptors are still
1305 * Other drivers will have some difficulty here as the entry in the
1306 * file system name space must be removed without sacrificing access
1307 * to the file itself. In NFS this is done with a mechanism referred
1308 * to as a `silly delete'. The file is moved to a temporary name
1309 * (usually .NFSXXXXXX, where the X's are replaced by the PID and some
1310 * unique characters) in order to simulate the proper semantic.
1312 if (syscall(SYS_unlink, path) != 0)
1319 native_inop_rename(struct pnode *old, struct pnode *new)
1322 char *opath, *npath;
1324 opath = _sysio_pb_path(old->p_base, '/');
1325 npath = _sysio_pb_path(new->p_base, '/');
1326 if (!(opath && npath)) {
1331 err = syscall(SYS_rename, opath, npath);
1345 dopio(void *buf, size_t count, _SYSIO_OFF_T off, struct native_io *nio)
1347 #if defined(_LARGEFILE64_SOURCE) && \
1348 defined(SYS_pread64) && \
1349 defined(SYS_pwrite64)
1350 #define _NATIVE_SYSCALL_PREAD SYS_pread64
1351 #define _NATIVE_SYSCALL_PWRITE SYS_pwrite64
1353 #define _NATIVE_SYSCALL_PREAD SYS_pread
1354 #define _NATIVE_SYSCALL_PWRITE SYS_pwrite
1358 if (!(off == nio->nio_nino->ni_fpos || nio->nio_nino->ni_seekok))
1361 if (!nio->nio_nino->ni_seekok) {
1362 if (off != nio->nio_nino->ni_fpos) {
1364 * They've done a p{read,write} or somesuch. Can't
1365 * seek on this descriptor so we err out now.
1371 syscall(nio->nio_op == 'r' ? SYS_read : SYS_write,
1372 nio->nio_nino->ni_fd,
1376 nio->nio_nino->ni_fpos += cc;
1379 syscall((nio->nio_op == 'r'
1380 ? _NATIVE_SYSCALL_PREAD
1381 : _NATIVE_SYSCALL_PWRITE),
1382 nio->nio_nino->ni_fd,
1388 #undef _NATIVE_SYSCALL_PREAD
1389 #undef _NATIVE_SYSCALL_PWRITE
1393 doiov(const struct iovec *iov,
1397 struct native_io *nio)
1401 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
1402 #define MAX_IOVEC INT_MAX
1409 * Avoid the reposition call if we're already at the right place.
1410 * Allows us to access pipes and fifos.
1412 if (off != nio->nio_nino->ni_fpos) {
1415 err = native_pos(nio->nio_nino->ni_fd, &off, SEEK_SET);
1418 nio->nio_nino->ni_fpos = off;
1422 * The {read,write}v is safe as this routine is only ever called
1423 * by _sysio_enumerate_extents() and that routine is exact. It never
1424 * passes iovectors including tails.
1429 ? syscall(nio->nio_op == 'r' ? SYS_readv : SYS_writev,
1430 nio->nio_nino->ni_fd,
1435 _sysio_enumerate_iovec(iov,
1439 (ssize_t (*)(void *,
1447 nio->nio_nino->ni_fpos += cc;
1450 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
1457 lockop_all(struct native_inode *nino,
1458 struct intnl_xtvec *xtv,
1468 flock.l_whence = SEEK_SET;
1470 flock.l_start = xtv->xtv_off;
1471 flock.l_len = xtv->xtv_len;
1475 #if !_LARGEFILE64_SOURCE
1491 order_xtv(const struct intnl_xtvec *xtv1, const struct intnl_xtvec *xtv2)
1494 if (xtv1->xtv_off < xtv2->xtv_off)
1496 if (xtv1->xtv_off > xtv2->xtv_off)
1503 doio(char op, struct ioctx *ioctx)
1505 struct native_inode *nino;
1508 struct intnl_xtvec *oxtv;
1511 struct native_io arguments;
1514 struct intnl_xtvec *front, *rear, tmp;
1517 nino = I2NI(ioctx->ioctx_ino);
1519 dolocks = ioctx->ioctx_xtvlen > 1 && nino->ni_seekok;
1522 * Must lock the regions (in order!) since we can't do
1523 * strided-IO as a single atomic operation.
1525 oxtv = malloc(ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec));
1530 ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec));
1532 ioctx->ioctx_xtvlen,
1533 sizeof(struct intnl_xtvec),
1534 (int (*)(const void *, const void *))order_xtv);
1537 oxtv, ioctx->ioctx_xtvlen,
1538 op == 'r' ? F_RDLCK : F_WRLCK);
1545 arguments.nio_op = op;
1546 arguments.nio_nino = nino;
1548 _sysio_enumerate_extents(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen,
1549 ioctx->ioctx_iov, ioctx->ioctx_iovlen,
1550 (ssize_t (*)(const struct iovec *,
1559 * Must unlock in reverse order.
1562 rear = front + ioctx->ioctx_xtvlen - 1;
1563 while (front < rear) {
1568 if (lockop_all(nino, oxtv, ioctx->ioctx_xtvlen, F_UNLCK) != 0)
1573 if ((ioctx->ioctx_cc = cc) < 0) {
1574 ioctx->ioctx_errno = -ioctx->ioctx_cc;
1575 ioctx->ioctx_cc = -1;
1581 native_inop_read(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
1584 return doio('r', ioctx);
1588 native_inop_write(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
1591 return doio('w', ioctx);
1595 native_inop_pos(struct inode *ino, _SYSIO_OFF_T off)
1597 struct native_inode *nino = I2NI(ino);
1600 err = native_pos(nino->ni_fd, &off, SEEK_SET);
1601 return err < 0 ? err : off;
1605 native_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
1609 * It's always done in this driver. It completed when posted.
1615 native_inop_fcntl(struct inode *ino,
1620 struct native_inode *nino = I2NI(ino);
1624 if (nino->ni_fd < 0)
1634 *rtn = syscall(SYS_fcntl, nino->ni_fd, cmd);
1647 arg = va_arg(ap, long);
1648 *rtn = syscall(SYS_fcntl, nino->ni_fd, cmd, arg);
1660 native_inop_mknod(struct pnode *pno __IS_UNUSED,
1661 mode_t mode __IS_UNUSED,
1662 dev_t dev __IS_UNUSED)
1668 #ifdef _HAVE_STATVFS
1670 native_inop_statvfs(struct pnode *pno,
1672 struct intnl_statvfs *buf)
1679 if (!ino || I2NI(ino)->ni_fd < 0) {
1680 path = _sysio_pb_path(pno->p_base, '/');
1686 * The syscall interface does not support SYS_fstatvfs.
1687 * Should possibly return ENOSYS, but thought it
1688 * better to use SYS_fstatfs and fill in as much of
1689 * the statvfs structure as possible. This allows
1690 * for more of a test of the sysio user interface.
1694 ? syscall(SYS_statfs, path, &fs)
1695 : syscall(SYS_fstatfs, I2NI(ino)->ni_fd, &fs);
1701 buf->f_bsize = fs.f_bsize; /* file system block size */
1702 buf->f_frsize = fs.f_bsize; /* file system fundamental block size */
1703 buf->f_blocks = fs.f_blocks;
1704 buf->f_bfree = fs.f_bfree;
1705 buf->f_bavail = fs.f_bavail;
1706 buf->f_files = fs.f_files; /* Total number serial numbers */
1707 buf->f_ffree = fs.f_ffree; /* Number free serial numbers */
1708 buf->f_favail = fs.f_ffree; /* Number free ser num for non-privileged*/
1709 buf->f_fsid = fs.f_fsid.__val[1];
1710 buf->f_flag = 0; /* No equiv in statfs; maybe use type? */
1711 buf->f_namemax = fs.f_namelen;
1717 native_inop_sync(struct inode *ino)
1721 assert(I2NI(ino)->ni_fd >= 0);
1723 err = syscall(SYS_fsync, I2NI(ino)->ni_fd);
1730 native_inop_datasync(struct inode *ino)
1734 assert(I2NI(ino)->ni_fd >= 0);
1736 #ifdef NATIVE_FDATASYNC
1737 err = syscall(NATIVE_FDATASYNC, I2NI(ino)->ni_fd);
1740 #warning No fdatasync system call -- Using fsync instead!
1742 err = syscall(SYS_fsync, I2NI(ino)->ni_fd);
1749 #ifdef HAVE_LUSTRE_HACK
1751 native_inop_ioctl(struct inode *ino,
1752 unsigned long int request,
1755 long arg1, arg2, arg3, arg4;
1757 assert(I2NI(ino)->ni_fd >= 0);
1759 arg1 = va_arg(ap, long);
1760 arg2 = va_arg(ap, long);
1761 arg3 = va_arg(ap, long);
1762 arg4 = va_arg(ap, long);
1764 return syscall(SYS_ioctl, I2NI(ino)->ni_fd, request,
1765 arg1, arg2, arg3, arg4);
1769 native_inop_ioctl(struct inode *ino __IS_UNUSED,
1770 unsigned long int request __IS_UNUSED,
1771 va_list ap __IS_UNUSED)
1775 * I'm lazy. Maybe implemented later.
1783 native_inop_gone(struct inode *ino)
1785 struct native_inode *nino = I2NI(ino);
1787 if (nino->ni_fd >= 0)
1788 (void )syscall(SYS_close, nino->ni_fd);
1790 free(ino->i_private);
1794 native_fsop_gone(struct filesys *fs __IS_UNUSED)
1798 * Do nothing. There is no private part maintained for the
1799 * native file interface.