123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- /*
- * kernfs.h - pseudo filesystem decoupled from vfs locking
- *
- * This file is released under the GPLv2.
- */
- #ifndef __LINUX_KERNFS_H
- #define __LINUX_KERNFS_H
- #include <linux/kernel.h>
- #include <linux/err.h>
- #include <linux/list.h>
- #include <linux/mutex.h>
- #include <linux/idr.h>
- #include <linux/lockdep.h>
- #include <linux/rbtree.h>
- #include <linux/atomic.h>
- #include <linux/wait.h>
- struct file;
- struct dentry;
- struct iattr;
- struct seq_file;
- struct vm_area_struct;
- struct super_block;
- struct file_system_type;
- struct kernfs_open_node;
- struct kernfs_iattrs;
- enum kernfs_node_type {
- KERNFS_DIR = 0x0001,
- KERNFS_FILE = 0x0002,
- KERNFS_LINK = 0x0004,
- };
- #define KERNFS_TYPE_MASK 0x000f
- #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK
- enum kernfs_node_flag {
- KERNFS_ACTIVATED = 0x0010,
- KERNFS_NS = 0x0020,
- KERNFS_HAS_SEQ_SHOW = 0x0040,
- KERNFS_HAS_MMAP = 0x0080,
- KERNFS_LOCKDEP = 0x0100,
- KERNFS_SUICIDAL = 0x0400,
- KERNFS_SUICIDED = 0x0800,
- KERNFS_EMPTY_DIR = 0x1000,
- };
- /* @flags for kernfs_create_root() */
- enum kernfs_root_flag {
- /*
- * kernfs_nodes are created in the deactivated state and invisible.
- * They require explicit kernfs_activate() to become visible. This
- * can be used to make related nodes become visible atomically
- * after all nodes are created successfully.
- */
- KERNFS_ROOT_CREATE_DEACTIVATED = 0x0001,
- /*
- * For regular flies, if the opener has CAP_DAC_OVERRIDE, open(2)
- * succeeds regardless of the RW permissions. sysfs had an extra
- * layer of enforcement where open(2) fails with -EACCES regardless
- * of CAP_DAC_OVERRIDE if the permission doesn't have the
- * respective read or write access at all (none of S_IRUGO or
- * S_IWUGO) or the respective operation isn't implemented. The
- * following flag enables that behavior.
- */
- KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK = 0x0002,
- };
- /* type-specific structures for kernfs_node union members */
- struct kernfs_elem_dir {
- unsigned long subdirs;
- /* children rbtree starts here and goes through kn->rb */
- struct rb_root children;
- /*
- * The kernfs hierarchy this directory belongs to. This fits
- * better directly in kernfs_node but is here to save space.
- */
- struct kernfs_root *root;
- };
- struct kernfs_elem_symlink {
- struct kernfs_node *target_kn;
- };
- struct kernfs_elem_attr {
- const struct kernfs_ops *ops;
- struct kernfs_open_node *open;
- loff_t size;
- struct kernfs_node *notify_next; /* for kernfs_notify() */
- };
- /*
- * kernfs_node - the building block of kernfs hierarchy. Each and every
- * kernfs node is represented by single kernfs_node. Most fields are
- * private to kernfs and shouldn't be accessed directly by kernfs users.
- *
- * As long as s_count reference is held, the kernfs_node itself is
- * accessible. Dereferencing elem or any other outer entity requires
- * active reference.
- */
- struct kernfs_node {
- atomic_t count;
- atomic_t active;
- #ifdef CONFIG_DEBUG_LOCK_ALLOC
- struct lockdep_map dep_map;
- #endif
- /*
- * Use kernfs_get_parent() and kernfs_name/path() instead of
- * accessing the following two fields directly. If the node is
- * never moved to a different parent, it is safe to access the
- * parent directly.
- */
- struct kernfs_node *parent;
- const char *name;
- struct rb_node rb;
- const void *ns; /* namespace tag */
- unsigned int hash; /* ns + name hash */
- union {
- struct kernfs_elem_dir dir;
- struct kernfs_elem_symlink symlink;
- struct kernfs_elem_attr attr;
- };
- void *priv;
- unsigned short flags;
- umode_t mode;
- unsigned int ino;
- struct kernfs_iattrs *iattr;
- };
- /*
- * kernfs_syscall_ops may be specified on kernfs_create_root() to support
- * syscalls. These optional callbacks are invoked on the matching syscalls
- * and can perform any kernfs operations which don't necessarily have to be
- * the exact operation requested. An active reference is held for each
- * kernfs_node parameter.
- */
- struct kernfs_syscall_ops {
- int (*remount_fs)(struct kernfs_root *root, int *flags, char *data);
- int (*show_options)(struct seq_file *sf, struct kernfs_root *root);
- int (*mkdir)(struct kernfs_node *parent, const char *name,
- umode_t mode);
- int (*rmdir)(struct kernfs_node *kn);
- int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent,
- const char *new_name);
- int (*show_path)(struct seq_file *sf, struct kernfs_node *kn,
- struct kernfs_root *root);
- };
- struct kernfs_root {
- /* published fields */
- struct kernfs_node *kn;
- unsigned int flags; /* KERNFS_ROOT_* flags */
- /* private fields, do not use outside kernfs proper */
- struct ida ino_ida;
- struct kernfs_syscall_ops *syscall_ops;
- /* list of kernfs_super_info of this root, protected by kernfs_mutex */
- struct list_head supers;
- wait_queue_head_t deactivate_waitq;
- };
- struct kernfs_open_file {
- /* published fields */
- struct kernfs_node *kn;
- struct file *file;
- void *priv;
- /* private fields, do not use outside kernfs proper */
- struct mutex mutex;
- struct mutex prealloc_mutex;
- int event;
- struct list_head list;
- char *prealloc_buf;
- size_t atomic_write_len;
- bool mmapped;
- const struct vm_operations_struct *vm_ops;
- };
- struct kernfs_ops {
- /*
- * Read is handled by either seq_file or raw_read().
- *
- * If seq_show() is present, seq_file path is active. Other seq
- * operations are optional and if not implemented, the behavior is
- * equivalent to single_open(). @sf->private points to the
- * associated kernfs_open_file.
- *
- * read() is bounced through kernel buffer and a read larger than
- * PAGE_SIZE results in partial operation of PAGE_SIZE.
- */
- int (*seq_show)(struct seq_file *sf, void *v);
- void *(*seq_start)(struct seq_file *sf, loff_t *ppos);
- void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos);
- void (*seq_stop)(struct seq_file *sf, void *v);
- ssize_t (*read)(struct kernfs_open_file *of, char *buf, size_t bytes,
- loff_t off);
- /*
- * write() is bounced through kernel buffer. If atomic_write_len
- * is not set, a write larger than PAGE_SIZE results in partial
- * operations of PAGE_SIZE chunks. If atomic_write_len is set,
- * writes upto the specified size are executed atomically but
- * larger ones are rejected with -E2BIG.
- */
- size_t atomic_write_len;
- /*
- * "prealloc" causes a buffer to be allocated at open for
- * all read/write requests. As ->seq_show uses seq_read()
- * which does its own allocation, it is incompatible with
- * ->prealloc. Provide ->read and ->write with ->prealloc.
- */
- bool prealloc;
- ssize_t (*write)(struct kernfs_open_file *of, char *buf, size_t bytes,
- loff_t off);
- int (*mmap)(struct kernfs_open_file *of, struct vm_area_struct *vma);
- #ifdef CONFIG_DEBUG_LOCK_ALLOC
- struct lock_class_key lockdep_key;
- #endif
- };
- #ifdef CONFIG_KERNFS
- static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn)
- {
- return kn->flags & KERNFS_TYPE_MASK;
- }
- /**
- * kernfs_enable_ns - enable namespace under a directory
- * @kn: directory of interest, should be empty
- *
- * This is to be called right after @kn is created to enable namespace
- * under it. All children of @kn must have non-NULL namespace tags and
- * only the ones which match the super_block's tag will be visible.
- */
- static inline void kernfs_enable_ns(struct kernfs_node *kn)
- {
- WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR);
- WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->dir.children));
- kn->flags |= KERNFS_NS;
- }
- /**
- * kernfs_ns_enabled - test whether namespace is enabled
- * @kn: the node to test
- *
- * Test whether namespace filtering is enabled for the children of @ns.
- */
- static inline bool kernfs_ns_enabled(struct kernfs_node *kn)
- {
- return kn->flags & KERNFS_NS;
- }
- int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen);
- int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn,
- char *buf, size_t buflen);
- void pr_cont_kernfs_name(struct kernfs_node *kn);
- void pr_cont_kernfs_path(struct kernfs_node *kn);
- struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn);
- struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
- const char *name, const void *ns);
- struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent,
- const char *path, const void *ns);
- void kernfs_get(struct kernfs_node *kn);
- void kernfs_put(struct kernfs_node *kn);
- struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry);
- struct kernfs_root *kernfs_root_from_sb(struct super_block *sb);
- struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn);
- struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
- struct super_block *sb);
- struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
- unsigned int flags, void *priv);
- void kernfs_destroy_root(struct kernfs_root *root);
- struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
- const char *name, umode_t mode,
- void *priv, const void *ns);
- struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
- const char *name);
- struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
- const char *name,
- umode_t mode, loff_t size,
- const struct kernfs_ops *ops,
- void *priv, const void *ns,
- struct lock_class_key *key);
- struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
- const char *name,
- struct kernfs_node *target);
- void kernfs_activate(struct kernfs_node *kn);
- void kernfs_remove(struct kernfs_node *kn);
- void kernfs_break_active_protection(struct kernfs_node *kn);
- void kernfs_unbreak_active_protection(struct kernfs_node *kn);
- bool kernfs_remove_self(struct kernfs_node *kn);
- int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
- const void *ns);
- int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
- const char *new_name, const void *new_ns);
- int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr);
- void kernfs_notify(struct kernfs_node *kn);
- const void *kernfs_super_ns(struct super_block *sb);
- struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
- struct kernfs_root *root, unsigned long magic,
- bool *new_sb_created, const void *ns);
- void kernfs_kill_sb(struct super_block *sb);
- struct super_block *kernfs_pin_sb(struct kernfs_root *root, const void *ns);
- void kernfs_init(void);
- #else /* CONFIG_KERNFS */
- static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn)
- { return 0; } /* whatever */
- static inline void kernfs_enable_ns(struct kernfs_node *kn) { }
- static inline bool kernfs_ns_enabled(struct kernfs_node *kn)
- { return false; }
- static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
- { return -ENOSYS; }
- static inline int kernfs_path_from_node(struct kernfs_node *root_kn,
- struct kernfs_node *kn,
- char *buf, size_t buflen)
- { return -ENOSYS; }
- static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { }
- static inline void pr_cont_kernfs_path(struct kernfs_node *kn) { }
- static inline struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
- { return NULL; }
- static inline struct kernfs_node *
- kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name,
- const void *ns)
- { return NULL; }
- static inline struct kernfs_node *
- kernfs_walk_and_get_ns(struct kernfs_node *parent, const char *path,
- const void *ns)
- { return NULL; }
- static inline void kernfs_get(struct kernfs_node *kn) { }
- static inline void kernfs_put(struct kernfs_node *kn) { }
- static inline struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry)
- { return NULL; }
- static inline struct kernfs_root *kernfs_root_from_sb(struct super_block *sb)
- { return NULL; }
- static inline struct inode *
- kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn)
- { return NULL; }
- static inline struct kernfs_root *
- kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags,
- void *priv)
- { return ERR_PTR(-ENOSYS); }
- static inline void kernfs_destroy_root(struct kernfs_root *root) { }
- static inline struct kernfs_node *
- kernfs_create_dir_ns(struct kernfs_node *parent, const char *name,
- umode_t mode, void *priv, const void *ns)
- { return ERR_PTR(-ENOSYS); }
- static inline struct kernfs_node *
- __kernfs_create_file(struct kernfs_node *parent, const char *name,
- umode_t mode, loff_t size, const struct kernfs_ops *ops,
- void *priv, const void *ns, struct lock_class_key *key)
- { return ERR_PTR(-ENOSYS); }
- static inline struct kernfs_node *
- kernfs_create_link(struct kernfs_node *parent, const char *name,
- struct kernfs_node *target)
- { return ERR_PTR(-ENOSYS); }
- static inline void kernfs_activate(struct kernfs_node *kn) { }
- static inline void kernfs_remove(struct kernfs_node *kn) { }
- static inline bool kernfs_remove_self(struct kernfs_node *kn)
- { return false; }
- static inline int kernfs_remove_by_name_ns(struct kernfs_node *kn,
- const char *name, const void *ns)
- { return -ENOSYS; }
- static inline int kernfs_rename_ns(struct kernfs_node *kn,
- struct kernfs_node *new_parent,
- const char *new_name, const void *new_ns)
- { return -ENOSYS; }
- static inline int kernfs_setattr(struct kernfs_node *kn,
- const struct iattr *iattr)
- { return -ENOSYS; }
- static inline void kernfs_notify(struct kernfs_node *kn) { }
- static inline const void *kernfs_super_ns(struct super_block *sb)
- { return NULL; }
- static inline struct dentry *
- kernfs_mount_ns(struct file_system_type *fs_type, int flags,
- struct kernfs_root *root, unsigned long magic,
- bool *new_sb_created, const void *ns)
- { return ERR_PTR(-ENOSYS); }
- static inline void kernfs_kill_sb(struct super_block *sb) { }
- static inline void kernfs_init(void) { }
- #endif /* CONFIG_KERNFS */
- /**
- * kernfs_path - build full path of a given node
- * @kn: kernfs_node of interest
- * @buf: buffer to copy @kn's name into
- * @buflen: size of @buf
- *
- * Builds and returns the full path of @kn in @buf of @buflen bytes. The
- * path is built from the end of @buf so the returned pointer usually
- * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated
- * and %NULL is returned.
- */
- static inline int kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen)
- {
- return kernfs_path_from_node(kn, NULL, buf, buflen);
- }
- static inline struct kernfs_node *
- kernfs_find_and_get(struct kernfs_node *kn, const char *name)
- {
- return kernfs_find_and_get_ns(kn, name, NULL);
- }
- static inline struct kernfs_node *
- kernfs_walk_and_get(struct kernfs_node *kn, const char *path)
- {
- return kernfs_walk_and_get_ns(kn, path, NULL);
- }
- static inline struct kernfs_node *
- kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode,
- void *priv)
- {
- return kernfs_create_dir_ns(parent, name, mode, priv, NULL);
- }
- static inline struct kernfs_node *
- kernfs_create_file_ns(struct kernfs_node *parent, const char *name,
- umode_t mode, loff_t size, const struct kernfs_ops *ops,
- void *priv, const void *ns)
- {
- struct lock_class_key *key = NULL;
- #ifdef CONFIG_DEBUG_LOCK_ALLOC
- key = (struct lock_class_key *)&ops->lockdep_key;
- #endif
- return __kernfs_create_file(parent, name, mode, size, ops, priv, ns,
- key);
- }
- static inline struct kernfs_node *
- kernfs_create_file(struct kernfs_node *parent, const char *name, umode_t mode,
- loff_t size, const struct kernfs_ops *ops, void *priv)
- {
- return kernfs_create_file_ns(parent, name, mode, size, ops, priv, NULL);
- }
- static inline int kernfs_remove_by_name(struct kernfs_node *parent,
- const char *name)
- {
- return kernfs_remove_by_name_ns(parent, name, NULL);
- }
- static inline int kernfs_rename(struct kernfs_node *kn,
- struct kernfs_node *new_parent,
- const char *new_name)
- {
- return kernfs_rename_ns(kn, new_parent, new_name, NULL);
- }
- static inline struct dentry *
- kernfs_mount(struct file_system_type *fs_type, int flags,
- struct kernfs_root *root, unsigned long magic,
- bool *new_sb_created)
- {
- return kernfs_mount_ns(fs_type, flags, root,
- magic, new_sb_created, NULL);
- }
- #endif /* __LINUX_KERNFS_H */
|