Whamcloud - gitweb
LU-2730 mdt: fix erroneous LASSERT in mdt_reint_opcode
[fs/lustre-release.git] / libsysio / drivers / incore / fs_incore.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-2003 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 <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <time.h>
52 #include <limits.h>
53 #include <errno.h>
54 #include <assert.h>
55 #include <sys/uio.h>
56 #include <sys/types.h>
57 #include <dirent.h>
58 #include <sys/stat.h>
59 #ifdef _HAVE_STATVFS
60 #include <sys/statvfs.h>
61 #endif
62 #include <sys/queue.h>
63
64 #include "sysio.h"
65 #include "xtio.h"
66 #include "fs.h"
67 #include "mount.h"
68 #include "inode.h"
69 #include "dev.h"
70
71 #include "fs_incore.h"
72
73
74 /*
75  * In-core file system pseudo-driver.
76  */
77
78 /*
79  * Pseudo-blocksize.
80  */
81 #define INCORE_BLKSIZE          (8192)
82
83 /*
84  * Format of an incore inode.
85  */
86 struct incore_inode {
87         LIST_ENTRY(incore_inode) ici_link;              /* i-nodes list link */
88         struct intnl_stat ici_st;                       /* attrs */
89         struct file_identifier ici_fileid;              /* file ID */
90         void    *ici_data;                              /* file data */
91 };
92
93 /*
94  * Given pointer to inode, return pointer to incore-inode.
95  */
96 #define I2IC(ino)       ((struct incore_inode *)(ino)->i_private)
97
98 struct incore_filesys {
99         LIST_HEAD(, incore_inode) icfs_icinodes;        /* all i-nodes list */
100 };
101
102 /*
103  * Given pointer to filesys, return pointer to incore-filesys.
104  */
105 #define FS2ICFS(fs)     ((struct incore_filesys *)(fs)->fs_private)
106
107 static int _sysio_incore_fsswop_mount(const char *source,
108                                       unsigned flags,
109                                       const void *data,
110                                       struct pnode *tocover,
111                                       struct mount **mntp);
112
113 static struct fssw_ops incore_fssw_ops = {
114                 _sysio_incore_fsswop_mount
115 };
116
117 static void _sysio_incore_fsop_gone(struct filesys *fs);
118
119 static struct filesys_ops incore_fs_ops = {
120                 _sysio_incore_fsop_gone,
121 };
122
123 static int _sysio_incore_dirop_lookup(struct pnode *pno,
124                                       struct inode **inop,
125                                       struct intent *intnt,
126                                       const char *path);
127 static int _sysio_incore_inop_getattr(struct pnode *pno,
128                                       struct inode *ino,
129                                       struct intnl_stat *stbuf);
130 static int _sysio_incore_inop_setattr(struct pnode *pno,
131                                       struct inode *ino,
132                                       unsigned mask,
133                                       struct intnl_stat *stbuf);
134 static ssize_t _sysio_incore_dirop_filldirentries(struct inode *ino,
135                                                   _SYSIO_OFF_T *posp,
136                                                   char *buf,
137                                                   size_t nbytes);
138 static int _sysio_incore_dirop_mkdir(struct pnode *pno, mode_t mode);
139 static int _sysio_incore_dirop_rmdir(struct pnode *pno);
140 static int _sysio_incore_inop_open(struct pnode *pno, int flags, mode_t mode);
141 static int _sysio_incore_inop_close(struct inode *ino);
142 static int _sysio_incore_dirop_link(struct pnode *old, struct pnode *new);
143 static int _sysio_incore_dirop_unlink(struct pnode *pno);
144 static int _sysio_incore_dirop_rename(struct pnode *old, struct pnode *new);
145 static int _sysio_incore_filop_read(struct inode *ino, struct ioctx *ioctx);
146 static int _sysio_incore_filop_write(struct inode *ino, struct ioctx *ioctx);
147 static _SYSIO_OFF_T _sysio_incore_filop_pos(struct inode *ino,
148                                             _SYSIO_OFF_T off);
149 static int _sysio_incore_filop_iodone(struct ioctx *ioctx);
150 static int _sysio_incore_filop_fcntl(struct inode *ino, 
151                                      int cmd, va_list ap, int *rtn);
152 static int _sysio_incore_inop_sync(struct inode *ino);
153 static int _sysio_incore_filop_ioctl(struct inode *ino,
154                                     unsigned long int request,
155                                     va_list ap);
156 static int _sysio_incore_dirop_mknod(struct pnode *pno, mode_t mode, dev_t dev);
157 #ifdef _HAVE_STATVFS
158 static int _sysio_incore_inop_statvfs(struct pnode *pno,
159                                       struct inode *ino,
160                                       struct intnl_statvfs *buf);
161 #endif
162 static void _sysio_incore_inop_gone(struct inode *ino);
163
164 #define _sysio_incore_dirop_symlink \
165         (int (*)(struct pnode *, const char *))_sysio_do_enosys
166 #define _sysio_incore_dirop_readlink \
167         (int (*)(struct pnode *, char *, size_t))_sysio_do_enosys
168 #define _sysio_incore_dirop_read \
169         (int (*)(struct inode *, \
170                  struct ioctx *))_sysio_do_eisdir
171 #define _sysio_incore_dirop_write \
172         (int (*)(struct inode *, \
173                  struct ioctx *))_sysio_do_eisdir
174 #define _sysio_incore_dirop_pos \
175         (_SYSIO_OFF_T (*)(struct inode *, \
176                           _SYSIO_OFF_T))_sysio_do_eisdir
177 #define _sysio_incore_dirop_iodone \
178         (int (*)(struct ioctx *))_sysio_do_illop
179 #define _sysio_incore_dirop_fcntl \
180         (int (*)(struct inode *, int, va_list, int *))_sysio_do_eisdir
181 #define _sysio_incore_dirop_ioctl \
182         (int (*)(struct inode *, \
183                  unsigned long int, \
184                  va_list))_sysio_do_eisdir
185
186 static struct inode_ops _sysio_incore_dir_ops = {
187         _sysio_incore_dirop_lookup,
188         _sysio_incore_inop_getattr,
189         _sysio_incore_inop_setattr,
190         _sysio_incore_dirop_filldirentries,
191         _sysio_incore_dirop_mkdir,
192         _sysio_incore_dirop_rmdir,
193         _sysio_incore_dirop_symlink,
194         _sysio_incore_dirop_readlink,
195         _sysio_incore_inop_open,
196         _sysio_incore_inop_close,
197         _sysio_incore_dirop_link,
198         _sysio_incore_dirop_unlink,
199         _sysio_incore_dirop_rename,
200         _sysio_incore_dirop_read,
201         _sysio_incore_dirop_write,
202         _sysio_incore_dirop_pos,
203         _sysio_incore_dirop_iodone,
204         _sysio_incore_dirop_fcntl,
205         _sysio_incore_inop_sync,
206         _sysio_incore_inop_sync,
207         _sysio_incore_dirop_ioctl,
208         _sysio_incore_dirop_mknod,
209 #ifdef _HAVE_STATVFS
210         _sysio_incore_inop_statvfs,
211 #endif
212         _sysio_incore_inop_gone
213 };
214
215 #define _sysio_incore_filop_lookup \
216         (int (*)(struct pnode *, \
217                  struct inode **, \
218                  struct intent *, \
219                  const char *))_sysio_do_illop
220 #define _sysio_incore_filop_filldirentries \
221         (ssize_t (*)(struct inode *, \
222                      _SYSIO_OFF_T *, \
223                      char *, \
224                      size_t))_sysio_do_illop
225 #define _sysio_incore_filop_mkdir \
226         (int (*)(struct pnode *, mode_t))_sysio_do_illop
227 #define _sysio_incore_filop_rmdir \
228         (int (*)(struct pnode *))_sysio_do_illop
229 #define _sysio_incore_filop_symlink \
230         (int (*)(struct pnode *, const char *))_sysio_do_illop
231 #define _sysio_incore_symlinkop_readlink \
232         (int (*)(struct pnode *, char *, size_t))_sysio_do_illop
233 #define _sysio_incore_filop_link \
234         (int (*)(struct pnode *old, struct pnode *new))_sysio_do_illop
235 #define _sysio_incore_filop_unlink \
236         (int (*)(struct pnode *pno))_sysio_do_illop
237 #define _sysio_incore_filop_rename \
238         (int (*)(struct pnode *old, struct pnode *new))_sysio_do_illop
239 #define _sysio_incore_filop_mknod \
240         (int (*)(struct pnode *pno, mode_t, dev_t))_sysio_do_illop
241
242 static struct inode_ops _sysio_incore_file_ops = {
243         _sysio_incore_filop_lookup,
244         _sysio_incore_inop_getattr,
245         _sysio_incore_inop_setattr,
246         _sysio_incore_filop_filldirentries,
247         _sysio_incore_filop_mkdir,
248         _sysio_incore_filop_rmdir,
249         _sysio_incore_filop_symlink,
250         _sysio_incore_symlinkop_readlink,
251         _sysio_incore_inop_open,
252         _sysio_incore_inop_close,
253         _sysio_incore_filop_link,
254         _sysio_incore_filop_unlink,
255         _sysio_incore_filop_rename,
256         _sysio_incore_filop_read,
257         _sysio_incore_filop_write,
258         _sysio_incore_filop_pos,
259         _sysio_incore_filop_iodone,
260         _sysio_incore_filop_fcntl,
261         _sysio_incore_inop_sync,
262         _sysio_incore_inop_sync,
263         _sysio_incore_filop_ioctl,
264         _sysio_incore_filop_mknod,
265 #ifdef _HAVE_STATVFS
266         _sysio_incore_inop_statvfs,
267 #endif
268         _sysio_incore_inop_gone
269 };
270
271 static struct inode_ops _sysio_incore_dev_ops = {
272         _sysio_incore_filop_lookup,
273         _sysio_incore_inop_getattr,
274         _sysio_incore_inop_setattr,
275         _sysio_incore_filop_filldirentries,
276         _sysio_incore_filop_mkdir,
277         _sysio_incore_filop_rmdir,
278         _sysio_incore_filop_symlink,
279         _sysio_incore_symlinkop_readlink,
280         _sysio_nodev_inop_open,
281         _sysio_nodev_inop_close,
282         _sysio_incore_filop_link,
283         _sysio_incore_filop_unlink,
284         _sysio_incore_filop_rename,
285         _sysio_nodev_inop_read,
286         _sysio_nodev_inop_write,
287         _sysio_nodev_inop_pos,
288         _sysio_nodev_inop_iodone,
289         _sysio_incore_filop_fcntl,
290         _sysio_incore_inop_sync,
291         _sysio_nodev_inop_sync,
292         _sysio_nodev_inop_ioctl,
293         _sysio_incore_filop_mknod,
294 #ifdef _HAVE_STATVFS
295         _sysio_incore_inop_statvfs,
296 #endif
297         _sysio_incore_inop_gone
298 };
299
300 typedef void *(*probe_ty)(void *data, size_t len, void *arg);
301
302 /*
303  * Lookup data argument bundle record.
304  */
305 struct lookup_data {
306         struct qstr *name;                              /* desired entry name */
307         struct intnl_dirent *de;                        /* last dirent */
308         size_t  minsiz;                                 /* min hole needed */
309         struct {
310                 void    *p;                             /* best hole */
311                 size_t  len;                            /* best hole len */
312         } hole;
313 };
314
315 /*
316  * Initialize lookup data argument bundle.
317  */
318 #define INCORE_LD_INIT(ld, minsz, qs) \
319         do { \
320                 (ld)->name = (qs); \
321                 (ld)->de = NULL; \
322                 (ld)->minsiz = (minsz); \
323                 (ld)->hole.p = NULL; \
324                 (ld)->hole.len = 0; \
325         } while (0)
326
327 /*
328  * Calculate size of a directory entry given length of the entry name.
329  */
330 #define INCORE_D_RECLEN(namlen) \
331         (((size_t )&((struct intnl_dirent *)0)->d_name + \
332           (namlen) + 1 + sizeof(void *)) & \
333          ~(sizeof(void *) - 1))
334
335 /*
336  * Given mode bits, return directory entry type code.
337  */
338 #define INCORE_D_TYPEOF(m)      (((m) & S_IFMT) >> 12)
339 #define INCORE_D_TEMPLATE_LEN   (INCORE_D_RECLEN(1) + INCORE_D_RECLEN(2))
340
341 char *incore_dir_template;
342 #if 0
343 static struct intnl_dirent incore_dir_template[] = {
344         {
345                 0,
346                 INCORE_D_RECLEN(1),
347                 INCORE_D_RECLEN(1),
348                 INCORE_D_TYPEOF(S_IFDIR),
349                 { '.', '\0' }
350         },
351         {
352                 0,
353                 INCORE_D_RECLEN(1) + INCORE_D_RECLEN(2),
354                 INCORE_D_RECLEN(2),
355                 INCORE_D_TYPEOF(S_IFDIR),
356                 { '.', '.', '\0' }
357         }
358 };
359 #endif
360
361 /*
362  * Initialize this driver.
363  */
364 int
365 _sysio_incore_init()
366 {
367         struct intnl_dirent *de;
368         off_t   off;
369
370         /*
371          * Fill in the directory template.
372          */
373         incore_dir_template = calloc(1, INCORE_D_TEMPLATE_LEN);
374         if (incore_dir_template == NULL)
375                 return -ENOMEM;
376         de = (struct intnl_dirent *)incore_dir_template;
377 #ifdef _DIRENT_HAVE_D_OFF
378         de->d_off =
379 #endif
380             off = de->d_reclen = INCORE_D_RECLEN(1);
381         de->d_type = INCORE_D_TYPEOF(S_IFDIR);
382         de->d_name[0] = '.';
383 #ifdef _DIRENT_HAVE_D_NAMLEN
384         de->d_namlen = 1;
385 #endif
386         /*
387          * Move to entry for `..'
388          */
389         de = (struct intnl_dirent *)((char *)de + off);
390         de->d_reclen = INCORE_D_RECLEN(2);
391 #ifdef _DIRENT_HAVE_D_NAMLEN
392         de->d_namlen = 2;
393 #endif
394 #ifdef _DIRENT_HAVE_D_OFF
395         de->d_off =
396 #endif
397             off += de->d_reclen;
398         de->d_type = INCORE_D_TYPEOF(S_IFDIR);
399         de->d_name[0] = de->d_name[1] = '.';
400         de->d_name[2] = ' ';
401
402         return _sysio_fssw_register("incore", &incore_fssw_ops);
403 }
404
405 static ino_t
406 incore_inum_alloc()
407 {
408         static ino_t nxtnum = 1;
409
410         assert(nxtnum);
411         return nxtnum++;
412 }
413
414 static struct incore_inode *
415 incore_i_alloc(struct incore_filesys *icfs, struct intnl_stat *st)
416 {
417         struct incore_inode *icino;
418
419         assert(st->st_ino);
420         assert(!st->st_size);
421
422         icino = malloc(sizeof(struct incore_inode));
423         if (!icino)
424                 return NULL;
425         icino->ici_st = *st;
426         icino->ici_fileid.fid_data = &icino->ici_st.st_ino;
427         icino->ici_fileid.fid_len = sizeof(icino->ici_st.st_ino);
428         icino->ici_data = NULL;
429
430         LIST_INSERT_HEAD(&icfs->icfs_icinodes, icino, ici_link);
431
432         return icino;
433 }
434
435 static int
436 incore_trunc(struct incore_inode *icino, _SYSIO_OFF_T size, int clear)
437 {
438         _SYSIO_OFF_T n;
439         void    *p;
440
441         if (size < 0) 
442                 return -EINVAL;
443         n = size;
444         if (!size) {
445                 if (icino->ici_data) {
446                         free(icino->ici_data);
447                         icino->ici_data = NULL;
448                 }
449                 n = 0;
450                 goto out;
451         }
452         p = realloc(icino->ici_data, (size_t )n);
453         if (!p)
454                 return -ENOSPC;
455         icino->ici_data = p;
456         if (clear && n > icino->ici_st.st_size)
457                 (void )memset((char *)icino->ici_data + icino->ici_st.st_size,
458                               0,
459                               (size_t )(n - icino->ici_st.st_size));
460 out:
461         icino->ici_st.st_size = n;
462         icino->ici_st.st_blocks =
463             (n + icino->ici_st.st_blksize - 1) / icino->ici_st.st_blksize;
464         icino->ici_st.st_mtime = time(NULL);
465         return 0;
466 }
467
468 static void
469 incore_i_destroy(struct incore_inode *icino)
470 {
471
472         LIST_REMOVE(icino, ici_link);
473         (void )incore_trunc(icino, 0, 0);
474         free(icino);
475 }
476
477 static struct incore_inode *
478 incore_directory_new(struct incore_filesys *icfs,
479                      struct incore_inode *parent,
480                      struct intnl_stat *st)
481 {
482         struct incore_inode *icino;
483         int     err;
484         struct intnl_dirent *de;
485
486         icino = incore_i_alloc(icfs, st);
487         if (!icino)
488                 return NULL;
489
490         if (!parent)
491                 parent = icino;                         /* root */
492
493         /*
494          * Allocate and init directory data.
495          */
496         err = incore_trunc(icino, INCORE_D_TEMPLATE_LEN, 1);
497         if (err) {
498                 incore_i_destroy(icino);
499                 return NULL;
500         }
501         (void )memcpy(icino->ici_data,
502                       &incore_dir_template,
503                       INCORE_D_TEMPLATE_LEN);
504         de = icino->ici_data;
505         de->d_ino = st->st_ino;
506         de =
507             (struct intnl_dirent *)((char *)de +
508 #ifdef _DIRENT_HAVE_D_OFF
509                                     de->d_off
510 #else
511                                     de->d_reclen
512 #endif
513                                     );
514         de->d_ino = parent->ici_st.st_ino;
515
516         /*
517          * Set creation time to modify time set by truncate.
518          */
519         st->st_ctime = st->st_mtime;
520
521         return icino;
522 }
523
524 static int
525 _sysio_incore_fsswop_mount(const char *source,
526                            unsigned flags,
527                            const void *data __IS_UNUSED,
528                            struct pnode *tocover,
529                            struct mount **mntp)
530 {
531         char    *cp;
532         unsigned long ul;
533         long    l;
534         mode_t  mode;
535         uid_t   uid;
536         gid_t   gid;
537         int     err;
538         dev_t   dev;
539         struct intnl_stat stat;
540         struct incore_filesys *icfs;
541         ino_t   inum;
542         struct incore_inode *icino;
543         struct filesys *fs;
544         struct inode *rooti;
545         struct pnode_base *rootpb;
546         struct mount *mnt;
547         static struct qstr noname = { NULL, 0, 0 };
548
549         /*
550          * Source is a specification for the root attributes of this
551          * new file system in the format:
552          *
553          * <permissions>[+<owner>][-<group>]
554          */
555         ul = strtoul(source, &cp, 0);
556         mode = (mode_t )ul & 07777;
557         uid = getuid();                                 /* default */
558         gid = getgid();                                 /* default */
559         if (*cp != '\0') {
560                 /*
561                  * Get user and/or group.
562                  */
563                 if (*cp != '+' ||
564                     (ul == ULONG_MAX && errno == ERANGE) ||
565                     (unsigned long)mode != ul ||
566                     mode > 07777)
567                         return -EINVAL;
568                 source = cp;
569                 l = strtol(source, &cp, 0);
570                 uid = (uid_t )l;
571                 if (((l == LONG_MIN || l == LONG_MAX) &&
572                      errno == ERANGE) ||
573                     (long )uid != l)
574                         return -EINVAL;
575                 if (*cp != '+')
576                         return -EINVAL;
577                 source = cp;
578                 l = strtol(source, &cp, 0);
579                 gid = (gid_t )l;
580                 if (((l == LONG_MIN || l == LONG_MAX) &&
581                      errno == ERANGE) ||
582                     (long )gid != l)
583                         return -EINVAL;
584                 if (*cp != '\0')
585                         return -EINVAL;
586         }
587
588         err = 0;
589
590         dev = _sysio_dev_alloc();
591
592         mnt = NULL;
593         rootpb = NULL;
594         rooti = NULL;
595         fs = NULL;
596         icino = NULL;
597         icfs = NULL;
598
599         /*
600          * Create new FS.
601          */
602         icfs = malloc(sizeof(struct incore_filesys));
603         if (!icfs) {
604                 err = -ENOMEM;
605                 goto error;
606         }
607         (void )memset(icfs, 0, sizeof(struct incore_filesys));
608         LIST_INIT(&icfs->icfs_icinodes);
609
610         /*
611          * Create root i-node.
612          */
613         (void )memset(&stat, 0, sizeof(stat));
614         stat.st_dev = dev;
615         inum = incore_inum_alloc();
616 #ifdef HAVE__ST_INO
617         stat.__st_ino = inum; 
618 #endif
619         stat.st_mode = S_IFDIR | (mode & 07777);
620         stat.st_nlink = 2;
621         stat.st_uid = uid;
622         stat.st_gid = gid;
623         stat.st_size = 0;
624         stat.st_blksize = INCORE_BLKSIZE;
625         stat.st_blocks = 0;
626         stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
627         stat.st_ino = inum;
628         icino = incore_directory_new(icfs, NULL, &stat);
629         if (!icino)
630                 return -ENOSPC;
631         icino->ici_st.st_atime = icino->ici_st.st_mtime;
632
633         fs =
634             _sysio_fs_new(&incore_fs_ops,
635                           (flags & MOUNT_F_RO) ? FS_F_RO : 0,
636                           icfs);
637         if (!fs) {
638                 err = -ENOMEM;
639                 goto error;
640         }
641
642         /*
643          * Create root for system.
644          *
645          * Persistent across remounts because we ask for immunity.
646          */
647         rooti =
648             _sysio_i_new(fs,
649                          &icino->ici_fileid,
650                          &icino->ici_st,
651                          1,
652                          &_sysio_incore_dir_ops,
653                          icino);
654         if (!rooti) {
655                 err = -ENOMEM;
656                 goto error;
657         }
658         rootpb = _sysio_pb_new(&noname, NULL, rooti);
659         if (!rootpb) {
660                 err = -ENOMEM;
661                 goto error;
662         }
663
664         /*
665          * Have path-node specified by the given source argument. Let the
666          * system finish the job, now.
667          */
668         mnt = NULL;
669         err =
670             _sysio_do_mount(fs,
671                             rootpb,
672                             flags,
673                             tocover,
674                             &mnt);
675         if (err)
676                 goto error;
677
678         *mntp = mnt;
679
680         goto out;
681
682 error:
683         if (mnt && _sysio_do_unmount(mnt) != 0)
684                         abort();
685         if (rootpb) {
686                 _sysio_pb_gone(rootpb);
687                 rooti = NULL;
688         }
689         if (rooti)
690                 I_RELE(rooti);
691         if (fs) {
692                 FS_RELE(fs);
693                 goto out;
694         }
695         if (icino) {
696                 incore_i_destroy(icino);
697                 goto out;
698         }
699         if (icfs) {
700                 free(icfs);
701                 goto out;
702         }
703
704 out:
705         return err;
706 }
707
708 static void
709 _sysio_incore_fsop_gone(struct filesys *fs)
710 {
711         struct incore_filesys *icfs;
712         struct incore_inode *icino, *oicino;
713
714         icfs = FS2ICFS(fs);
715
716         /*
717          * Free up i-node resource associated with this file system.
718          */
719         icino = icfs->icfs_icinodes.lh_first;
720         while (icino) {
721                 oicino = icino;
722                 icino = icino->ici_link.le_next;
723                 incore_i_destroy(oicino);
724         }
725
726         /*
727          * Free the FS record.
728          */
729         free(icfs);
730 }
731
732 /*
733  * A directory search engine. Various functions are carried out by
734  * supplying appropriate callback functions.
735  *
736  * The two arguments, entry and hole, are called, if not null, for each
737  * directory entry and hole, respectively.
738  */
739 static void *
740 incore_directory_probe(void *data,
741                        size_t siz,
742                        _SYSIO_OFF_T origin
743 #ifndef _DIRENT_HAVE_D_OFF
744                                 __IS_UNUSED
745 #endif
746                        ,
747                        probe_ty entry,
748                        probe_ty hole,
749                        void *arg)
750 {
751         struct intnl_dirent *de;
752         void    *p;
753         size_t  n;
754
755         de = data;
756         for (;;) {
757 #ifdef _DIRENT_HAVE_D_OFF
758                 assert(de->d_off);
759 #else
760                 assert(de->d_reclen);
761 #endif
762                 if (entry && (p = (*entry)(de, de->d_reclen, arg)))
763                         return p;
764                 n =
765 #ifdef _DIRENT_HAVE_D_OFF
766                     de->d_off - origin;
767 #else
768                     ((void *)de - data) + de->d_reclen;
769 #endif
770                 if (hole) {
771                         p = (*hole)((void *)de, de->d_reclen, arg);
772                         if (p)
773                                 return p;
774                 }
775                 if (n >= siz)
776                         break;
777                 de = (struct intnl_dirent *)((char *)data + n);
778         }
779
780         return NULL;
781 }
782
783 static struct intnl_dirent *
784 incore_directory_match(struct intnl_dirent *de,
785                        size_t reclen,
786                        struct lookup_data *ld)
787 {
788         size_t  len;
789
790 #if defined(BSD) || defined(REDSTORM)
791         if (IFTODT(de->d_type) == DT_WHT)
792                 return NULL;
793 #endif
794 #ifdef _DIRENT_HAVE_D_NAMLEN
795         len = de->d_namlen;
796 #else
797         {
798                 const char *cp, *end;
799
800                 cp = de->d_name;
801                 end = (const char *)de + reclen;
802                 while (cp < end && *cp != '\0')
803                         cp++;
804                 len = cp - de->d_name;
805         }
806 #endif
807         if (ld->name->len == len &&
808             strncmp(de->d_name, ld->name->name, ld->name->len) == 0)
809                 return de;
810         ld->de = de;
811         return NULL;
812 }
813
814 static int
815 _sysio_incore_dirop_lookup(struct pnode *pno,
816                            struct inode **inop,
817                            struct intent *intnt __IS_UNUSED,
818                            const char *path __IS_UNUSED)
819 {
820         struct inode *ino;
821         struct intnl_dirent *de;
822         struct incore_inode *icino;
823         struct lookup_data lookup_data;
824         struct file_identifier fileid;
825 #ifdef notdef
826         struct inode_ops *ops;
827 #endif
828
829         /*
830          * Revalidate?
831          */
832         if (*inop) {
833                 icino = I2IC(*inop);
834                 assert(icino);
835                 (*inop)->i_stbuf = icino->ici_st;
836                 return 0;
837         }
838
839         ino = pno->p_parent->p_base->pb_ino;
840         icino = I2IC(ino);
841         INCORE_LD_INIT(&lookup_data,
842                        ULONG_MAX,
843                        &pno->p_base->pb_name);
844         de =
845             incore_directory_probe(icino->ici_data,
846                                    icino->ici_st.st_size,
847                                    0,
848                                    (probe_ty )incore_directory_match,
849                                    NULL,
850                                    &lookup_data);
851         if (!de)
852                 return -ENOENT;
853
854         fileid.fid_data = &de->d_ino;
855         fileid.fid_len = sizeof(de->d_ino);
856         ino =
857             _sysio_i_find(ino->i_fs, &fileid);
858 #ifdef notdef
859         if (ino)
860                 goto out;
861         icino->ici_fileid.fid_data = &icino->ici_st.st_ino;
862         icino->ici_fileid.fid_len = sizeof(icino->ici_st.st_ino);
863         ops = NULL;
864         switch (icino->ici_st.st_mode & S_IFMT) {
865         case S_IFDIR:
866                 ops = &_sysio_incore_dir_ops;
867                 break;
868         case S_IFREG:
869                 ops = &_sysio_incore_file_ops;
870                 break;
871         default:
872                 break;
873         }
874         if (!ops)
875                 abort();
876         ino =
877             _sysio_i_new(ino->i_fs,
878                          &icino->ici_fileid,
879                          &icino->ici_st
880                          1,
881                          ops,
882                          icino);
883 #endif
884         if (!ino)
885                 return -ENOMEM;
886
887 #ifdef notdef
888 out:
889 #endif
890         *inop = ino;
891         return 0;
892 }
893
894 static int
895 _sysio_incore_inop_getattr(struct pnode *pno,
896                            struct inode *ino,
897                            struct intnl_stat *stbuf)
898 {
899         struct incore_inode *icino;
900
901         if (!ino)
902                 ino = pno->p_base->pb_ino;
903         icino = I2IC(ino);
904         *stbuf = icino->ici_st;
905         return 0;
906 }
907
908 static int
909 _sysio_incore_inop_setattr(struct pnode *pno,
910                            struct inode *ino,
911                            unsigned mask,
912                            struct intnl_stat *stbuf)
913 {
914         struct incore_inode *icino;
915         int     err;
916
917         if (!ino)
918                 ino = pno->p_base->pb_ino;
919         if (!ino)
920                 return -EBADF;
921         icino = I2IC(ino);
922
923         err = 0;
924         if (mask & SETATTR_LEN) {
925                 err = incore_trunc(icino, stbuf->st_size, 1);
926                 if (err)
927                         goto out;
928                 mask &= ~SETATTR_LEN;
929         }
930         if (mask & SETATTR_MODE) {
931                 icino->ici_st.st_mode =
932                     (icino->ici_st.st_mode & S_IFMT) | (stbuf->st_mode & 07777);
933         }
934         if (mask & SETATTR_MTIME)
935                 icino->ici_st.st_mtime = stbuf->st_mtime;
936         if (mask & SETATTR_ATIME)
937                 icino->ici_st.st_atime = stbuf->st_atime;
938         if (mask & SETATTR_UID)
939                 icino->ici_st.st_uid = stbuf->st_uid;
940         if (mask & SETATTR_GID)
941                 icino->ici_st.st_gid = stbuf->st_gid;
942         icino->ici_st.st_ctime = time(NULL);
943
944         ino->i_stbuf = icino->ici_st;
945 out:
946         return err;
947 }
948
949 static void *
950 incore_directory_position(struct intnl_dirent *de,
951                           size_t reclen __IS_UNUSED,
952                           void *p)
953 {
954
955         return (void *)de >= p ? de : NULL;
956 }
957
958 struct copy_info {
959         void    *data;
960         size_t  nbytes;
961         unsigned count;
962 };
963
964 /*
965  * Eumeration callback.
966  *
967  * Note:
968  * Whiteout entries are never returned.
969  */
970 static void *
971 incore_directory_enumerate(struct intnl_dirent *de,
972                            size_t reclen,
973                            struct copy_info *cinfo) {
974
975 #ifdef DT_WHT
976         if (de->d_type == DT_WHT) {
977                 /*
978                  * Keep going  but skip the copy.
979                  */
980                 return NULL;
981         }
982 #endif
983         cinfo->count++;
984         if (reclen > cinfo->nbytes)
985                 return de;
986         (void *)memcpy(cinfo->data, de, reclen);
987         cinfo->data = (char *)cinfo->data + reclen;
988         cinfo->nbytes -= reclen;
989         return NULL;
990 }
991
992 static ssize_t
993 _sysio_incore_dirop_filldirentries(struct inode *ino,
994                                    _SYSIO_OFF_T *posp,
995                                    char *buf,
996                                    size_t nbytes)
997 {
998         struct incore_inode *icino = I2IC(ino);
999         off_t   off;
1000         struct intnl_dirent *de;
1001         struct copy_info copy_info;
1002
1003         if (*posp >= icino->ici_st.st_size)
1004                 return 0;
1005
1006         de =
1007             incore_directory_probe(icino->ici_data,
1008                                    icino->ici_st.st_size,
1009                                    *posp,
1010                                    (probe_ty )incore_directory_position,
1011                                    NULL,
1012                                    (char *)icino->ici_data + *posp);
1013         if (!de) {
1014                 /*
1015                  * Past EOF.
1016                  */
1017                 return 0;
1018         }
1019
1020         copy_info.data = buf;
1021         copy_info.nbytes = nbytes;
1022         copy_info.count = 0;
1023         off = (char *)de - (char *)icino->ici_data;
1024         de =
1025             incore_directory_probe(de,
1026                                    icino->ici_st.st_size - off,
1027                                    off,
1028                                    (probe_ty )incore_directory_enumerate,
1029                                    NULL,
1030                                    &copy_info);
1031         icino->ici_st.st_atime = time(NULL);
1032         if (nbytes == copy_info.nbytes && copy_info.count)
1033                 return -EINVAL;
1034         nbytes -= copy_info.nbytes;
1035 #if 0
1036         if (!nbytes)
1037                 return -EOVERFLOW;
1038 #endif
1039         *posp += nbytes;
1040         return (ssize_t )nbytes;
1041 }
1042
1043 static struct intnl_dirent *
1044 incore_directory_best_fit(void *data, size_t len, struct lookup_data *ld)
1045 {
1046
1047         if (!ld->hole.len || len < ld->hole.len) {
1048                 ld->hole.p = data;
1049                 ld->hole.len = len;
1050         }
1051
1052         return NULL;
1053 }
1054
1055 static int
1056 incore_directory_insert(struct incore_inode *parent,
1057                         struct qstr *name,
1058                         ino_t inum,
1059                         unsigned char type)
1060 {
1061         size_t  reclen;
1062         struct lookup_data lookup_data;
1063         struct intnl_dirent *de;
1064         size_t  xt;
1065         size_t  n;
1066         size_t  r;
1067
1068         reclen = INCORE_D_RECLEN(name->len);
1069         INCORE_LD_INIT(&lookup_data, reclen, name);
1070         de =
1071             incore_directory_probe(parent->ici_data,
1072                                    parent->ici_st.st_size,
1073                                    0,
1074                                    (probe_ty )incore_directory_match,
1075                                    (probe_ty )incore_directory_best_fit,
1076                                    &lookup_data);
1077         if (de)
1078                 return -EEXIST;
1079         de = lookup_data.de;
1080         xt = (char *)lookup_data.de - (char *)parent->ici_data;
1081         n =
1082 #ifdef _DIRENT_HAVE_D_OFF
1083             de->d_off;
1084 #else
1085             xt + de->d_reclen;
1086 #endif
1087         r =
1088 #ifdef _DIRENT_HAVE_D_OFF
1089             de->d_reclen;
1090 #else
1091             INCORE_D_RECLEN(de->d_namlen);
1092 #endif
1093         if (!parent->ici_st.st_size ||
1094             xt + r + reclen > (size_t )parent->ici_st.st_size) {
1095                 int     err;
1096
1097                 err = incore_trunc(parent, xt + r + reclen, 1);
1098                 if (err)
1099                         return err;
1100                 de = (struct intnl_dirent *)((char *)parent->ici_data + xt);
1101                 n = parent->ici_st.st_size;
1102         }
1103
1104 #ifdef _DIRENT_HAVE_D_OFF
1105         de->d_off = xt + r;                             /* trim */
1106 #else
1107         de->d_reclen = r;
1108 #endif
1109         de = (struct intnl_dirent *)((char *)de + r);                           /* reposition */
1110         xt += r;
1111
1112 #ifndef _DIRENT_HAVE_D_OFF
1113         /*
1114          * Will we split this hole or use all of it?
1115          */
1116         if (lookup_data.hole.len - reclen &&
1117             lookup_data.hole.len - reclen <= INCORE_D_RECLEN(1))
1118                 reclen = lookup_data.hole.len;
1119 #endif
1120
1121         /*
1122          * Insert new.
1123          */
1124         de->d_ino = inum;
1125 #ifdef _DIRENT_HAVE_D_OFF
1126         de->d_off = n;
1127 #endif
1128         de->d_reclen = reclen;
1129         de->d_type = type;
1130         (void )memcpy(de->d_name, name->name, name->len);
1131 #ifdef _DIRENT_HAVE_D_NAMLEN
1132         de->d_namlen = name->len;
1133 #endif
1134
1135 #ifndef _DIRENT_HAVE_D_OFF
1136         xt += reclen;
1137         if (n - xt) {
1138                 /*
1139                  * White-out remaining part of the hole.
1140                  */
1141                 (void *)de += reclen;
1142                 de->d_ino = 0;
1143                 de->d_reclen = n - xt;
1144                 de->d_type = DT_WHT;
1145                 de->d_namlen = 0;
1146         }
1147 #endif
1148
1149         /*
1150          * Update attributes to reflect the new entry.
1151          */
1152         parent->ici_st.st_nlink++;
1153         assert(parent->ici_st.st_nlink);
1154         parent->ici_st.st_atime = parent->ici_st.st_mtime = time(NULL);
1155
1156         return 0;
1157 }
1158
1159 static int
1160 _sysio_incore_dirop_mkdir(struct pnode *pno, mode_t mode)
1161 {
1162         struct intnl_stat stat;
1163         struct incore_inode *icino, *parent;
1164         ino_t   inum;
1165         int     err;
1166         struct intnl_dirent *de = NULL;
1167         struct inode *ino;
1168
1169         ino = pno->p_parent->p_base->pb_ino;
1170         parent = I2IC(ino);
1171
1172         if (!S_ISDIR(parent->ici_st.st_mode))
1173                 return -ENOTDIR;
1174
1175         (void )memset(&stat, 0, sizeof(stat));
1176         stat.st_dev = pno->p_parent->p_base->pb_ino->i_fs->fs_dev;
1177         inum = incore_inum_alloc();
1178 #ifdef HAVE__ST_INO
1179         stat.__st_ino = inum;
1180 #endif
1181         stat.st_mode = S_IFDIR | (mode & 07777);
1182         stat.st_nlink = 2;
1183         stat.st_uid = getuid();
1184         stat.st_gid = getgid();
1185         stat.st_size = 0;
1186         stat.st_blksize = 4096;
1187         stat.st_blocks = 0;
1188         stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
1189         stat.st_ino = inum;
1190         icino = incore_directory_new(FS2ICFS(ino->i_fs), parent, &stat);
1191         if (!icino)
1192                 return -ENOSPC;
1193
1194         /*
1195          * Tell the system about the new inode.
1196          *
1197          * Persistent across remounts because we ask for immunity.
1198          */
1199         ino =
1200             _sysio_i_new(pno->p_parent->p_base->pb_ino->i_fs,
1201                          &icino->ici_fileid,
1202                          &stat,
1203                          1,
1204                          &_sysio_incore_dir_ops,
1205                          icino);
1206         if (!ino) {
1207                 incore_i_destroy(icino);
1208                 return -ENOMEM;
1209         }
1210
1211         /*
1212          * Insert into parent.
1213          */
1214         err =
1215             incore_directory_insert(parent,
1216                                     &pno->p_base->pb_name,
1217                                     stat.st_ino,
1218                                     INCORE_D_TYPEOF(S_IFDIR));
1219
1220         if (err) {
1221                 de->d_ino = 0;                          /* bad parent */
1222                 I_RELE(ino);
1223                 _sysio_i_gone(ino);
1224                 return err;
1225         }
1226
1227         pno->p_base->pb_ino = ino;
1228         return 0;
1229 }
1230
1231 static int
1232 incore_unlink_entry(struct incore_inode *icino,
1233                     struct qstr *name)
1234 {
1235         struct lookup_data lookup_data;
1236         struct intnl_dirent *de;
1237         size_t  reclen;
1238 #ifdef _DIRENT_HAVE_D_OFF
1239         size_t  off;
1240 #endif
1241
1242         if (!S_ISDIR(icino->ici_st.st_mode))
1243                 return -ENOTDIR;
1244
1245         INCORE_LD_INIT(&lookup_data, 0, name);
1246         de =
1247             incore_directory_probe(icino->ici_data,
1248                                    icino->ici_st.st_size,
1249                                    0,
1250                                    (probe_ty )incore_directory_match,
1251                                    NULL,
1252                                    &lookup_data);
1253         if (!de)
1254                 return -ENOENT;
1255         assert((size_t )((char *)de - (char *)icino->ici_data) >=
1256                INCORE_D_TEMPLATE_LEN);
1257 #ifndef _DIRENT_HAVE_D_OFF
1258         reclen = de->d_reclen;
1259 #else
1260         off = de->d_off;
1261         reclen = off - ((char *)de - (char *)icino->ici_data);
1262 #endif
1263         (void )memset(de, 0, reclen);
1264 #ifndef _DIRENT_HAVE_D_OFF
1265         de->d_type = (__uint8_t )DTTOIF(DT_WHT);
1266         de->d_reclen = reclen;
1267 #else
1268         lookup_data.de->d_off = off;
1269 #endif
1270
1271         /*
1272          * Adjust link count.
1273          */
1274         assert(icino->ici_st.st_nlink > 2);
1275         icino->ici_st.st_nlink--;
1276
1277         return 0;
1278 }
1279
1280 static int
1281 _sysio_incore_dirop_rmdir(struct pnode *pno)
1282 {
1283         struct inode *ino = pno->p_base->pb_ino;
1284         struct incore_inode *icino = I2IC(ino);
1285         int     err;
1286
1287         if (!pno->p_base->pb_name.len ||
1288             (pno->p_base->pb_name.name[0] == '.' &&
1289              (pno->p_base->pb_name.len == 1 ||
1290               (pno->p_base->pb_name.len == 2 &&
1291                pno->p_base->pb_name.name[1] == '.'))))
1292                 return -EINVAL;
1293
1294         if (!S_ISDIR(icino->ici_st.st_mode))
1295                 return -ENOTDIR;
1296
1297         if (icino->ici_st.st_nlink > 2)
1298                 return -ENOTEMPTY;
1299
1300         pno->p_base->pb_ino = NULL;
1301         err =
1302             incore_unlink_entry(I2IC(pno->p_parent->p_base->pb_ino),
1303                                 &pno->p_base->pb_name);
1304         return err;
1305 }
1306
1307 static int
1308 incore_create(struct pnode *pno, struct intnl_stat *stat)
1309 {
1310         struct inode *dino, *ino;
1311         struct incore_inode *icino;
1312         int     err;
1313
1314         dino = pno->p_parent->p_base->pb_ino;
1315         assert(dino);
1316
1317         icino = incore_i_alloc(FS2ICFS(dino->i_fs), stat);
1318         if (!icino)
1319                 return -ENOSPC;
1320
1321         /*
1322          * Tell the system about the new inode.
1323          */
1324         ino =
1325             _sysio_i_new(dino->i_fs,
1326                          &icino->ici_fileid,
1327                          stat,
1328                          1,
1329                          S_ISREG(stat->st_mode)
1330                            ? &_sysio_incore_file_ops
1331                            : &_sysio_incore_dev_ops,
1332                          icino);
1333         if (!ino) {
1334                 incore_i_destroy(icino);
1335                 return -ENOMEM;
1336         }
1337
1338         /*
1339          * Insert into parent.
1340          */
1341         err =
1342             incore_directory_insert(I2IC(dino),
1343                                     &pno->p_base->pb_name,
1344                                     stat->st_ino,
1345                                     INCORE_D_TYPEOF(icino->ici_st.st_mode));
1346         if (err) {
1347                 I_RELE(ino);
1348                 _sysio_i_gone(ino);
1349                 return err;
1350         }
1351
1352         pno->p_base->pb_ino = ino;
1353         return 0;
1354 }
1355
1356 static int
1357 _sysio_incore_inop_open(struct pnode *pno, int flags __IS_UNUSED, mode_t mode)
1358 {
1359         struct intnl_stat stat;
1360         ino_t   inum;
1361
1362         /*
1363          * File exists. Nothing to do.
1364          */
1365         if (pno->p_base->pb_ino)
1366                 return 0;
1367
1368         /*
1369          * Must create a new, regular, file.
1370          */
1371         (void )memset(&stat, 0, sizeof(stat));
1372         stat.st_dev = pno->p_parent->p_base->pb_ino->i_fs->fs_dev;
1373         inum = incore_inum_alloc();
1374 #ifdef HAVE__ST_INO
1375         stat.__st_ino = inum;
1376 #endif
1377         stat.st_mode = S_IFREG | (mode & 07777);
1378         stat.st_nlink = 1;
1379         stat.st_uid = getuid();
1380         stat.st_gid = getgid();
1381         stat.st_rdev = 0;
1382         stat.st_size = 0;
1383         stat.st_blksize = 4096;
1384         stat.st_blocks = 0;
1385         stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
1386         stat.st_ino = inum;
1387
1388         return incore_create(pno, &stat);
1389 }
1390
1391 static int
1392 _sysio_incore_inop_close(struct inode *ino __IS_UNUSED)
1393 {
1394
1395         return 0;
1396 }
1397
1398 static int
1399 _sysio_incore_dirop_link(struct pnode *old, struct pnode *new)
1400 {
1401         struct incore_inode *icino = I2IC(old->p_base->pb_ino);
1402         int     err;
1403
1404         assert(!new->p_base->pb_ino);
1405         assert(!S_ISDIR(old->p_base->pb_ino->i_stbuf.st_mode));
1406
1407         /*
1408          * Can bump the link count?
1409          */
1410         if (!(icino->ici_st.st_nlink + 1))
1411                 return -EMLINK;
1412         /*
1413          * Insert into parent.
1414          */
1415         err =
1416             incore_directory_insert(I2IC(new->p_parent->p_base->pb_ino),
1417                                     &new->p_base->pb_name,
1418                                     icino->ici_st.st_ino,
1419                                     INCORE_D_TYPEOF(icino->ici_st.st_mode));
1420         if (err)
1421                 return err;
1422         /*
1423          * Bump the link count.
1424          */
1425         icino->ici_st.st_nlink++;
1426
1427         return 0;
1428 }
1429
1430 static int
1431 _sysio_incore_dirop_rename(struct pnode *old, struct pnode *new)
1432 {
1433         int     err;
1434         struct incore_inode *icino = I2IC(old->p_base->pb_ino);
1435
1436         if (new->p_base->pb_ino) {
1437                 /*
1438                  * Have to kill off the target first.
1439                  */
1440                 if (S_ISDIR(I2IC(new->p_base->pb_ino)->ici_st.st_mode) &&
1441                     I2IC(new->p_base->pb_ino)->ici_st.st_nlink > 2)
1442                         return -ENOTEMPTY;
1443                 err =
1444                     incore_unlink_entry(I2IC(new->p_parent->p_base->pb_ino),
1445                                         &new->p_base->pb_name);
1446                 if (err)
1447                         return err;
1448         }
1449
1450         /*
1451          * Insert into new parent.
1452          */
1453         err =
1454             incore_directory_insert(I2IC(new->p_parent->p_base->pb_ino),
1455                                     &new->p_base->pb_name,
1456                                     icino->ici_st.st_ino,
1457                                     INCORE_D_TYPEOF(icino->ici_st.st_mode));
1458         if (err)
1459                 abort();
1460         /*
1461          * Remove from the old parent.
1462          */
1463         err =
1464             incore_unlink_entry(I2IC(old->p_parent->p_base->pb_ino),
1465                                 &old->p_base->pb_name);
1466         if (err)
1467                 abort();
1468
1469         if (S_ISDIR(icino->ici_st.st_mode)) {
1470                 struct intnl_dirent *de;
1471
1472                 /*
1473                  * We moved a directory. The entry for `..' must be corrected.
1474                  */
1475                 de = icino->ici_data;
1476                 de++;
1477                 assert(strcmp(de->d_name, "..") == 0);
1478                 de->d_ino = I2IC(new->p_parent->p_base->pb_ino)->ici_st.st_ino;
1479         }
1480         return 0;
1481 }
1482
1483 static int
1484 _sysio_incore_dirop_unlink(struct pnode *pno)
1485 {
1486         struct inode *ino = pno->p_base->pb_ino;
1487         struct incore_inode *icino = I2IC(ino);
1488         int     err;
1489
1490         if (S_ISDIR(icino->ici_st.st_mode))
1491                 return -EISDIR;
1492
1493         err =
1494             incore_unlink_entry(I2IC(pno->p_parent->p_base->pb_ino),
1495                                 &pno->p_base->pb_name);
1496         return err;
1497 }
1498
1499 static int
1500 doio(ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, struct incore_inode *),
1501      struct inode *ino,
1502      struct ioctx *ioctx)
1503 {
1504
1505         ioctx->ioctx_cc =
1506             _sysio_doio(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen,
1507                         ioctx->ioctx_iov, ioctx->ioctx_iovlen,
1508                         (ssize_t (*)(void *, size_t, _SYSIO_OFF_T, void *))f,
1509                         I2IC(ino));
1510         if (ioctx->ioctx_cc  < 0) {
1511                 ioctx->ioctx_errno = -ioctx->ioctx_cc;
1512                 ioctx->ioctx_cc = -1;
1513         }
1514         ioctx->ioctx_done = 1;
1515
1516         return 0;
1517 }
1518
1519 static ssize_t
1520 incore_read(void *buf, size_t nbytes,
1521             _SYSIO_OFF_T off,
1522             struct incore_inode *icino)
1523 {
1524         size_t  n;
1525
1526         if (off < 0)
1527                 return -EINVAL;
1528         if (!nbytes || off > icino->ici_st.st_size)
1529                 return 0;
1530         n = icino->ici_st.st_size - (size_t )off;
1531         if (n > nbytes)
1532                 n = nbytes;
1533         (void )memcpy(buf, (char *)icino->ici_data + off, (size_t )n);
1534
1535         return (ssize_t )n;
1536 }
1537
1538 static int
1539 _sysio_incore_filop_read(struct inode *ino, struct ioctx *ioctx)
1540 {
1541         
1542
1543         return doio(incore_read, ino, ioctx);
1544 }
1545
1546 static ssize_t
1547 incore_write(const void *buf, size_t nbytes,
1548              _SYSIO_OFF_T off,
1549              struct incore_inode *icino)
1550 {
1551         _SYSIO_OFF_T pos;
1552
1553         if (off < 0)
1554                 return -EINVAL;
1555         if (!nbytes || off > icino->ici_st.st_size)
1556                 return 0;
1557         pos = off + nbytes;
1558         if (off && pos <= off) {
1559                 /*
1560                  * It's all or nothing. We won't write just part of
1561                  * the buffer.
1562                  */
1563                 return -EFBIG;
1564         }
1565         if (pos > icino->ici_st.st_size) {
1566                 int     err;
1567
1568                 err = incore_trunc(icino, (size_t )pos, 0);
1569                 if (err)
1570                         return err;
1571         }
1572         (void )memcpy((char *)icino->ici_data + off, buf, nbytes);
1573
1574         return (ssize_t )nbytes;
1575 }
1576
1577 static int
1578 _sysio_incore_filop_write(struct inode *ino, struct ioctx *ioctx)
1579 {
1580
1581         return doio((ssize_t (*)(void *, size_t,
1582                                  _SYSIO_OFF_T,
1583                                  struct incore_inode *))incore_write,
1584                     ino,
1585                     ioctx);
1586 }
1587
1588 static _SYSIO_OFF_T
1589 _sysio_incore_filop_pos(struct inode *ino __IS_UNUSED, _SYSIO_OFF_T off)
1590 {
1591
1592         return off;
1593 }
1594
1595 static int
1596 _sysio_incore_filop_iodone(struct ioctx *iocp __IS_UNUSED)
1597 {
1598
1599         /*
1600          * It's always done in this driver. It completed when posted.
1601          */
1602         return 1;
1603 }
1604
1605 static int
1606 _sysio_incore_filop_fcntl(struct inode *ino __IS_UNUSED,
1607                           int cmd __IS_UNUSED,
1608                           va_list ap __IS_UNUSED,
1609                           int *rtn)
1610 {
1611
1612         /*
1613          * No fcntl's supported.
1614          */
1615         *rtn = -1;
1616         return -ENOTTY;
1617 }
1618
1619 static int
1620 _sysio_incore_inop_sync(struct inode *ino __IS_UNUSED)
1621 {
1622
1623         /*
1624          * With what?
1625          */
1626         return 0;
1627 }
1628
1629 static int
1630 _sysio_incore_filop_ioctl(struct inode *ino __IS_UNUSED,
1631                           unsigned long int request __IS_UNUSED,
1632                           va_list ap __IS_UNUSED)
1633 {
1634
1635         /*
1636          * No ioctl's supported.
1637          */
1638         return -ENOTTY;
1639 }
1640
1641 static int
1642 _sysio_incore_dirop_mknod(struct pnode *pno, mode_t mode, dev_t dev)
1643 {
1644         mode_t  m;
1645         struct intnl_stat stat;
1646         ino_t   inum;
1647
1648         assert(!pno->p_base->pb_ino);
1649
1650         m = mode & S_IFMT;
1651         if (S_ISCHR(m))
1652                 m &= ~S_IFCHR;
1653         else if (S_ISFIFO(m))
1654                 m &= ~S_IFIFO;
1655         else if (S_ISBLK(m))
1656                 m &= ~S_IFCHR;
1657         else
1658                 return -EINVAL;
1659         if (m)
1660                 return -EINVAL;
1661
1662         /*
1663          * Initialize attributes.
1664          */
1665         (void )memset(&stat, 0, sizeof(stat));
1666         stat.st_dev = pno->p_parent->p_base->pb_ino->i_fs->fs_dev;
1667         inum = incore_inum_alloc();
1668 #ifdef HAVE__ST_INO
1669         stat.__st_ino = inum;
1670 #endif
1671         stat.st_mode = mode;
1672         stat.st_nlink = 1;
1673         stat.st_uid = getuid();
1674         stat.st_gid = getgid();
1675         stat.st_rdev = dev;
1676         stat.st_size = 0;
1677         stat.st_blksize = 4096;
1678         stat.st_blocks = 0;
1679         stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
1680         stat.st_ino = inum;
1681
1682         return incore_create(pno, &stat);
1683 }
1684
1685 #ifdef _HAVE_STATVFS
1686 static int
1687 _sysio_incore_inop_statvfs(struct pnode *pno,
1688                            struct inode *ino,
1689                            struct intnl_statvfs *buf)
1690 {
1691         struct filesys *fs;
1692
1693         if (!ino)
1694                 ino = pno->p_base->pb_ino;
1695         assert(ino);
1696
1697         fs = pno->p_base->pb_ino->i_fs;
1698
1699         (void )memset(buf, 0, sizeof(struct intnl_statvfs));
1700
1701         /*
1702          * Mostly, we lie.
1703          */
1704         buf->f_bsize = fs->fs_bsize;
1705         buf->f_frsize = buf->f_bsize;
1706         buf->f_blocks = ~0;
1707         buf->f_blocks /= buf->f_bsize;
1708         buf->f_bfree = buf->f_blocks - 1;
1709         buf->f_bavail = buf->f_bfree;
1710         buf->f_files = buf->f_blocks;
1711         buf->f_ffree = buf->f_files - 1;
1712         buf->f_favail = buf->f_ffree;
1713         buf->f_fsid = fs->fs_id;
1714         buf->f_flag = 0;
1715         buf->f_namemax = ULONG_MAX;
1716
1717         return 0;
1718 }
1719 #endif
1720
1721 void
1722 _sysio_incore_inop_gone(struct inode *ino)
1723 {
1724         struct incore_inode *icino = I2IC(ino);
1725
1726         incore_i_destroy(icino);
1727 }