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