2 * This Cplant(TM) source code is the property of Sandia National
5 * This Cplant(TM) source code is copyrighted by Sandia National
8 * The redistribution of this Cplant(TM) source code is subject to the
9 * terms of the GNU Lesser General Public License
10 * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
12 * Cplant(TM) Copyright 1998-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
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * Questions or comments about this library should be sent to:
37 * Sandia National Laboratories, New Mexico
39 * Albuquerque, NM 87185-1110
56 #include <sys/types.h>
60 #include <sys/statvfs.h>
62 #include <sys/queue.h>
71 #include "fs_incore.h"
75 * In-core file system pseudo-driver.
81 #define INCORE_BLKSIZE (8192)
84 * Format of an 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 */
94 * Given pointer to inode, return pointer to incore-inode.
96 #define I2IC(ino) ((struct incore_inode *)(ino)->i_private)
98 struct incore_filesys {
99 LIST_HEAD(, incore_inode) icfs_icinodes; /* all i-nodes list */
103 * Given pointer to filesys, return pointer to incore-filesys.
105 #define FS2ICFS(fs) ((struct incore_filesys *)(fs)->fs_private)
107 static int _sysio_incore_fsswop_mount(const char *source,
110 struct pnode *tocover,
111 struct mount **mntp);
113 static struct fssw_ops incore_fssw_ops = {
114 _sysio_incore_fsswop_mount
117 static void _sysio_incore_fsop_gone(struct filesys *fs);
119 static struct filesys_ops incore_fs_ops = {
120 _sysio_incore_fsop_gone,
123 static int _sysio_incore_dirop_lookup(struct pnode *pno,
125 struct intent *intnt,
127 static int _sysio_incore_inop_getattr(struct pnode *pno,
129 struct intnl_stat *stbuf);
130 static int _sysio_incore_inop_setattr(struct pnode *pno,
133 struct intnl_stat *stbuf);
134 static ssize_t _sysio_incore_dirop_filldirentries(struct inode *ino,
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,
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,
156 static int _sysio_incore_dirop_mknod(struct pnode *pno, mode_t mode, dev_t dev);
158 static int _sysio_incore_inop_statvfs(struct pnode *pno,
160 struct intnl_statvfs *buf);
162 static void _sysio_incore_inop_gone(struct inode *ino);
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 *, \
184 va_list))_sysio_do_eisdir
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,
210 _sysio_incore_inop_statvfs,
212 _sysio_incore_inop_gone
215 #define _sysio_incore_filop_lookup \
216 (int (*)(struct pnode *, \
219 const char *))_sysio_do_illop
220 #define _sysio_incore_filop_filldirentries \
221 (ssize_t (*)(struct inode *, \
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
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,
266 _sysio_incore_inop_statvfs,
268 _sysio_incore_inop_gone
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,
295 _sysio_incore_inop_statvfs,
297 _sysio_incore_inop_gone
300 typedef void *(*probe_ty)(void *data, size_t len, void *arg);
303 * Lookup data argument bundle record.
306 struct qstr *name; /* desired entry name */
307 struct intnl_dirent *de; /* last dirent */
308 size_t minsiz; /* min hole needed */
310 void *p; /* best hole */
311 size_t len; /* best hole len */
316 * Initialize lookup data argument bundle.
318 #define INCORE_LD_INIT(ld, minsz, qs) \
322 (ld)->minsiz = (minsz); \
323 (ld)->hole.p = NULL; \
324 (ld)->hole.len = 0; \
328 * Calculate size of a directory entry given length of the entry name.
330 #define INCORE_D_RECLEN(namlen) \
331 (((size_t )&((struct intnl_dirent *)0)->d_name + \
332 (namlen) + 1 + sizeof(void *)) & \
333 ~(sizeof(void *) - 1))
336 * Given mode bits, return directory entry type code.
338 #define INCORE_D_TYPEOF(m) (((m) & S_IFMT) >> 12)
339 #define INCORE_D_TEMPLATE_LEN (INCORE_D_RECLEN(1) + INCORE_D_RECLEN(2))
341 char *incore_dir_template;
343 static struct intnl_dirent incore_dir_template[] = {
348 INCORE_D_TYPEOF(S_IFDIR),
353 INCORE_D_RECLEN(1) + INCORE_D_RECLEN(2),
355 INCORE_D_TYPEOF(S_IFDIR),
362 * Initialize this driver.
367 struct intnl_dirent *de;
371 * Fill in the directory template.
373 incore_dir_template = calloc(1, INCORE_D_TEMPLATE_LEN);
374 if (incore_dir_template == NULL)
376 de = (struct intnl_dirent *)incore_dir_template;
377 #ifdef _DIRENT_HAVE_D_OFF
380 off = de->d_reclen = INCORE_D_RECLEN(1);
381 de->d_type = INCORE_D_TYPEOF(S_IFDIR);
383 #ifdef _DIRENT_HAVE_D_NAMLEN
387 * Move to entry for `..'
389 de = (struct intnl_dirent *)((char *)de + off);
390 de->d_reclen = INCORE_D_RECLEN(2);
391 #ifdef _DIRENT_HAVE_D_NAMLEN
394 #ifdef _DIRENT_HAVE_D_OFF
398 de->d_type = INCORE_D_TYPEOF(S_IFDIR);
399 de->d_name[0] = de->d_name[1] = '.';
402 return _sysio_fssw_register("incore", &incore_fssw_ops);
408 static ino_t nxtnum = 1;
414 static struct incore_inode *
415 incore_i_alloc(struct incore_filesys *icfs, struct intnl_stat *st)
417 struct incore_inode *icino;
420 assert(!st->st_size);
422 icino = malloc(sizeof(struct incore_inode));
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;
430 LIST_INSERT_HEAD(&icfs->icfs_icinodes, icino, ici_link);
436 incore_trunc(struct incore_inode *icino, _SYSIO_OFF_T size, int clear)
445 if (icino->ici_data) {
446 free(icino->ici_data);
447 icino->ici_data = NULL;
452 p = realloc(icino->ici_data, (size_t )n);
456 if (clear && n > icino->ici_st.st_size)
457 (void )memset((char *)icino->ici_data + icino->ici_st.st_size,
459 (size_t )(n - icino->ici_st.st_size));
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);
469 incore_i_destroy(struct incore_inode *icino)
472 LIST_REMOVE(icino, ici_link);
473 (void )incore_trunc(icino, 0, 0);
477 static struct incore_inode *
478 incore_directory_new(struct incore_filesys *icfs,
479 struct incore_inode *parent,
480 struct intnl_stat *st)
482 struct incore_inode *icino;
484 struct intnl_dirent *de;
486 icino = incore_i_alloc(icfs, st);
491 parent = icino; /* root */
494 * Allocate and init directory data.
496 err = incore_trunc(icino, INCORE_D_TEMPLATE_LEN, 1);
498 incore_i_destroy(icino);
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;
507 (struct intnl_dirent *)((char *)de +
508 #ifdef _DIRENT_HAVE_D_OFF
514 de->d_ino = parent->ici_st.st_ino;
517 * Set creation time to modify time set by truncate.
519 st->st_ctime = st->st_mtime;
525 _sysio_incore_fsswop_mount(const char *source,
527 const void *data __IS_UNUSED,
528 struct pnode *tocover,
539 struct intnl_stat stat;
540 struct incore_filesys *icfs;
542 struct incore_inode *icino;
545 struct pnode_base *rootpb;
547 static struct qstr noname = { NULL, 0, 0 };
550 * Source is a specification for the root attributes of this
551 * new file system in the format:
553 * <permissions>[+<owner>][-<group>]
555 ul = strtoul(source, &cp, 0);
556 mode = (mode_t )ul & 07777;
557 uid = getuid(); /* default */
558 gid = getgid(); /* default */
561 * Get user and/or group.
564 (ul == ULONG_MAX && errno == ERANGE) ||
565 (unsigned long)mode != ul ||
569 l = strtol(source, &cp, 0);
571 if (((l == LONG_MIN || l == LONG_MAX) &&
578 l = strtol(source, &cp, 0);
580 if (((l == LONG_MIN || l == LONG_MAX) &&
590 dev = _sysio_dev_alloc();
602 icfs = malloc(sizeof(struct incore_filesys));
607 (void )memset(icfs, 0, sizeof(struct incore_filesys));
608 LIST_INIT(&icfs->icfs_icinodes);
611 * Create root i-node.
613 (void )memset(&stat, 0, sizeof(stat));
615 inum = incore_inum_alloc();
617 stat.__st_ino = inum;
619 stat.st_mode = S_IFDIR | (mode & 07777);
624 stat.st_blksize = INCORE_BLKSIZE;
626 stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
628 icino = incore_directory_new(icfs, NULL, &stat);
631 icino->ici_st.st_atime = icino->ici_st.st_mtime;
634 _sysio_fs_new(&incore_fs_ops,
635 (flags & MOUNT_F_RO) ? FS_F_RO : 0,
643 * Create root for system.
645 * Persistent across remounts because we ask for immunity.
652 &_sysio_incore_dir_ops,
658 rootpb = _sysio_pb_new(&noname, NULL, rooti);
665 * Have path-node specified by the given source argument. Let the
666 * system finish the job, now.
683 if (mnt && _sysio_do_unmount(mnt) != 0)
686 _sysio_pb_gone(rootpb);
696 incore_i_destroy(icino);
709 _sysio_incore_fsop_gone(struct filesys *fs)
711 struct incore_filesys *icfs;
712 struct incore_inode *icino, *oicino;
717 * Free up i-node resource associated with this file system.
719 icino = icfs->icfs_icinodes.lh_first;
722 icino = icino->ici_link.le_next;
723 incore_i_destroy(oicino);
727 * Free the FS record.
733 * A directory search engine. Various functions are carried out by
734 * supplying appropriate callback functions.
736 * The two arguments, entry and hole, are called, if not null, for each
737 * directory entry and hole, respectively.
740 incore_directory_probe(void *data,
743 #ifndef _DIRENT_HAVE_D_OFF
751 struct intnl_dirent *de;
757 #ifdef _DIRENT_HAVE_D_OFF
760 assert(de->d_reclen);
762 if (entry && (p = (*entry)(de, de->d_reclen, arg)))
765 #ifdef _DIRENT_HAVE_D_OFF
768 ((void *)de - data) + de->d_reclen;
771 p = (*hole)((void *)de, de->d_reclen, arg);
777 de = (struct intnl_dirent *)((char *)data + n);
783 static struct intnl_dirent *
784 incore_directory_match(struct intnl_dirent *de,
786 struct lookup_data *ld)
790 #if defined(BSD) || defined(REDSTORM)
791 if (IFTODT(de->d_type) == DT_WHT)
794 #ifdef _DIRENT_HAVE_D_NAMLEN
798 const char *cp, *end;
801 end = (const char *)de + reclen;
802 while (cp < end && *cp != '\0')
804 len = cp - de->d_name;
807 if (ld->name->len == len &&
808 strncmp(de->d_name, ld->name->name, ld->name->len) == 0)
815 _sysio_incore_dirop_lookup(struct pnode *pno,
817 struct intent *intnt __IS_UNUSED,
818 const char *path __IS_UNUSED)
821 struct intnl_dirent *de;
822 struct incore_inode *icino;
823 struct lookup_data lookup_data;
824 struct file_identifier fileid;
826 struct inode_ops *ops;
835 (*inop)->i_stbuf = icino->ici_st;
839 ino = pno->p_parent->p_base->pb_ino;
841 INCORE_LD_INIT(&lookup_data,
843 &pno->p_base->pb_name);
845 incore_directory_probe(icino->ici_data,
846 icino->ici_st.st_size,
848 (probe_ty )incore_directory_match,
854 fileid.fid_data = &de->d_ino;
855 fileid.fid_len = sizeof(de->d_ino);
857 _sysio_i_find(ino->i_fs, &fileid);
861 icino->ici_fileid.fid_data = &icino->ici_st.st_ino;
862 icino->ici_fileid.fid_len = sizeof(icino->ici_st.st_ino);
864 switch (icino->ici_st.st_mode & S_IFMT) {
866 ops = &_sysio_incore_dir_ops;
869 ops = &_sysio_incore_file_ops;
877 _sysio_i_new(ino->i_fs,
895 _sysio_incore_inop_getattr(struct pnode *pno,
897 struct intnl_stat *stbuf)
899 struct incore_inode *icino;
902 ino = pno->p_base->pb_ino;
904 *stbuf = icino->ici_st;
909 _sysio_incore_inop_setattr(struct pnode *pno,
912 struct intnl_stat *stbuf)
914 struct incore_inode *icino;
918 ino = pno->p_base->pb_ino;
924 if (mask & SETATTR_LEN) {
925 err = incore_trunc(icino, stbuf->st_size, 1);
928 mask &= ~SETATTR_LEN;
930 if (mask & SETATTR_MODE) {
931 icino->ici_st.st_mode =
932 (icino->ici_st.st_mode & S_IFMT) | (stbuf->st_mode & 07777);
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);
944 ino->i_stbuf = icino->ici_st;
950 incore_directory_position(struct intnl_dirent *de,
951 size_t reclen __IS_UNUSED,
955 return (void *)de >= p ? de : NULL;
965 * Eumeration callback.
968 * Whiteout entries are never returned.
971 incore_directory_enumerate(struct intnl_dirent *de,
973 struct copy_info *cinfo) {
976 if (de->d_type == DT_WHT) {
978 * Keep going but skip the copy.
984 if (reclen > cinfo->nbytes)
986 (void *)memcpy(cinfo->data, de, reclen);
987 cinfo->data = (char *)cinfo->data + reclen;
988 cinfo->nbytes -= reclen;
993 _sysio_incore_dirop_filldirentries(struct inode *ino,
998 struct incore_inode *icino = I2IC(ino);
1000 struct intnl_dirent *de;
1001 struct copy_info copy_info;
1003 if (*posp >= icino->ici_st.st_size)
1007 incore_directory_probe(icino->ici_data,
1008 icino->ici_st.st_size,
1010 (probe_ty )incore_directory_position,
1012 (char *)icino->ici_data + *posp);
1020 copy_info.data = buf;
1021 copy_info.nbytes = nbytes;
1022 copy_info.count = 0;
1023 off = (char *)de - (char *)icino->ici_data;
1025 incore_directory_probe(de,
1026 icino->ici_st.st_size - off,
1028 (probe_ty )incore_directory_enumerate,
1031 icino->ici_st.st_atime = time(NULL);
1032 if (nbytes == copy_info.nbytes && copy_info.count)
1034 nbytes -= copy_info.nbytes;
1040 return (ssize_t )nbytes;
1043 static struct intnl_dirent *
1044 incore_directory_best_fit(void *data, size_t len, struct lookup_data *ld)
1047 if (!ld->hole.len || len < ld->hole.len) {
1056 incore_directory_insert(struct incore_inode *parent,
1062 struct lookup_data lookup_data;
1063 struct intnl_dirent *de;
1068 reclen = INCORE_D_RECLEN(name->len);
1069 INCORE_LD_INIT(&lookup_data, reclen, name);
1071 incore_directory_probe(parent->ici_data,
1072 parent->ici_st.st_size,
1074 (probe_ty )incore_directory_match,
1075 (probe_ty )incore_directory_best_fit,
1079 de = lookup_data.de;
1080 xt = (char *)lookup_data.de - (char *)parent->ici_data;
1082 #ifdef _DIRENT_HAVE_D_OFF
1088 #ifdef _DIRENT_HAVE_D_OFF
1091 INCORE_D_RECLEN(de->d_namlen);
1093 if (!parent->ici_st.st_size ||
1094 xt + r + reclen > (size_t )parent->ici_st.st_size) {
1097 err = incore_trunc(parent, xt + r + reclen, 1);
1100 de = (struct intnl_dirent *)((char *)parent->ici_data + xt);
1101 n = parent->ici_st.st_size;
1104 #ifdef _DIRENT_HAVE_D_OFF
1105 de->d_off = xt + r; /* trim */
1109 de = (struct intnl_dirent *)((char *)de + r); /* reposition */
1112 #ifndef _DIRENT_HAVE_D_OFF
1114 * Will we split this hole or use all of it?
1116 if (lookup_data.hole.len - reclen &&
1117 lookup_data.hole.len - reclen <= INCORE_D_RECLEN(1))
1118 reclen = lookup_data.hole.len;
1125 #ifdef _DIRENT_HAVE_D_OFF
1128 de->d_reclen = reclen;
1130 (void )memcpy(de->d_name, name->name, name->len);
1131 #ifdef _DIRENT_HAVE_D_NAMLEN
1132 de->d_namlen = name->len;
1135 #ifndef _DIRENT_HAVE_D_OFF
1139 * White-out remaining part of the hole.
1141 (void *)de += reclen;
1143 de->d_reclen = n - xt;
1144 de->d_type = DT_WHT;
1150 * Update attributes to reflect the new entry.
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);
1160 _sysio_incore_dirop_mkdir(struct pnode *pno, mode_t mode)
1162 struct intnl_stat stat;
1163 struct incore_inode *icino, *parent;
1166 struct intnl_dirent *de = NULL;
1169 ino = pno->p_parent->p_base->pb_ino;
1172 if (!S_ISDIR(parent->ici_st.st_mode))
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();
1179 stat.__st_ino = inum;
1181 stat.st_mode = S_IFDIR | (mode & 07777);
1183 stat.st_uid = getuid();
1184 stat.st_gid = getgid();
1186 stat.st_blksize = 4096;
1188 stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
1190 icino = incore_directory_new(FS2ICFS(ino->i_fs), parent, &stat);
1195 * Tell the system about the new inode.
1197 * Persistent across remounts because we ask for immunity.
1200 _sysio_i_new(pno->p_parent->p_base->pb_ino->i_fs,
1204 &_sysio_incore_dir_ops,
1207 incore_i_destroy(icino);
1212 * Insert into parent.
1215 incore_directory_insert(parent,
1216 &pno->p_base->pb_name,
1218 INCORE_D_TYPEOF(S_IFDIR));
1221 de->d_ino = 0; /* bad parent */
1227 pno->p_base->pb_ino = ino;
1232 incore_unlink_entry(struct incore_inode *icino,
1235 struct lookup_data lookup_data;
1236 struct intnl_dirent *de;
1238 #ifdef _DIRENT_HAVE_D_OFF
1242 if (!S_ISDIR(icino->ici_st.st_mode))
1245 INCORE_LD_INIT(&lookup_data, 0, name);
1247 incore_directory_probe(icino->ici_data,
1248 icino->ici_st.st_size,
1250 (probe_ty )incore_directory_match,
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;
1261 reclen = off - ((char *)de - (char *)icino->ici_data);
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;
1268 lookup_data.de->d_off = off;
1272 * Adjust link count.
1274 assert(icino->ici_st.st_nlink > 2);
1275 icino->ici_st.st_nlink--;
1281 _sysio_incore_dirop_rmdir(struct pnode *pno)
1283 struct inode *ino = pno->p_base->pb_ino;
1284 struct incore_inode *icino = I2IC(ino);
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] == '.'))))
1294 if (!S_ISDIR(icino->ici_st.st_mode))
1297 if (icino->ici_st.st_nlink > 2)
1300 pno->p_base->pb_ino = NULL;
1302 incore_unlink_entry(I2IC(pno->p_parent->p_base->pb_ino),
1303 &pno->p_base->pb_name);
1308 incore_create(struct pnode *pno, struct intnl_stat *stat)
1310 struct inode *dino, *ino;
1311 struct incore_inode *icino;
1314 dino = pno->p_parent->p_base->pb_ino;
1317 icino = incore_i_alloc(FS2ICFS(dino->i_fs), stat);
1322 * Tell the system about the new inode.
1325 _sysio_i_new(dino->i_fs,
1329 S_ISREG(stat->st_mode)
1330 ? &_sysio_incore_file_ops
1331 : &_sysio_incore_dev_ops,
1334 incore_i_destroy(icino);
1339 * Insert into parent.
1342 incore_directory_insert(I2IC(dino),
1343 &pno->p_base->pb_name,
1345 INCORE_D_TYPEOF(icino->ici_st.st_mode));
1352 pno->p_base->pb_ino = ino;
1357 _sysio_incore_inop_open(struct pnode *pno, int flags __IS_UNUSED, mode_t mode)
1359 struct intnl_stat stat;
1363 * File exists. Nothing to do.
1365 if (pno->p_base->pb_ino)
1369 * Must create a new, regular, file.
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();
1375 stat.__st_ino = inum;
1377 stat.st_mode = S_IFREG | (mode & 07777);
1379 stat.st_uid = getuid();
1380 stat.st_gid = getgid();
1383 stat.st_blksize = 4096;
1385 stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
1388 return incore_create(pno, &stat);
1392 _sysio_incore_inop_close(struct inode *ino __IS_UNUSED)
1399 _sysio_incore_dirop_link(struct pnode *old, struct pnode *new)
1401 struct incore_inode *icino = I2IC(old->p_base->pb_ino);
1404 assert(!new->p_base->pb_ino);
1405 assert(!S_ISDIR(old->p_base->pb_ino->i_stbuf.st_mode));
1408 * Can bump the link count?
1410 if (!(icino->ici_st.st_nlink + 1))
1413 * Insert into parent.
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));
1423 * Bump the link count.
1425 icino->ici_st.st_nlink++;
1431 _sysio_incore_dirop_rename(struct pnode *old, struct pnode *new)
1434 struct incore_inode *icino = I2IC(old->p_base->pb_ino);
1436 if (new->p_base->pb_ino) {
1438 * Have to kill off the target first.
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)
1444 incore_unlink_entry(I2IC(new->p_parent->p_base->pb_ino),
1445 &new->p_base->pb_name);
1451 * Insert into new parent.
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));
1461 * Remove from the old parent.
1464 incore_unlink_entry(I2IC(old->p_parent->p_base->pb_ino),
1465 &old->p_base->pb_name);
1469 if (S_ISDIR(icino->ici_st.st_mode)) {
1470 struct intnl_dirent *de;
1473 * We moved a directory. The entry for `..' must be corrected.
1475 de = icino->ici_data;
1477 assert(strcmp(de->d_name, "..") == 0);
1478 de->d_ino = I2IC(new->p_parent->p_base->pb_ino)->ici_st.st_ino;
1484 _sysio_incore_dirop_unlink(struct pnode *pno)
1486 struct inode *ino = pno->p_base->pb_ino;
1487 struct incore_inode *icino = I2IC(ino);
1490 if (S_ISDIR(icino->ici_st.st_mode))
1494 incore_unlink_entry(I2IC(pno->p_parent->p_base->pb_ino),
1495 &pno->p_base->pb_name);
1500 doio(ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, struct incore_inode *),
1502 struct ioctx *ioctx)
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,
1510 if (ioctx->ioctx_cc < 0) {
1511 ioctx->ioctx_errno = -ioctx->ioctx_cc;
1512 ioctx->ioctx_cc = -1;
1514 ioctx->ioctx_done = 1;
1520 incore_read(void *buf, size_t nbytes,
1522 struct incore_inode *icino)
1528 if (!nbytes || off > icino->ici_st.st_size)
1530 n = icino->ici_st.st_size - (size_t )off;
1533 (void )memcpy(buf, (char *)icino->ici_data + off, (size_t )n);
1539 _sysio_incore_filop_read(struct inode *ino, struct ioctx *ioctx)
1543 return doio(incore_read, ino, ioctx);
1547 incore_write(const void *buf, size_t nbytes,
1549 struct incore_inode *icino)
1555 if (!nbytes || off > icino->ici_st.st_size)
1558 if (off && pos <= off) {
1560 * It's all or nothing. We won't write just part of
1565 if (pos > icino->ici_st.st_size) {
1568 err = incore_trunc(icino, (size_t )pos, 0);
1572 (void )memcpy((char *)icino->ici_data + off, buf, nbytes);
1574 return (ssize_t )nbytes;
1578 _sysio_incore_filop_write(struct inode *ino, struct ioctx *ioctx)
1581 return doio((ssize_t (*)(void *, size_t,
1583 struct incore_inode *))incore_write,
1589 _sysio_incore_filop_pos(struct inode *ino __IS_UNUSED, _SYSIO_OFF_T off)
1596 _sysio_incore_filop_iodone(struct ioctx *iocp __IS_UNUSED)
1600 * It's always done in this driver. It completed when posted.
1606 _sysio_incore_filop_fcntl(struct inode *ino __IS_UNUSED,
1607 int cmd __IS_UNUSED,
1608 va_list ap __IS_UNUSED,
1613 * No fcntl's supported.
1620 _sysio_incore_inop_sync(struct inode *ino __IS_UNUSED)
1630 _sysio_incore_filop_ioctl(struct inode *ino __IS_UNUSED,
1631 unsigned long int request __IS_UNUSED,
1632 va_list ap __IS_UNUSED)
1636 * No ioctl's supported.
1642 _sysio_incore_dirop_mknod(struct pnode *pno, mode_t mode, dev_t dev)
1645 struct intnl_stat stat;
1648 assert(!pno->p_base->pb_ino);
1653 else if (S_ISFIFO(m))
1655 else if (S_ISBLK(m))
1663 * Initialize attributes.
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();
1669 stat.__st_ino = inum;
1671 stat.st_mode = mode;
1673 stat.st_uid = getuid();
1674 stat.st_gid = getgid();
1677 stat.st_blksize = 4096;
1679 stat.st_ctime = stat.st_mtime = stat.st_atime = 0;
1682 return incore_create(pno, &stat);
1685 #ifdef _HAVE_STATVFS
1687 _sysio_incore_inop_statvfs(struct pnode *pno,
1689 struct intnl_statvfs *buf)
1694 ino = pno->p_base->pb_ino;
1697 fs = pno->p_base->pb_ino->i_fs;
1699 (void )memset(buf, 0, sizeof(struct intnl_statvfs));
1704 buf->f_bsize = fs->fs_bsize;
1705 buf->f_frsize = buf->f_bsize;
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;
1715 buf->f_namemax = ULONG_MAX;
1722 _sysio_incore_inop_gone(struct inode *ino)
1724 struct incore_inode *icino = I2IC(ino);
1726 incore_i_destroy(icino);