Whamcloud - gitweb
b=10163
[fs/lustre-release.git] / libsysio / drivers / native / fs_native.c
1 /*
2  *    This Cplant(TM) source code is the property of Sandia National
3  *    Laboratories.
4  *
5  *    This Cplant(TM) source code is copyrighted by Sandia National
6  *    Laboratories.
7  *
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)
11  *
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
16  *    Government.
17  */
18
19 /*
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.
24  * 
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.
29  * 
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
33  *
34  * Questions or comments about this library should be sent to:
35  *
36  * Lee Ward
37  * Sandia National Laboratories, New Mexico
38  * P.O. Box 5800
39  * Albuquerque, NM 87185-1110
40  *
41  * lee@sandia.gov
42  */
43
44 #ifdef __linux__
45 #define _BSD_SOURCE
46 #endif
47
48 #include <stdio.h>                                      /* for NULL */
49 #include <stdlib.h>
50 #ifdef __linux__
51 #include <string.h>
52 #endif
53 #include <unistd.h>
54 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
55 #include <limits.h>
56 #endif
57 #include <errno.h>
58 #include <assert.h>
59 #include <syscall.h>
60 #include <sys/time.h>
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <sys/fcntl.h>
64 #if 0
65 #include <sys/vfs.h>
66 #endif
67 #ifdef _HAVE_STATVFS
68 #include <sys/statvfs.h>
69 #include <sys/statfs.h>
70 #endif
71 #include <utime.h>
72 #include <sys/uio.h>
73 #include <sys/queue.h>
74
75 #include "sysio.h"
76 #include "xtio.h"
77 #include "native.h"
78 #include "fs.h"
79 #include "mount.h"
80 #include "inode.h"
81
82 #include "fs_native.h"
83
84 #ifdef REDSTORM
85 #include <sys/uio.h>
86 #endif
87
88 #if defined(SYSIO_SYS_getdirentries)
89 #define DIR_CVT_64 0
90 #elif defined(SYSIO_SYS_getdents64)
91 #define DIR_CVT_64 0
92 #elif defined(SYSIO_SYS_getdents)
93 #if defined(_LARGEFILE64_SOURCE)
94 #define DIR_CVT_64 1
95 /*
96  * Kernel version of directory entry.
97  */
98 struct linux_dirent {
99         unsigned long ld_ino;
100         unsigned long ld_off;
101         unsigned short ld_reclen;
102         char    ld_name[1];
103 };
104 #include <dirent.h>
105 #else /* !defined(_LARGEFILE64_SOURCE) */
106 #define DIR_CVT_64 0
107 #endif /* defined(_LARGEFILE64_SOURCE) */
108 #else /* catch-none */
109 #error No usable directory fill entries interface available
110 #endif
111
112 /*
113  * Native file system information we keep per FS.
114  */
115 struct native_filesystem {
116         time_t  nfs_atimo;                              /* attr timeout (sec) */
117 };
118
119 /*
120  * Given fs, return driver private part.
121  */
122 #define FS2NFS(fs) \
123         ((struct native_filesystem *)(fs)->fs_private)
124
125 /*
126  * Native file identifiers format.
127  */
128 struct native_inode_identifier {
129         dev_t   dev;                                    /* device number */
130         ino_t   ino;                                    /* i-number */
131 #ifdef HAVE_GENERATION
132         unsigned int gen;                               /* generation number */
133 #endif
134 };
135
136 /*
137  * Driver-private i-node information we keep about local host file
138  * system objects.
139  */
140 struct native_inode {
141         unsigned
142                 ni_seekok               : 1,            /* can seek? */
143                 ni_attrvalid            : 1,            /* cached attrs ok? */
144                 ni_resetfpos            : 1;            /* reset fpos? */
145         struct native_inode_identifier ni_ident;        /* unique identifier */
146         struct file_identifier ni_fileid;               /* ditto */
147         int     ni_fd;                                  /* host fildes */
148         int     ni_oflags;                              /* flags, from open */
149         unsigned ni_nopens;                             /* soft ref count */
150         _SYSIO_OFF_T ni_fpos;                           /* current pos */
151         time_t  ni_attrtim;                             /* attrs expire time */
152 };
153
154 /*
155  * Cached attributes usable?
156  */
157 #define NATIVE_ATTRS_VALID(nino, t) \
158         ((nino)->ni_attrtim && (t) < (nino)->ni_attrtim)
159
160 /*
161  * Native IO path arguments.
162  */
163 struct native_io {
164         char    nio_op;                                 /* 'r' or 'w' */
165         struct native_inode *nio_nino;                  /* native ino */
166 };
167
168 static int native_inop_lookup(struct pnode *pno,
169                               struct inode **inop,
170                               struct intent *intnt,
171                               const char *path);
172 static int native_inop_getattr(struct pnode *pno,
173                                struct inode *ino,
174                                struct intnl_stat *stbuf);
175 static int native_inop_setattr(struct pnode *pno,
176                                struct inode *ino,
177                                unsigned mask,
178                                struct intnl_stat *stbuf);
179 static ssize_t native_filldirentries(struct inode *ino,
180                                      _SYSIO_OFF_T *posp,
181                                      char *buf,
182                                      size_t nbytes);
183 static int native_inop_mkdir(struct pnode *pno, mode_t mode);
184 static int native_inop_rmdir(struct pnode *pno);
185 static int native_inop_symlink(struct pnode *pno, const char *data);
186 static int native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz);
187 static int native_inop_open(struct pnode *pno, int flags, mode_t mode);
188 static int native_inop_close(struct inode *ino);
189 static int native_inop_link(struct pnode *old, struct pnode *new);
190 static int native_inop_unlink(struct pnode *pno);
191 static int native_inop_rename(struct pnode *old, struct pnode *new);
192 static int native_inop_read(struct inode *ino, struct ioctx *ioctx);
193 static int native_inop_write(struct inode *ino, struct ioctx *ioctx);
194 static _SYSIO_OFF_T native_inop_pos(struct inode *ino, _SYSIO_OFF_T off);
195 static int native_inop_iodone(struct ioctx *ioctx);
196 static int native_inop_fcntl(struct inode *ino, int cmd, va_list ap, int *rtn);
197 static int native_inop_sync(struct inode *ino);
198 static int native_inop_datasync(struct inode *ino);
199 static int native_inop_ioctl(struct inode *ino,
200                              unsigned long int request,
201                              va_list ap);
202 static int native_inop_mknod(struct pnode *pno, mode_t mode, dev_t dev);
203 #ifdef _HAVE_STATVFS
204 static int native_inop_statvfs(struct pnode *pno,
205                                struct inode *ino,
206                                struct intnl_statvfs *buf);
207 #endif
208 static void native_inop_gone(struct inode *ino);
209
210 static struct inode_ops native_i_ops = {
211         native_inop_lookup,
212         native_inop_getattr,
213         native_inop_setattr,
214         native_filldirentries,
215         native_inop_mkdir,
216         native_inop_rmdir,
217         native_inop_symlink,
218         native_inop_readlink,
219         native_inop_open,
220         native_inop_close,
221         native_inop_link,
222         native_inop_unlink,
223         native_inop_rename,
224         native_inop_read,
225         native_inop_write,
226         native_inop_pos,
227         native_inop_iodone,
228         native_inop_fcntl,
229         native_inop_sync,
230         native_inop_datasync,
231         native_inop_ioctl,
232         native_inop_mknod,
233 #ifdef _HAVE_STATVFS
234         native_inop_statvfs,
235 #endif
236         native_inop_gone
237 };
238
239 static int native_fsswop_mount(const char *source,
240                                unsigned flags,
241                                const void *data,
242                                struct pnode *tocover,
243                                struct mount **mntp);
244
245 static struct fssw_ops native_fssw_ops = {
246         native_fsswop_mount
247 };
248
249 static void native_fsop_gone(struct filesys *fs);
250
251 static struct filesys_ops native_inodesys_ops = {
252         native_fsop_gone,
253 };
254
255 /*
256  * This example driver plays a strange game. It maintains a private,
257  * internal mount -- It's own separate, rooted, name space. The local
258  * file system's entire name space is available via this tree.
259  *
260  * This simplifies the implementation. At mount time, we need to generate
261  * a path-node to be used as a root. This allows us to look up the needed
262  * node in the host name space and leverage a whole lot of support from
263  * the system.
264  */
265 static struct mount *native_internal_mount = NULL;
266
267 /*
268  * Given i-node, return driver private part.
269  */
270 #define I2NI(ino)       ((struct native_inode *)((ino)->i_private))
271
272 /*
273  * stat -- by path.
274  */
275 static int
276 native_stat(const char *path,
277             struct inode *ino,
278             time_t t,
279             struct intnl_stat *buf)
280 {
281         struct native_inode *nino;
282         int     err;
283         struct _sysio_native_stat stbuf;
284
285         nino = ino ? I2NI(ino) : NULL;
286
287         if (path)
288                 err = syscall(SYSIO_SYS_stat, path, &stbuf);
289         else if (nino && nino->ni_fd >= 0)
290                 err = syscall(SYSIO_SYS_fstat, nino->ni_fd, &stbuf);
291         else
292                 abort();
293         if (err) {
294                 if (nino)
295                         nino->ni_attrtim = 0;
296                 return -errno;
297         }
298         if (nino) {
299                 nino->ni_attrtim = t;
300                 SYSIO_COPY_STAT(&stbuf, &ino->i_stbuf);
301                 if (buf)
302                         *buf = ino->i_stbuf;
303                 return 0;
304         }
305         if (!buf)
306                 return 0;
307         SYSIO_COPY_STAT(&stbuf, buf);
308         return 0;
309 }
310
311 /*
312  * Introduce an i-node to the system.
313  */
314 static struct inode *
315 native_i_new(struct filesys *fs, time_t expiration, struct intnl_stat *buf)
316 {
317         struct native_inode *nino;
318         struct inode *ino;
319
320         nino = malloc(sizeof(struct native_inode));
321         if (!nino)
322                 return NULL;
323         bzero(&nino->ni_ident, sizeof(nino->ni_ident));
324         nino->ni_seekok = 0;
325         nino->ni_attrvalid = 0;
326         nino->ni_resetfpos = 0;
327         nino->ni_ident.dev = buf->st_dev;
328         nino->ni_ident.ino = buf->st_ino;
329 #ifdef HAVE_GENERATION
330         nino->ni_ident.gen = buf->st_gen;
331 #endif
332         nino->ni_fileid.fid_data = &nino->ni_ident;
333         nino->ni_fileid.fid_len = sizeof(nino->ni_ident);
334         nino->ni_fd = -1;
335         nino->ni_oflags = 0;
336         nino->ni_nopens = 0;
337         nino->ni_fpos = 0;
338         nino->ni_attrtim = expiration;
339         ino =
340             _sysio_i_new(fs,
341                          &nino->ni_fileid,
342                          buf,
343                          0,
344                          &native_i_ops,
345                          nino);
346         if (!ino)
347                 free(nino);
348         return ino;
349 }
350
351 /*
352  * Initialize this driver.
353  */
354 int
355 _sysio_native_init()
356 {
357
358         /*
359          * Capture current process umask and reset our process umask to
360          * zero. All permission bits to open/creat/setattr are absolute --
361          * They've already had a umask applied, when appropriate.
362          */
363 #ifndef REDSTORM
364         _sysio_umask = syscall(SYSIO_SYS_umask, 0);
365         /*
366          *      For Red Storm, this functionality is handled in cstart.
367          *      The mask to be "captured" has been sent already.
368          *      This eliminates a system call from every node!
369          */
370 #endif  /* REDSTORM  */
371
372         return _sysio_fssw_register("native", &native_fssw_ops);
373 }
374
375 /*
376  * Create private, internal, view of the hosts name space.
377  */
378 static int
379 create_internal_namespace(const void *data)
380 {
381         char    *opts;
382         ssize_t len;
383         char    *cp;
384         struct native_filesystem *nfs;
385         int     err;
386         struct mount *mnt;
387         struct inode *rootino;
388         struct pnode_base *rootpb;
389         static struct qstr noname = { NULL, 0, 0 };
390         struct filesys *fs;
391         time_t  t;
392         struct intnl_stat stbuf;
393         unsigned long ul;
394         static struct option_value_info v[] = {
395                 { "atimo",      "30" },
396                 { NULL,         NULL }
397         };
398
399         if (native_internal_mount) {
400                 /*
401                  * Reentered!
402                  */
403                 abort();
404         }
405
406         /*
407          * Get mount options.
408          */
409         opts = NULL;
410         if (data && (len = strlen((char *)data))) {
411                 opts = malloc(len + 1);
412                 if (!opts)
413                         return -ENOMEM;
414                 (void )strcpy(opts, data);
415                 if (_sysio_get_args(opts, v) - opts != (ssize_t )len)
416                         return -EINVAL;
417         }
418         ul = strtoul(v[0].ovi_value, &cp, 0);
419         if (*cp != '\0' || ul >= UINT_MAX)
420                 return -EINVAL;
421         if (opts) {
422                 free(opts);
423                 opts = NULL;
424         }
425
426         /*
427          * We maintain an artificial, internal, name space in order to
428          * have access to fully qualified path names in the various routines.
429          * Initialize that name space now.
430          */
431         fs = NULL;
432         mnt = NULL;
433         rootino = NULL;
434         rootpb = NULL;
435         /*
436          * This really should be per-mount. Hmm, but that's best done
437          * as proper sub-mounts in the core and not this driver. We reconcile
438          * now, here, by putting the mount options on the file system. That
439          * means they are global and only can be passed at the initial mount.
440          *
441          * Maybe do it right some day?
442          */
443         nfs = malloc(sizeof(struct native_filesystem));
444         if (!nfs) {
445                 err = -ENOMEM;
446                 goto error;
447         }
448         nfs->nfs_atimo = ul;
449         if ((unsigned long)nfs->nfs_atimo != ul) {
450                 err = -EINVAL;
451                 goto error;
452         }
453         fs = _sysio_fs_new(&native_inodesys_ops, 0, nfs);
454         if (!fs) {
455                 err = -ENOMEM;
456                 goto error;
457         }
458
459         /*
460          * Get root i-node.
461          */
462         t = _SYSIO_LOCAL_TIME();
463         err = native_stat("/", NULL, 0, &stbuf);
464         if (err)
465                 goto error;
466         rootino = native_i_new(fs, t + FS2NFS(fs)->nfs_atimo, &stbuf);
467         if (!rootino) {
468                 err = -ENOMEM;
469                 goto error;
470         }
471
472         /*
473          * Generate base path-node for root.
474          */
475         rootpb = _sysio_pb_new(&noname, NULL, rootino);
476         if (!rootpb) {
477                 err = -ENOMEM;
478                 goto error;
479         }
480
481         /*
482          * Mount it. This name space is disconnected from the
483          * rest of the system -- Only available within this driver.
484          */
485         err = _sysio_do_mount(fs, rootpb, 0, NULL, &mnt);
486         if (err)
487                 goto error;
488
489         native_internal_mount = mnt;
490         return 0;
491 error:
492         if (mnt) {
493                 if (_sysio_do_unmount(mnt) != 0)
494                         abort();
495                 nfs = NULL;
496                 fs = NULL;
497                 rootpb = NULL;
498                 rootino = NULL;
499         }
500         if (rootpb)
501                 _sysio_pb_gone(rootpb);
502         if (fs) {
503                 FS_RELE(fs);
504                 nfs = NULL;
505         }
506         if (nfs)
507                 free(nfs);
508         if (opts)
509                 free(opts);
510
511         return err;
512 }
513
514 static int
515 native_fsswop_mount(const char *source,
516                     unsigned flags,
517                     const void *data,
518                     struct pnode *tocover,
519                     struct mount **mntp)
520 {
521         int     err;
522         struct nameidata nameidata;
523         struct mount *mnt;
524
525         /*
526          * Caller must use fully qualified path names when specifying
527          * the source.
528          */
529         if (*source != '/')
530                 return -ENOENT;
531
532         if (!native_internal_mount) {
533                 err = create_internal_namespace(data);
534                 if (err)
535                         return err;
536         } else if (data && *(char *)data)
537                 return -EINVAL;
538
539         /*
540          * Lookup the source in the internally maintained name space.
541          */
542         ND_INIT(&nameidata, 0, source, native_internal_mount->mnt_root, NULL);
543         err = _sysio_path_walk(native_internal_mount->mnt_root, &nameidata);
544         if (err)
545                 return err;
546
547         /*
548          * Have path-node specified by the given source argument. Let the
549          * system finish the job, now.
550          */
551         err =
552             _sysio_do_mount(native_internal_mount->mnt_fs,
553                             nameidata.nd_pno->p_base,
554                             flags,
555                             tocover,
556                             &mnt);
557         /*
558          * Release the internal name space pnode and clean up any
559          * aliases we might have generated. We really don't need to cache them
560          * as they are only used at mount time..
561          */
562         P_RELE(nameidata.nd_pno);
563         (void )_sysio_p_prune(native_internal_mount->mnt_root);
564
565         if (!err) {
566                 FS_REF(native_internal_mount->mnt_fs);
567                 *mntp = mnt;
568         }
569         return err;
570 }
571
572 static int
573 native_i_invalid(struct inode *inop, struct intnl_stat *stat)
574 {
575         struct native_inode *nino;
576
577         /*
578          * Validate passed in inode against stat struct info
579          */
580         nino = I2NI(inop);
581         
582         if (!nino->ni_attrtim ||
583             (nino->ni_ident.dev != stat->st_dev ||
584              nino->ni_ident.ino != stat->st_ino ||
585 #ifdef HAVE_GENERATION
586              nino->ni_ident.gen != stat->st_gen ||
587 #endif
588              ((inop)->i_stbuf.st_mode & S_IFMT) != (stat->st_mode & S_IFMT)) ||
589             (((inop)->i_stbuf.st_rdev != stat->st_rdev) &&
590                (S_ISCHR((inop)->i_stbuf.st_mode) ||
591                 S_ISBLK((inop)->i_stbuf.st_mode)))) {
592                 nino->ni_attrtim = 0;                   /* invalidate attrs */
593                 return 1;
594         }
595         return 0;
596 }
597
598 static struct inode *
599 native_iget(struct filesys *fs, time_t expire, struct intnl_stat *stbp)
600 {
601         struct inode *ino;
602         struct native_inode_identifier ident;
603         struct file_identifier fileid;
604
605         bzero(&ident, sizeof(ident)); 
606         ident.dev = stbp->st_dev;
607         ident.ino = stbp->st_ino;
608 #ifdef HAVE_GENERATION
609         ident.gen = stbp->st_gen;
610 #endif
611         fileid.fid_data = &ident;
612         fileid.fid_len = sizeof(ident);
613         ino = _sysio_i_find(fs, &fileid);
614         if (ino) {
615                 ino->i_stbuf = *stbp;
616                 I2NI(ino)->ni_attrtim = expire;
617                 return ino;
618         }
619         return native_i_new(fs, expire, stbp);
620 }
621
622 /*
623  * Find, and validate, or create i-node by host-relative path. Returned i-node
624  * is referenced.
625  */
626 static int
627 native_ibind(struct filesys *fs,
628              char *path,
629              time_t t,
630              struct inode **inop)
631 {
632         struct intnl_stat ostbuf, stbuf;
633         int     err;
634         struct inode *ino;
635
636         if (*inop)
637                 ostbuf = (*inop)->i_stbuf;
638
639         err = native_stat(path, *inop, t, &stbuf);
640         if (err)
641                 return err;
642
643         /* 
644          * Validate?
645          */
646         if (*inop) {
647                 if (!native_i_invalid(*inop, &ostbuf))
648                         return 0;
649                 /*
650                  * Invalidate.
651                  */
652                 _sysio_i_undead(*inop);
653                 *inop = NULL;
654         }
655
656         if (!(ino = native_iget(fs, t + FS2NFS(fs)->nfs_atimo, &stbuf)))
657                 return -ENOMEM;
658
659         *inop = ino;
660         return 0;
661 }
662
663 static int
664 native_inop_lookup(struct pnode *pno,
665                    struct inode **inop,
666                    struct intent *intnt __IS_UNUSED,
667                    const char *path __IS_UNUSED)
668 {
669         time_t  t;
670         char    *fqpath;
671         struct filesys *fs;
672         int     err;
673
674         *inop = pno->p_base->pb_ino;
675
676         /*
677          * Try to use the cached attributes unless the intent
678          * indicates we are looking up the last component and
679          * caller wants attributes. In that case, force a refresh.
680          */
681         t = _SYSIO_LOCAL_TIME();
682         if (*inop &&
683             (path || !intnt || (intnt->int_opmask & INT_GETATTR) == 0) &&
684             NATIVE_ATTRS_VALID(I2NI(*inop), t))
685                 return 0;
686
687         /*
688          * Don't have an inode yet. Because we translate everything back to
689          * a single name space for the host, we will assume the object the
690          * caller is looking for has no existing alias in our internal
691          * name space. We don't see the same file on different mounts in the
692          * underlying host FS as the same file.
693          *
694          * The file identifier *will* be unique. It's got to have a different
695          * dev.
696          */
697         fqpath = _sysio_pb_path(pno->p_base, '/');
698         if (!fqpath)
699                 return -ENOMEM;
700         fs = pno->p_mount->mnt_fs;
701         err = native_ibind(fs, fqpath, t + FS2NFS(fs)->nfs_atimo, inop);
702         free(fqpath);
703         if (err)
704                 *inop = NULL;
705         return err;
706 }
707
708 static int
709 native_inop_getattr(struct pnode *pno,
710                     struct inode *ino,
711                     struct intnl_stat *stat)
712 {
713         struct native_inode *nino;
714         int     err;
715
716         /*
717          * We just cannot use the cached attributes when getattr is
718          * called. Had the caller felt those were sufficient then
719          * they could have (would have?) simply used what was cached
720          * after revalidating. In this case, there's a good chance the
721          * caller is looking for the current time stamps and/or size. Something
722          * pretty volatile anyway.
723          */
724         err = 0;                                        /* compiler cookie */
725         if (pno) {
726                 char    *path;
727                 struct filesys *fs;
728                 time_t  t;
729
730                 path = _sysio_pb_path(pno->p_base, '/');
731                 if (!path)
732                         return -ENOMEM;
733                 fs = pno->p_mount->mnt_fs;
734                 t = _SYSIO_LOCAL_TIME();
735                 err = native_stat(path, ino, t + FS2NFS(fs)->nfs_atimo, stat);
736                 free(path);
737         } else if ((nino = I2NI(ino))->ni_fd >= 0)
738                 /*
739                  * Don't have access to the fs record anymore. Just
740                  * refresh but keep the current timeout.
741                  */
742                 err = native_stat(NULL, ino, nino->ni_attrtim, stat);
743         else {
744                 /*
745                  * Dev inodes don't open in this driver. We won't have
746                  * a file descriptor with which to do the deed then. Satisfy
747                  * the request from the cached copy of the attributes.
748                  */
749                 (void )memcpy(stat,
750                               &ino->i_stbuf,
751                               sizeof(struct intnl_stat));
752                 err = 0;
753         }
754         
755         return err;
756 }
757
758 #ifdef SYSIO_SYS_utime
759 static int
760 _ut(const char *path, time_t actime, time_t modtime)
761 {
762         struct utimbuf ut;
763
764         ut.actime = actime;
765         ut.modtime = modtime;
766         return syscall(SYSIO_SYS_utime, path, &ut);
767 }
768 #else
769 static int
770 _ut(const char *path, time_t actime, time_t modtime)
771 {
772         struct timeval tv[2];
773
774         tv[0].tv_sec = actime;
775         tv[0].tv_usec = 0;
776         tv[1].tv_sec = modtime;
777         tv[1].tv_usec = 0;
778         return syscall(SYSIO_SYS_utimes, path, &tv);
779 }
780 #endif
781
782 static int
783 native_inop_setattr(struct pnode *pno,
784                     struct inode *ino,
785                     unsigned mask,
786                     struct intnl_stat *stat)
787 {
788         char    *path;
789         struct native_inode *nino;
790         int     fd;
791         int     err;
792
793         path = NULL;
794         nino = ino ? I2NI(ino) : NULL;
795         fd = -1;
796         if (nino)
797                 fd = nino->ni_fd;
798         if (fd < 0 || mask & (SETATTR_MTIME|SETATTR_ATIME)) {
799                 if (!pno)
800                         return -EEXIST;
801                 path = _sysio_pb_path(pno->p_base, '/');
802                 if (!path)
803                         return -ENOMEM;
804         }
805
806         /*
807          * Get current status for undo.
808          */
809         err = native_stat(path, ino, 0, NULL);
810         if (err)
811                 goto out;
812
813         if (mask & SETATTR_MODE) {
814                 mode_t  mode;
815
816                 /*
817                  * Alter permissions attribute.
818                  */
819                 mode = stat->st_mode & 07777;
820                 err =
821                     fd < 0
822                       ? syscall(SYSIO_SYS_chmod, path, mode)
823                       : syscall(SYSIO_SYS_fchmod, fd, mode);
824                 if (err)
825                         err = -errno;
826         }
827         if (err)
828                 mask &= ~SETATTR_MODE;
829         else if (mask & (SETATTR_MTIME|SETATTR_ATIME)) {
830                 time_t  actime, modtime;
831
832                 /*
833                  * Alter access and/or modify time attributes.
834                  */
835                 actime  = ino->i_stbuf.st_atime;
836                 modtime  = ino->i_stbuf.st_mtime;
837                 if (mask & SETATTR_ATIME)
838                         actime = stat->st_atime;
839                 if (mask & SETATTR_MTIME)
840                         modtime = stat->st_mtime;
841                 if (_ut(path, actime, modtime) != 0)
842                         return -errno;
843         }
844         if (err)
845                 mask &= ~(SETATTR_MTIME|SETATTR_ATIME);
846         else if (mask & (SETATTR_UID|SETATTR_GID)) {
847
848                 /*
849                  * Alter owner and/or group identifiers.
850                  */
851                 err =
852                     fd < 0
853                       ? syscall(SYSIO_SYS_chown,
854                                 path,
855                                 mask & SETATTR_UID
856                                   ? stat->st_uid
857                                   : (uid_t )-1,
858                                 mask & SETATTR_GID
859                                   ? stat->st_gid
860                                   : (gid_t )-1)
861                       : syscall(SYSIO_SYS_fchown,
862                                 fd,
863                                 mask & SETATTR_UID
864                                   ? stat->st_uid
865                                   : (uid_t )-1,
866                                 mask & SETATTR_GID
867                                   ? stat->st_gid
868                                   : (gid_t )-1);
869                 if (err)
870                         err = -errno;
871         }
872         if (err)
873                 mask &= ~(SETATTR_UID|SETATTR_GID);
874         else if (mask & SETATTR_LEN) {
875                 /*
876                  * Do the truncate last. It can't be undone.
877                  */
878                  (void )(fd < 0
879                            ? syscall(SYSIO_SYS_truncate, path, stat->st_size)
880                            : syscall(SYSIO_SYS_ftruncate, fd, stat->st_size));
881         }
882         if (!err)
883                 goto out;
884         /*
885          * Undo after error. Some or all of this might not work... We
886          * can but try.
887          */
888         if (mask & (SETATTR_UID|SETATTR_GID)) {
889                  (void )(fd < 0
890                            ? syscall(SYSIO_SYS_chown,
891                                      path,
892                                      mask & SETATTR_UID
893                                        ? ino->i_stbuf.st_uid
894                                        : (uid_t )-1,
895                                      mask & SETATTR_GID
896                                        ? ino->i_stbuf.st_gid
897                                        : (gid_t )-1)
898                            : syscall(SYSIO_SYS_fchown,
899                                      fd,
900                                      mask & SETATTR_UID
901                                        ? ino->i_stbuf.st_uid
902                                        : (uid_t )-1,
903                                      mask & SETATTR_GID
904                                        ? ino->i_stbuf.st_gid
905                                        : (gid_t )-1));
906         }
907         if (mask & (SETATTR_MTIME|SETATTR_ATIME))
908                 (void )_ut(path, ino->i_stbuf.st_atime, ino->i_stbuf.st_mtime);
909         if (mask & SETATTR_MODE) {
910                 fd < 0
911                   ? syscall(SYSIO_SYS_chmod, path, ino->i_stbuf.st_mode & 07777)
912                   : syscall(SYSIO_SYS_fchmod, ino->i_stbuf.st_mode & 07777);
913         }
914 out:
915         /*
916          * We must refresh the cached attributes.
917          */
918         if (!err && native_stat(path, ino, _SYSIO_LOCAL_TIME(), NULL) != 0)
919                 abort();
920         if (path)
921                 free(path);
922         return err;
923 }
924
925 static int
926 native_pos(int fd, _SYSIO_OFF_T *offset, int whence)
927 {
928         _SYSIO_OFF_T off;
929
930         assert(fd >= 0);
931         assert(*offset >= 0);
932
933         off = *offset;
934 #if _LARGEFILE64_SOURCE && defined(SYSIO_SYS__llseek)
935         {
936                 int     err;
937                 err =
938                     syscall(SYSIO_SYS__llseek,
939                             (unsigned int)fd,
940                             (unsigned int)(off >> 32),
941                             (unsigned int)off,
942                             &off,
943                             whence);
944                 if (err == -1)
945                         return -errno;
946         }
947 #else
948         off =
949             syscall(SYSIO_SYS_lseek,
950                     fd,
951                     off,
952                     whence);
953         if (off == -1)
954                 return -errno;
955 #endif
956         *offset = off;
957
958         return 0;
959 }
960
961 static ssize_t
962 native_ifilldirentries(struct native_inode *nino,
963                        _SYSIO_OFF_T *posp,
964                        char *buf,
965                        size_t nbytes)
966 {
967         int     err;
968         ssize_t cc;
969 #if defined(SYSIO_SYS_getdirentries)
970         _SYSIO_OFF_T    waste;
971 #endif
972
973         if (*posp < 0)
974                 return -EINVAL;
975
976         /*
977          * Stream-oriented access requires that we reposition prior to the
978          * fill call.
979          */
980         assert(nino->ni_seekok);
981         if (*posp != nino->ni_fpos || nino->ni_resetfpos) {
982                 nino->ni_fpos = *posp;
983                 err = native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_SET);
984                 if (err) {
985                         nino->ni_resetfpos = 1;
986                         return err;
987                 }
988                 nino->ni_resetfpos = 0;
989         }
990
991         cc =
992 #if defined(SYSIO_SYS_getdirentries)
993             syscall(SYSIO_SYS_getdirentries,
994                     nino->ni_fd,
995                     buf,
996                     nbytes,
997                     &waste);
998 #elif defined(SYSIO_SYS_getdents64)
999             syscall(SYSIO_SYS_getdents64, nino->ni_fd, buf, nbytes);
1000 #elif defined(SYSIO_SYS_getdents)
1001             syscall(SYSIO_SYS_getdents, nino->ni_fd, buf, nbytes);
1002 #endif
1003
1004         if (cc < 0)
1005                 return -errno;
1006         /*
1007          * Stream-oriented access requires that we discover where we are
1008          * after the call.
1009          */
1010         if ((err = native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_CUR)) != 0) {
1011                 /*
1012                  * Leave the position at the old I suppose.
1013                  */
1014                 nino->ni_resetfpos = 1;
1015                 return err;
1016         }
1017         *posp = nino->ni_fpos;
1018         return cc;
1019 }
1020
1021 static ssize_t
1022 native_filldirentries(struct inode *ino,
1023                       _SYSIO_OFF_T *posp,
1024                       char *buf,
1025                       size_t nbytes)
1026 {
1027         struct native_inode *nino = I2NI(ino);
1028 #if DIR_CVT_64
1029         char    *bp;
1030         size_t  count;
1031         struct linux_dirent *ldp;
1032         struct dirent64 *d64p;
1033         size_t  namlen;
1034         size_t  reclen;
1035 #else
1036 #define bp buf
1037 #define count nbytes
1038 #endif
1039         ssize_t cc;
1040
1041         assert(nino->ni_fd >= 0);
1042
1043 #if DIR_CVT_64
1044         count = nbytes;
1045         while (!(bp = malloc(count))) {
1046                 count /= 2;
1047                 if (count < sizeof(struct dirent))
1048                         return -ENOMEM;
1049         }
1050 #endif
1051         cc = native_ifilldirentries(nino, posp, bp, count);
1052         if (cc < 0) {
1053 #if DIR_CVT_64
1054                 free(bp);
1055 #endif
1056                 return cc;
1057         }
1058 #if DIR_CVT_64
1059         ldp = (struct linux_dirent *)bp;
1060         d64p = (struct dirent64 *)buf;
1061         while (cc) {
1062                 namlen = strlen(ldp->ld_name);
1063                 reclen = sizeof(*d64p) - sizeof(d64p->d_name) + namlen;
1064                 if (nbytes <= reclen)
1065                         break;
1066                 d64p->d_ino = ldp->ld_ino;
1067                 d64p->d_off = nino->ni_fpos = ldp->ld_off;
1068                 d64p->d_reclen = 
1069                     (((reclen + sizeof(long))) / sizeof(long)) * sizeof(long);
1070                 if (nbytes < d64p->d_reclen)
1071                         d64p->d_reclen = reclen + 1;
1072                 d64p->d_type = DT_UNKNOWN;              /* you lose -- sorry. */
1073                 (void )memcpy(d64p->d_name, ldp->ld_name, namlen);
1074                 /*
1075                  * Zero pad the rest.
1076                  */
1077                 for (cp = d64p->d_name + namlen, n = d64p->d_reclen - reclen;
1078                      n;
1079                      n--)
1080                         *cp++ = 0;
1081                 cc -= ldp->ld_reclen;
1082                 ldp = (struct linux_dirent *)((char *)ldp + ldp->ld_reclen);
1083                 nbytes -= d64p->d_reclen;
1084                 d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen);
1085         }
1086         free(bp);
1087         cc =
1088             (d64p == (struct dirent64 *)buf && cc)
1089               ? -EINVAL
1090               : (char *)d64p - buf;
1091 #else
1092 #undef bp
1093 #undef count
1094 #endif
1095         return cc;
1096 }
1097
1098 static int
1099 native_inop_mkdir(struct pnode *pno, mode_t mode)
1100 {
1101         char    *path;
1102         int     err;
1103
1104         path = _sysio_pb_path(pno->p_base, '/');
1105         if (!path)
1106                 return -ENOMEM;
1107
1108         err = syscall(SYSIO_SYS_mkdir, path, mode);
1109         if (err != 0)
1110                 err = -errno;
1111         free(path);
1112         return err;
1113 }
1114
1115 static int
1116 native_inop_rmdir(struct pnode *pno)
1117 {
1118         char    *path;
1119         int     err;
1120
1121         path = _sysio_pb_path(pno->p_base, '/');
1122         if (!path)
1123                 return -ENOMEM;
1124
1125         err = syscall(SYSIO_SYS_rmdir, path);
1126         if (err != 0)
1127                 err = -errno;
1128         free(path);
1129         return err;
1130 }
1131
1132 static int
1133 native_inop_symlink(struct pnode *pno, const char *data)
1134 {
1135         char    *path;
1136         int     err;
1137
1138         path = _sysio_pb_path(pno->p_base, '/');
1139         if (!path)
1140                 return -ENOMEM;
1141
1142         err = syscall(SYSIO_SYS_symlink, data, path);
1143         if (err != 0)
1144                 err = -errno;
1145         free(path);
1146         return err;
1147 }
1148
1149 static int
1150 native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz)
1151 {
1152         char    *path;
1153         int     i;
1154
1155         path = _sysio_pb_path(pno->p_base, '/');
1156         if (!path)
1157                 return -ENOMEM;
1158         i = syscall(SYSIO_SYS_readlink, path, buf, bufsiz);
1159         if (i < 0)
1160                 i = -errno;
1161         free(path);
1162         return i;
1163 }
1164
1165 static int 
1166 native_inop_open(struct pnode *pno, int flags, mode_t mode)
1167 {
1168         struct native_inode *nino;
1169         char    *path;
1170         int     fd;
1171
1172         path = _sysio_pb_path(pno->p_base, '/');
1173         if (!path)
1174                 return -ENOMEM;
1175
1176         /*
1177          * Whether the file is already open, or not, makes no difference.
1178          * Want to always give the host OS a chance to authorize in case
1179          * something has changed underneath us.
1180          */
1181         if (flags & O_WRONLY) {
1182                 /*
1183                  * Promote write-only attempt to RW.
1184                  */
1185                 flags &= ~O_WRONLY;
1186                 flags |= O_RDWR;
1187         }
1188 #ifdef O_LARGEFILE
1189         flags |= O_LARGEFILE;
1190 #endif
1191         fd = syscall(SYSIO_SYS_open, path, flags, mode);
1192         if (!pno->p_base->pb_ino && fd >= 0) {
1193                 struct filesys *fs;
1194                 int     err;
1195
1196                 /*
1197                  * Success but we need to return an i-node.
1198                  */
1199                 fs = pno->p_mount->mnt_fs;
1200                 err =
1201                     native_ibind(fs,
1202                                  path,
1203                                  _SYSIO_LOCAL_TIME() + FS2NFS(fs)->nfs_atimo,
1204                                  &pno->p_base->pb_ino);
1205                 if (err) {
1206                         (void )syscall(SYSIO_SYS_close, fd);
1207                         if (err == -EEXIST)
1208                                 abort();
1209                         fd = err;
1210                 }
1211         }
1212         free(path);
1213         if (fd < 0)
1214                 return -errno;
1215
1216         /*
1217          * Remember this new open.
1218          */
1219         nino = I2NI(pno->p_base->pb_ino);
1220         nino->ni_nopens++;
1221         assert(nino->ni_nopens);
1222
1223         if (nino->ni_fd >= 0) {
1224                 if ((nino->ni_oflags & O_RDWR) ||
1225                     (flags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_RDONLY) {
1226                         /*
1227                          * Keep existing.
1228                          */
1229                         (void )syscall(SYSIO_SYS_close, fd);
1230                         return 0;
1231                 }
1232                 (void )syscall(SYSIO_SYS_close, nino->ni_fd);
1233         }
1234         /*
1235          * Invariant; First open. Must init.
1236          */
1237         nino->ni_resetfpos = 0;
1238         nino->ni_fpos = 0;
1239         nino->ni_fd = fd;
1240         /*
1241          * Need to know whether we can seek on this
1242          * descriptor.
1243          */
1244         nino->ni_seekok =
1245             native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_CUR) != 0 ? 0 : 1;
1246
1247         return 0;
1248 }
1249
1250 static int
1251 native_inop_close(struct inode *ino)
1252 {
1253         struct native_inode *nino = I2NI(ino);
1254         int     err;
1255
1256         if (nino->ni_fd < 0)
1257                 abort();
1258
1259         assert(nino->ni_nopens);
1260         if (--nino->ni_nopens) {
1261                 /*
1262                  * Hmmm. We really don't need anything else. However, some
1263                  * filesystems try to implement a sync-on-close semantic.
1264                  * As this appears now, that is lost. Might want to change
1265                  * it somehow in the future?
1266                  */
1267                 return 0;
1268         }
1269
1270         err = syscall(SYSIO_SYS_close, nino->ni_fd);
1271         if (err)
1272                 return -errno;
1273
1274         nino->ni_fd = -1;
1275         nino->ni_resetfpos = 0;
1276         nino->ni_fpos = 0;
1277         return 0;
1278 }
1279
1280 static int
1281 native_inop_link(struct pnode *old, struct pnode *new)
1282 {
1283         int     err;
1284         char    *opath, *npath;
1285
1286         err = 0;
1287
1288         opath = _sysio_pb_path(old->p_base, '/');
1289         npath = _sysio_pb_path(new->p_base, '/');
1290         if (!(opath && npath)) {
1291                 err = -ENOMEM;
1292                 goto out;
1293         }
1294
1295         err = syscall(SYSIO_SYS_link, opath, npath);
1296         if (err != 0)
1297                 err = -errno;
1298
1299 out:
1300         if (opath)
1301                 free(opath);
1302         if (npath)
1303                 free(npath);
1304         return err;
1305 }
1306
1307 static int
1308 native_inop_unlink(struct pnode *pno)
1309 {
1310         char    *path;
1311         int     err = 0;
1312
1313         path = _sysio_pb_path(pno->p_base, '/');
1314         if (!path)
1315                 return -ENOMEM;
1316
1317         /*
1318          * For this driver, unlink is easy with open files. Since the
1319          * file remains open to the system, too, the descriptors are still
1320          * valid.
1321          *
1322          * Other drivers will have some difficulty here as the entry in the
1323          * file system name space must be removed without sacrificing access
1324          * to the file itself. In NFS this is done with a mechanism referred
1325          * to as a `silly delete'. The file is moved to a temporary name
1326          * (usually .NFSXXXXXX, where the X's are replaced by the PID and some
1327          * unique characters) in order to simulate the proper semantic.
1328          */
1329         if (syscall(SYSIO_SYS_unlink, path) != 0)
1330                 err = -errno;
1331         free(path);
1332         return err;
1333 }
1334
1335 static int
1336 native_inop_rename(struct pnode *old, struct pnode *new)
1337 {
1338         int     err;
1339         char    *opath, *npath;
1340
1341         opath = _sysio_pb_path(old->p_base, '/');
1342         npath = _sysio_pb_path(new->p_base, '/');
1343         if (!(opath && npath)) {
1344                 err = -ENOMEM;
1345                 goto out;
1346         }
1347
1348         err = syscall(SYSIO_SYS_rename, opath, npath);
1349         if (err != 0)
1350                 err = -errno;
1351
1352 out:
1353         if (opath)
1354                 free(opath);
1355         if (npath)
1356                 free(npath);
1357         return err;
1358 }
1359
1360 static ssize_t
1361 dopio(void *buf, size_t count, _SYSIO_OFF_T off, struct native_io *nio)
1362 {
1363         ssize_t cc;
1364
1365         if (!nio->nio_nino->ni_seekok) {
1366                 if (off != nio->nio_nino->ni_fpos) {
1367                         /*
1368                          * They're trying to reposition. Can't
1369                          * seek on this descriptor so we err out now.
1370                          */
1371                         errno = ESPIPE;
1372                         return -1;
1373                 }
1374                 cc =
1375                     syscall(nio->nio_op == 'r'
1376                               ? SYSIO_SYS_read
1377                               : SYSIO_SYS_write,
1378                             nio->nio_nino->ni_fd,
1379                             buf,
1380                             count);
1381                 if (cc > 0)
1382                         nio->nio_nino->ni_fpos += cc;
1383         } else
1384                 cc =
1385                     syscall((nio->nio_op == 'r'
1386                                ? SYSIO_SYS_pread
1387                                : SYSIO_SYS_pwrite),
1388                             nio->nio_nino->ni_fd,
1389                             buf,
1390                             count,
1391                             off);
1392
1393         return cc;
1394 }
1395
1396 static ssize_t
1397 doiov(const struct iovec *iov,
1398       int count,
1399       _SYSIO_OFF_T off,
1400       ssize_t limit,
1401       struct native_io *nio)
1402 {
1403         ssize_t cc;
1404
1405 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
1406 #define MAX_IOVEC      INT_MAX
1407 #endif
1408
1409
1410         if (count <= 0)
1411                 return -EINVAL;
1412
1413         /*
1414          * Avoid the reposition call if we're already at the right place.
1415          * Allows us to access pipes and fifos.
1416          */
1417         if (off != nio->nio_nino->ni_fpos) {
1418                 int     err;
1419
1420                 err = native_pos(nio->nio_nino->ni_fd, &off, SEEK_SET);
1421                 if (err) {
1422                         nio->nio_nino->ni_resetfpos = 1;
1423                         return err;
1424                 }
1425                 nio->nio_nino->ni_resetfpos = 0;
1426                 nio->nio_nino->ni_fpos = off;
1427         }
1428
1429         /*
1430          * The {read,write}v is safe as this routine is only ever called
1431          * by _sysio_enumerate_extents() and that routine is exact. It never
1432          * passes iovectors including tails.
1433          */
1434         cc =
1435 #ifndef REDSTORM
1436             count <= MAX_IOVEC
1437               ? syscall(nio->nio_op == 'r' ? SYSIO_SYS_readv : SYSIO_SYS_writev,
1438                         nio->nio_nino->ni_fd,
1439                         iov,
1440                         count)
1441               :
1442 #endif
1443                 _sysio_enumerate_iovec(iov,
1444                                        count,
1445                                        off,
1446                                        limit,
1447                                        (ssize_t (*)(void *,
1448                                                     size_t,
1449                                                     _SYSIO_OFF_T,
1450                                                     void *))dopio,
1451                                        nio);
1452         if (cc < 0)
1453                 cc = -errno;
1454         else
1455                 nio->nio_nino->ni_fpos += cc;
1456         return cc;
1457
1458 #if !(defined(REDSTORM) || defined(MAX_IOVEC))
1459 #undef MAX_IOVEC
1460 #endif
1461 }
1462
1463 #if 0
1464 static int
1465 lockop_all(struct native_inode *nino,
1466            struct intnl_xtvec *xtv,
1467            size_t count,
1468            short op)
1469 {
1470         struct flock flock;
1471         int     err;
1472
1473         if (!count)
1474                 return -EINVAL;
1475         flock.l_type = op;
1476         flock.l_whence = SEEK_SET;
1477         while (count--) {
1478                 flock.l_start = xtv->xtv_off;
1479                 flock.l_len = xtv->xtv_len;
1480                 xtv++;
1481                 err =
1482                     syscall(SYSIO_SYS_fcntl,
1483                             nino->ni_fd,
1484                             F_SETLK,
1485                             &flock);
1486                 if (err != 0)
1487                         return -errno;
1488         }
1489         return 0;
1490 }
1491
1492 static int
1493 order_xtv(const struct intnl_xtvec *xtv1, const struct intnl_xtvec *xtv2)
1494 {
1495
1496         if (xtv1->xtv_off < xtv2->xtv_off)
1497                 return -1;
1498         if (xtv1->xtv_off > xtv2->xtv_off)
1499                 return 1;
1500         return 0;
1501 }
1502 #endif
1503
1504 static int
1505 doio(char op, struct ioctx *ioctx)
1506 {
1507         struct native_inode *nino;
1508 #if 0
1509         int     dolocks;
1510         struct intnl_xtvec *oxtv;
1511         int     err;
1512 #endif
1513         struct native_io arguments;
1514         ssize_t cc;
1515 #if 0
1516         struct intnl_xtvec *front, *rear, tmp;
1517 #endif
1518
1519         nino = I2NI(ioctx->ioctx_ino);
1520 #if 0
1521         dolocks = ioctx->ioctx_xtvlen > 1 && nino->ni_seekok;
1522         if (dolocks) {
1523                 /*
1524                  * Must lock the regions (in order!) since we can't do
1525                  * strided-IO as a single atomic operation.
1526                  */
1527                 oxtv = malloc(ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec));
1528                 if (!oxtv)
1529                         return -ENOMEM;
1530                 (void )memcpy(oxtv,
1531                               ioctx->ioctx_xtv, 
1532                               ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec));
1533                 qsort(oxtv,
1534                       ioctx->ioctx_xtvlen,
1535                       sizeof(struct intnl_xtvec),
1536                       (int (*)(const void *, const void *))order_xtv);
1537                 err =
1538                     lockop_all(nino,
1539                                oxtv, ioctx->ioctx_xtvlen,
1540                                op == 'r' ? F_RDLCK : F_WRLCK);
1541                 if (err) {
1542                         free(oxtv);
1543                         return err;
1544                 }
1545         }
1546 #endif
1547         arguments.nio_op = op;
1548         arguments.nio_nino = nino;
1549         cc =
1550             _sysio_enumerate_extents(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen, 
1551                                      ioctx->ioctx_iov, ioctx->ioctx_iovlen,
1552                                      (ssize_t (*)(const struct iovec *,
1553                                                   int,
1554                                                   _SYSIO_OFF_T,
1555                                                   ssize_t,
1556                                                   void *))doiov,
1557                                      &arguments);
1558 #if 0
1559         if (dolocks) {
1560                 /*
1561                  * Must unlock in reverse order.
1562                  */
1563                 front = oxtv;
1564                 rear = front + ioctx->ioctx_xtvlen - 1;
1565                 while (front < rear) {
1566                         tmp = *front;
1567                         *front++ = *rear;
1568                         *rear-- = tmp;
1569                 }
1570                 if (lockop_all(nino, oxtv, ioctx->ioctx_xtvlen, F_UNLCK) != 0)
1571                         abort();
1572                 free(oxtv);
1573         }
1574 #endif
1575         if ((ioctx->ioctx_cc = cc) < 0) {
1576                 ioctx->ioctx_errno = -ioctx->ioctx_cc;
1577                 ioctx->ioctx_cc = -1;
1578         }
1579         return 0;
1580 }
1581
1582 static int
1583 native_inop_read(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
1584 {
1585
1586         return doio('r', ioctx);
1587 }
1588
1589 static int
1590 native_inop_write(struct inode *ino __IS_UNUSED, struct ioctx *ioctx)
1591 {
1592
1593         return doio('w', ioctx);
1594 }
1595
1596 static _SYSIO_OFF_T
1597 native_inop_pos(struct inode *ino, _SYSIO_OFF_T off)
1598 {
1599         struct native_inode *nino = I2NI(ino);
1600         int     err;
1601
1602         err = native_pos(nino->ni_fd, &off, SEEK_SET);
1603         return err < 0 ? err : off;
1604 }
1605
1606 static int
1607 native_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
1608 {
1609
1610         /*
1611          * It's always done in this driver. It completed when posted.
1612          */
1613         return 1;
1614 }
1615
1616 static int
1617 native_inop_fcntl(struct inode *ino,
1618                   int cmd,
1619                   va_list ap,
1620                   int *rtn)
1621 {
1622         struct native_inode *nino = I2NI(ino);
1623         long    arg;
1624         int     err;
1625
1626         if (nino->ni_fd < 0)
1627                 abort();
1628
1629         err = 0;
1630         switch (cmd) {
1631         case F_GETFD:
1632         case F_GETFL:
1633 #ifdef F_GETOWN
1634         case F_GETOWN:
1635 #endif
1636                 *rtn = syscall(SYSIO_SYS_fcntl, nino->ni_fd, cmd);
1637                 if (*rtn == -1)
1638                         err = -errno;
1639                 break;
1640         case F_DUPFD:
1641         case F_SETFD:
1642         case F_SETFL:
1643         case F_GETLK:
1644         case F_SETLK:
1645         case F_SETLKW:
1646 #ifdef F_SETOWN
1647         case F_SETOWN:
1648 #endif
1649                 arg = va_arg(ap, long);
1650                 *rtn = syscall(SYSIO_SYS_fcntl, nino->ni_fd, cmd, arg);
1651                 if (*rtn == -1)
1652                         err = -errno;
1653                 break;
1654         default:
1655                 *rtn = -1;
1656                 err = -EINVAL;
1657         }
1658         return err;
1659 }
1660
1661 static int
1662 native_inop_mknod(struct pnode *pno __IS_UNUSED,
1663                   mode_t mode __IS_UNUSED,
1664                   dev_t dev __IS_UNUSED)
1665 {
1666
1667         return -ENOSYS;
1668 }
1669
1670 #ifdef _HAVE_STATVFS
1671 static int
1672 native_inop_statvfs(struct pnode *pno,
1673                     struct inode *ino,
1674                     struct intnl_statvfs *buf)
1675 {
1676         char    *path;
1677         int    rc;
1678         struct statfs fs;
1679
1680         path = NULL;
1681         if (!ino || I2NI(ino)->ni_fd < 0) {
1682                 path = _sysio_pb_path(pno->p_base, '/');
1683                 if (!path)
1684                         return -ENOMEM;
1685         }
1686
1687         /*
1688          * The syscall interface does not support SYSIO_SYS_fstatvfs.
1689          * Should possibly return ENOSYS, but thought it
1690          * better to use SYSIO_SYS_fstatfs and fill in as much of
1691          * the statvfs structure as possible.  This allows
1692          * for more of a test of the sysio user interface.
1693          */
1694         rc =
1695             path
1696               ? syscall(SYSIO_SYS_statfs, path, &fs)
1697               : syscall(SYSIO_SYS_fstatfs, I2NI(ino)->ni_fd, &fs);
1698         if (path)
1699                 free(path);
1700         if (rc < 0)
1701                 return -errno;
1702
1703         buf->f_bsize = fs.f_bsize;  /* file system block size */
1704         buf->f_frsize = fs.f_bsize; /* file system fundamental block size */
1705         buf->f_blocks = fs.f_blocks;
1706         buf->f_bfree = fs.f_bfree;
1707         buf->f_bavail = fs.f_bavail;
1708         buf->f_files = fs.f_files;  /* Total number serial numbers */
1709         buf->f_ffree = fs.f_ffree;  /* Number free serial numbers */
1710         buf->f_favail = fs.f_ffree; /* Number free ser num for non-privileged*/
1711         buf->f_fsid = fs.f_fsid.__val[1];
1712         buf->f_flag = 0;            /* No equiv in statfs; maybe use type? */
1713         buf->f_namemax = fs.f_namelen;
1714         return 0;
1715 }
1716 #endif
1717
1718 static int
1719 native_inop_sync(struct inode *ino)
1720 {
1721         int     err;
1722
1723         assert(I2NI(ino)->ni_fd >= 0);
1724
1725         err = syscall(SYSIO_SYS_fsync, I2NI(ino)->ni_fd);
1726         if (err)
1727                 err = -errno;
1728         return err;
1729 }
1730
1731 static int
1732 native_inop_datasync(struct inode *ino)
1733 {
1734         struct native_inode *nino;
1735         int     err;
1736
1737         nino = I2NI(ino);
1738         assert(nino->ni_fd >= 0);
1739
1740 #ifdef SYSIO_SYS_fdatasync
1741         err = syscall(SYSIO_SYS_fdatasync, I2NI(ino)->ni_fd);
1742 #else
1743 #if 0
1744 #warning No fdatasync system call -- Using fsync instead!
1745 #endif
1746         err = syscall(SYSIO_SYS_fsync, I2NI(ino)->ni_fd);
1747 #endif
1748         if (err)
1749                 err = -errno;
1750         return err;
1751 }
1752
1753 #ifdef HAVE_LUSTRE_HACK
1754 static int
1755 native_inop_ioctl(struct inode *ino,
1756                   unsigned long int request,
1757                   va_list ap)
1758 {
1759         struct native_inode *nino;
1760         long arg1, arg2, arg3, arg4;
1761         int     rtn;
1762
1763         nino = I2NI(ino);
1764         assert(nino->ni_fd >= 0);
1765         arg1 = va_arg(ap, long);
1766         arg2 = va_arg(ap, long);
1767         arg3 = va_arg(ap, long);
1768         arg4 = va_arg(ap, long);
1769
1770         rtn =
1771             syscall(SYSIO_SYS_ioctl, I2NI(ino)->ni_fd, request,
1772                     arg1, arg2, arg3, arg4);
1773         if (rtn < 0)
1774                 rtn = -errno;
1775         return rtn;
1776 }
1777 #else
1778 static int
1779 native_inop_ioctl(struct inode *ino __IS_UNUSED,
1780                   unsigned long int request __IS_UNUSED,
1781                   va_list ap __IS_UNUSED)
1782 {
1783
1784         /*
1785          * I'm lazy. Maybe implemented later.
1786          */
1787         return -ENOTTY;
1788 }
1789 #endif
1790
1791 static void
1792 native_inop_gone(struct inode *ino)
1793 {
1794         struct native_inode *nino = I2NI(ino);
1795
1796         if (nino->ni_fd >= 0)
1797                 (void )syscall(SYSIO_SYS_close, nino->ni_fd);
1798
1799         free(ino->i_private);
1800 }
1801
1802 static void
1803 native_fsop_gone(struct filesys *fs __IS_UNUSED)
1804 {
1805
1806         free(fs->fs_private);
1807         /*
1808          * Do nothing. There is no private part maintained for the
1809          * native file interface.
1810          */
1811 }