DCACHE_RCUACCESS is gone; having an RCU delay on dentry freeing is the
default. DCACHE_NORCU opts out, and only d_alloc_pseudo() has any
business doing so.
+--
+[mandatory]
+ d_alloc_pseudo() is internal-only; uses outside of alloc_file_pseudo() are
+ very suspect (and won't work in modules). Such uses are very likely to
+ be misspelled d_alloc_anon().
void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
+ name->name = dentry->d_name;
if (unlikely(dname_external(dentry))) {
- struct external_name *p = external_name(dentry);
- atomic_inc(&p->u.count);
- spin_unlock(&dentry->d_lock);
- name->name = p->name;
+ atomic_inc(&external_name(dentry)->u.count);
} else {
memcpy(name->inline_name, dentry->d_iname,
dentry->d_name.len + 1);
- spin_unlock(&dentry->d_lock);
- name->name = name->inline_name;
+ name->name.name = name->inline_name;
}
+ spin_unlock(&dentry->d_lock);
}
EXPORT_SYMBOL(take_dentry_name_snapshot);
void release_dentry_name_snapshot(struct name_snapshot *name)
{
- if (unlikely(name->name != name->inline_name)) {
+ if (unlikely(name->name.name != name->inline_name)) {
struct external_name *p;
- p = container_of(name->name, struct external_name, name[0]);
+ p = container_of(name->name.name, struct external_name, name[0]);
if (unlikely(atomic_dec_and_test(&p->u.count)))
kfree_rcu(p, u.head);
}
* never be anyone's children or parents. Unlike all other
* dentries, these will not have RCU delay between dropping the
* last reference and freeing them.
+ *
+ * The only user is alloc_file_pseudo() and that's what should
+ * be considered a public interface. Don't use directly.
*/
struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
{
dentry->d_flags |= DCACHE_NORCU;
return dentry;
}
-EXPORT_SYMBOL(d_alloc_pseudo);
struct dentry *d_alloc_name(struct dentry *parent, const char *name)
{
goto exit;
}
d_move(old_dentry, dentry);
- fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name.name,
+ fsnotify_move(d_inode(old_dir), d_inode(new_dir), &old_name.name,
d_is_dir(old_dentry),
NULL, old_dentry);
release_dentry_name_snapshot(&old_name);
extern int d_set_mounted(struct dentry *dentry);
extern long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc);
extern struct dentry *d_alloc_cursor(struct dentry *);
+extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
/*
* read_write.c
list_for_each_entry(info, &kernfs_root(kn)->supers, node) {
struct kernfs_node *parent;
struct inode *inode;
+ struct qstr name;
/*
* We want fsnotify_modify() on @kn but as the
if (!inode)
continue;
+ name = (struct qstr)QSTR_INIT(kn->name, strlen(kn->name));
parent = kernfs_get_parent(kn);
if (parent) {
struct inode *p_inode;
p_inode = ilookup(info->sb, parent->id.ino);
if (p_inode) {
fsnotify(p_inode, FS_MODIFY | FS_EVENT_ON_CHILD,
- inode, FSNOTIFY_EVENT_INODE, kn->name, 0);
+ inode, FSNOTIFY_EVENT_INODE, &name, 0);
iput(p_inode);
}
}
fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE,
- kn->name, 0);
+ &name, 0);
iput(inode);
}
inode_unlock(target);
dput(new_dentry);
if (!error) {
- fsnotify_move(old_dir, new_dir, old_name.name, is_dir,
+ fsnotify_move(old_dir, new_dir, &old_name.name, is_dir,
!(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry);
if (flags & RENAME_EXCHANGE) {
- fsnotify_move(new_dir, old_dir, old_dentry->d_name.name,
+ fsnotify_move(new_dir, old_dir, &old_dentry->d_name,
new_is_dir, NULL, new_dentry);
}
}
static int dnotify_handle_event(struct fsnotify_group *group,
struct inode *inode,
u32 mask, const void *data, int data_type,
- const unsigned char *file_name, u32 cookie,
+ const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info)
{
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
static int fanotify_handle_event(struct fsnotify_group *group,
struct inode *inode,
u32 mask, const void *data, int data_type,
- const unsigned char *file_name, u32 cookie,
+ const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info)
{
int ret = 0;
take_dentry_name_snapshot(&name, dentry);
if (path)
ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
- name.name, 0);
+ &name.name, 0);
else
ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
- name.name, 0);
+ &name.name, 0);
release_dentry_name_snapshot(&name);
}
static int send_to_group(struct inode *to_tell,
__u32 mask, const void *data,
int data_is, u32 cookie,
- const unsigned char *file_name,
+ const struct qstr *file_name,
struct fsnotify_iter_info *iter_info)
{
struct fsnotify_group *group = NULL;
* notification event in whatever means they feel necessary.
*/
int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
- const unsigned char *file_name, u32 cookie)
+ const struct qstr *file_name, u32 cookie)
{
struct fsnotify_iter_info iter_info = {};
struct super_block *sb = to_tell->i_sb;
extern int inotify_handle_event(struct fsnotify_group *group,
struct inode *inode,
u32 mask, const void *data, int data_type,
- const unsigned char *file_name, u32 cookie,
+ const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info);
extern const struct fsnotify_ops inotify_fsnotify_ops;
int inotify_handle_event(struct fsnotify_group *group,
struct inode *inode,
u32 mask, const void *data, int data_type,
- const unsigned char *file_name, u32 cookie,
+ const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info)
{
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
return 0;
}
if (file_name) {
- len = strlen(file_name);
+ len = file_name->len;
alloc_len += len + 1;
}
event->sync_cookie = cookie;
event->name_len = len;
if (len)
- strcpy(event->name, file_name);
+ strcpy(event->name, file_name->name);
ret = fsnotify_add_event(group, fsn_event, inotify_merge);
if (ret) {
void *ns_get_path_cb(struct path *path, ns_get_path_helper_t *ns_get_cb,
void *private_data)
{
- struct ns_common *ns;
void *ret;
-again:
- ns = ns_get_cb(private_data);
- if (!ns)
- return ERR_PTR(-ENOENT);
+ do {
+ struct ns_common *ns = ns_get_cb(private_data);
+ if (!ns)
+ return ERR_PTR(-ENOENT);
+
+ ret = __ns_get_path(path, ns);
+ } while (ret == ERR_PTR(-EAGAIN));
- ret = __ns_get_path(path, ns);
- if (IS_ERR(ret) && PTR_ERR(ret) == -EAGAIN)
- goto again;
return ret;
}
if (fd < 0)
return fd;
- while (1) {
+ do {
struct ns_common *relative;
relative = get_ns(ns);
}
err = __ns_get_path(&path, relative);
- if (IS_ERR(err) && PTR_ERR(err) == -EAGAIN)
- continue;
- break;
- }
+ } while (err == ERR_PTR(-EAGAIN));
+
if (IS_ERR(err)) {
put_unused_fd(fd);
return PTR_ERR(err);
* pointer because we hold no lock on the real dentry.
*/
take_dentry_name_snapshot(&name, real);
- this = lookup_one_len(name.name, connected, strlen(name.name));
+ this = lookup_one_len(name.name.name, connected, name.name.len);
err = PTR_ERR(this);
if (IS_ERR(this)) {
goto fail;
return err;
}
-static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
-{
- /* Truncate the name in place, avoids having to define a compare
- function. */
- if (qstr->len > SYSV_NAMELEN) {
- qstr->len = SYSV_NAMELEN;
- qstr->hash = full_name_hash(dentry, qstr->name, qstr->len);
- }
- return 0;
-}
-
-const struct dentry_operations sysv_dentry_operations = {
- .d_hash = sysv_hash,
-};
-
static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
{
struct inode * inode = NULL;
flavour_setup[sbi->s_type](sbi, &sb->s_max_links);
- sbi->s_truncate = 1;
sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone;
sbi->s_inodes_per_block = bsize >> 6;
sbi->s_inodes_per_block_1 = (bsize >> 6)-1;
sb->s_op = &sysv_sops;
if (sbi->s_forced_ro)
sb->s_flags |= SB_RDONLY;
- if (sbi->s_truncate)
- sb->s_d_op = &sysv_dentry_operations;
root_inode = sysv_iget(sb, SYSV_ROOT_INO);
if (IS_ERR(root_inode)) {
printk("SysV FS: get root inode failed\n");
struct super_block *s_sb; /* VFS superblock */
int s_type; /* file system type: FSTYPE_{XENIX|SYSV|COH} */
char s_bytesex; /* bytesex (le/be/pdp) */
- char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */
- /* if 0: they are disallowed (ENAMETOOLONG) */
unsigned int s_inodes_per_block; /* number of inodes per block */
unsigned int s_inodes_per_block_1; /* inodes_per_block - 1 */
unsigned int s_inodes_per_block_bits; /* log2(inodes_per_block) */
extern const struct file_operations sysv_dir_operations;
extern const struct address_space_operations sysv_aops;
extern const struct super_operations sysv_sops;
-extern const struct dentry_operations sysv_dentry_operations;
enum {
/* allocate/de-allocate */
extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
extern struct dentry * d_alloc_anon(struct super_block *);
-extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *,
wait_queue_head_t *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
}
struct name_snapshot {
- const unsigned char *name;
+ struct qstr name;
unsigned char inline_name[DNAME_INLINE_LEN];
};
void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
__u32 mask)
{
return fsnotify(dir, mask, d_inode(dentry), FSNOTIFY_EVENT_INODE,
- dentry->d_name.name, 0);
+ &dentry->d_name, 0);
}
/* Notify this dentry's parent about a child's events. */
* fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
*/
static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
- const unsigned char *old_name,
+ const struct qstr *old_name,
int isdir, struct inode *target,
struct dentry *moved)
{
__u32 old_dir_mask = FS_MOVED_FROM;
__u32 new_dir_mask = FS_MOVED_TO;
__u32 mask = FS_MOVE_SELF;
- const unsigned char *new_name = moved->d_name.name;
+ const struct qstr *new_name = &moved->d_name;
if (old_dir == new_dir)
old_dir_mask |= FS_DN_RENAME;
take_dentry_name_snapshot(&name, dentry);
fsnotify(d_inode(parent), mask, d_inode(dentry), FSNOTIFY_EVENT_INODE,
- name.name, 0);
+ &name.name, 0);
release_dentry_name_snapshot(&name);
dput(parent);
fsnotify_link_count(inode);
audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE);
- fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0);
+ fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, &new_dentry->d_name, 0);
}
/*
int (*handle_event)(struct fsnotify_group *group,
struct inode *inode,
u32 mask, const void *data, int data_type,
- const unsigned char *file_name, u32 cookie,
+ const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info);
void (*free_group_priv)(struct fsnotify_group *group);
void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
/* main fsnotify call to send events */
extern int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
- const unsigned char *name, u32 cookie);
+ const struct qstr *name, u32 cookie);
extern int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask);
extern void __fsnotify_inode_delete(struct inode *inode);
extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
#else
static inline int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
- const unsigned char *name, u32 cookie)
+ const struct qstr *name, u32 cookie)
{
return 0;
}
extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right);
extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right);
extern int parent_len(const char *path);
-extern int audit_compare_dname_path(const char *dname, const char *path, int plen);
+extern int audit_compare_dname_path(const struct qstr *dname, const char *path, int plen);
extern struct sk_buff *audit_make_reply(int seq, int type, int done, int multi,
const void *payload, int size);
extern void audit_panic(const char *message);
static int audit_mark_handle_event(struct fsnotify_group *group,
struct inode *to_tell,
u32 mask, const void *data, int data_type,
- const unsigned char *dname, u32 cookie,
+ const struct qstr *dname, u32 cookie,
struct fsnotify_iter_info *iter_info)
{
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
static int audit_tree_handle_event(struct fsnotify_group *group,
struct inode *to_tell,
u32 mask, const void *data, int data_type,
- const unsigned char *file_name, u32 cookie,
+ const struct qstr *file_name, u32 cookie,
struct fsnotify_iter_info *iter_info)
{
return 0;
/* Update inode info in audit rules based on filesystem event. */
static void audit_update_watch(struct audit_parent *parent,
- const char *dname, dev_t dev,
+ const struct qstr *dname, dev_t dev,
unsigned long ino, unsigned invalidating)
{
struct audit_watch *owatch, *nwatch, *nextw;
static int audit_watch_handle_event(struct fsnotify_group *group,
struct inode *to_tell,
u32 mask, const void *data, int data_type,
- const unsigned char *dname, u32 cookie,
+ const struct qstr *dname, u32 cookie,
struct fsnotify_iter_info *iter_info)
{
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
* @parentlen: length of the parent if known. Passing in AUDIT_NAME_FULL
* here indicates that we must compute this value.
*/
-int audit_compare_dname_path(const char *dname, const char *path, int parentlen)
+int audit_compare_dname_path(const struct qstr *dname, const char *path, int parentlen)
{
int dlen, pathlen;
const char *p;
- dlen = strlen(dname);
+ dlen = dname->len;
pathlen = strlen(path);
if (pathlen < dlen)
return 1;
p = path + parentlen;
- return strncmp(p, dname, dlen);
+ return strncmp(p, dname->name, dlen);
}
int audit_filter(int msgtype, unsigned int listtype)
{
struct audit_context *context = audit_context();
struct inode *inode = d_backing_inode(dentry);
- const char *dname = dentry->d_name.name;
+ const struct qstr *dname = &dentry->d_name;
struct audit_names *n, *found_parent = NULL, *found_child = NULL;
struct audit_entry *e;
struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS];
(n->type != type && n->type != AUDIT_TYPE_UNKNOWN))
continue;
- if (!strcmp(dname, n->name->name) ||
+ if (!strcmp(dname->name, n->name->name) ||
!audit_compare_dname_path(dname, n->name->name,
found_parent ?
found_parent->name_len :