Revert "kernfs: invoke kernfs_unmap_bin_file() directly from __kernfs_remove()"
[deliverable/linux.git] / fs / kernfs / file.c
index 2714a394cd812932514edfde7119eea68fa17e14..231a171f48b6f107f729594a82165f4973e56073 100644 (file)
@@ -49,11 +49,43 @@ 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;
 }
 
+/*
+ * 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;
@@ -64,12 +96,16 @@ 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);
        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);
 
-       sysfs_put_active(of->kn);
+       if (v != ERR_PTR(-ENODEV))
+               kernfs_seq_stop_active(sf, v);
        mutex_unlock(&of->mutex);
 }
 
@@ -147,7 +184,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 +196,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,25 +215,25 @@ 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);
 
-       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);
 }
 
 /**
- * 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 +248,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 +271,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 +283,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 +301,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 +319,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 +340,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 +349,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 +363,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 +385,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 +406,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 +428,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 +452,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;
@@ -428,13 +465,13 @@ 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);
 
        rc = -ENODEV;
-       if (!sysfs_get_active(of->kn))
+       if (!kernfs_get_active(of->kn))
                goto out_unlock;
 
        ops = kernfs_ops(of->kn);
@@ -465,7 +502,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 +510,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 +523,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 +564,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 +574,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 +597,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 +605,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 +670,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,28 +684,28 @@ 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;
 
-       if (!(kn->flags & SYSFS_FLAG_HAS_MMAP))
+       if (!(kn->flags & KERNFS_HAS_MMAP))
                return;
 
        spin_lock_irq(&kernfs_open_node_lock);
@@ -686,10 +723,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 +740,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;
@@ -738,7 +776,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);
@@ -750,18 +788,18 @@ void kernfs_notify(struct kernfs_node *kn)
 }
 EXPORT_SYMBOL_GPL(kernfs_notify);
 
-const struct file_operations kernfs_file_operations = {
-       .read           = kernfs_file_read,
-       .write          = kernfs_file_write,
+const struct file_operations kernfs_file_fops = {
+       .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,
 };
 
 /**
- * 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
@@ -769,23 +807,30 @@ const struct file_operations kernfs_file_operations = {
  * @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;
 
-       kn = sysfs_new_dirent(kernfs_root(parent), name,
-                             (mode & S_IALLUGO) | S_IFREG, SYSFS_KOBJ_ATTR);
+       flags = KERNFS_FILE;
+       if (name_is_static)
+               flags |= KERNFS_STATIC_NAME;
+
+       kn = kernfs_new_node(kernfs_root(parent), name,
+                            (mode & S_IALLUGO) | S_IFREG, flags);
        if (!kn)
                return ERR_PTR(-ENOMEM);
 
@@ -797,7 +842,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,13 +852,17 @@ 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;
-
-       sysfs_addrm_start(&acxt);
-       rc = sysfs_add_one(&acxt, kn, parent);
-       sysfs_addrm_finish(&acxt);
+               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);
+       }
 
        if (rc) {
                kernfs_put(kn);
This page took 0.034385 seconds and 5 git commands to generate.