#ifndef __KERN_FS_VFS_INODE_H__ #define __KERN_FS_VFS_INODE_H__ #include #include #include #include #include struct stat; struct iobuf; /* * A struct inode is an abstract representation of a file. * * It is an interface that allows the kernel's filesystem-independent * code to interact usefully with multiple sets of filesystem code. */ /* * Abstract low-level file. * * Note: in_info is Filesystem-specific data, in_type is the inode type * * open_count is managed using VOP_INCOPEN and VOP_DECOPEN by * vfs_open() and vfs_close(). Code above the VFS layer should not * need to worry about it. */ struct inode { union { struct device __device_info; struct sfs_inode __sfs_inode_info; } in_info; enum { inode_type_device_info = 0x1234, inode_type_sfs_inode_info, } in_type; atomic_t ref_count; atomic_t open_count; struct fs *in_fs; const struct inode_ops *in_ops; }; #define __in_type(type) inode_type_##type##_info #define check_inode_type(node, type) ((node)->in_type == __in_type(type)) #define __vop_info(node, type) \ ({ \ struct inode *__node = (node); \ assert(__node != NULL && check_inode_type(__node, type)); \ &(__node->in_info.__##type##_info); \ }) #define vop_info(node, type) __vop_info(node, type) #define info2node(info, type) \ to_struct((info), struct inode, in_info.__##type##_info) struct inode *__alloc_inode(int type); #define alloc_inode(type) __alloc_inode(__in_type(type)) #define MAX_INODE_COUNT 0x10000 int inode_ref_inc(struct inode *node); int inode_ref_dec(struct inode *node); int inode_open_inc(struct inode *node); int inode_open_dec(struct inode *node); void inode_init(struct inode *node, const struct inode_ops *ops, struct fs *fs); void inode_kill(struct inode *node); #define VOP_MAGIC 0x8c4ba476 /* * Abstract operations on a inode. * * These are used in the form VOP_FOO(inode, args), which are macros * that expands to inode->inode_ops->vop_foo(inode, args). The operations * "foo" are: * * vop_open - Called on open() of a file. Can be used to * reject illegal or undesired open modes. Note that * various operations can be performed without the * file actually being opened. * The inode need not look at O_CREAT, O_EXCL, or * O_TRUNC, as these are handled in the VFS layer. * * VOP_EACHOPEN should not be called directly from * above the VFS layer - use vfs_open() to open inodes. * This maintains the open count so VOP_LASTCLOSE can * be called at the right time. * * vop_close - To be called on *last* close() of a file. * * VOP_LASTCLOSE should not be called directly from * above the VFS layer - use vfs_close() to close * inodes opened with vfs_open(). * * vop_reclaim - Called when inode is no longer in use. Note that * this may be substantially after vop_lastclose is * called. * ***************************************** * * vop_read - Read data from file to uio, at offset specified * in the uio, updating uio_resid to reflect the * amount read, and updating uio_offset to match. * Not allowed on directories or symlinks. * * vop_getdirentry - Read a single filename from a directory into a * uio, choosing what name based on the offset * field in the uio, and updating that field. * Unlike with I/O on regular files, the value of * the offset field is not interpreted outside * the filesystem and thus need not be a byte * count. However, the uio_resid field should be * handled in the normal fashion. * On non-directory objects, return ENOTDIR. * * vop_write - Write data from uio to file at offset specified * in the uio, updating uio_resid to reflect the * amount written, and updating uio_offset to match. * Not allowed on directories or symlinks. * * vop_ioctl - Perform ioctl operation OP on file using data * DATA. The interpretation of the data is specific * to each ioctl. * * vop_fstat -Return info about a file. The pointer is a * pointer to struct stat; see stat.h. * * vop_gettype - Return type of file. The values for file types * are in sfs.h. * * vop_tryseek - Check if seeking to the specified position within * the file is legal. (For instance, all seeks * are illegal on serial port devices, and seeks * past EOF on files whose sizes are fixed may be * as well.) * * vop_fsync - Force any dirty buffers associated with this file * to stable storage. * * vop_truncate - Forcibly set size of file to the length passed * in, discarding any excess blocks. * * vop_namefile - Compute pathname relative to filesystem root * of the file and copy to the specified io buffer. * Need not work on objects that are not * directories. * ***************************************** * * vop_creat - Create a regular file named NAME in the passed * directory DIR. If boolean EXCL is true, fail if * the file already exists; otherwise, use the * existing file if there is one. Hand back the * inode for the file as per vop_lookup. * ***************************************** * * vop_lookup - Parse PATHNAME relative to the passed directory * DIR, and hand back the inode for the file it * refers to. May destroy PATHNAME. Should increment * refcount on inode handed back. */ struct inode_ops { unsigned long vop_magic; int (*vop_open)(struct inode *node, uint32_t open_flags); int (*vop_close)(struct inode *node); int (*vop_read)(struct inode *node, struct iobuf *iob); int (*vop_write)(struct inode *node, struct iobuf *iob); int (*vop_fstat)(struct inode *node, struct stat *stat); int (*vop_fsync)(struct inode *node); int (*vop_namefile)(struct inode *node, struct iobuf *iob); int (*vop_getdirentry)(struct inode *node, struct iobuf *iob); int (*vop_reclaim)(struct inode *node); int (*vop_gettype)(struct inode *node, uint32_t *type_store); int (*vop_tryseek)(struct inode *node, off_t pos); int (*vop_truncate)(struct inode *node, off_t len); int (*vop_create)(struct inode *node, const char *name, bool excl, struct inode **node_store); int (*vop_lookup)(struct inode *node, char *path, struct inode **node_store); int (*vop_ioctl)(struct inode *node, int op, void *data); }; /* * Consistency check */ void inode_check(struct inode *node, const char *opstr); #define __vop_op(node, sym) \ ({ \ struct inode *__node = (node); \ assert(__node != NULL && __node->in_ops != NULL && __node->in_ops->vop_##sym != NULL); \ inode_check(__node, #sym); \ __node->in_ops->vop_##sym; \ }) #define vop_open(node, open_flags) (__vop_op(node, open)(node, open_flags)) #define vop_close(node) (__vop_op(node, close)(node)) #define vop_read(node, iob) (__vop_op(node, read)(node, iob)) #define vop_write(node, iob) (__vop_op(node, write)(node, iob)) #define vop_fstat(node, stat) (__vop_op(node, fstat)(node, stat)) #define vop_fsync(node) (__vop_op(node, fsync)(node)) #define vop_namefile(node, iob) (__vop_op(node, namefile)(node, iob)) #define vop_getdirentry(node, iob) (__vop_op(node, getdirentry)(node, iob)) #define vop_reclaim(node) (__vop_op(node, reclaim)(node)) #define vop_ioctl(node, op, data) (__vop_op(node, ioctl)(node, op, data)) #define vop_gettype(node, type_store) (__vop_op(node, gettype)(node, type_store)) #define vop_tryseek(node, pos) (__vop_op(node, tryseek)(node, pos)) #define vop_truncate(node, len) (__vop_op(node, truncate)(node, len)) #define vop_create(node, name, excl, node_store) (__vop_op(node, create)(node, name, excl, node_store)) #define vop_lookup(node, path, node_store) (__vop_op(node, lookup)(node, path, node_store)) #define vop_fs(node) ((node)->in_fs) #define vop_init(node, ops, fs) inode_init(node, ops, fs) #define vop_kill(node) inode_kill(node) /* * Reference count manipulation (handled above filesystem level) */ #define vop_ref_inc(node) inode_ref_inc(node) #define vop_ref_dec(node) inode_ref_dec(node) /* * Open count manipulation (handled above filesystem level) * * VOP_INCOPEN is called by vfs_open. VOP_DECOPEN is called by vfs_close. * Neither of these should need to be called from above the vfs layer. */ #define vop_open_inc(node) inode_open_inc(node) #define vop_open_dec(node) inode_open_dec(node) static inline int inode_ref_count(struct inode *node) { return atomic_read(&(node->ref_count)); } static inline int inode_open_count(struct inode *node) { return atomic_read(&(node->open_count)); } #endif /* !__KERN_FS_VFS_INODE_H__ */