Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 164685
b: refs/heads/master
c: 562787a
h: refs/heads/master
i:
  164683: 70c16d6
v: v3
  • Loading branch information
Davide Libenzi authored and Linus Torvalds committed Sep 23, 2009
1 parent 07065d8 commit 0ad09e6
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 31 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: 515350b6fd041396f425180589e08812dd13615f
refs/heads/master: 562787a5c32ccdf182de27793a83a9f2ee86cd77
68 changes: 51 additions & 17 deletions trunk/fs/anon_inodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,28 +77,24 @@ static const struct address_space_operations anon_aops = {
*
* Creates a new file by hooking it on a single inode. This is useful for files
* that do not need to have a full-fledged inode in order to operate correctly.
* All the files created with anon_inode_getfd() will share a single inode,
* All the files created with anon_inode_getfile() will share a single inode,
* hence saving memory and avoiding code duplication for the file/inode/dentry
* setup. Returns new descriptor or -error.
* setup. Returns the newly created file* or an error pointer.
*/
int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv, int flags)
struct file *anon_inode_getfile(const char *name,
const struct file_operations *fops,
void *priv, int flags)
{
struct qstr this;
struct dentry *dentry;
struct file *file;
int error, fd;
int error;

if (IS_ERR(anon_inode_inode))
return -ENODEV;
return ERR_PTR(-ENODEV);

if (fops->owner && !try_module_get(fops->owner))
return -ENOENT;

error = get_unused_fd_flags(flags);
if (error < 0)
goto err_module;
fd = error;
return ERR_PTR(-ENOENT);

/*
* Link the inode to a directory entry by creating a unique name
Expand All @@ -110,7 +106,7 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
this.hash = 0;
dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
if (!dentry)
goto err_put_unused_fd;
goto err_module;

/*
* We know the anon_inode inode count is always greater than zero,
Expand All @@ -136,16 +132,54 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
file->f_version = 0;
file->private_data = priv;

return file;

err_dput:
dput(dentry);
err_module:
module_put(fops->owner);
return ERR_PTR(error);
}
EXPORT_SYMBOL_GPL(anon_inode_getfile);

/**
* anon_inode_getfd - creates a new file instance by hooking it up to an
* anonymous inode, and a dentry that describe the "class"
* of the file
*
* @name: [in] name of the "class" of the new file
* @fops: [in] file operations for the new file
* @priv: [in] private data for the new file (will be file's private_data)
* @flags: [in] flags
*
* Creates a new file by hooking it on a single inode. This is useful for files
* that do not need to have a full-fledged inode in order to operate correctly.
* All the files created with anon_inode_getfd() will share a single inode,
* hence saving memory and avoiding code duplication for the file/inode/dentry
* setup. Returns new descriptor or an error code.
*/
int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv, int flags)
{
int error, fd;
struct file *file;

error = get_unused_fd_flags(flags);
if (error < 0)
return error;
fd = error;

file = anon_inode_getfile(name, fops, priv, flags);
if (IS_ERR(file)) {
error = PTR_ERR(file);
goto err_put_unused_fd;
}
fd_install(fd, file);

return fd;

err_dput:
dput(dentry);
err_put_unused_fd:
put_unused_fd(fd);
err_module:
module_put(fops->owner);
return error;
}
EXPORT_SYMBOL_GPL(anon_inode_getfd);
Expand Down
67 changes: 54 additions & 13 deletions trunk/fs/eventfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,16 @@ int eventfd_signal(struct eventfd_ctx *ctx, int n)
}
EXPORT_SYMBOL_GPL(eventfd_signal);

static void eventfd_free_ctx(struct eventfd_ctx *ctx)
{
kfree(ctx);
}

static void eventfd_free(struct kref *kref)
{
struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref);

kfree(ctx);
eventfd_free_ctx(ctx);
}

/**
Expand Down Expand Up @@ -298,36 +303,72 @@ struct eventfd_ctx *eventfd_ctx_fileget(struct file *file)
}
EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);

SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
/**
* eventfd_file_create - Creates an eventfd file pointer.
* @count: Initial eventfd counter value.
* @flags: Flags for the eventfd file.
*
* This function creates an eventfd file pointer, w/out installing it into
* the fd table. This is useful when the eventfd file is used during the
* initialization of data structures that require extra setup after the eventfd
* creation. So the eventfd creation is split into the file pointer creation
* phase, and the file descriptor installation phase.
* In this way races with userspace closing the newly installed file descriptor
* can be avoided.
* Returns an eventfd file pointer, or a proper error pointer.
*/
struct file *eventfd_file_create(unsigned int count, int flags)
{
int fd;
struct file *file;
struct eventfd_ctx *ctx;

/* Check the EFD_* constants for consistency. */
BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC);
BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK);

if (flags & ~EFD_FLAGS_SET)
return -EINVAL;
return ERR_PTR(-EINVAL);

ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
return ERR_PTR(-ENOMEM);

kref_init(&ctx->kref);
init_waitqueue_head(&ctx->wqh);
ctx->count = count;
ctx->flags = flags;

/*
* When we call this, the initialization must be complete, since
* anon_inode_getfd() will install the fd.
*/
fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx,
flags & EFD_SHARED_FCNTL_FLAGS);
if (fd < 0)
kfree(ctx);
file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx,
flags & EFD_SHARED_FCNTL_FLAGS);
if (IS_ERR(file))
eventfd_free_ctx(ctx);

return file;
}

SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
{
int fd, error;
struct file *file;

error = get_unused_fd_flags(flags & EFD_SHARED_FCNTL_FLAGS);
if (error < 0)
return error;
fd = error;

file = eventfd_file_create(count, flags);
if (IS_ERR(file)) {
error = PTR_ERR(file);
goto err_put_unused_fd;
}
fd_install(fd, file);

return fd;

err_put_unused_fd:
put_unused_fd(fd);

return error;
}

SYSCALL_DEFINE1(eventfd, unsigned int, count)
Expand Down
3 changes: 3 additions & 0 deletions trunk/include/linux/anon_inodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#ifndef _LINUX_ANON_INODES_H
#define _LINUX_ANON_INODES_H

struct file *anon_inode_getfile(const char *name,
const struct file_operations *fops,
void *priv, int flags);
int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv, int flags);

Expand Down
6 changes: 6 additions & 0 deletions trunk/include/linux/eventfd.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#ifdef CONFIG_EVENTFD

struct file *eventfd_file_create(unsigned int count, int flags);
struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx);
void eventfd_ctx_put(struct eventfd_ctx *ctx);
struct file *eventfd_fget(int fd);
Expand All @@ -40,6 +41,11 @@ int eventfd_signal(struct eventfd_ctx *ctx, int n);
* Ugly ugly ugly error layer to support modules that uses eventfd but
* pretend to work in !CONFIG_EVENTFD configurations. Namely, AIO.
*/
static inline struct file *eventfd_file_create(unsigned int count, int flags)
{
return ERR_PTR(-ENOSYS);
}

static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd)
{
return ERR_PTR(-ENOSYS);
Expand Down

0 comments on commit 0ad09e6

Please sign in to comment.