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
44 #if defined(AUTOMOUNT_FILE_NAME) && !defined(MAX_MOUNT_DEPTH)
46 * Maximum number of automounts to attempt in path traversal.
48 #define MAX_MOUNT_DEPTH 64
52 * Each i-node is uniquely identified by a file identifier, supplied by
53 * the relevant file system driver. The i-node number returned in the getattrs
54 * call is not always enough.
56 struct file_identifier {
73 * Operations on i-nodes.
75 * Should this be split up into file and name space operations?
78 int (*inop_lookup)(struct pnode *pno,
82 int (*inop_getattr)(struct pnode *pno,
84 struct intnl_stat *stbuf);
85 int (*inop_setattr)(struct pnode *pno,
88 struct intnl_stat *stbuf);
89 ssize_t (*inop_getdirentries)(struct inode *ino,
93 int (*inop_mkdir)(struct pnode *pno, mode_t mode);
94 int (*inop_rmdir)(struct pnode *pno);
95 int (*inop_symlink)(struct pnode *pno, const char *data);
96 int (*inop_readlink)(struct pnode *pno, char *buf, size_t bufsiz);
97 int (*inop_open)(struct pnode *pno, int flags, mode_t mode);
98 int (*inop_close)(struct inode *ino);
99 int (*inop_link)(struct pnode *old, struct pnode *new);
100 int (*inop_unlink)(struct pnode *pno);
101 int (*inop_rename)(struct pnode *old, struct pnode *new);
102 int (*inop_read)(struct inode *ino, struct ioctx *ioctx);
103 int (*inop_write)(struct inode *ino, struct ioctx *ioctx);
104 _SYSIO_OFF_T (*inop_pos)(struct inode *ino, _SYSIO_OFF_T off);
105 int (*inop_iodone)(struct ioctx *iocp);
106 int (*inop_fcntl)(struct inode *ino, int cmd, va_list ap, int *rtn);
107 int (*inop_sync)(struct inode *ino);
108 int (*inop_datasync)(struct inode *ino);
109 int (*inop_ioctl)(struct inode *ino, unsigned long int request, va_list ap);
110 int (*inop_mknod)(struct pnode *pno, mode_t mode, dev_t dev);
112 int (*inop_statvfs)(struct pnode *pno,
114 struct intnl_statvfs *buf);
116 void (*inop_gone)(struct inode *ino);
120 * Values for the mask to inop_setattr.
122 #define SETATTR_MODE 0x01
123 #define SETATTR_MTIME 0x02
124 #define SETATTR_ATIME 0x04
125 #define SETATTR_UID 0x08
126 #define SETATTR_GID 0x10
127 #define SETATTR_LEN 0x20
130 * An i-node record is maintained for each file object in the system.
133 LIST_ENTRY(inode) i_link; /* FS i-nodes link */
135 i_immune : 1, /* immune from GC */
136 i_zombie : 1; /* stale inode */
137 unsigned i_ref; /* soft ref counter */
138 mode_t i_mode; /* mode (see stat.h) */
139 dev_t i_rdev; /* dev (if device) */
140 struct inode_ops i_ops; /* operations */
141 struct filesys *i_fs; /* file system ptr */
142 struct file_identifier *i_fid; /* file ident */
143 void *i_private; /* driver data */
144 TAILQ_ENTRY(inode) i_nodes; /* all i-nodes link */
148 * Init an i-node record.
150 #define I_INIT(ino, fs, mode, rdev, ops, fid, immunity, private) \
152 (ino)->i_immune = (immunity) ? 1 : 0; \
153 (ino)->i_zombie = 0; \
155 (ino)->i_mode = (mode); \
156 (ino)->i_rdev = (rdev); \
157 (ino)->i_ops = *(ops); \
158 (ino)->i_fs = (fs); \
159 (ino)->i_fid = (fid); \
160 (ino)->i_private = (private); \
164 * Take soft reference to i-node.
168 TAILQ_REMOVE(&_sysio_inodes, (ino), i_nodes); \
169 TAILQ_INSERT_TAIL(&_sysio_inodes, (ino), i_nodes); \
171 assert((ino)->i_ref); \
175 * Release soft reference to i-node.
177 #define I_RELE(ino) \
179 assert((ino)->i_ref); \
180 if (!--(ino)->i_ref && (ino)->i_zombie) \
181 _sysio_i_gone(ino); \
185 * Attempt to kill an inode.
187 #define I_GONE(ino) \
189 _sysio_i_undead(ino); \
194 * The "quick string" record (inspired by the structure of the same name
195 * from Linux) is used to pass a string without delimiters as well as useful
196 * information about the string.
205 * A path node is an entry in a directory. It may have many aliases, one
206 * for each name space in which it occurs. This record holds the
207 * common information.
210 struct qstr pb_name; /* entry name */
211 struct inode *pb_ino; /* inode */
212 LIST_HEAD(, pnode_base) pb_children; /* children if a dir */
213 LIST_ENTRY(pnode_base) pb_sibs; /* links to siblings */
214 LIST_ENTRY(pnode_base) pb_names; /* near names links */
215 LIST_HEAD(, pnode) pb_aliases; /* aliases */
216 struct pnode_base *pb_parent; /* parent */
220 * Since a file system may be multiply mounted, in different parts of the local
221 * tree, a file system object may appear in different places. We handle that
222 * with aliases. There is one pnode for every alias the system is tracking.
224 * Name space traversal depends heavily on the interpretation of many
225 * of the fields in this structure. For that reason a detailed discussion
226 * of the various fields is given.
228 * The reference field records soft references to the record. For instance,
229 * it tracks file and directory opens. It does not track sibling references,
230 * though, as those are hard references and can be found by examining the
231 * aliases list in the base part of the node.
233 * The parent value points to the parent directory for this entry, in the
234 * *system* name space -- Not the mounted volumes. If you want to examine
235 * the moutned volume name space, use the base record.
237 * The base value points to the base path node information. It is info common
238 * to all of the aliases.
240 * The mount value points to the mount record for the rooted name space in
241 * which the alias is found. Notably, if a node is the root of a sub-tree then
242 * the mount record, among other things, indicates another node
243 * (in another sub-tree) that is covered by this one.
245 * Another sub-tree, mounted on this node, is indicated by a non-null cover.
246 * The pnode pointed to, then, is the root of the mounted sub-tree.
248 * The links list entry holds pointers to other aliases for the base path
251 * The nodes link is bookkeeping.
254 unsigned p_ref; /* soft ref count */
255 struct pnode *p_parent; /* parent */
256 struct pnode_base *p_base; /* base part */
257 struct mount *p_mount; /* mount info */
258 struct pnode *p_cover; /* covering pnode */
259 LIST_ENTRY(pnode) p_links; /* other aliases */
260 TAILQ_ENTRY(pnode) p_nodes; /* all nodes links */
264 * Reference path-tree node.
268 TAILQ_REMOVE(&_sysio_pnodes, (pno), p_nodes); \
269 TAILQ_INSERT_TAIL(&_sysio_pnodes, (pno), p_nodes); \
271 assert((pno)->p_ref); \
275 * Release reference to path-tree node.
277 #define P_RELE(pno) \
279 assert((pno)->p_ref); \
284 * An intent record allows callers of namei and lookup to pass some information
285 * about what they want to accomplish in the end.
296 #define INT_GETATTR 0x01 /* get attrs */
297 #define INT_SETATTR 0x02 /* set attrs */
298 #define INT_UPDPARENT 0x04 /* insert/delete */
299 #define INT_OPEN 0x08 /* open */
300 #define INT_CREAT (INT_UPDPARENT|0x10) /* insert */
301 #define INT_READLINK 0x12 /* readlink */
303 #define INTENT_INIT(intnt, mask, arg1, arg2) \
305 (intnt)->int_opmask = (mask); \
306 (intnt)->int_arg1 = (arg1); \
307 (intnt)->int_arg2 = (arg2); \
311 * Bundled up arguments to _sysio_path_walk.
314 unsigned nd_flags; /* flags (see below) */
315 const char *nd_path; /* path arg */
316 struct pnode *nd_pno; /* returned pnode */
317 struct pnode *nd_root; /* system/user root */
318 struct intent *nd_intent; /* intent (NULL ok) */
319 unsigned nd_slicnt; /* symlink indirects */
320 #ifdef AUTOMOUNT_FILE_NAME
321 unsigned nd_amcnt; /* automounts */
326 * Values for nameidata flags field.
328 #define ND_NOFOLLOW 0x01 /* no follow symlinks */
329 #define ND_NEGOK 0x02 /* last missing is ok */
331 #ifdef AUTOMOUNT_FILE_NAME
332 #define _ND_INIT_AUTOMOUNT(nd) ((nd)->nd_amcnt = 0)
334 #define _ND_INIT_AUTOMOUNT(nd)
337 #define _ND_INIT_OTHERS(nd) \
338 _ND_INIT_AUTOMOUNT(nd)
341 * Init nameidata record.
343 #define ND_INIT(nd, flags, path, root, intnt) \
345 (nd)->nd_flags = (flags); \
346 (nd)->nd_path = (path); \
347 (nd)->nd_pno = NULL; \
348 (nd)->nd_root = (root); \
349 (nd)->nd_intent = (intnt); \
350 (nd)->nd_slicnt = 0; \
351 _ND_INIT_OTHERS(nd); \
355 * IO completion callback record.
357 struct ioctx_callback {
358 TAILQ_ENTRY(ioctx_callback) iocb_next; /* list link */
359 void (*iocb_f)(struct ioctx *, void *); /* cb func */
360 void *iocb_data; /* cb data */
364 * All IO internally is done with an asynchronous mechanism. This record
365 * holds the completion information. It's too big :-(
368 LIST_ENTRY(ioctx) ioctx_link; /* AIO list link */
370 ioctx_fast : 1, /* from stack space */
371 ioctx_done : 1, /* transfer complete */
372 ioctx_write : 1; /* op is a write */
373 struct inode *ioctx_ino; /* i-node */
374 const struct iovec *ioctx_iov; /* scatter/gather vec */
375 size_t ioctx_iovlen; /* iovec length */
376 const struct intnl_xtvec *ioctx_xtv; /* extents */
377 size_t ioctx_xtvlen; /* xtv length */
378 ssize_t ioctx_cc; /* rtn char count */
379 int ioctx_errno; /* error number */
380 TAILQ_HEAD(, ioctx_callback) ioctx_cbq; /* callback queue */
381 void *ioctx_private; /* driver data */
385 * Init IO context record.
387 #define IOCTX_INIT(ioctx, fast, wr, ino, iov, iovlen, xtv, xtvlen) \
389 (ioctx)->ioctx_fast = (fast); \
390 (ioctx)->ioctx_done = 0; \
391 (ioctx)->ioctx_write = (wr) ? 1 : 0; \
392 (ioctx)->ioctx_ino = (ino); \
393 (ioctx)->ioctx_iov = (iov); \
394 (ioctx)->ioctx_iovlen = (iovlen); \
395 (ioctx)->ioctx_xtv = (xtv); \
396 (ioctx)->ioctx_xtvlen = (xtvlen); \
397 (ioctx)->ioctx_cc = 0; \
398 (ioctx)->ioctx_errno = 0; \
399 TAILQ_INIT(&(ioctx)->ioctx_cbq); \
400 (ioctx)->ioctx_private = NULL; \
404 * Return whether a pnode/inode is on a read-only mount or file system.
406 #define IS_RDONLY(pno, ino) \
407 ((((struct pnode *)(pno)) && \
408 ((((struct pnode *)(pno))->p_mount->mnt_flags & MOUNT_F_RO) || \
409 (((struct pnode *)(pno))->p_base->pb_ino && \
410 (((struct pnode *)(pno))->p_base->pb_ino->i_fs->fs_flags & \
412 (((struct inode *)(ino)) && \
413 (((struct inode *)(ino))->i_fs->fs_flags & FS_F_RO)))
415 extern struct pnode *_sysio_root;
417 extern TAILQ_HEAD(inodes_head, inode) _sysio_inodes;
418 extern TAILQ_HEAD(pnodes_head, pnode) _sysio_pnodes;
420 extern int _sysio_i_init(void);
422 extern void _sysio_i_shutdown(void);
424 extern struct inode *_sysio_i_new(struct filesys *fs,
425 struct file_identifier *fid,
429 struct inode_ops *ops,
431 extern struct inode *_sysio_i_find(struct filesys *fs,
432 struct file_identifier *fid);
433 extern void _sysio_i_gone(struct inode *ino);
434 extern void _sysio_i_undead(struct inode *ino);
435 extern int _sysio_p_find_alias(struct pnode *parent,
437 struct pnode **pnop);
438 extern int _sysio_p_validate(struct pnode *pno,
439 struct intent *intnt,
441 extern struct pnode_base *_sysio_pb_new(struct qstr *name,
442 struct pnode_base *parent,
444 extern void _sysio_pb_gone(struct pnode_base *pb);
445 extern struct pnode *_sysio_p_new_alias(struct pnode *parent,
446 struct pnode_base *pb,
448 extern void _sysio_p_gone(struct pnode *pno);
449 extern size_t _sysio_p_prune(struct pnode *root);
450 extern int _sysio_p_kill_all(struct pnode *root);
451 extern char *_sysio_pb_path(struct pnode_base *pb, char separator);
452 extern int _sysio_setattr(struct pnode *pno,
455 struct intnl_stat *stbuf);
456 extern void _sysio_do_noop(void);
457 extern void _sysio_do_illop(void);
458 extern int _sysio_do_ebadf(void);
459 extern int _sysio_do_einval(void);
460 extern int _sysio_do_enoent(void);
461 extern int _sysio_do_enodev(void);
462 extern int _sysio_do_espipe(void);
463 extern int _sysio_do_eisdir(void);
464 extern int _sysio_do_enosys(void);
465 extern int _sysio_path_walk(struct pnode *parent, struct nameidata *nd);
466 #ifdef AUTOMOUNT_FILE_NAME
467 extern void _sysio_next_component(const char *path, struct qstr *name);
469 extern int _sysio_namei(struct pnode *pno,
472 struct intent *intnt,
473 struct pnode **pnop);
474 extern int _sysio_p_chdir(struct pnode *pno);
475 extern int _sysio_ioctx_init(void);
476 extern void _sysio_ioctx_enter(struct ioctx *ioctx);
477 extern struct ioctx *_sysio_ioctx_new(struct inode *ino,
479 const struct iovec *iov,
481 const struct intnl_xtvec *xtv,
483 extern int _sysio_ioctx_cb(struct ioctx *ioctx,
484 void (*f)(struct ioctx *, void *),
486 extern void _sysio_ioctx_cb_free(struct ioctx_callback *cb);
487 extern struct ioctx *_sysio_ioctx_find(void *id);
488 extern ssize_t _sysio_ioctx_wait(struct ioctx *ioctx);
489 extern void _sysio_ioctx_complete(struct ioctx *ioctx);
490 extern ssize_t _sysio_validx(const struct intnl_xtvec *xtv, size_t xtvlen,
491 const struct iovec *iov, size_t iovlen,
493 extern ssize_t _sysio_enumerate_extents(const struct intnl_xtvec *xtv,
495 const struct iovec *iov,
497 ssize_t (*f)(const struct iovec *,
503 extern ssize_t _sysio_enumerate_iovec(const struct iovec *iov,
512 extern ssize_t _sysio_doio(const struct intnl_xtvec *xtv, size_t xtvlen,
513 const struct iovec *iov, size_t iovlen,
514 ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *),
516 extern int _sysio_open(struct pnode *pno, int flags, mode_t mode);