From b8441ed279bff09a0a5ddeacf8f4087d2fb424ca Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 24 Nov 2013 09:54:58 -0500 Subject: sysfs, kernfs: add skeletons for kernfs Core sysfs implementation will be separated into kernfs so that it can be used by other non-kobject users. This patch creates fs/kernfs/ directory and makes boilerplate changes. kernfs interface will be directly based on sysfs_dirent and its forward declaration is moved to include/linux/kernfs.h which is included from include/linux/sysfs.h. sysfs core implementation will be gradually separated out and moved to kernfs. This patch doesn't introduce any functional changes. v2: mount.c added. Signed-off-by: Tejun Heo Cc: linux-fsdevel@vger.kernel.org Cc: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 fs/kernfs/file.c (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c new file mode 100644 index 000000000000..90b1e88dad44 --- /dev/null +++ b/fs/kernfs/file.c @@ -0,0 +1,9 @@ +/* + * fs/kernfs/file.c - kernfs file implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007, 2013 Tejun Heo + * + * This file is released under the GPLv2. + */ -- cgit v1.2.3 From 414985ae23c031efbd6d16d484dea8b5de28b8f7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:34 -0500 Subject: sysfs, kernfs: move file core code to fs/kernfs/file.c Move core file code to fs/kernfs/file.c. fs/sysfs/file.c now contains sysfs kernfs_ops callbacks, sysfs wrappers around kernfs interfaces, and sysfs_schedule_callback(). The respective declarations in fs/sysfs/sysfs.h are moved to fs/kernfs/kernfs-internal.h. This is pure relocation. v2: Refreshed on top of the v2 of "sysfs, kernfs: prepare read path for kernfs". v3: Refreshed on top of the v3 of "sysfs, kernfs: prepare read path for kernfs". Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 805 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 805 insertions(+) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 90b1e88dad44..fa172e86047f 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -7,3 +7,808 @@ * * This file is released under the GPLv2. */ + +#include +#include +#include +#include +#include +#include +#include + +#include "kernfs-internal.h" + +/* + * There's one sysfs_open_file for each open file and one sysfs_open_dirent + * for each sysfs_dirent with one or more open files. + * + * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open is + * protected by sysfs_open_dirent_lock. + * + * filp->private_data points to seq_file whose ->private points to + * sysfs_open_file. sysfs_open_files are chained at + * sysfs_open_dirent->files, which is protected by sysfs_open_file_mutex. + */ +static DEFINE_SPINLOCK(sysfs_open_dirent_lock); +static DEFINE_MUTEX(sysfs_open_file_mutex); + +struct sysfs_open_dirent { + atomic_t refcnt; + atomic_t event; + wait_queue_head_t poll; + struct list_head files; /* goes through sysfs_open_file.list */ +}; + +static struct sysfs_open_file *sysfs_of(struct file *file) +{ + return ((struct seq_file *)file->private_data)->private; +} + +/* + * Determine the kernfs_ops for the given sysfs_dirent. This function must + * be called while holding an active reference. + */ +static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd) +{ + if (sd->s_flags & SYSFS_FLAG_LOCKDEP) + lockdep_assert_held(sd); + return sd->s_attr.ops; +} + +static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) +{ + struct sysfs_open_file *of = sf->private; + const struct kernfs_ops *ops; + + /* + * @of->mutex nests outside active ref and is just to ensure that + * the ops aren't called concurrently for the same open file. + */ + mutex_lock(&of->mutex); + if (!sysfs_get_active(of->sd)) + return ERR_PTR(-ENODEV); + + ops = kernfs_ops(of->sd); + if (ops->seq_start) { + return ops->seq_start(sf, ppos); + } else { + /* + * The same behavior and code as single_open(). Returns + * !NULL if pos is at the beginning; otherwise, NULL. + */ + return NULL + !*ppos; + } +} + +static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) +{ + struct sysfs_open_file *of = sf->private; + const struct kernfs_ops *ops = kernfs_ops(of->sd); + + if (ops->seq_next) { + return ops->seq_next(sf, v, ppos); + } else { + /* + * The same behavior and code as single_open(), always + * terminate after the initial read. + */ + ++*ppos; + return NULL; + } +} + +static void kernfs_seq_stop(struct seq_file *sf, void *v) +{ + struct sysfs_open_file *of = sf->private; + const struct kernfs_ops *ops = kernfs_ops(of->sd); + + if (ops->seq_stop) + ops->seq_stop(sf, v); + + sysfs_put_active(of->sd); + mutex_unlock(&of->mutex); +} + +static int kernfs_seq_show(struct seq_file *sf, void *v) +{ + struct sysfs_open_file *of = sf->private; + + of->event = atomic_read(&of->sd->s_attr.open->event); + + return of->sd->s_attr.ops->seq_show(sf, v); +} + +static const struct seq_operations kernfs_seq_ops = { + .start = kernfs_seq_start, + .next = kernfs_seq_next, + .stop = kernfs_seq_stop, + .show = kernfs_seq_show, +}; + +/* + * As reading a bin file can have side-effects, the exact offset and bytes + * specified in read(2) call should be passed to the read callback making + * it difficult to use seq_file. Implement simplistic custom buffering for + * bin files. + */ +static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + ssize_t len = min_t(size_t, count, PAGE_SIZE); + const struct kernfs_ops *ops; + char *buf; + + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* + * @of->mutex nests outside active ref and is just to ensure that + * the ops aren't called concurrently for the same open file. + */ + mutex_lock(&of->mutex); + if (!sysfs_get_active(of->sd)) { + len = -ENODEV; + mutex_unlock(&of->mutex); + goto out_free; + } + + ops = kernfs_ops(of->sd); + if (ops->read) + len = ops->read(of, buf, len, *ppos); + else + len = -EINVAL; + + sysfs_put_active(of->sd); + mutex_unlock(&of->mutex); + + if (len < 0) + goto out_free; + + if (copy_to_user(user_buf, buf, len)) { + len = -EFAULT; + goto out_free; + } + + *ppos += len; + + out_free: + kfree(buf); + return len; +} + +/** + * kernfs_file_read - kernfs vfs read callback + * @file: file pointer + * @user_buf: data to write + * @count: number of bytes + * @ppos: starting offset + */ +static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct sysfs_open_file *of = sysfs_of(file); + + if (of->sd->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW) + return seq_read(file, user_buf, count, ppos); + else + return kernfs_file_direct_read(of, user_buf, count, ppos); +} + +/** + * kernfs_file_write - kernfs vfs write callback + * @file: file pointer + * @user_buf: data to write + * @count: number of bytes + * @ppos: starting offset + * + * Copy data in from userland and pass it to the matching kernfs write + * operation. + * + * There is no easy way for us to know if userspace is only doing a partial + * write, so we don't support them. We expect the entire buffer to come on + * the first write. Hint: if you're writing a value, first read the file, + * modify only the the value you're changing, then write entire buffer + * back. + */ +static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct sysfs_open_file *of = sysfs_of(file); + ssize_t len = min_t(size_t, count, PAGE_SIZE); + const struct kernfs_ops *ops; + char *buf; + + buf = kmalloc(len + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, user_buf, len)) { + len = -EFAULT; + goto out_free; + } + buf[len] = '\0'; /* guarantee string termination */ + + /* + * @of->mutex nests outside active ref and is just to ensure that + * the ops aren't called concurrently for the same open file. + */ + mutex_lock(&of->mutex); + if (!sysfs_get_active(of->sd)) { + mutex_unlock(&of->mutex); + len = -ENODEV; + goto out_free; + } + + ops = kernfs_ops(of->sd); + if (ops->write) + len = ops->write(of, buf, len, *ppos); + else + len = -EINVAL; + + sysfs_put_active(of->sd); + mutex_unlock(&of->mutex); + + if (len > 0) + *ppos += len; +out_free: + kfree(buf); + return len; +} + +static void kernfs_vma_open(struct vm_area_struct *vma) +{ + struct file *file = vma->vm_file; + struct sysfs_open_file *of = sysfs_of(file); + + if (!of->vm_ops) + return; + + if (!sysfs_get_active(of->sd)) + return; + + if (of->vm_ops->open) + of->vm_ops->open(vma); + + sysfs_put_active(of->sd); +} + +static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct file *file = vma->vm_file; + struct sysfs_open_file *of = sysfs_of(file); + int ret; + + if (!of->vm_ops) + return VM_FAULT_SIGBUS; + + if (!sysfs_get_active(of->sd)) + return VM_FAULT_SIGBUS; + + ret = VM_FAULT_SIGBUS; + if (of->vm_ops->fault) + ret = of->vm_ops->fault(vma, vmf); + + sysfs_put_active(of->sd); + return ret; +} + +static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + struct file *file = vma->vm_file; + struct sysfs_open_file *of = sysfs_of(file); + int ret; + + if (!of->vm_ops) + return VM_FAULT_SIGBUS; + + if (!sysfs_get_active(of->sd)) + return VM_FAULT_SIGBUS; + + ret = 0; + if (of->vm_ops->page_mkwrite) + ret = of->vm_ops->page_mkwrite(vma, vmf); + else + file_update_time(file); + + sysfs_put_active(of->sd); + return ret; +} + +static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr, + void *buf, int len, int write) +{ + struct file *file = vma->vm_file; + struct sysfs_open_file *of = sysfs_of(file); + int ret; + + if (!of->vm_ops) + return -EINVAL; + + if (!sysfs_get_active(of->sd)) + return -EINVAL; + + ret = -EINVAL; + if (of->vm_ops->access) + ret = of->vm_ops->access(vma, addr, buf, len, write); + + sysfs_put_active(of->sd); + return ret; +} + +#ifdef CONFIG_NUMA +static int kernfs_vma_set_policy(struct vm_area_struct *vma, + struct mempolicy *new) +{ + struct file *file = vma->vm_file; + struct sysfs_open_file *of = sysfs_of(file); + int ret; + + if (!of->vm_ops) + return 0; + + if (!sysfs_get_active(of->sd)) + return -EINVAL; + + ret = 0; + if (of->vm_ops->set_policy) + ret = of->vm_ops->set_policy(vma, new); + + sysfs_put_active(of->sd); + return ret; +} + +static struct mempolicy *kernfs_vma_get_policy(struct vm_area_struct *vma, + unsigned long addr) +{ + struct file *file = vma->vm_file; + struct sysfs_open_file *of = sysfs_of(file); + struct mempolicy *pol; + + if (!of->vm_ops) + return vma->vm_policy; + + if (!sysfs_get_active(of->sd)) + return vma->vm_policy; + + pol = vma->vm_policy; + if (of->vm_ops->get_policy) + pol = of->vm_ops->get_policy(vma, addr); + + sysfs_put_active(of->sd); + return pol; +} + +static int kernfs_vma_migrate(struct vm_area_struct *vma, + const nodemask_t *from, const nodemask_t *to, + unsigned long flags) +{ + struct file *file = vma->vm_file; + struct sysfs_open_file *of = sysfs_of(file); + int ret; + + if (!of->vm_ops) + return 0; + + if (!sysfs_get_active(of->sd)) + return 0; + + ret = 0; + if (of->vm_ops->migrate) + ret = of->vm_ops->migrate(vma, from, to, flags); + + sysfs_put_active(of->sd); + return ret; +} +#endif + +static const struct vm_operations_struct kernfs_vm_ops = { + .open = kernfs_vma_open, + .fault = kernfs_vma_fault, + .page_mkwrite = kernfs_vma_page_mkwrite, + .access = kernfs_vma_access, +#ifdef CONFIG_NUMA + .set_policy = kernfs_vma_set_policy, + .get_policy = kernfs_vma_get_policy, + .migrate = kernfs_vma_migrate, +#endif +}; + +static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct sysfs_open_file *of = sysfs_of(file); + const struct kernfs_ops *ops; + int rc; + + mutex_lock(&of->mutex); + + rc = -ENODEV; + if (!sysfs_get_active(of->sd)) + goto out_unlock; + + ops = kernfs_ops(of->sd); + if (ops->mmap) + rc = ops->mmap(of, vma); + if (rc) + goto out_put; + + /* + * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup() + * to satisfy versions of X which crash if the mmap fails: that + * substitutes a new vm_file, and we don't then want bin_vm_ops. + */ + if (vma->vm_file != file) + goto out_put; + + rc = -EINVAL; + if (of->mmapped && of->vm_ops != vma->vm_ops) + goto out_put; + + /* + * It is not possible to successfully wrap close. + * So error if someone is trying to use close. + */ + rc = -EINVAL; + if (vma->vm_ops && vma->vm_ops->close) + goto out_put; + + rc = 0; + of->mmapped = 1; + of->vm_ops = vma->vm_ops; + vma->vm_ops = &kernfs_vm_ops; +out_put: + sysfs_put_active(of->sd); +out_unlock: + mutex_unlock(&of->mutex); + + return rc; +} + +/** + * sysfs_get_open_dirent - get or create sysfs_open_dirent + * @sd: target sysfs_dirent + * @of: sysfs_open_file for this instance of open + * + * If @sd->s_attr.open exists, increment its reference count; + * otherwise, create one. @of is chained to the files list. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +static int sysfs_get_open_dirent(struct sysfs_dirent *sd, + struct sysfs_open_file *of) +{ + struct sysfs_open_dirent *od, *new_od = NULL; + + retry: + mutex_lock(&sysfs_open_file_mutex); + spin_lock_irq(&sysfs_open_dirent_lock); + + if (!sd->s_attr.open && new_od) { + sd->s_attr.open = new_od; + new_od = NULL; + } + + od = sd->s_attr.open; + if (od) { + atomic_inc(&od->refcnt); + list_add_tail(&of->list, &od->files); + } + + spin_unlock_irq(&sysfs_open_dirent_lock); + mutex_unlock(&sysfs_open_file_mutex); + + if (od) { + kfree(new_od); + return 0; + } + + /* not there, initialize a new one and retry */ + new_od = kmalloc(sizeof(*new_od), GFP_KERNEL); + if (!new_od) + return -ENOMEM; + + atomic_set(&new_od->refcnt, 0); + atomic_set(&new_od->event, 1); + init_waitqueue_head(&new_od->poll); + INIT_LIST_HEAD(&new_od->files); + goto retry; +} + +/** + * sysfs_put_open_dirent - put sysfs_open_dirent + * @sd: target sysfs_dirent + * @of: associated sysfs_open_file + * + * Put @sd->s_attr.open and unlink @of from the files list. If + * reference count reaches zero, disassociate and free it. + * + * LOCKING: + * None. + */ +static void sysfs_put_open_dirent(struct sysfs_dirent *sd, + struct sysfs_open_file *of) +{ + struct sysfs_open_dirent *od = sd->s_attr.open; + unsigned long flags; + + mutex_lock(&sysfs_open_file_mutex); + spin_lock_irqsave(&sysfs_open_dirent_lock, flags); + + if (of) + list_del(&of->list); + + if (atomic_dec_and_test(&od->refcnt)) + sd->s_attr.open = NULL; + else + od = NULL; + + spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); + mutex_unlock(&sysfs_open_file_mutex); + + kfree(od); +} + +static int kernfs_file_open(struct inode *inode, struct file *file) +{ + struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + const struct kernfs_ops *ops; + struct sysfs_open_file *of; + bool has_read, has_write, has_mmap; + int error = -EACCES; + + if (!sysfs_get_active(attr_sd)) + return -ENODEV; + + ops = kernfs_ops(attr_sd); + + has_read = ops->seq_show || ops->read || ops->mmap; + has_write = ops->write || ops->mmap; + has_mmap = ops->mmap; + + /* check perms and supported operations */ + if ((file->f_mode & FMODE_WRITE) && + (!(inode->i_mode & S_IWUGO) || !has_write)) + goto err_out; + + if ((file->f_mode & FMODE_READ) && + (!(inode->i_mode & S_IRUGO) || !has_read)) + goto err_out; + + /* allocate a sysfs_open_file for the file */ + error = -ENOMEM; + of = kzalloc(sizeof(struct sysfs_open_file), GFP_KERNEL); + if (!of) + goto err_out; + + /* + * The following is done to give a different lockdep key to + * @of->mutex for files which implement mmap. This is a rather + * crude way to avoid false positive lockdep warning around + * mm->mmap_sem - mmap nests @of->mutex under mm->mmap_sem and + * reading /sys/block/sda/trace/act_mask grabs sr_mutex, under + * which mm->mmap_sem nests, while holding @of->mutex. As each + * open file has a separate mutex, it's okay as long as those don't + * happen on the same file. At this point, we can't easily give + * each file a separate locking class. Let's differentiate on + * whether the file has mmap or not for now. + */ + if (has_mmap) + mutex_init(&of->mutex); + else + mutex_init(&of->mutex); + + of->sd = attr_sd; + of->file = file; + + /* + * Always instantiate seq_file even if read access doesn't use + * seq_file or is not requested. This unifies private data access + * and readable regular files are the vast majority anyway. + */ + if (ops->seq_show) + error = seq_open(file, &kernfs_seq_ops); + else + error = seq_open(file, NULL); + if (error) + goto err_free; + + ((struct seq_file *)file->private_data)->private = of; + + /* seq_file clears PWRITE unconditionally, restore it if WRITE */ + if (file->f_mode & FMODE_WRITE) + file->f_mode |= FMODE_PWRITE; + + /* make sure we have open dirent struct */ + error = sysfs_get_open_dirent(attr_sd, of); + if (error) + goto err_close; + + /* open succeeded, put active references */ + sysfs_put_active(attr_sd); + return 0; + +err_close: + seq_release(inode, file); +err_free: + kfree(of); +err_out: + sysfs_put_active(attr_sd); + return error; +} + +static int kernfs_file_release(struct inode *inode, struct file *filp) +{ + struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; + struct sysfs_open_file *of = sysfs_of(filp); + + sysfs_put_open_dirent(sd, of); + seq_release(inode, filp); + kfree(of); + + return 0; +} + +void sysfs_unmap_bin_file(struct sysfs_dirent *sd) +{ + struct sysfs_open_dirent *od; + struct sysfs_open_file *of; + + if (!(sd->s_flags & SYSFS_FLAG_HAS_MMAP)) + return; + + spin_lock_irq(&sysfs_open_dirent_lock); + od = sd->s_attr.open; + if (od) + atomic_inc(&od->refcnt); + spin_unlock_irq(&sysfs_open_dirent_lock); + if (!od) + return; + + mutex_lock(&sysfs_open_file_mutex); + list_for_each_entry(of, &od->files, list) { + struct inode *inode = file_inode(of->file); + unmap_mapping_range(inode->i_mapping, 0, 0, 1); + } + mutex_unlock(&sysfs_open_file_mutex); + + sysfs_put_open_dirent(sd, NULL); +} + +/* Sysfs attribute files are pollable. The idea is that you read + * the content and then you use 'poll' or 'select' to wait for + * the content to change. When the content changes (assuming the + * manager for the kobject supports notification), poll will + * return POLLERR|POLLPRI, and select will return the fd whether + * it is waiting for read, write, or exceptions. + * Once poll/select indicates that the value has changed, you + * need to close and re-open the file, or seek to 0 and read again. + * Reminder: this only works for attributes which actively support + * it, and it is not possible to test an attribute from userspace + * to see if it supports poll (Neither 'poll' nor 'select' return + * an appropriate error code). When in doubt, set a suitable timeout value. + */ +static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) +{ + struct sysfs_open_file *of = sysfs_of(filp); + struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; + struct sysfs_open_dirent *od = attr_sd->s_attr.open; + + /* need parent for the kobj, grab both */ + if (!sysfs_get_active(attr_sd)) + goto trigger; + + poll_wait(filp, &od->poll, wait); + + sysfs_put_active(attr_sd); + + if (of->event != atomic_read(&od->event)) + goto trigger; + + return DEFAULT_POLLMASK; + + trigger: + return DEFAULT_POLLMASK|POLLERR|POLLPRI; +} + +/** + * kernfs_notify - notify a kernfs file + * @sd: file to notify + * + * Notify @sd such that poll(2) on @sd wakes up. + */ +void kernfs_notify(struct sysfs_dirent *sd) +{ + struct sysfs_open_dirent *od; + unsigned long flags; + + spin_lock_irqsave(&sysfs_open_dirent_lock, flags); + + if (!WARN_ON(sysfs_type(sd) != SYSFS_KOBJ_ATTR)) { + od = sd->s_attr.open; + if (od) { + atomic_inc(&od->event); + wake_up_interruptible(&od->poll); + } + } + + spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); +} +EXPORT_SYMBOL_GPL(kernfs_notify); + +const struct file_operations kernfs_file_operations = { + .read = kernfs_file_read, + .write = kernfs_file_write, + .llseek = generic_file_llseek, + .mmap = kernfs_file_mmap, + .open = kernfs_file_open, + .release = kernfs_file_release, + .poll = kernfs_file_poll, +}; + +/** + * kernfs_create_file_ns_key - create a file + * @parent: directory to create the file in + * @name: name of the file + * @mode: mode of the file + * @size: size of the file + * @ops: kernfs operations for the file + * @priv: private data for the file + * @ns: optional namespace tag of the file + * @key: lockdep key for the file's active_ref, %NULL to disable lockdep + * + * Returns the created node on success, ERR_PTR() value on error. + */ +struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *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 sysfs_addrm_cxt acxt; + struct sysfs_dirent *sd; + int rc; + + sd = sysfs_new_dirent(name, (mode & S_IALLUGO) | S_IFREG, + SYSFS_KOBJ_ATTR); + if (!sd) + return ERR_PTR(-ENOMEM); + + sd->s_attr.ops = ops; + sd->s_attr.size = size; + sd->s_ns = ns; + sd->priv = priv; + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + if (key) { + lockdep_init_map(&sd->dep_map, "s_active", key, 0); + sd->s_flags |= SYSFS_FLAG_LOCKDEP; + } +#endif + + /* + * sd->s_attr.ops is accesible only while holding active ref. We + * need to know whether some ops are implemented outside active + * ref. Cache their existence in flags. + */ + if (ops->seq_show) + sd->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW; + if (ops->mmap) + sd->s_flags |= SYSFS_FLAG_HAS_MMAP; + + sysfs_addrm_start(&acxt); + rc = sysfs_add_one(&acxt, sd, parent); + sysfs_addrm_finish(&acxt); + + if (rc) { + kernfs_put(sd); + return ERR_PTR(rc); + } + return sd; +} -- cgit v1.2.3 From bc755553df9ab33f389c1a0a8bd0b4f4646e80ef Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:41 -0500 Subject: sysfs, kernfs: make inode number ida per kernfs_root kernfs is being updated to allow multiple sysfs_dirent hierarchies so that it can also be used by other users. Currently, inode number is allocated using a global ida, sysfs_ino_ida; however, inos for different hierarchies should be handled separately. This patch makes ino allocation per kernfs_root. sysfs_ino_ida is replaced by kernfs_root->ino_ida and sysfs_new_dirent() is updated to take @root and allocate ino from it. ida_simple_get/remove() are used instead of sysfs_ino_lock and sysfs_alloc/free_ino(). Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index fa172e86047f..990c97fa7045 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -775,8 +775,8 @@ struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, struct sysfs_dirent *sd; int rc; - sd = sysfs_new_dirent(name, (mode & S_IALLUGO) | S_IFREG, - SYSFS_KOBJ_ATTR); + sd = sysfs_new_dirent(kernfs_root(parent), name, + (mode & S_IALLUGO) | S_IFREG, SYSFS_KOBJ_ATTR); if (!sd) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From 21d71662f895462abaa3054d504af55a306f42ba Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 7 Dec 2013 14:07:36 +0800 Subject: sysfs, kernfs: remove duplicated include from file.c Remove duplicated include. Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 990c97fa7045..4a5863b79de9 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "kernfs-internal.h" -- cgit v1.2.3 From 9b2db6e1894577d48f4e290381bac6e573593838 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 10 Dec 2013 09:29:17 -0500 Subject: sysfs: bail early from kernfs_file_mmap() to avoid spurious lockdep warning This is v3.14 fix for the same issue that a8b14744429f ("sysfs: give different locking key to regular and bin files") addresses for v3.13. Due to the extensive kernfs reorganization in v3.14 branch, the same fix couldn't be ported as-is. The v3.13 fix was ignored while merging it into v3.14 branch. 027a485d12e0 ("sysfs: use a separate locking class for open files depending on mmap") assigned different lockdep key to sysfs_open_file->mutex depending on whether the file implements mmap or not in an attempt to avoid spurious lockdep warning caused by merging of regular and bin file paths. While this restored some of the original behavior of using different locks (at least lockdep is concerned) for the different clases of files. The restoration wasn't full because now the lockdep key assignment depends on whether the file has mmap or not instead of whether it's a regular file or not. This means that bin files which don't implement mmap will get assigned the same lockdep class as regular files. This is problematic because file_operations for bin files still implements the mmap file operation and checking whether the sysfs file actually implements mmap happens in the file operation after grabbing @sysfs_open_file->mutex. We still end up adding locking dependency from mmap locking to sysfs_open_file->mutex to the regular file mutex which triggers spurious circular locking warning. For v3.13, a8b14744429f ("sysfs: give different locking key to regular and bin files") fixed it by giving sysfs_open_file->mutex different lockdep keys depending on whether the file is regular or bin instead of whether mmap exists or not; however, due to the way sysfs is now layered behind kernfs, this approach is no longer viable. kernfs can tell whether a sysfs node has mmap implemented or not but can't tell whether a bin file from a regular one. This patch updates kernfs such that kernfs_file_mmap() checks SYSFS_FLAG_HAS_MMAP and bail before grabbing sysfs_open_file->mutex so that it doesn't add spurious locking dependency from mmap to sysfs_open_file->mutex and changes sysfs so that it specifies kernfs_ops->mmap iff the sysfs file implements mmap. Combined, this ensures that sysfs_open_file->mutex is grabbed under mmap path iff the sysfs file actually implements mmap. As sysfs_open_file->mutex is already given a different lockdep key if mmap is implemented, this removes the spurious locking dependency. Signed-off-by: Tejun Heo Reported-by: Dave Jones Link: http://lkml.kernel.org/g/20131203184324.GA11320@redhat.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 4a5863b79de9..fa053151fa96 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -421,6 +421,16 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) const struct kernfs_ops *ops; int rc; + /* + * mmap path and of->mutex are prone to triggering spurious lockdep + * warnings and we don't want to add spurious locking dependency + * between the two. Check whether mmap is actually implemented + * without grabbing @of->mutex by testing HAS_MMAP flag. See the + * comment in kernfs_file_open() for more details. + */ + if (!(of->sd->s_flags & SYSFS_FLAG_HAS_MMAP)) + return -ENODEV; + mutex_lock(&of->mutex); rc = -ENODEV; @@ -428,10 +438,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) goto out_unlock; ops = kernfs_ops(of->sd); - if (ops->mmap) - rc = ops->mmap(of, vma); - if (rc) - goto out_put; + rc = ops->mmap(of, vma); /* * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup() @@ -596,6 +603,9 @@ static int kernfs_file_open(struct inode *inode, struct file *file) * happen on the same file. At this point, we can't easily give * each file a separate locking class. Let's differentiate on * whether the file has mmap or not for now. + * + * Both paths of the branch look the same. They're supposed to + * look that way and give @of->mutex different static lockdep keys. */ if (has_mmap) mutex_init(&of->mutex); -- cgit v1.2.3 From 324a56e16e44baecac3ca799fd216154145c14bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:53 -0500 Subject: kernfs: s/sysfs_dirent/kernfs_node/ and rename its friends accordingly kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/sysfs_elem_dir/kernfs_elem_dir/ * s/sysfs_elem_symlink/kernfs_elem_symlink/ * s/sysfs_elem_attr/kernfs_elem_file/ * s/sysfs_dirent/kernfs_node/ * s/sd/kn/ in kernfs proper * s/parent_sd/parent/ * s/target_sd/target/ * s/dir_sd/parent/ * s/to_sysfs_dirent()/rb_to_kn()/ * misc renames of local vars when they conflict with the above Because md, mic and gpio dig into sysfs details, this patch ends up modifying them. All are sysfs_dirent renames and trivial. While we can avoid these by introducing a dummy wrapping struct sysfs_dirent around kernfs_node, given the limited usage outside kernfs and sysfs proper, I don't think such workaround is called for. This patch is strictly rename only and doesn't introduce any functional difference. - mic / gpio renames were missing. Spotted by kbuild test robot. Signed-off-by: Tejun Heo Cc: Neil Brown Cc: Linus Walleij Cc: Ashutosh Dixit Cc: kbuild test robot Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 186 +++++++++++++++++++++++++++---------------------------- 1 file changed, 93 insertions(+), 93 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index fa053151fa96..1bf07ded826a 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -19,9 +19,9 @@ /* * There's one sysfs_open_file for each open file and one sysfs_open_dirent - * for each sysfs_dirent with one or more open files. + * for each kernfs_node with one or more open files. * - * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open is + * kernfs_node->s_attr.open points to sysfs_open_dirent. s_attr.open is * protected by sysfs_open_dirent_lock. * * filp->private_data points to seq_file whose ->private points to @@ -44,14 +44,14 @@ static struct sysfs_open_file *sysfs_of(struct file *file) } /* - * Determine the kernfs_ops for the given sysfs_dirent. This function must + * Determine the kernfs_ops for the given kernfs_node. This function must * be called while holding an active reference. */ -static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd) +static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) { - if (sd->s_flags & SYSFS_FLAG_LOCKDEP) - lockdep_assert_held(sd); - return sd->s_attr.ops; + if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + lockdep_assert_held(kn); + return kn->s_attr.ops; } static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) @@ -64,10 +64,10 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return ERR_PTR(-ENODEV); - ops = kernfs_ops(of->sd); + ops = kernfs_ops(of->kn); if (ops->seq_start) { return ops->seq_start(sf, ppos); } else { @@ -82,7 +82,7 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) { struct sysfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->sd); + const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_next) { return ops->seq_next(sf, v, ppos); @@ -99,12 +99,12 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) static void kernfs_seq_stop(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->sd); + const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_stop) ops->seq_stop(sf, v); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); mutex_unlock(&of->mutex); } @@ -112,9 +112,9 @@ static int kernfs_seq_show(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; - of->event = atomic_read(&of->sd->s_attr.open->event); + of->event = atomic_read(&of->kn->s_attr.open->event); - return of->sd->s_attr.ops->seq_show(sf, v); + return of->kn->s_attr.ops->seq_show(sf, v); } static const struct seq_operations kernfs_seq_ops = { @@ -147,19 +147,19 @@ static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->sd)) { + if (!sysfs_get_active(of->kn)) { len = -ENODEV; mutex_unlock(&of->mutex); goto out_free; } - ops = kernfs_ops(of->sd); + ops = kernfs_ops(of->kn); if (ops->read) len = ops->read(of, buf, len, *ppos); else len = -EINVAL; - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); mutex_unlock(&of->mutex); if (len < 0) @@ -189,7 +189,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, { struct sysfs_open_file *of = sysfs_of(file); - if (of->sd->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW) + if (of->kn->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); else return kernfs_file_direct_read(of, user_buf, count, ppos); @@ -234,19 +234,19 @@ static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->sd)) { + if (!sysfs_get_active(of->kn)) { mutex_unlock(&of->mutex); len = -ENODEV; goto out_free; } - ops = kernfs_ops(of->sd); + ops = kernfs_ops(of->kn); if (ops->write) len = ops->write(of, buf, len, *ppos); else len = -EINVAL; - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); mutex_unlock(&of->mutex); if (len > 0) @@ -264,13 +264,13 @@ static void kernfs_vma_open(struct vm_area_struct *vma) if (!of->vm_ops) return; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return; if (of->vm_ops->open) of->vm_ops->open(vma); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); } static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -282,14 +282,14 @@ static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!of->vm_ops) return VM_FAULT_SIGBUS; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return VM_FAULT_SIGBUS; ret = VM_FAULT_SIGBUS; if (of->vm_ops->fault) ret = of->vm_ops->fault(vma, vmf); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } @@ -303,7 +303,7 @@ static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, if (!of->vm_ops) return VM_FAULT_SIGBUS; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return VM_FAULT_SIGBUS; ret = 0; @@ -312,7 +312,7 @@ static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, else file_update_time(file); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } @@ -326,14 +326,14 @@ static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr, if (!of->vm_ops) return -EINVAL; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return -EINVAL; ret = -EINVAL; if (of->vm_ops->access) ret = of->vm_ops->access(vma, addr, buf, len, write); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } @@ -348,14 +348,14 @@ static int kernfs_vma_set_policy(struct vm_area_struct *vma, if (!of->vm_ops) return 0; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return -EINVAL; ret = 0; if (of->vm_ops->set_policy) ret = of->vm_ops->set_policy(vma, new); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } @@ -369,14 +369,14 @@ static struct mempolicy *kernfs_vma_get_policy(struct vm_area_struct *vma, if (!of->vm_ops) return vma->vm_policy; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return vma->vm_policy; pol = vma->vm_policy; if (of->vm_ops->get_policy) pol = of->vm_ops->get_policy(vma, addr); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return pol; } @@ -391,14 +391,14 @@ static int kernfs_vma_migrate(struct vm_area_struct *vma, if (!of->vm_ops) return 0; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return 0; ret = 0; if (of->vm_ops->migrate) ret = of->vm_ops->migrate(vma, from, to, flags); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } #endif @@ -428,16 +428,16 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) * without grabbing @of->mutex by testing HAS_MMAP flag. See the * comment in kernfs_file_open() for more details. */ - if (!(of->sd->s_flags & SYSFS_FLAG_HAS_MMAP)) + if (!(of->kn->s_flags & SYSFS_FLAG_HAS_MMAP)) return -ENODEV; mutex_lock(&of->mutex); rc = -ENODEV; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) goto out_unlock; - ops = kernfs_ops(of->sd); + ops = kernfs_ops(of->kn); rc = ops->mmap(of, vma); /* @@ -465,7 +465,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) of->vm_ops = vma->vm_ops; vma->vm_ops = &kernfs_vm_ops; out_put: - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); out_unlock: mutex_unlock(&of->mutex); @@ -474,10 +474,10 @@ out_unlock: /** * sysfs_get_open_dirent - get or create sysfs_open_dirent - * @sd: target sysfs_dirent + * @kn: target kernfs_node * @of: sysfs_open_file for this instance of open * - * If @sd->s_attr.open exists, increment its reference count; + * If @kn->s_attr.open exists, increment its reference count; * otherwise, create one. @of is chained to the files list. * * LOCKING: @@ -486,7 +486,7 @@ out_unlock: * RETURNS: * 0 on success, -errno on failure. */ -static int sysfs_get_open_dirent(struct sysfs_dirent *sd, +static int sysfs_get_open_dirent(struct kernfs_node *kn, struct sysfs_open_file *of) { struct sysfs_open_dirent *od, *new_od = NULL; @@ -495,12 +495,12 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, mutex_lock(&sysfs_open_file_mutex); spin_lock_irq(&sysfs_open_dirent_lock); - if (!sd->s_attr.open && new_od) { - sd->s_attr.open = new_od; + if (!kn->s_attr.open && new_od) { + kn->s_attr.open = new_od; new_od = NULL; } - od = sd->s_attr.open; + od = kn->s_attr.open; if (od) { atomic_inc(&od->refcnt); list_add_tail(&of->list, &od->files); @@ -528,19 +528,19 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, /** * sysfs_put_open_dirent - put sysfs_open_dirent - * @sd: target sysfs_dirent + * @kn: target kernfs_nodet * @of: associated sysfs_open_file * - * Put @sd->s_attr.open and unlink @of from the files list. If + * Put @kn->s_attr.open and unlink @of from the files list. If * reference count reaches zero, disassociate and free it. * * LOCKING: * None. */ -static void sysfs_put_open_dirent(struct sysfs_dirent *sd, +static void sysfs_put_open_dirent(struct kernfs_node *kn, struct sysfs_open_file *of) { - struct sysfs_open_dirent *od = sd->s_attr.open; + struct sysfs_open_dirent *od = kn->s_attr.open; unsigned long flags; mutex_lock(&sysfs_open_file_mutex); @@ -550,7 +550,7 @@ static void sysfs_put_open_dirent(struct sysfs_dirent *sd, list_del(&of->list); if (atomic_dec_and_test(&od->refcnt)) - sd->s_attr.open = NULL; + kn->s_attr.open = NULL; else od = NULL; @@ -562,16 +562,16 @@ static void sysfs_put_open_dirent(struct sysfs_dirent *sd, static int kernfs_file_open(struct inode *inode, struct file *file) { - struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + struct kernfs_node *kn = file->f_path.dentry->d_fsdata; const struct kernfs_ops *ops; struct sysfs_open_file *of; bool has_read, has_write, has_mmap; int error = -EACCES; - if (!sysfs_get_active(attr_sd)) + if (!sysfs_get_active(kn)) return -ENODEV; - ops = kernfs_ops(attr_sd); + ops = kernfs_ops(kn); has_read = ops->seq_show || ops->read || ops->mmap; has_write = ops->write || ops->mmap; @@ -612,7 +612,7 @@ static int kernfs_file_open(struct inode *inode, struct file *file) else mutex_init(&of->mutex); - of->sd = attr_sd; + of->kn = kn; of->file = file; /* @@ -634,12 +634,12 @@ static int kernfs_file_open(struct inode *inode, struct file *file) file->f_mode |= FMODE_PWRITE; /* make sure we have open dirent struct */ - error = sysfs_get_open_dirent(attr_sd, of); + error = sysfs_get_open_dirent(kn, of); if (error) goto err_close; /* open succeeded, put active references */ - sysfs_put_active(attr_sd); + sysfs_put_active(kn); return 0; err_close: @@ -647,32 +647,32 @@ err_close: err_free: kfree(of); err_out: - sysfs_put_active(attr_sd); + sysfs_put_active(kn); return error; } static int kernfs_file_release(struct inode *inode, struct file *filp) { - struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; + struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; struct sysfs_open_file *of = sysfs_of(filp); - sysfs_put_open_dirent(sd, of); + sysfs_put_open_dirent(kn, of); seq_release(inode, filp); kfree(of); return 0; } -void sysfs_unmap_bin_file(struct sysfs_dirent *sd) +void sysfs_unmap_bin_file(struct kernfs_node *kn) { struct sysfs_open_dirent *od; struct sysfs_open_file *of; - if (!(sd->s_flags & SYSFS_FLAG_HAS_MMAP)) + if (!(kn->s_flags & SYSFS_FLAG_HAS_MMAP)) return; spin_lock_irq(&sysfs_open_dirent_lock); - od = sd->s_attr.open; + od = kn->s_attr.open; if (od) atomic_inc(&od->refcnt); spin_unlock_irq(&sysfs_open_dirent_lock); @@ -686,7 +686,7 @@ void sysfs_unmap_bin_file(struct sysfs_dirent *sd) } mutex_unlock(&sysfs_open_file_mutex); - sysfs_put_open_dirent(sd, NULL); + sysfs_put_open_dirent(kn, NULL); } /* Sysfs attribute files are pollable. The idea is that you read @@ -705,16 +705,16 @@ void sysfs_unmap_bin_file(struct sysfs_dirent *sd) static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) { struct sysfs_open_file *of = sysfs_of(filp); - struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; - struct sysfs_open_dirent *od = attr_sd->s_attr.open; + struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; + struct sysfs_open_dirent *od = kn->s_attr.open; /* need parent for the kobj, grab both */ - if (!sysfs_get_active(attr_sd)) + if (!sysfs_get_active(kn)) goto trigger; poll_wait(filp, &od->poll, wait); - sysfs_put_active(attr_sd); + sysfs_put_active(kn); if (of->event != atomic_read(&od->event)) goto trigger; @@ -727,19 +727,19 @@ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) /** * kernfs_notify - notify a kernfs file - * @sd: file to notify + * @kn: file to notify * - * Notify @sd such that poll(2) on @sd wakes up. + * Notify @kn such that poll(2) on @kn wakes up. */ -void kernfs_notify(struct sysfs_dirent *sd) +void kernfs_notify(struct kernfs_node *kn) { struct sysfs_open_dirent *od; unsigned long flags; spin_lock_irqsave(&sysfs_open_dirent_lock, flags); - if (!WARN_ON(sysfs_type(sd) != SYSFS_KOBJ_ATTR)) { - od = sd->s_attr.open; + if (!WARN_ON(sysfs_type(kn) != SYSFS_KOBJ_ATTR)) { + od = kn->s_attr.open; if (od) { atomic_inc(&od->event); wake_up_interruptible(&od->poll); @@ -773,51 +773,51 @@ const struct file_operations kernfs_file_operations = { * * Returns the created node on success, ERR_PTR() value on error. */ -struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *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_file_ns_key(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 sysfs_addrm_cxt acxt; - struct sysfs_dirent *sd; + struct kernfs_node *kn; int rc; - sd = sysfs_new_dirent(kernfs_root(parent), name, + kn = sysfs_new_dirent(kernfs_root(parent), name, (mode & S_IALLUGO) | S_IFREG, SYSFS_KOBJ_ATTR); - if (!sd) + if (!kn) return ERR_PTR(-ENOMEM); - sd->s_attr.ops = ops; - sd->s_attr.size = size; - sd->s_ns = ns; - sd->priv = priv; + kn->s_attr.ops = ops; + kn->s_attr.size = size; + kn->s_ns = ns; + kn->priv = priv; #ifdef CONFIG_DEBUG_LOCK_ALLOC if (key) { - lockdep_init_map(&sd->dep_map, "s_active", key, 0); - sd->s_flags |= SYSFS_FLAG_LOCKDEP; + lockdep_init_map(&kn->dep_map, "s_active", key, 0); + kn->s_flags |= SYSFS_FLAG_LOCKDEP; } #endif /* - * sd->s_attr.ops is accesible only while holding active ref. We + * kn->s_attr.ops is accesible only while holding active ref. We * need to know whether some ops are implemented outside active * ref. Cache their existence in flags. */ if (ops->seq_show) - sd->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW; + kn->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW; if (ops->mmap) - sd->s_flags |= SYSFS_FLAG_HAS_MMAP; + kn->s_flags |= SYSFS_FLAG_HAS_MMAP; sysfs_addrm_start(&acxt); - rc = sysfs_add_one(&acxt, sd, parent); + rc = sysfs_add_one(&acxt, kn, parent); sysfs_addrm_finish(&acxt); if (rc) { - kernfs_put(sd); + kernfs_put(kn); return ERR_PTR(rc); } - return sd; + return kn; } -- cgit v1.2.3 From adc5e8b58f4886d45f79f4ff41a09001a76a6b12 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:54 -0500 Subject: kernfs: drop s_ prefix from kernfs_node members kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. s_ prefix for kernfs members is used inconsistently and a misnomer now. It's not like kernfs_node is used widely across the kernel making the ability to grep for the members particularly useful. Let's just drop the prefix. This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 1bf07ded826a..5277021196a7 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -21,7 +21,7 @@ * There's one sysfs_open_file for each open file and one sysfs_open_dirent * for each kernfs_node with one or more open files. * - * kernfs_node->s_attr.open points to sysfs_open_dirent. s_attr.open is + * kernfs_node->attr.open points to sysfs_open_dirent. attr.open is * protected by sysfs_open_dirent_lock. * * filp->private_data points to seq_file whose ->private points to @@ -49,9 +49,9 @@ static struct sysfs_open_file *sysfs_of(struct file *file) */ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) { - if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & SYSFS_FLAG_LOCKDEP) lockdep_assert_held(kn); - return kn->s_attr.ops; + return kn->attr.ops; } static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) @@ -112,9 +112,9 @@ static int kernfs_seq_show(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; - of->event = atomic_read(&of->kn->s_attr.open->event); + of->event = atomic_read(&of->kn->attr.open->event); - return of->kn->s_attr.ops->seq_show(sf, v); + return of->kn->attr.ops->seq_show(sf, v); } static const struct seq_operations kernfs_seq_ops = { @@ -189,7 +189,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, { struct sysfs_open_file *of = sysfs_of(file); - if (of->kn->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW) + if (of->kn->flags & SYSFS_FLAG_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); else return kernfs_file_direct_read(of, user_buf, count, ppos); @@ -428,7 +428,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) * without grabbing @of->mutex by testing HAS_MMAP flag. See the * comment in kernfs_file_open() for more details. */ - if (!(of->kn->s_flags & SYSFS_FLAG_HAS_MMAP)) + if (!(of->kn->flags & SYSFS_FLAG_HAS_MMAP)) return -ENODEV; mutex_lock(&of->mutex); @@ -477,8 +477,8 @@ out_unlock: * @kn: target kernfs_node * @of: sysfs_open_file for this instance of open * - * If @kn->s_attr.open exists, increment its reference count; - * otherwise, create one. @of is chained to the files list. + * If @kn->attr.open exists, increment its reference count; otherwise, + * create one. @of is chained to the files list. * * LOCKING: * Kernel thread context (may sleep). @@ -495,12 +495,12 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, mutex_lock(&sysfs_open_file_mutex); spin_lock_irq(&sysfs_open_dirent_lock); - if (!kn->s_attr.open && new_od) { - kn->s_attr.open = new_od; + if (!kn->attr.open && new_od) { + kn->attr.open = new_od; new_od = NULL; } - od = kn->s_attr.open; + od = kn->attr.open; if (od) { atomic_inc(&od->refcnt); list_add_tail(&of->list, &od->files); @@ -531,7 +531,7 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, * @kn: target kernfs_nodet * @of: associated sysfs_open_file * - * Put @kn->s_attr.open and unlink @of from the files list. If + * Put @kn->attr.open and unlink @of from the files list. If * reference count reaches zero, disassociate and free it. * * LOCKING: @@ -540,7 +540,7 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, static void sysfs_put_open_dirent(struct kernfs_node *kn, struct sysfs_open_file *of) { - struct sysfs_open_dirent *od = kn->s_attr.open; + struct sysfs_open_dirent *od = kn->attr.open; unsigned long flags; mutex_lock(&sysfs_open_file_mutex); @@ -550,7 +550,7 @@ static void sysfs_put_open_dirent(struct kernfs_node *kn, list_del(&of->list); if (atomic_dec_and_test(&od->refcnt)) - kn->s_attr.open = NULL; + kn->attr.open = NULL; else od = NULL; @@ -668,11 +668,11 @@ void sysfs_unmap_bin_file(struct kernfs_node *kn) struct sysfs_open_dirent *od; struct sysfs_open_file *of; - if (!(kn->s_flags & SYSFS_FLAG_HAS_MMAP)) + if (!(kn->flags & SYSFS_FLAG_HAS_MMAP)) return; spin_lock_irq(&sysfs_open_dirent_lock); - od = kn->s_attr.open; + od = kn->attr.open; if (od) atomic_inc(&od->refcnt); spin_unlock_irq(&sysfs_open_dirent_lock); @@ -706,7 +706,7 @@ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) { struct sysfs_open_file *of = sysfs_of(filp); struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; - struct sysfs_open_dirent *od = kn->s_attr.open; + struct sysfs_open_dirent *od = kn->attr.open; /* need parent for the kobj, grab both */ if (!sysfs_get_active(kn)) @@ -739,7 +739,7 @@ void kernfs_notify(struct kernfs_node *kn) spin_lock_irqsave(&sysfs_open_dirent_lock, flags); if (!WARN_ON(sysfs_type(kn) != SYSFS_KOBJ_ATTR)) { - od = kn->s_attr.open; + od = kn->attr.open; if (od) { atomic_inc(&od->event); wake_up_interruptible(&od->poll); @@ -789,27 +789,27 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, if (!kn) return ERR_PTR(-ENOMEM); - kn->s_attr.ops = ops; - kn->s_attr.size = size; - kn->s_ns = ns; + kn->attr.ops = ops; + kn->attr.size = size; + kn->ns = ns; kn->priv = priv; #ifdef CONFIG_DEBUG_LOCK_ALLOC if (key) { lockdep_init_map(&kn->dep_map, "s_active", key, 0); - kn->s_flags |= SYSFS_FLAG_LOCKDEP; + kn->flags |= SYSFS_FLAG_LOCKDEP; } #endif /* - * kn->s_attr.ops is accesible only while holding active ref. We + * kn->attr.ops is accesible only while holding active ref. We * need to know whether some ops are implemented outside active * ref. Cache their existence in flags. */ if (ops->seq_show) - kn->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW; + kn->flags |= SYSFS_FLAG_HAS_SEQ_SHOW; if (ops->mmap) - kn->s_flags |= SYSFS_FLAG_HAS_MMAP; + kn->flags |= SYSFS_FLAG_HAS_MMAP; sysfs_addrm_start(&acxt); rc = sysfs_add_one(&acxt, kn, parent); -- cgit v1.2.3 From c525aaddc366df23eb095d58a2bdf11cce62a98b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:55 -0500 Subject: kernfs: s/sysfs/kernfs/ in various data structures kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/sysfs_open_dirent/kernfs_open_node/ * s/sysfs_open_file/kernfs_open_file/ * s/sysfs_inode_attrs/kernfs_iattrs/ * s/sysfs_addrm_cxt/kernfs_addrm_cxt/ * s/sysfs_super_info/kernfs_super_info/ * s/sysfs_info()/kernfs_info()/ * s/sysfs_open_dirent_lock/kernfs_open_node_lock/ * s/sysfs_open_file_mutex/kernfs_open_file_mutex/ * s/sysfs_of()/kernfs_of()/ This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 172 +++++++++++++++++++++++++++---------------------------- 1 file changed, 86 insertions(+), 86 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 5277021196a7..2714a394cd81 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -18,27 +18,27 @@ #include "kernfs-internal.h" /* - * There's one sysfs_open_file for each open file and one sysfs_open_dirent + * There's one kernfs_open_file for each open file and one kernfs_open_node * for each kernfs_node with one or more open files. * - * kernfs_node->attr.open points to sysfs_open_dirent. attr.open is - * protected by sysfs_open_dirent_lock. + * kernfs_node->attr.open points to kernfs_open_node. attr.open is + * protected by kernfs_open_node_lock. * * filp->private_data points to seq_file whose ->private points to - * sysfs_open_file. sysfs_open_files are chained at - * sysfs_open_dirent->files, which is protected by sysfs_open_file_mutex. + * kernfs_open_file. kernfs_open_files are chained at + * kernfs_open_node->files, which is protected by kernfs_open_file_mutex. */ -static DEFINE_SPINLOCK(sysfs_open_dirent_lock); -static DEFINE_MUTEX(sysfs_open_file_mutex); +static DEFINE_SPINLOCK(kernfs_open_node_lock); +static DEFINE_MUTEX(kernfs_open_file_mutex); -struct sysfs_open_dirent { +struct kernfs_open_node { atomic_t refcnt; atomic_t event; wait_queue_head_t poll; - struct list_head files; /* goes through sysfs_open_file.list */ + struct list_head files; /* goes through kernfs_open_file.list */ }; -static struct sysfs_open_file *sysfs_of(struct file *file) +static struct kernfs_open_file *kernfs_of(struct file *file) { return ((struct seq_file *)file->private_data)->private; } @@ -56,7 +56,7 @@ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; const struct kernfs_ops *ops; /* @@ -81,7 +81,7 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_next) { @@ -98,7 +98,7 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) static void kernfs_seq_stop(struct seq_file *sf, void *v) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_stop) @@ -110,7 +110,7 @@ static void kernfs_seq_stop(struct seq_file *sf, void *v) static int kernfs_seq_show(struct seq_file *sf, void *v) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; of->event = atomic_read(&of->kn->attr.open->event); @@ -130,7 +130,7 @@ static const struct seq_operations kernfs_seq_ops = { * it difficult to use seq_file. Implement simplistic custom buffering for * bin files. */ -static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, +static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of, char __user *user_buf, size_t count, loff_t *ppos) { @@ -187,7 +187,7 @@ static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); if (of->kn->flags & SYSFS_FLAG_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); @@ -214,7 +214,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); ssize_t len = min_t(size_t, count, PAGE_SIZE); const struct kernfs_ops *ops; char *buf; @@ -259,7 +259,7 @@ out_free: static void kernfs_vma_open(struct vm_area_struct *vma) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); if (!of->vm_ops) return; @@ -276,7 +276,7 @@ static void kernfs_vma_open(struct vm_area_struct *vma) static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -297,7 +297,7 @@ static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -320,7 +320,7 @@ static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr, void *buf, int len, int write) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -342,7 +342,7 @@ static int kernfs_vma_set_policy(struct vm_area_struct *vma, struct mempolicy *new) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -363,7 +363,7 @@ static struct mempolicy *kernfs_vma_get_policy(struct vm_area_struct *vma, unsigned long addr) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); struct mempolicy *pol; if (!of->vm_ops) @@ -385,7 +385,7 @@ static int kernfs_vma_migrate(struct vm_area_struct *vma, unsigned long flags) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -417,7 +417,7 @@ static const struct vm_operations_struct kernfs_vm_ops = { static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) { - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); const struct kernfs_ops *ops; int rc; @@ -473,9 +473,9 @@ out_unlock: } /** - * sysfs_get_open_dirent - get or create sysfs_open_dirent + * sysfs_get_open_dirent - get or create kernfs_open_node * @kn: target kernfs_node - * @of: sysfs_open_file for this instance of open + * @of: kernfs_open_file for this instance of open * * If @kn->attr.open exists, increment its reference count; otherwise, * create one. @of is chained to the files list. @@ -487,49 +487,49 @@ out_unlock: * 0 on success, -errno on failure. */ static int sysfs_get_open_dirent(struct kernfs_node *kn, - struct sysfs_open_file *of) + struct kernfs_open_file *of) { - struct sysfs_open_dirent *od, *new_od = NULL; + struct kernfs_open_node *on, *new_on = NULL; retry: - mutex_lock(&sysfs_open_file_mutex); - spin_lock_irq(&sysfs_open_dirent_lock); + mutex_lock(&kernfs_open_file_mutex); + spin_lock_irq(&kernfs_open_node_lock); - if (!kn->attr.open && new_od) { - kn->attr.open = new_od; - new_od = NULL; + if (!kn->attr.open && new_on) { + kn->attr.open = new_on; + new_on = NULL; } - od = kn->attr.open; - if (od) { - atomic_inc(&od->refcnt); - list_add_tail(&of->list, &od->files); + on = kn->attr.open; + if (on) { + atomic_inc(&on->refcnt); + list_add_tail(&of->list, &on->files); } - spin_unlock_irq(&sysfs_open_dirent_lock); - mutex_unlock(&sysfs_open_file_mutex); + spin_unlock_irq(&kernfs_open_node_lock); + mutex_unlock(&kernfs_open_file_mutex); - if (od) { - kfree(new_od); + if (on) { + kfree(new_on); return 0; } /* not there, initialize a new one and retry */ - new_od = kmalloc(sizeof(*new_od), GFP_KERNEL); - if (!new_od) + new_on = kmalloc(sizeof(*new_on), GFP_KERNEL); + if (!new_on) return -ENOMEM; - atomic_set(&new_od->refcnt, 0); - atomic_set(&new_od->event, 1); - init_waitqueue_head(&new_od->poll); - INIT_LIST_HEAD(&new_od->files); + atomic_set(&new_on->refcnt, 0); + atomic_set(&new_on->event, 1); + init_waitqueue_head(&new_on->poll); + INIT_LIST_HEAD(&new_on->files); goto retry; } /** - * sysfs_put_open_dirent - put sysfs_open_dirent + * sysfs_put_open_dirent - put kernfs_open_node * @kn: target kernfs_nodet - * @of: associated sysfs_open_file + * @of: associated kernfs_open_file * * Put @kn->attr.open and unlink @of from the files list. If * reference count reaches zero, disassociate and free it. @@ -538,33 +538,33 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, * None. */ static void sysfs_put_open_dirent(struct kernfs_node *kn, - struct sysfs_open_file *of) + struct kernfs_open_file *of) { - struct sysfs_open_dirent *od = kn->attr.open; + struct kernfs_open_node *on = kn->attr.open; unsigned long flags; - mutex_lock(&sysfs_open_file_mutex); - spin_lock_irqsave(&sysfs_open_dirent_lock, flags); + mutex_lock(&kernfs_open_file_mutex); + spin_lock_irqsave(&kernfs_open_node_lock, flags); if (of) list_del(&of->list); - if (atomic_dec_and_test(&od->refcnt)) + if (atomic_dec_and_test(&on->refcnt)) kn->attr.open = NULL; else - od = NULL; + on = NULL; - spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); - mutex_unlock(&sysfs_open_file_mutex); + spin_unlock_irqrestore(&kernfs_open_node_lock, flags); + mutex_unlock(&kernfs_open_file_mutex); - kfree(od); + kfree(on); } static int kernfs_file_open(struct inode *inode, struct file *file) { struct kernfs_node *kn = file->f_path.dentry->d_fsdata; const struct kernfs_ops *ops; - struct sysfs_open_file *of; + struct kernfs_open_file *of; bool has_read, has_write, has_mmap; int error = -EACCES; @@ -586,9 +586,9 @@ static int kernfs_file_open(struct inode *inode, struct file *file) (!(inode->i_mode & S_IRUGO) || !has_read)) goto err_out; - /* allocate a sysfs_open_file for the file */ + /* allocate a kernfs_open_file for the file */ error = -ENOMEM; - of = kzalloc(sizeof(struct sysfs_open_file), GFP_KERNEL); + of = kzalloc(sizeof(struct kernfs_open_file), GFP_KERNEL); if (!of) goto err_out; @@ -654,7 +654,7 @@ err_out: static int kernfs_file_release(struct inode *inode, struct file *filp) { struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; - struct sysfs_open_file *of = sysfs_of(filp); + struct kernfs_open_file *of = kernfs_of(filp); sysfs_put_open_dirent(kn, of); seq_release(inode, filp); @@ -665,26 +665,26 @@ static int kernfs_file_release(struct inode *inode, struct file *filp) void sysfs_unmap_bin_file(struct kernfs_node *kn) { - struct sysfs_open_dirent *od; - struct sysfs_open_file *of; + struct kernfs_open_node *on; + struct kernfs_open_file *of; if (!(kn->flags & SYSFS_FLAG_HAS_MMAP)) return; - spin_lock_irq(&sysfs_open_dirent_lock); - od = kn->attr.open; - if (od) - atomic_inc(&od->refcnt); - spin_unlock_irq(&sysfs_open_dirent_lock); - if (!od) + spin_lock_irq(&kernfs_open_node_lock); + on = kn->attr.open; + if (on) + atomic_inc(&on->refcnt); + spin_unlock_irq(&kernfs_open_node_lock); + if (!on) return; - mutex_lock(&sysfs_open_file_mutex); - list_for_each_entry(of, &od->files, list) { + mutex_lock(&kernfs_open_file_mutex); + list_for_each_entry(of, &on->files, list) { struct inode *inode = file_inode(of->file); unmap_mapping_range(inode->i_mapping, 0, 0, 1); } - mutex_unlock(&sysfs_open_file_mutex); + mutex_unlock(&kernfs_open_file_mutex); sysfs_put_open_dirent(kn, NULL); } @@ -704,19 +704,19 @@ void sysfs_unmap_bin_file(struct kernfs_node *kn) */ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) { - struct sysfs_open_file *of = sysfs_of(filp); + struct kernfs_open_file *of = kernfs_of(filp); struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; - struct sysfs_open_dirent *od = kn->attr.open; + struct kernfs_open_node *on = kn->attr.open; /* need parent for the kobj, grab both */ if (!sysfs_get_active(kn)) goto trigger; - poll_wait(filp, &od->poll, wait); + poll_wait(filp, &on->poll, wait); sysfs_put_active(kn); - if (of->event != atomic_read(&od->event)) + if (of->event != atomic_read(&on->event)) goto trigger; return DEFAULT_POLLMASK; @@ -733,20 +733,20 @@ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) */ void kernfs_notify(struct kernfs_node *kn) { - struct sysfs_open_dirent *od; + struct kernfs_open_node *on; unsigned long flags; - spin_lock_irqsave(&sysfs_open_dirent_lock, flags); + spin_lock_irqsave(&kernfs_open_node_lock, flags); if (!WARN_ON(sysfs_type(kn) != SYSFS_KOBJ_ATTR)) { - od = kn->attr.open; - if (od) { - atomic_inc(&od->event); - wake_up_interruptible(&od->poll); + on = kn->attr.open; + if (on) { + atomic_inc(&on->event); + wake_up_interruptible(&on->poll); } } - spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); + spin_unlock_irqrestore(&kernfs_open_node_lock, flags); } EXPORT_SYMBOL_GPL(kernfs_notify); @@ -780,7 +780,7 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, void *priv, const void *ns, struct lock_class_key *key) { - struct sysfs_addrm_cxt acxt; + struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; int rc; -- cgit v1.2.3 From df23fc39bce03bb26e63bea57fc5f5bf6882d74b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:56 -0500 Subject: kernfs: s/sysfs/kernfs/ in constants kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/SYSFS_DIR/KERNFS_DIR/ * s/SYSFS_KOBJ_ATTR/KERNFS_FILE/ * s/SYSFS_KOBJ_LINK/KERNFS_LINK/ * s/SYSFS_{TYPE_FLAGS}/KERNFS_{TYPE_FLAGS}/ * s/SYSFS_FLAG_{FLAG}/KERNFS_{FLAG}/ * s/sysfs_type()/kernfs_type()/ * s/SD_DEACTIVATED_BIAS/KN_DEACTIVATED_BIAS/ This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 2714a394cd81..abe93e12089c 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -49,7 +49,7 @@ static struct kernfs_open_file *kernfs_of(struct file *file) */ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) { - if (kn->flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & KERNFS_LOCKDEP) lockdep_assert_held(kn); return kn->attr.ops; } @@ -189,7 +189,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, { struct kernfs_open_file *of = kernfs_of(file); - if (of->kn->flags & SYSFS_FLAG_HAS_SEQ_SHOW) + if (of->kn->flags & KERNFS_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); else return kernfs_file_direct_read(of, user_buf, count, ppos); @@ -428,7 +428,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) * without grabbing @of->mutex by testing HAS_MMAP flag. See the * comment in kernfs_file_open() for more details. */ - if (!(of->kn->flags & SYSFS_FLAG_HAS_MMAP)) + if (!(of->kn->flags & KERNFS_HAS_MMAP)) return -ENODEV; mutex_lock(&of->mutex); @@ -668,7 +668,7 @@ void sysfs_unmap_bin_file(struct kernfs_node *kn) struct kernfs_open_node *on; struct kernfs_open_file *of; - if (!(kn->flags & SYSFS_FLAG_HAS_MMAP)) + if (!(kn->flags & KERNFS_HAS_MMAP)) return; spin_lock_irq(&kernfs_open_node_lock); @@ -738,7 +738,7 @@ void kernfs_notify(struct kernfs_node *kn) spin_lock_irqsave(&kernfs_open_node_lock, flags); - if (!WARN_ON(sysfs_type(kn) != SYSFS_KOBJ_ATTR)) { + if (!WARN_ON(kernfs_type(kn) != KERNFS_FILE)) { on = kn->attr.open; if (on) { atomic_inc(&on->event); @@ -785,7 +785,7 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, int rc; kn = sysfs_new_dirent(kernfs_root(parent), name, - (mode & S_IALLUGO) | S_IFREG, SYSFS_KOBJ_ATTR); + (mode & S_IALLUGO) | S_IFREG, KERNFS_FILE); if (!kn) return ERR_PTR(-ENOMEM); @@ -797,7 +797,7 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, #ifdef CONFIG_DEBUG_LOCK_ALLOC if (key) { lockdep_init_map(&kn->dep_map, "s_active", key, 0); - kn->flags |= SYSFS_FLAG_LOCKDEP; + kn->flags |= KERNFS_LOCKDEP; } #endif @@ -807,9 +807,9 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, * ref. Cache their existence in flags. */ if (ops->seq_show) - kn->flags |= SYSFS_FLAG_HAS_SEQ_SHOW; + kn->flags |= KERNFS_HAS_SEQ_SHOW; if (ops->mmap) - kn->flags |= SYSFS_FLAG_HAS_MMAP; + kn->flags |= KERNFS_HAS_MMAP; sysfs_addrm_start(&acxt); rc = sysfs_add_one(&acxt, kn, parent); -- cgit v1.2.3 From a797bfc30532388e8a11ca726df60cdd77aa8675 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:57 -0500 Subject: kernfs: s/sysfs/kernfs/ in global variables kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/sysfs_mutex/kernfs_mutex/ * s/sysfs_dentry_ops/kernfs_dops/ * s/sysfs_dir_operations/kernfs_dir_fops/ * s/sysfs_dir_inode_operations/kernfs_dir_iops/ * s/kernfs_file_operations/kernfs_file_fops/ - renamed for consistency * s/sysfs_symlink_inode_operations/kernfs_symlink_iops/ * s/sysfs_aops/kernfs_aops/ * s/sysfs_backing_dev_info/kernfs_bdi/ * s/sysfs_inode_operations/kernfs_iops/ * s/sysfs_dir_cachep/kernfs_node_cache/ * s/sysfs_ops/kernfs_sops/ This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index abe93e12089c..32364ddb24de 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -750,7 +750,7 @@ void kernfs_notify(struct kernfs_node *kn) } EXPORT_SYMBOL_GPL(kernfs_notify); -const struct file_operations kernfs_file_operations = { +const struct file_operations kernfs_file_fops = { .read = kernfs_file_read, .write = kernfs_file_write, .llseek = generic_file_llseek, -- cgit v1.2.3 From c637b8acbe079edb477d887041755b489036f146 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:58 -0500 Subject: kernfs: s/sysfs/kernfs/ in internal functions and whatever is left kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/sysfs_*()/kernfs_*()/ in all internal functions * s/sysfs/kernfs/ in internal strings, comments and whatever is remaining * Uniformly rename various vfs operations so that they're consistently named and distinguishable. This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 121 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 60 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 32364ddb24de..053cfd9a6a40 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -64,7 +64,7 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) return ERR_PTR(-ENODEV); ops = kernfs_ops(of->kn); @@ -104,7 +104,7 @@ static void kernfs_seq_stop(struct seq_file *sf, void *v) if (ops->seq_stop) ops->seq_stop(sf, v); - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); mutex_unlock(&of->mutex); } @@ -147,7 +147,7 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of, * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->kn)) { + if (!kernfs_get_active(of->kn)) { len = -ENODEV; mutex_unlock(&of->mutex); goto out_free; @@ -159,7 +159,7 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of, else len = -EINVAL; - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); mutex_unlock(&of->mutex); if (len < 0) @@ -178,14 +178,14 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of, } /** - * kernfs_file_read - kernfs vfs read callback + * kernfs_fop_read - kernfs vfs read callback * @file: file pointer * @user_buf: data to write * @count: number of bytes * @ppos: starting offset */ -static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct kernfs_open_file *of = kernfs_of(file); @@ -196,7 +196,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, } /** - * kernfs_file_write - kernfs vfs write callback + * kernfs_fop_write - kernfs vfs write callback * @file: file pointer * @user_buf: data to write * @count: number of bytes @@ -211,8 +211,8 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, * modify only the the value you're changing, then write entire buffer * back. */ -static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) { struct kernfs_open_file *of = kernfs_of(file); ssize_t len = min_t(size_t, count, PAGE_SIZE); @@ -234,7 +234,7 @@ static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->kn)) { + if (!kernfs_get_active(of->kn)) { mutex_unlock(&of->mutex); len = -ENODEV; goto out_free; @@ -246,7 +246,7 @@ static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, else len = -EINVAL; - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); mutex_unlock(&of->mutex); if (len > 0) @@ -264,13 +264,13 @@ static void kernfs_vma_open(struct vm_area_struct *vma) if (!of->vm_ops) return; - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) return; if (of->vm_ops->open) of->vm_ops->open(vma); - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); } static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -282,14 +282,14 @@ static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!of->vm_ops) return VM_FAULT_SIGBUS; - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) return VM_FAULT_SIGBUS; ret = VM_FAULT_SIGBUS; if (of->vm_ops->fault) ret = of->vm_ops->fault(vma, vmf); - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); return ret; } @@ -303,7 +303,7 @@ static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, if (!of->vm_ops) return VM_FAULT_SIGBUS; - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) return VM_FAULT_SIGBUS; ret = 0; @@ -312,7 +312,7 @@ static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, else file_update_time(file); - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); return ret; } @@ -326,14 +326,14 @@ static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr, if (!of->vm_ops) return -EINVAL; - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) return -EINVAL; ret = -EINVAL; if (of->vm_ops->access) ret = of->vm_ops->access(vma, addr, buf, len, write); - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); return ret; } @@ -348,14 +348,14 @@ static int kernfs_vma_set_policy(struct vm_area_struct *vma, if (!of->vm_ops) return 0; - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) return -EINVAL; ret = 0; if (of->vm_ops->set_policy) ret = of->vm_ops->set_policy(vma, new); - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); return ret; } @@ -369,14 +369,14 @@ static struct mempolicy *kernfs_vma_get_policy(struct vm_area_struct *vma, if (!of->vm_ops) return vma->vm_policy; - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) return vma->vm_policy; pol = vma->vm_policy; if (of->vm_ops->get_policy) pol = of->vm_ops->get_policy(vma, addr); - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); return pol; } @@ -391,14 +391,14 @@ static int kernfs_vma_migrate(struct vm_area_struct *vma, if (!of->vm_ops) return 0; - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) return 0; ret = 0; if (of->vm_ops->migrate) ret = of->vm_ops->migrate(vma, from, to, flags); - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); return ret; } #endif @@ -415,7 +415,7 @@ static const struct vm_operations_struct kernfs_vm_ops = { #endif }; -static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) +static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma) { struct kernfs_open_file *of = kernfs_of(file); const struct kernfs_ops *ops; @@ -434,7 +434,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) mutex_lock(&of->mutex); rc = -ENODEV; - if (!sysfs_get_active(of->kn)) + if (!kernfs_get_active(of->kn)) goto out_unlock; ops = kernfs_ops(of->kn); @@ -465,7 +465,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) of->vm_ops = vma->vm_ops; vma->vm_ops = &kernfs_vm_ops; out_put: - sysfs_put_active(of->kn); + kernfs_put_active(of->kn); out_unlock: mutex_unlock(&of->mutex); @@ -473,7 +473,7 @@ out_unlock: } /** - * sysfs_get_open_dirent - get or create kernfs_open_node + * kernfs_get_open_node - get or create kernfs_open_node * @kn: target kernfs_node * @of: kernfs_open_file for this instance of open * @@ -486,8 +486,8 @@ out_unlock: * RETURNS: * 0 on success, -errno on failure. */ -static int sysfs_get_open_dirent(struct kernfs_node *kn, - struct kernfs_open_file *of) +static int kernfs_get_open_node(struct kernfs_node *kn, + struct kernfs_open_file *of) { struct kernfs_open_node *on, *new_on = NULL; @@ -527,7 +527,7 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, } /** - * sysfs_put_open_dirent - put kernfs_open_node + * kernfs_put_open_node - put kernfs_open_node * @kn: target kernfs_nodet * @of: associated kernfs_open_file * @@ -537,8 +537,8 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, * LOCKING: * None. */ -static void sysfs_put_open_dirent(struct kernfs_node *kn, - struct kernfs_open_file *of) +static void kernfs_put_open_node(struct kernfs_node *kn, + struct kernfs_open_file *of) { struct kernfs_open_node *on = kn->attr.open; unsigned long flags; @@ -560,7 +560,7 @@ static void sysfs_put_open_dirent(struct kernfs_node *kn, kfree(on); } -static int kernfs_file_open(struct inode *inode, struct file *file) +static int kernfs_fop_open(struct inode *inode, struct file *file) { struct kernfs_node *kn = file->f_path.dentry->d_fsdata; const struct kernfs_ops *ops; @@ -568,7 +568,7 @@ static int kernfs_file_open(struct inode *inode, struct file *file) bool has_read, has_write, has_mmap; int error = -EACCES; - if (!sysfs_get_active(kn)) + if (!kernfs_get_active(kn)) return -ENODEV; ops = kernfs_ops(kn); @@ -633,13 +633,13 @@ static int kernfs_file_open(struct inode *inode, struct file *file) if (file->f_mode & FMODE_WRITE) file->f_mode |= FMODE_PWRITE; - /* make sure we have open dirent struct */ - error = sysfs_get_open_dirent(kn, of); + /* make sure we have open node struct */ + error = kernfs_get_open_node(kn, of); if (error) goto err_close; /* open succeeded, put active references */ - sysfs_put_active(kn); + kernfs_put_active(kn); return 0; err_close: @@ -647,23 +647,23 @@ err_close: err_free: kfree(of); err_out: - sysfs_put_active(kn); + kernfs_put_active(kn); return error; } -static int kernfs_file_release(struct inode *inode, struct file *filp) +static int kernfs_fop_release(struct inode *inode, struct file *filp) { struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; struct kernfs_open_file *of = kernfs_of(filp); - sysfs_put_open_dirent(kn, of); + kernfs_put_open_node(kn, of); seq_release(inode, filp); kfree(of); return 0; } -void sysfs_unmap_bin_file(struct kernfs_node *kn) +void kernfs_unmap_bin_file(struct kernfs_node *kn) { struct kernfs_open_node *on; struct kernfs_open_file *of; @@ -686,10 +686,11 @@ void sysfs_unmap_bin_file(struct kernfs_node *kn) } mutex_unlock(&kernfs_open_file_mutex); - sysfs_put_open_dirent(kn, NULL); + kernfs_put_open_node(kn, NULL); } -/* Sysfs attribute files are pollable. The idea is that you read +/* + * Kernfs attribute files are pollable. The idea is that you read * the content and then you use 'poll' or 'select' to wait for * the content to change. When the content changes (assuming the * manager for the kobject supports notification), poll will @@ -702,19 +703,19 @@ void sysfs_unmap_bin_file(struct kernfs_node *kn) * to see if it supports poll (Neither 'poll' nor 'select' return * an appropriate error code). When in doubt, set a suitable timeout value. */ -static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) +static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait) { struct kernfs_open_file *of = kernfs_of(filp); struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; struct kernfs_open_node *on = kn->attr.open; /* need parent for the kobj, grab both */ - if (!sysfs_get_active(kn)) + if (!kernfs_get_active(kn)) goto trigger; poll_wait(filp, &on->poll, wait); - sysfs_put_active(kn); + kernfs_put_active(kn); if (of->event != atomic_read(&on->event)) goto trigger; @@ -751,13 +752,13 @@ void kernfs_notify(struct kernfs_node *kn) EXPORT_SYMBOL_GPL(kernfs_notify); const struct file_operations kernfs_file_fops = { - .read = kernfs_file_read, - .write = kernfs_file_write, + .read = kernfs_fop_read, + .write = kernfs_fop_write, .llseek = generic_file_llseek, - .mmap = kernfs_file_mmap, - .open = kernfs_file_open, - .release = kernfs_file_release, - .poll = kernfs_file_poll, + .mmap = kernfs_fop_mmap, + .open = kernfs_fop_open, + .release = kernfs_fop_release, + .poll = kernfs_fop_poll, }; /** @@ -784,8 +785,8 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, struct kernfs_node *kn; int rc; - kn = sysfs_new_dirent(kernfs_root(parent), name, - (mode & S_IALLUGO) | S_IFREG, KERNFS_FILE); + kn = kernfs_new_node(kernfs_root(parent), name, + (mode & S_IALLUGO) | S_IFREG, KERNFS_FILE); if (!kn) return ERR_PTR(-ENOMEM); @@ -811,9 +812,9 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, if (ops->mmap) kn->flags |= KERNFS_HAS_MMAP; - sysfs_addrm_start(&acxt); - rc = sysfs_add_one(&acxt, kn, parent); - sysfs_addrm_finish(&acxt); + kernfs_addrm_start(&acxt); + rc = kernfs_add_one(&acxt, kn, parent); + kernfs_addrm_finish(&acxt); if (rc) { kernfs_put(kn); -- cgit v1.2.3 From 2063d608f5110d120db60e896ec2c70c95bb7978 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 16:02:57 -0500 Subject: kernfs: mark static names with KERNFS_STATIC_NAME Because sysfs used struct attribute which are supposed to stay constant, sysfs didn't copy names when creating regular files. The specified string for name was supposed to stay constant. Such distinction isn't inherent for kernfs. kernfs_create_file[_ns]() should be able to take the same @name as kernfs_create_dir[_ns]() As there can be huge number of sysfs attributes, we still want to be able to use static names for sysfs attributes. This patch renames kernfs_create_file_ns_key() to __kernfs_create_file() and adds @name_is_static parameter so that the caller can explicitly indicate that @name can be used without copying. kernfs is updated to use KERNFS_STATIC_NAME to distinguish static and copied names. This patch doesn't introduce any behavior changes. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 053cfd9a6a40..316604cc3a1c 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -762,7 +762,7 @@ const struct file_operations kernfs_file_fops = { }; /** - * kernfs_create_file_ns_key - create a file + * __kernfs_create_file - kernfs internal function to create a file * @parent: directory to create the file in * @name: name of the file * @mode: mode of the file @@ -770,23 +770,30 @@ const struct file_operations kernfs_file_fops = { * @ops: kernfs operations for the file * @priv: private data for the file * @ns: optional namespace tag of the file + * @static_name: don't copy file name * @key: lockdep key for the file's active_ref, %NULL to disable lockdep * * Returns the created node on success, ERR_PTR() value on error. */ -struct kernfs_node *kernfs_create_file_ns_key(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_file(struct kernfs_node *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + bool name_is_static, + struct lock_class_key *key) { struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; + unsigned flags; int rc; + flags = KERNFS_FILE; + if (name_is_static) + flags |= KERNFS_STATIC_NAME; + kn = kernfs_new_node(kernfs_root(parent), name, - (mode & S_IALLUGO) | S_IFREG, KERNFS_FILE); + (mode & S_IALLUGO) | S_IFREG, flags); if (!kn) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From d92d2e6bd72b653f9811e0c9c46307c743b3fc58 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:18 -0500 Subject: kernfs: fix get_active failure handling in kernfs_seq_*() When kernfs_seq_start() fails to obtain an active reference, it returns ERR_PTR(-ENODEV). kernfs_seq_stop() is then invoked with the error pointer value; however, it still proceeds to invoke kernfs_put_active() on the node leading to unbalanced put. If kernfs_seq_stop() is called even after active ref failure, it should skip invocation of @ops->seq_stop() and put_active. Unfortunately, this is a bit complicated because active ref failure isn't the only thing which may fail with ERR_PTR(-ENODEV). @ops->seq_start/next() may also fail with the error value and kernfs_seq_stop() doesn't have a way to tell apart those failures. Work it around by factoring out the active part of kernfs_seq_stop() into kernfs_seq_stop_active() and invoking it directly if @ops->seq_start/next() fail with ERR_PTR(-ENODEV) and updating kernfs_seq_stop() to skip kernfs_seq_stop_active() on ERR_PTR(-ENODEV). This is a bit nasty but ensures that the active put is skipped iff get_active failed in kernfs_seq_start(). Signed-off-by: Tejun Heo Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 316604cc3a1c..bdd38854ef65 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -54,6 +54,38 @@ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) return kn->attr.ops; } +/* + * As kernfs_seq_stop() is also called after kernfs_seq_start() or + * kernfs_seq_next() failure, it needs to distinguish whether it's stopping + * a seq_file iteration which is fully initialized with an active reference + * or an aborted kernfs_seq_start() due to get_active failure. The + * position pointer is the only context for each seq_file iteration and + * thus the stop condition should be encoded in it. As the return value is + * directly visible to userland, ERR_PTR(-ENODEV) is the only acceptable + * choice to indicate get_active failure. + * + * Unfortunately, this is complicated due to the optional custom seq_file + * operations which may return ERR_PTR(-ENODEV) too. kernfs_seq_stop() + * can't distinguish whether ERR_PTR(-ENODEV) is from get_active failure or + * custom seq_file operations and thus can't decide whether put_active + * should be performed or not only on ERR_PTR(-ENODEV). + * + * This is worked around by factoring out the custom seq_stop() and + * put_active part into kernfs_seq_stop_active(), skipping it from + * kernfs_seq_stop() if ERR_PTR(-ENODEV) while invoking it directly after + * custom seq_file operations fail with ERR_PTR(-ENODEV) - this ensures + * that kernfs_seq_stop_active() is skipped only after get_active failure. + */ +static void kernfs_seq_stop_active(struct seq_file *sf, void *v) +{ + struct kernfs_open_file *of = sf->private; + const struct kernfs_ops *ops = kernfs_ops(of->kn); + + if (ops->seq_stop) + ops->seq_stop(sf, v); + kernfs_put_active(of->kn); +} + static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) { struct kernfs_open_file *of = sf->private; @@ -69,7 +101,11 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) ops = kernfs_ops(of->kn); if (ops->seq_start) { - return ops->seq_start(sf, ppos); + void *next = ops->seq_start(sf, ppos); + /* see the comment above kernfs_seq_stop_active() */ + if (next == ERR_PTR(-ENODEV)) + kernfs_seq_stop_active(sf, next); + return next; } else { /* * The same behavior and code as single_open(). Returns @@ -85,7 +121,11 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_next) { - return ops->seq_next(sf, v, ppos); + void *next = ops->seq_next(sf, v, ppos); + /* see the comment above kernfs_seq_stop_active() */ + if (next == ERR_PTR(-ENODEV)) + kernfs_seq_stop_active(sf, next); + return next; } else { /* * The same behavior and code as single_open(), always @@ -99,12 +139,9 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) static void kernfs_seq_stop(struct seq_file *sf, void *v) { struct kernfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->kn); - if (ops->seq_stop) - ops->seq_stop(sf, v); - - kernfs_put_active(of->kn); + if (v != ERR_PTR(-ENODEV)) + kernfs_seq_stop_active(sf, v); mutex_unlock(&of->mutex); } -- cgit v1.2.3 From ae34372eb8408b3d07e870f1939f99007a730d28 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:21 -0500 Subject: kernfs: remove KERNFS_REMOVED KERNFS_REMOVED is used to mark half-initialized and dying nodes so that they don't show up in lookups and deny adding new nodes under or renaming it; however, its role overlaps those of deactivation and removal from rbtree. It's necessary to deny addition of new children while removal is in progress; however, this role considerably intersects with deactivation - KERNFS_REMOVED prevents new children while deactivation prevents new file operations. There's no reason to have them separate making things more complex than necessary. KERNFS_REMOVED is also used to decide whether a node is still visible to vfs layer, which is rather redundant as equivalent determination can be made by testing whether the node is on its parent's children rbtree or not. This patch removes KERNFS_REMOVED. * Instead of KERNFS_REMOVED, each node now starts its life deactivated. This means that we now use both atomic_add() and atomic_sub() on KN_DEACTIVATED_BIAS, which is INT_MIN. The compiler generates an overflow warnings when negating INT_MIN as the negation can't be represented as a positive number. Nothing is actually broken but let's bump BIAS by one to avoid the warnings for archs which negates the subtrahend.. * KERNFS_REMOVED tests in add and rename paths are replaced with kernfs_get/put_active() of the target nodes. Due to the way the add path is structured now, active ref handling is done in the callers of kernfs_add_one(). This will be consolidated up later. * kernfs_remove_one() is updated to deactivate instead of setting KERNFS_REMOVED. This removes deactivation from kernfs_deactivate(), which is now renamed to kernfs_drain(). * kernfs_dop_revalidate() now tests RB_EMPTY_NODE(&kn->rb) instead of KERNFS_REMOVED and KERNFS_REMOVED test in kernfs_dir_pos() is dropped. A node which is removed from the children rbtree is not included in the iteration in the first place. This means that a node may be visible through vfs a bit longer - it's now also visible after deactivation until the actual removal. This slightly enlarged window difference doesn't make any difference to the userland. * Sanity check on KERNFS_REMOVED in kernfs_put() is replaced with checks on the active ref. * Some comment style updates in the affected area. v2: Reordered before removal path restructuring. kernfs_active() dropped and kernfs_get/put_active() used instead. RB_EMPTY_NODE() used in the lookup paths. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index bdd38854ef65..231a171f48b6 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -856,9 +856,13 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, if (ops->mmap) kn->flags |= KERNFS_HAS_MMAP; - kernfs_addrm_start(&acxt); - rc = kernfs_add_one(&acxt, kn, parent); - kernfs_addrm_finish(&acxt); + rc = -ENOENT; + if (kernfs_get_active(parent)) { + kernfs_addrm_start(&acxt); + rc = kernfs_add_one(&acxt, kn, parent); + kernfs_addrm_finish(&acxt); + kernfs_put_active(parent); + } if (rc) { kernfs_put(kn); -- cgit v1.2.3 From f601f9a2bf7dc1f7ee18feece4c4e2fc6845d6c4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:23 -0500 Subject: kernfs: invoke kernfs_unmap_bin_file() directly from __kernfs_remove() kernfs_unmap_bin_file() is supposed to unmap all memory mappings of the target file before kernfs_remove() finishes; however, it currently is being called from kernfs_addrm_finish() and has the same race problem as the original implementation of deactivation when there are multiple removers - only the remover which snatches the node to its addrm_cxt->removed list is guaranteed to wait for its completion before returning. It can be fixed by moving kernfs_unmap_bin_file() invocation from kernfs_addrm_finish() to __kernfs_remove(). The function may be called multiple times but that shouldn't do any harm. We end up dropping kernfs_mutex in the removal loop and the node may be removed inbetween by someone else. kernfs_unlink_sibling() is updated to test whether the node has already been removed and return accordingly. __kernfs_remove() in turn performs post-unlinking cleanup only if it actually unlinked the node. KERNFS_HAS_MMAP test is moved out of the unmap function into __kernfs_remove() so that we don't unlock kernfs_mutex unnecessarily. While at it, drop the now meaningless "bin" qualifier from the function name. v2: Rewritten to fit the v2 restructuring of removal path. HAS_MMAP test relocated. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 231a171f48b6..404ffd2f27bc 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -700,14 +700,11 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp) return 0; } -void kernfs_unmap_bin_file(struct kernfs_node *kn) +void kernfs_unmap_file(struct kernfs_node *kn) { struct kernfs_open_node *on; struct kernfs_open_file *of; - if (!(kn->flags & KERNFS_HAS_MMAP)) - return; - spin_lock_irq(&kernfs_open_node_lock); on = kn->attr.open; if (on) -- cgit v1.2.3 From 99177a34110889a8f2c36420c34e3bcc9bfd8a70 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:24 -0500 Subject: kernfs: remove kernfs_addrm_cxt kernfs_addrm_cxt and the accompanying kernfs_addrm_start/finish() were added because there were operations which should be performed outside kernfs_mutex after adding and removing kernfs_nodes. The necessary operations were recorded in kernfs_addrm_cxt and performed by kernfs_addrm_finish(); however, after the recent changes which relocated deactivation and unmapping so that they're performed directly during removal, the only operation kernfs_addrm_finish() performs is kernfs_put(), which can be moved inside the removal path too. This patch moves the kernfs_put() of the base ref to __kernfs_remove() and remove kernfs_addrm_cxt and kernfs_addrm_start/finish(). * kernfs_add_one() is updated to grab and release the parent's active ref and kernfs_mutex itself. kernfs_get/put_active() and kernfs_addrm_start/finish() invocations around it are removed from all users. * __kernfs_remove() puts an unlinked node directly instead of chaining it to kernfs_addrm_cxt. Its callers are updated to grab and release kernfs_mutex instead of calling kernfs_addrm_start/finish() around it. v2: Updated to fit the v2 restructuring of removal path. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 404ffd2f27bc..ffe1bebf9197 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -817,7 +817,6 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, bool name_is_static, struct lock_class_key *key) { - struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; unsigned flags; int rc; @@ -853,14 +852,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, if (ops->mmap) kn->flags |= KERNFS_HAS_MMAP; - rc = -ENOENT; - if (kernfs_get_active(parent)) { - kernfs_addrm_start(&acxt); - rc = kernfs_add_one(&acxt, kn, parent); - kernfs_addrm_finish(&acxt); - kernfs_put_active(parent); - } - + rc = kernfs_add_one(kn, parent); if (rc) { kernfs_put(kn); return ERR_PTR(rc); -- cgit v1.2.3 From 7653fe9d6cddc3fc5e4220608079006d8ac0054c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:20:56 -0800 Subject: Revert "kernfs: remove kernfs_addrm_cxt" This reverts commit 99177a34110889a8f2c36420c34e3bcc9bfd8a70. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index ffe1bebf9197..404ffd2f27bc 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -817,6 +817,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, bool name_is_static, struct lock_class_key *key) { + struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; unsigned flags; int rc; @@ -852,7 +853,14 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, if (ops->mmap) kn->flags |= KERNFS_HAS_MMAP; - rc = kernfs_add_one(kn, parent); + rc = -ENOENT; + if (kernfs_get_active(parent)) { + kernfs_addrm_start(&acxt); + rc = kernfs_add_one(&acxt, kn, parent); + kernfs_addrm_finish(&acxt); + kernfs_put_active(parent); + } + if (rc) { kernfs_put(kn); return ERR_PTR(rc); -- cgit v1.2.3 From 55f6e30d0a6a8975cc0831e8a4a3715b815b6a2f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:27:16 -0800 Subject: Revert "kernfs: invoke kernfs_unmap_bin_file() directly from __kernfs_remove()" This reverts commit f601f9a2bf7dc1f7ee18feece4c4e2fc6845d6c4. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 404ffd2f27bc..231a171f48b6 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -700,11 +700,14 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp) return 0; } -void kernfs_unmap_file(struct kernfs_node *kn) +void kernfs_unmap_bin_file(struct kernfs_node *kn) { struct kernfs_open_node *on; struct kernfs_open_file *of; + if (!(kn->flags & KERNFS_HAS_MMAP)) + return; + spin_lock_irq(&kernfs_open_node_lock); on = kn->attr.open; if (on) -- cgit v1.2.3 From 798c75a0d44cdbd6e3d82a6a676e6de38525b3bb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:36:03 -0800 Subject: Revert "kernfs: remove KERNFS_REMOVED" This reverts commit ae34372eb8408b3d07e870f1939f99007a730d28. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 231a171f48b6..bdd38854ef65 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -856,13 +856,9 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, if (ops->mmap) kn->flags |= KERNFS_HAS_MMAP; - rc = -ENOENT; - if (kernfs_get_active(parent)) { - kernfs_addrm_start(&acxt); - rc = kernfs_add_one(&acxt, kn, parent); - kernfs_addrm_finish(&acxt); - kernfs_put_active(parent); - } + kernfs_addrm_start(&acxt); + rc = kernfs_add_one(&acxt, kn, parent); + kernfs_addrm_finish(&acxt); if (rc) { kernfs_put(kn); -- cgit v1.2.3 From 683bb2761fbf123b24aed03a1c0d5d7556ec3018 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:49:01 -0800 Subject: Revert "kernfs: fix get_active failure handling in kernfs_seq_*()" This reverts commit d92d2e6bd72b653f9811e0c9c46307c743b3fc58. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 51 +++++++-------------------------------------------- 1 file changed, 7 insertions(+), 44 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index bdd38854ef65..316604cc3a1c 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -54,38 +54,6 @@ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) return kn->attr.ops; } -/* - * As kernfs_seq_stop() is also called after kernfs_seq_start() or - * kernfs_seq_next() failure, it needs to distinguish whether it's stopping - * a seq_file iteration which is fully initialized with an active reference - * or an aborted kernfs_seq_start() due to get_active failure. The - * position pointer is the only context for each seq_file iteration and - * thus the stop condition should be encoded in it. As the return value is - * directly visible to userland, ERR_PTR(-ENODEV) is the only acceptable - * choice to indicate get_active failure. - * - * Unfortunately, this is complicated due to the optional custom seq_file - * operations which may return ERR_PTR(-ENODEV) too. kernfs_seq_stop() - * can't distinguish whether ERR_PTR(-ENODEV) is from get_active failure or - * custom seq_file operations and thus can't decide whether put_active - * should be performed or not only on ERR_PTR(-ENODEV). - * - * This is worked around by factoring out the custom seq_stop() and - * put_active part into kernfs_seq_stop_active(), skipping it from - * kernfs_seq_stop() if ERR_PTR(-ENODEV) while invoking it directly after - * custom seq_file operations fail with ERR_PTR(-ENODEV) - this ensures - * that kernfs_seq_stop_active() is skipped only after get_active failure. - */ -static void kernfs_seq_stop_active(struct seq_file *sf, void *v) -{ - struct kernfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->kn); - - if (ops->seq_stop) - ops->seq_stop(sf, v); - kernfs_put_active(of->kn); -} - static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) { struct kernfs_open_file *of = sf->private; @@ -101,11 +69,7 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) ops = kernfs_ops(of->kn); if (ops->seq_start) { - void *next = ops->seq_start(sf, ppos); - /* see the comment above kernfs_seq_stop_active() */ - if (next == ERR_PTR(-ENODEV)) - kernfs_seq_stop_active(sf, next); - return next; + return ops->seq_start(sf, ppos); } else { /* * The same behavior and code as single_open(). Returns @@ -121,11 +85,7 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_next) { - void *next = ops->seq_next(sf, v, ppos); - /* see the comment above kernfs_seq_stop_active() */ - if (next == ERR_PTR(-ENODEV)) - kernfs_seq_stop_active(sf, next); - return next; + return ops->seq_next(sf, v, ppos); } else { /* * The same behavior and code as single_open(), always @@ -139,9 +99,12 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) static void kernfs_seq_stop(struct seq_file *sf, void *v) { struct kernfs_open_file *of = sf->private; + const struct kernfs_ops *ops = kernfs_ops(of->kn); - if (v != ERR_PTR(-ENODEV)) - kernfs_seq_stop_active(sf, v); + if (ops->seq_stop) + ops->seq_stop(sf, v); + + kernfs_put_active(of->kn); mutex_unlock(&of->mutex); } -- cgit v1.2.3 From bb305947bdbb67325e1f949183cdd208fc2a7999 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Jan 2014 09:52:01 -0500 Subject: kernfs: fix get_active failure handling in kernfs_seq_*() When kernfs_seq_start() fails to obtain an active reference, it returns ERR_PTR(-ENODEV). kernfs_seq_stop() is then invoked with the error pointer value; however, it still proceeds to invoke kernfs_put_active() on the node leading to unbalanced put. If kernfs_seq_stop() is called even after active ref failure, it should skip invocation of @ops->seq_stop() and put_active. Unfortunately, this is a bit complicated because active ref failure isn't the only thing which may fail with ERR_PTR(-ENODEV). @ops->seq_start/next() may also fail with the error value and kernfs_seq_stop() doesn't have a way to tell apart those failures. Work it around by factoring out the active part of kernfs_seq_stop() into kernfs_seq_stop_active() and invoking it directly if @ops->seq_start/next() fail with ERR_PTR(-ENODEV) and updating kernfs_seq_stop() to skip kernfs_seq_stop_active() on ERR_PTR(-ENODEV). This is a bit nasty but ensures that the active put is skipped iff get_active failed in kernfs_seq_start(). tj: This was originally committed as d92d2e6bd72b but got reverted by 683bb2761fbf along with other kernfs self removal patches. However, this one is an independent fix and shouldn't have been reverted together. Reinstate the change. Sorry about the mess. Signed-off-by: Tejun Heo Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 316604cc3a1c..bdd38854ef65 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -54,6 +54,38 @@ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) return kn->attr.ops; } +/* + * As kernfs_seq_stop() is also called after kernfs_seq_start() or + * kernfs_seq_next() failure, it needs to distinguish whether it's stopping + * a seq_file iteration which is fully initialized with an active reference + * or an aborted kernfs_seq_start() due to get_active failure. The + * position pointer is the only context for each seq_file iteration and + * thus the stop condition should be encoded in it. As the return value is + * directly visible to userland, ERR_PTR(-ENODEV) is the only acceptable + * choice to indicate get_active failure. + * + * Unfortunately, this is complicated due to the optional custom seq_file + * operations which may return ERR_PTR(-ENODEV) too. kernfs_seq_stop() + * can't distinguish whether ERR_PTR(-ENODEV) is from get_active failure or + * custom seq_file operations and thus can't decide whether put_active + * should be performed or not only on ERR_PTR(-ENODEV). + * + * This is worked around by factoring out the custom seq_stop() and + * put_active part into kernfs_seq_stop_active(), skipping it from + * kernfs_seq_stop() if ERR_PTR(-ENODEV) while invoking it directly after + * custom seq_file operations fail with ERR_PTR(-ENODEV) - this ensures + * that kernfs_seq_stop_active() is skipped only after get_active failure. + */ +static void kernfs_seq_stop_active(struct seq_file *sf, void *v) +{ + struct kernfs_open_file *of = sf->private; + const struct kernfs_ops *ops = kernfs_ops(of->kn); + + if (ops->seq_stop) + ops->seq_stop(sf, v); + kernfs_put_active(of->kn); +} + static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) { struct kernfs_open_file *of = sf->private; @@ -69,7 +101,11 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) ops = kernfs_ops(of->kn); if (ops->seq_start) { - return ops->seq_start(sf, ppos); + void *next = ops->seq_start(sf, ppos); + /* see the comment above kernfs_seq_stop_active() */ + if (next == ERR_PTR(-ENODEV)) + kernfs_seq_stop_active(sf, next); + return next; } else { /* * The same behavior and code as single_open(). Returns @@ -85,7 +121,11 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_next) { - return ops->seq_next(sf, v, ppos); + void *next = ops->seq_next(sf, v, ppos); + /* see the comment above kernfs_seq_stop_active() */ + if (next == ERR_PTR(-ENODEV)) + kernfs_seq_stop_active(sf, next); + return next; } else { /* * The same behavior and code as single_open(), always @@ -99,12 +139,9 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) static void kernfs_seq_stop(struct seq_file *sf, void *v) { struct kernfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->kn); - if (ops->seq_stop) - ops->seq_stop(sf, v); - - kernfs_put_active(of->kn); + if (v != ERR_PTR(-ENODEV)) + kernfs_seq_stop_active(sf, v); mutex_unlock(&of->mutex); } -- cgit v1.2.3 From db4aad209bc9aefd91f0a9aeb9e37364088b39ad Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Jan 2014 09:58:25 -0500 Subject: kernfs: associate a new kernfs_node with its parent on creation Once created, a kernfs_node is always destroyed by kernfs_put(). Since ba7443bc656e ("sysfs, kernfs: implement kernfs_create/destroy_root()"), kernfs_put() depends on kernfs_root() to locate the ino_ida. kernfs_root() in turn depends on kernfs_node->parent being set for !dir nodes. This means that kernfs_put() of a !dir node requires its ->parent to be initialized. This leads to oops when a newly created !dir node is destroyed without going through kernfs_add_one() or after failing kernfs_add_one() before ->parent is set. kernfs_root() invoked from kernfs_put() will try to dereference NULL parent. Fix it by moving parent association to kernfs_new_node() from kernfs_add_one(). kernfs_new_node() now takes @parent instead of @root and determines the root from the parent and also sets the new node's parent properly. @parent parameter is removed from kernfs_add_one(). As there's no parent when creating the root node, __kernfs_new_node() which takes @root as before and doesn't set the parent is used in that case. This ensures that a kernfs_node in any stage in its life has its parent associated and thus can be put. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs/kernfs/file.c') diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index bdd38854ef65..dbf397bfdff2 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -829,8 +829,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, if (name_is_static) flags |= KERNFS_STATIC_NAME; - kn = kernfs_new_node(kernfs_root(parent), name, - (mode & S_IALLUGO) | S_IFREG, flags); + kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG, flags); if (!kn) return ERR_PTR(-ENOMEM); @@ -857,7 +856,7 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, kn->flags |= KERNFS_HAS_MMAP; kernfs_addrm_start(&acxt); - rc = kernfs_add_one(&acxt, kn, parent); + rc = kernfs_add_one(&acxt, kn); kernfs_addrm_finish(&acxt); if (rc) { -- cgit v1.2.3