Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/mszeredi/fuse

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: invalidation reverse calls
  fuse: allow umask processing in userspace
  fuse: fix bad return value in fuse_file_poll()
  fuse: fix return value of fuse_dev_write()
  • Loading branch information
Linus Torvalds committed Jul 1, 2009
2 parents a15a519 + 3b463ae commit fa172f4
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 11 deletions.
83 changes: 82 additions & 1 deletion fs/fuse/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -849,13 +849,94 @@ static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size,
return err;
}

static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size,
struct fuse_copy_state *cs)
{
struct fuse_notify_inval_inode_out outarg;
int err = -EINVAL;

if (size != sizeof(outarg))
goto err;

err = fuse_copy_one(cs, &outarg, sizeof(outarg));
if (err)
goto err;
fuse_copy_finish(cs);

down_read(&fc->killsb);
err = -ENOENT;
if (!fc->sb)
goto err_unlock;

err = fuse_reverse_inval_inode(fc->sb, outarg.ino,
outarg.off, outarg.len);

err_unlock:
up_read(&fc->killsb);
return err;

err:
fuse_copy_finish(cs);
return err;
}

static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
struct fuse_copy_state *cs)
{
struct fuse_notify_inval_entry_out outarg;
int err = -EINVAL;
char buf[FUSE_NAME_MAX+1];
struct qstr name;

if (size < sizeof(outarg))
goto err;

err = fuse_copy_one(cs, &outarg, sizeof(outarg));
if (err)
goto err;

err = -ENAMETOOLONG;
if (outarg.namelen > FUSE_NAME_MAX)
goto err;

name.name = buf;
name.len = outarg.namelen;
err = fuse_copy_one(cs, buf, outarg.namelen + 1);
if (err)
goto err;
fuse_copy_finish(cs);
buf[outarg.namelen] = 0;
name.hash = full_name_hash(name.name, name.len);

down_read(&fc->killsb);
err = -ENOENT;
if (!fc->sb)
goto err_unlock;

err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name);

err_unlock:
up_read(&fc->killsb);
return err;

err:
fuse_copy_finish(cs);
return err;
}

static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
unsigned int size, struct fuse_copy_state *cs)
{
switch (code) {
case FUSE_NOTIFY_POLL:
return fuse_notify_poll(fc, size, cs);

case FUSE_NOTIFY_INVAL_INODE:
return fuse_notify_inval_inode(fc, size, cs);

case FUSE_NOTIFY_INVAL_ENTRY:
return fuse_notify_inval_entry(fc, size, cs);

default:
fuse_copy_finish(cs);
return -EINVAL;
Expand Down Expand Up @@ -910,7 +991,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
int err;
unsigned nbytes = iov_length(iov, nr_segs);
size_t nbytes = iov_length(iov, nr_segs);
struct fuse_req *req;
struct fuse_out_header oh;
struct fuse_copy_state cs;
Expand Down
57 changes: 54 additions & 3 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req;
struct fuse_req *forget_req;
struct fuse_open_in inarg;
struct fuse_create_in inarg;
struct fuse_open_out outopen;
struct fuse_entry_out outentry;
struct fuse_file *ff;
Expand All @@ -399,15 +399,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
if (!ff)
goto out_put_request;

if (!fc->dont_mask)
mode &= ~current_umask();

flags &= ~O_NOCTTY;
memset(&inarg, 0, sizeof(inarg));
memset(&outentry, 0, sizeof(outentry));
inarg.flags = flags;
inarg.mode = mode;
inarg.umask = current_umask();
req->in.h.opcode = FUSE_CREATE;
req->in.h.nodeid = get_node_id(dir);
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) :
sizeof(inarg);
req->in.args[0].value = &inarg;
req->in.args[1].size = entry->d_name.len + 1;
req->in.args[1].value = entry->d_name.name;
Expand Down Expand Up @@ -546,12 +551,17 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
if (IS_ERR(req))
return PTR_ERR(req);

if (!fc->dont_mask)
mode &= ~current_umask();

memset(&inarg, 0, sizeof(inarg));
inarg.mode = mode;
inarg.rdev = new_encode_dev(rdev);
inarg.umask = current_umask();
req->in.h.opcode = FUSE_MKNOD;
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE :
sizeof(inarg);
req->in.args[0].value = &inarg;
req->in.args[1].size = entry->d_name.len + 1;
req->in.args[1].value = entry->d_name.name;
Expand All @@ -578,8 +588,12 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
if (IS_ERR(req))
return PTR_ERR(req);

if (!fc->dont_mask)
mode &= ~current_umask();

memset(&inarg, 0, sizeof(inarg));
inarg.mode = mode;
inarg.umask = current_umask();
req->in.h.opcode = FUSE_MKDIR;
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
Expand Down Expand Up @@ -845,6 +859,43 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
return err;
}

int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
struct qstr *name)
{
int err = -ENOTDIR;
struct inode *parent;
struct dentry *dir;
struct dentry *entry;

parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid);
if (!parent)
return -ENOENT;

mutex_lock(&parent->i_mutex);
if (!S_ISDIR(parent->i_mode))
goto unlock;

err = -ENOENT;
dir = d_find_alias(parent);
if (!dir)
goto unlock;

entry = d_lookup(dir, name);
dput(dir);
if (!entry)
goto unlock;

fuse_invalidate_attr(parent);
fuse_invalidate_entry(entry);
dput(entry);
err = 0;

unlock:
mutex_unlock(&parent->i_mutex);
iput(parent);
return err;
}

/*
* Calling into a user-controlled filesystem gives the filesystem
* daemon ptrace-like capabilities over the requester process. This
Expand Down
2 changes: 1 addition & 1 deletion fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1922,7 +1922,7 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait)

req = fuse_get_req(fc);
if (IS_ERR(req))
return PTR_ERR(req);
return POLLERR;

req->in.h.opcode = FUSE_POLL;
req->in.h.nodeid = ff->nodeid;
Expand Down
27 changes: 27 additions & 0 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ struct fuse_conn {
/** Do multi-page cached writes */
unsigned big_writes:1;

/** Don't apply umask to creation modes */
unsigned dont_mask:1;

/** The number of requests waiting for completion */
atomic_t num_waiting;

Expand Down Expand Up @@ -481,6 +484,12 @@ struct fuse_conn {

/** Called on final put */
void (*release)(struct fuse_conn *);

/** Super block for this connection. */
struct super_block *sb;

/** Read/write semaphore to hold when accessing sb. */
struct rw_semaphore killsb;
};

static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
Expand Down Expand Up @@ -508,6 +517,11 @@ extern const struct file_operations fuse_dev_operations;

extern const struct dentry_operations fuse_dentry_operations;

/**
* Inode to nodeid comparison.
*/
int fuse_inode_eq(struct inode *inode, void *_nodeidp);

/**
* Get a filled in inode
*/
Expand Down Expand Up @@ -708,6 +722,19 @@ void fuse_release_nowrite(struct inode *inode);

u64 fuse_get_attr_version(struct fuse_conn *fc);

/**
* File-system tells the kernel to invalidate cache for the given node id.
*/
int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
loff_t offset, loff_t len);

/**
* File-system tells the kernel to invalidate parent attributes and
* the dentry matching parent/name.
*/
int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
struct qstr *name);

int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
bool isdir);
ssize_t fuse_direct_io(struct file *file, const char __user *buf,
Expand Down
Loading

0 comments on commit fa172f4

Please sign in to comment.