/* * fs/sysfs/file.c - sysfs regular (text) file implementation * * Copyright (c) 2001-3 Patrick Mochel * Copyright (c) 2007 SUSE Linux Products GmbH * Copyright (c) 2007 Tejun Heo <teheo@suse.de> * * This file is released under the GPLv2. * * Please see Documentation/filesystems/sysfs.txt for more information. */ #include <linux/module.h>#include <linux/kobject.h>#include <linux/kallsyms.h>#include <linux/slab.h>#include <linux/fsnotify.h>#include <linux/namei.h>#include <linux/poll.h>#include <linux/list.h>#include <linux/mutex.h>#include <linux/limits.h>#include <linux/uaccess.h>#include <linux/seq_file.h>#include <linux/mm.h> #include "sysfs.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 */}; struct sysfs_open_file { struct sysfs_dirent *sd; struct file *file; struct mutex mutex; int event; struct list_head list; bool mmapped; const struct vm_operations_struct *vm_ops;}; static bool sysfs_is_bin(struct sysfs_dirent *sd){ return sysfs_type(sd) == SYSFS_KOBJ_BIN_ATTR;} static struct sysfs_open_file *sysfs_of(struct file *file){ return ((struct seq_file *)file->private_data)->private;} /* * Determine ktype->sysfs_ops for the given sysfs_dirent. This function * must be called while holding an active reference. */static const struct sysfs_ops *sysfs_file_ops(struct sysfs_dirent *sd){ struct kobject *kobj = sd->s_parent->s_dir.kobj; if (!sysfs_ignore_lockdep(sd)) lockdep_assert_held(sd); return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;} /* * Reads on sysfs are handled through seq_file, which takes care of hairy * details like buffering and seeking. The following function pipes * sysfs_ops->show() result through seq_file. */static int sysfs_seq_show(struct seq_file *sf, void *v){ struct sysfs_open_file *of = sf->private; struct kobject *kobj = of->sd->s_parent->s_dir.kobj; const struct sysfs_ops *ops; char *buf; ssize_t count; /* acquire buffer and ensure that it's >= PAGE_SIZE */ count = seq_get_buf(sf, &buf); if (count < PAGE_SIZE) { seq_commit(sf, -1); return 0; } /* * Need @of->sd for attr and ops, its parent for kobj. @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); return -ENODEV; } of->event = atomic_read(&of->sd->s_attr.open->event); /* * Lookup @ops and invoke show(). Control may reach here via seq * file lseek even if @ops->show() isn't implemented. */ ops = sysfs_file_ops(of->sd); if (ops->show) count = ops->show(kobj, of->sd->s_attr.attr, buf); else count = 0; sysfs_put_active(of->sd); mutex_unlock(&of->mutex); if (count < 0) return count; /* * The code works fine with PAGE_SIZE return but it's likely to * indicate truncated result or overflow in normal use cases. */ if (count >= (ssize_t)PAGE_SIZE) { print_symbol("fill_read_buffer: %s returned bad count\n", (unsigned long)ops->show); /* Try to struggle along */ count = PAGE_SIZE - 1; } seq_commit(sf, count); return 0;} /* * Read method for bin files. 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 sysfs_bin_read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off){ struct sysfs_open_file *of = sysfs_of(file); struct bin_attribute *battr = of->sd->s_attr.bin_attr; struct kobject *kobj = of->sd->s_parent->s_dir.kobj; loff_t size = file_inode(file)->i_size; int count = min_t(size_t, bytes, PAGE_SIZE); loff_t offs = *off; char *buf; if (!bytes) return 0; if (size) { if (offs > size) return 0; if (offs + count > size) count = size - offs; } buf = kmalloc(count, GFP_KERNEL); if (!buf) return -ENOMEM; /* need of->sd for battr, its parent for kobj */ mutex_lock(&of->mutex); if (!sysfs_get_active(of->sd)) { count = -ENODEV; mutex_unlock(&of->mutex); goto out_free; } if (battr->read) count = battr->read(file, kobj, battr, buf, offs, count); else count = -EIO; sysfs_put_active(of->sd); mutex_unlock(&of->mutex); if (count < 0) goto out_free; if (copy_to_user(userbuf, buf, count)) { count = -EFAULT; goto out_free; } pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); *off = offs + count; out_free: kfree(buf); return count;} /** * flush_write_buffer - push buffer to kobject * @of: open file * @buf: data buffer for file * @off: file offset to write to * @count: number of bytes * * Get the correct pointers for the kobject and the attribute we're dealing * with, then call the store() method for it with @buf. */static int flush_write_buffer(struct sysfs_open_file *of, char *buf, loff_t off, size_t count){ struct kobject *kobj = of->sd->s_parent->s_dir.kobj; int rc = 0; /* * Need @of->sd for attr and ops, its parent for kobj. @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); return -ENODEV; } if (sysfs_is_bin(of->sd)) { struct bin_attribute *battr = of->sd->s_attr.bin_attr; rc = -EIO; if (battr->write) rc = battr->write(of->file, kobj, battr, buf, off, count); } else { const struct sysfs_ops *ops = sysfs_file_ops(of->sd); rc = ops->store(kobj, of->sd->s_attr.attr, buf, count); } sysfs_put_active(of->sd); mutex_unlock(&of->mutex); return rc;} /** * sysfs_write_file - write an attribute * @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 * sysfs_ops->store() by invoking flush_write_buffer(). * * 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 sysfs_write_file(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); loff_t size = file_inode(file)->i_size; char *buf; if (sysfs_is_bin(of->sd) && size) { if (size <= *ppos) return 0; len = min_t(ssize_t, len, size - *ppos); } if (!len) return 0; 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 */ len = flush_write_buffer(of, buf, *ppos, len); if (len > 0) *ppos += len;out_free: kfree(buf); return len;} static void sysfs_bin_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 sysfs_bin_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 sysfs_bin_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 sysfs_bin_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_NUMAstatic int sysfs_bin_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 *sysfs_bin_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 sysfs_bin_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 sysfs_bin_vm_ops = { .open = sysfs_bin_vma_open, .fault = sysfs_bin_fault, .page_mkwrite = sysfs_bin_page_mkwrite, .access = sysfs_bin_access,#ifdef CONFIG_NUMA .set_policy = sysfs_bin_set_policy, .get_policy = sysfs_bin_get_policy, .migrate = sysfs_bin_migrate,#endif}; static int sysfs_bin_mmap(struct file *file, struct vm_area_struct *vma){ struct sysfs_open_file *of = sysfs_of(file); struct bin_attribute *battr = of->sd->s_attr.bin_attr; struct kobject *kobj = of->sd->s_parent->s_dir.kobj; int rc; mutex_lock(&of->mutex); /* need of->sd for battr, its parent for kobj */ rc = -ENODEV; if (!sysfs_get_active(of->sd)) goto out_unlock; if (!battr->mmap) goto out_put; rc = battr->mmap(file, kobj, battr, 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.Lines 1–500 of 1121. Load more
/* * fs/sysfs/file.c - sysfs regular (text) file implementation * * Copyright (c) 2001-3 Patrick Mochel * Copyright (c) 2007 SUSE Linux Products GmbH * Copyright (c) 2007 Tejun Heo <teheo@suse.de> * * This file is released under the GPLv2. * * Please see Documentation/filesystems/sysfs.txt for more information. */ #include <linux/module.h> #include <linux/kobject.h> #include <linux/kallsyms.h> #include <linux/slab.h> #include <linux/fsnotify.h> #include <linux/namei.h> #include <linux/poll.h> #include <linux/list.h> #include <linux/mutex.h> #include <linux/limits.h> #include <linux/uaccess.h> #include <linux/seq_file.h> #include <linux/mm.h> #include "sysfs.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 */ }; struct sysfs_open_file { struct sysfs_dirent *sd; struct file *file; struct mutex mutex; int event; struct list_head list; bool mmapped; const struct vm_operations_struct *vm_ops; }; static bool sysfs_is_bin(struct sysfs_dirent *sd) { return sysfs_type(sd) == SYSFS_KOBJ_BIN_ATTR; } static struct sysfs_open_file *sysfs_of(struct file *file) { return ((struct seq_file *)file->private_data)->private; } /* * Determine ktype->sysfs_ops for the given sysfs_dirent. This function * must be called while holding an active reference. */ static const struct sysfs_ops *sysfs_file_ops(struct sysfs_dirent *sd) { struct kobject *kobj = sd->s_parent->s_dir.kobj; if (!sysfs_ignore_lockdep(sd)) lockdep_assert_held(sd); return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; } /* * Reads on sysfs are handled through seq_file, which takes care of hairy * details like buffering and seeking. The following function pipes * sysfs_ops->show() result through seq_file. */ static int sysfs_seq_show(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; struct kobject *kobj = of->sd->s_parent->s_dir.kobj; const struct sysfs_ops *ops; char *buf; ssize_t count; /* acquire buffer and ensure that it's >= PAGE_SIZE */ count = seq_get_buf(sf, &buf); if (count < PAGE_SIZE) { seq_commit(sf, -1); return 0; } /* * Need @of->sd for attr and ops, its parent for kobj. @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); return -ENODEV; } of->event = atomic_read(&of->sd->s_attr.open->event); /* * Lookup @ops and invoke show(). Control may reach here via seq * file lseek even if @ops->show() isn't implemented. */ ops = sysfs_file_ops(of->sd); if (ops->show) count = ops->show(kobj, of->sd->s_attr.attr, buf); else count = 0; sysfs_put_active(of->sd); mutex_unlock(&of->mutex); if (count < 0) return count; /* * The code works fine with PAGE_SIZE return but it's likely to * indicate truncated result or overflow in normal use cases. */ if (count >= (ssize_t)PAGE_SIZE) { print_symbol("fill_read_buffer: %s returned bad count\n", (unsigned long)ops->show); /* Try to struggle along */ count = PAGE_SIZE - 1; } seq_commit(sf, count); return 0; } /* * Read method for bin files. 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 sysfs_bin_read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) { struct sysfs_open_file *of = sysfs_of(file); struct bin_attribute *battr = of->sd->s_attr.bin_attr; struct kobject *kobj = of->sd->s_parent->s_dir.kobj; loff_t size = file_inode(file)->i_size; int count = min_t(size_t, bytes, PAGE_SIZE); loff_t offs = *off; char *buf; if (!bytes) return 0; if (size) { if (offs > size) return 0; if (offs + count > size) count = size - offs; } buf = kmalloc(count, GFP_KERNEL); if (!buf) return -ENOMEM; /* need of->sd for battr, its parent for kobj */ mutex_lock(&of->mutex); if (!sysfs_get_active(of->sd)) { count = -ENODEV; mutex_unlock(&of->mutex); goto out_free; } if (battr->read) count = battr->read(file, kobj, battr, buf, offs, count); else count = -EIO; sysfs_put_active(of->sd); mutex_unlock(&of->mutex); if (count < 0) goto out_free; if (copy_to_user(userbuf, buf, count)) { count = -EFAULT; goto out_free; } pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); *off = offs + count; out_free: kfree(buf); return count; } /** * flush_write_buffer - push buffer to kobject * @of: open file * @buf: data buffer for file * @off: file offset to write to * @count: number of bytes * * Get the correct pointers for the kobject and the attribute we're dealing * with, then call the store() method for it with @buf. */ static int flush_write_buffer(struct sysfs_open_file *of, char *buf, loff_t off, size_t count) { struct kobject *kobj = of->sd->s_parent->s_dir.kobj; int rc = 0; /* * Need @of->sd for attr and ops, its parent for kobj. @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); return -ENODEV; } if (sysfs_is_bin(of->sd)) { struct bin_attribute *battr = of->sd->s_attr.bin_attr; rc = -EIO; if (battr->write) rc = battr->write(of->file, kobj, battr, buf, off, count); } else { const struct sysfs_ops *ops = sysfs_file_ops(of->sd); rc = ops->store(kobj, of->sd->s_attr.attr, buf, count); } sysfs_put_active(of->sd); mutex_unlock(&of->mutex); return rc; } /** * sysfs_write_file - write an attribute * @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 * sysfs_ops->store() by invoking flush_write_buffer(). * * 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 sysfs_write_file(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); loff_t size = file_inode(file)->i_size; char *buf; if (sysfs_is_bin(of->sd) && size) { if (size <= *ppos) return 0; len = min_t(ssize_t, len, size - *ppos); } if (!len) return 0; 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 */ len = flush_write_buffer(of, buf, *ppos, len); if (len > 0) *ppos += len; out_free: kfree(buf); return len; } static void sysfs_bin_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 sysfs_bin_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 sysfs_bin_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 sysfs_bin_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 sysfs_bin_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 *sysfs_bin_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 sysfs_bin_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 sysfs_bin_vm_ops = { .open = sysfs_bin_vma_open, .fault = sysfs_bin_fault, .page_mkwrite = sysfs_bin_page_mkwrite, .access = sysfs_bin_access, #ifdef CONFIG_NUMA .set_policy = sysfs_bin_set_policy, .get_policy = sysfs_bin_get_policy, .migrate = sysfs_bin_migrate, #endif }; static int sysfs_bin_mmap(struct file *file, struct vm_area_struct *vma) { struct sysfs_open_file *of = sysfs_of(file); struct bin_attribute *battr = of->sd->s_attr.bin_attr; struct kobject *kobj = of->sd->s_parent->s_dir.kobj; int rc; mutex_lock(&of->mutex); /* need of->sd for battr, its parent for kobj */ rc = -ENODEV; if (!sysfs_get_active(of->sd)) goto out_unlock; if (!battr->mmap) goto out_put; rc = battr->mmap(file, kobj, battr, 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.