Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 133456
b: refs/heads/master
c: e0edd3c
h: refs/heads/master
v: v3
  • Loading branch information
Eric W. Biederman authored and Greg Kroah-Hartman committed Mar 24, 2009
1 parent 94ec816 commit 6e1991e
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 14 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ae1b41715ee2aae356fbcca032838b71d70b855f
refs/heads/master: e0edd3c65aa5b53e20280565a7ce11675eb7ed6b
184 changes: 171 additions & 13 deletions trunk/fs/sysfs/bin.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,28 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/mm.h>

#include <asm/uaccess.h>

#include "sysfs.h"

/*
* There's one bin_buffer for each open file.
*
* filp->private_data points to bin_buffer and
* sysfs_dirent->s_bin_attr.buffers points to a the bin_buffer s
* sysfs_dirent->s_bin_attr.buffers is protected by sysfs_bin_lock
*/
static DEFINE_MUTEX(sysfs_bin_lock);

struct bin_buffer {
struct mutex mutex;
void *buffer;
int mmapped;
struct mutex mutex;
void *buffer;
int mmapped;
struct vm_operations_struct *vm_ops;
struct file *file;
struct hlist_node list;
};

static int
Expand Down Expand Up @@ -168,29 +181,148 @@ static ssize_t write(struct file *file, const char __user *userbuf,
return count;
}

static void bin_vma_open(struct vm_area_struct *vma)
{
struct file *file = vma->vm_file;
struct bin_buffer *bb = file->private_data;
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;

if (!bb->vm_ops || !bb->vm_ops->open)
return;

if (!sysfs_get_active_two(attr_sd))
return;

bb->vm_ops->open(vma);

sysfs_put_active_two(attr_sd);
}

static void bin_vma_close(struct vm_area_struct *vma)
{
struct file *file = vma->vm_file;
struct bin_buffer *bb = file->private_data;
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;

if (!bb->vm_ops || !bb->vm_ops->close)
return;

if (!sysfs_get_active_two(attr_sd))
return;

bb->vm_ops->close(vma);

sysfs_put_active_two(attr_sd);
}

static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct file *file = vma->vm_file;
struct bin_buffer *bb = file->private_data;
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
int ret;

if (!bb->vm_ops || !bb->vm_ops->fault)
return VM_FAULT_SIGBUS;

if (!sysfs_get_active_two(attr_sd))
return VM_FAULT_SIGBUS;

ret = bb->vm_ops->fault(vma, vmf);

sysfs_put_active_two(attr_sd);
return ret;
}

static int bin_page_mkwrite(struct vm_area_struct *vma, struct page *page)
{
struct file *file = vma->vm_file;
struct bin_buffer *bb = file->private_data;
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
int ret;

if (!bb->vm_ops || !bb->vm_ops->page_mkwrite)
return -EINVAL;

if (!sysfs_get_active_two(attr_sd))
return -EINVAL;

ret = bb->vm_ops->page_mkwrite(vma, page);

sysfs_put_active_two(attr_sd);
return ret;
}

static int bin_access(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
struct file *file = vma->vm_file;
struct bin_buffer *bb = file->private_data;
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
int ret;

if (!bb->vm_ops || !bb->vm_ops->access)
return -EINVAL;

if (!sysfs_get_active_two(attr_sd))
return -EINVAL;

ret = bb->vm_ops->access(vma, addr, buf, len, write);

sysfs_put_active_two(attr_sd);
return ret;
}

static struct vm_operations_struct bin_vm_ops = {
.open = bin_vma_open,
.close = bin_vma_close,
.fault = bin_fault,
.page_mkwrite = bin_page_mkwrite,
.access = bin_access,
};

static int mmap(struct file *file, struct vm_area_struct *vma)
{
struct bin_buffer *bb = file->private_data;
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
struct vm_operations_struct *vm_ops;
int rc;

mutex_lock(&bb->mutex);

/* need attr_sd for attr, its parent for kobj */
rc = -ENODEV;
if (!sysfs_get_active_two(attr_sd))
return -ENODEV;
goto out_unlock;

rc = -EINVAL;
if (attr->mmap)
rc = attr->mmap(kobj, attr, vma);
if (!attr->mmap)
goto out_put;

if (rc == 0 && !bb->mmapped)
bb->mmapped = 1;
else
sysfs_put_active_two(attr_sd);
rc = attr->mmap(kobj, attr, vma);
vm_ops = vma->vm_ops;
vma->vm_ops = &bin_vm_ops;
if (rc)
goto out_put;

rc = -EINVAL;
if (bb->mmapped && bb->vm_ops != vma->vm_ops)
goto out_put;

#ifdef CONFIG_NUMA
rc = -EINVAL;
if (vm_ops && ((vm_ops->set_policy || vm_ops->get_policy || vm_ops->migrate)))
goto out_put;
#endif

rc = 0;
bb->mmapped = 1;
bb->vm_ops = vm_ops;
out_put:
sysfs_put_active_two(attr_sd);
out_unlock:
mutex_unlock(&bb->mutex);

return rc;
Expand Down Expand Up @@ -223,8 +355,13 @@ static int open(struct inode * inode, struct file * file)
goto err_out;

mutex_init(&bb->mutex);
bb->file = file;
file->private_data = bb;

mutex_lock(&sysfs_bin_lock);
hlist_add_head(&bb->list, &attr_sd->s_bin_attr.buffers);
mutex_unlock(&sysfs_bin_lock);

/* open succeeded, put active references */
sysfs_put_active_two(attr_sd);
return 0;
Expand All @@ -237,11 +374,12 @@ static int open(struct inode * inode, struct file * file)

static int release(struct inode * inode, struct file * file)
{
struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
struct bin_buffer *bb = file->private_data;

if (bb->mmapped)
sysfs_put_active_two(attr_sd);
mutex_lock(&sysfs_bin_lock);
hlist_del(&bb->list);
mutex_unlock(&sysfs_bin_lock);

kfree(bb->buffer);
kfree(bb);
return 0;
Expand All @@ -256,6 +394,26 @@ const struct file_operations bin_fops = {
.release = release,
};


void unmap_bin_file(struct sysfs_dirent *attr_sd)
{
struct bin_buffer *bb;
struct hlist_node *tmp;

if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR)
return;

mutex_lock(&sysfs_bin_lock);

hlist_for_each_entry(bb, tmp, &attr_sd->s_bin_attr.buffers, list) {
struct inode *inode = bb->file->f_path.dentry->d_inode;

unmap_mapping_range(inode->i_mapping, 0, 0, 1);
}

mutex_unlock(&sysfs_bin_lock);
}

/**
* sysfs_create_bin_file - create binary file for object.
* @kobj: object.
Expand Down
1 change: 1 addition & 0 deletions trunk/fs/sysfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)

sysfs_drop_dentry(sd);
sysfs_deactivate(sd);
unmap_bin_file(sd);
sysfs_put(sd);
}
}
Expand Down
2 changes: 2 additions & 0 deletions trunk/fs/sysfs/sysfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct sysfs_elem_attr {

struct sysfs_elem_bin_attr {
struct bin_attribute *bin_attr;
struct hlist_head buffers;
};

/*
Expand Down Expand Up @@ -164,6 +165,7 @@ int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
* bin.c
*/
extern const struct file_operations bin_fops;
void unmap_bin_file(struct sysfs_dirent *attr_sd);

/*
* symlink.c
Expand Down

0 comments on commit 6e1991e

Please sign in to comment.