fuse: convert release to simple api

Since we cannot reserve the request structure up-front, make sure that the
request allocation doesn't fail using __GFP_NOFAIL.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Miklos Szeredi 2019-09-10 15:04:10 +02:00
parent b50ef7c52a
commit 4cb548666e
2 changed files with 42 additions and 41 deletions

View File

@ -53,6 +53,12 @@ static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
return fuse_simple_request(fc, &args);
}
struct fuse_release_args {
struct fuse_args args;
struct fuse_release_in inarg;
struct inode *inode;
};
struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
{
struct fuse_file *ff;
@ -62,8 +68,8 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
return NULL;
ff->fc = fc;
ff->reserved_req = fuse_request_alloc(0);
if (unlikely(!ff->reserved_req)) {
ff->release_args = kzalloc(sizeof(*ff->release_args), GFP_KERNEL);
if (!ff->release_args) {
kfree(ff);
return NULL;
}
@ -81,7 +87,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
void fuse_file_free(struct fuse_file *ff)
{
fuse_request_free(ff->reserved_req);
kfree(ff->release_args);
mutex_destroy(&ff->readdir.lock);
kfree(ff);
}
@ -92,34 +98,31 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff)
return ff;
}
static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
static void fuse_release_end(struct fuse_conn *fc, struct fuse_args *args,
int error)
{
iput(req->misc.release.inode);
struct fuse_release_args *ra = container_of(args, typeof(*ra), args);
iput(ra->inode);
kfree(ra);
}
static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir)
{
if (refcount_dec_and_test(&ff->count)) {
struct fuse_req *req = ff->reserved_req;
struct fuse_args *args = &ff->release_args->args;
if (isdir ? ff->fc->no_opendir : ff->fc->no_open) {
/*
* Drop the release request when client does not
* implement 'open'
*/
__clear_bit(FR_BACKGROUND, &req->flags);
iput(req->misc.release.inode);
fuse_put_request(ff->fc, req);
/* Do nothing when client does not implement 'open' */
fuse_release_end(ff->fc, args, 0);
} else if (sync) {
__set_bit(FR_FORCE, &req->flags);
__clear_bit(FR_BACKGROUND, &req->flags);
fuse_request_send(ff->fc, req);
iput(req->misc.release.inode);
fuse_put_request(ff->fc, req);
fuse_simple_request(ff->fc, args);
fuse_release_end(ff->fc, args, 0);
} else {
req->end = fuse_release_end;
__set_bit(FR_BACKGROUND, &req->flags);
fuse_request_send_background(ff->fc, req);
args->end = fuse_release_end;
if (fuse_simple_background(ff->fc, args,
GFP_KERNEL | __GFP_NOFAIL))
fuse_release_end(ff->fc, args, -ENOTCONN);
}
kfree(ff);
}
@ -239,8 +242,7 @@ static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff,
int flags, int opcode)
{
struct fuse_conn *fc = ff->fc;
struct fuse_req *req = ff->reserved_req;
struct fuse_release_in *inarg = &req->misc.release.in;
struct fuse_release_args *ra = ff->release_args;
/* Inode is NULL on error path of fuse_create_open() */
if (likely(fi)) {
@ -255,32 +257,33 @@ static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff,
wake_up_interruptible_all(&ff->poll_wait);
inarg->fh = ff->fh;
inarg->flags = flags;
req->in.h.opcode = opcode;
req->in.h.nodeid = ff->nodeid;
req->in.numargs = 1;
req->in.args[0].size = sizeof(struct fuse_release_in);
req->in.args[0].value = inarg;
ra->inarg.fh = ff->fh;
ra->inarg.flags = flags;
ra->args.in_numargs = 1;
ra->args.in_args[0].size = sizeof(struct fuse_release_in);
ra->args.in_args[0].value = &ra->inarg;
ra->args.opcode = opcode;
ra->args.nodeid = ff->nodeid;
ra->args.force = true;
ra->args.nocreds = true;
}
void fuse_release_common(struct file *file, bool isdir)
{
struct fuse_inode *fi = get_fuse_inode(file_inode(file));
struct fuse_file *ff = file->private_data;
struct fuse_req *req = ff->reserved_req;
struct fuse_release_args *ra = ff->release_args;
int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE;
fuse_prepare_release(fi, ff, file->f_flags, opcode);
if (ff->flock) {
struct fuse_release_in *inarg = &req->misc.release.in;
inarg->release_flags |= FUSE_RELEASE_FLOCK_UNLOCK;
inarg->lock_owner = fuse_lock_owner_id(ff->fc,
ra->inarg.release_flags |= FUSE_RELEASE_FLOCK_UNLOCK;
ra->inarg.lock_owner = fuse_lock_owner_id(ff->fc,
(fl_owner_t) file);
}
/* Hold inode until release is finished */
req->misc.release.inode = igrab(file_inode(file));
ra->inode = igrab(file_inode(file));
/*
* Normally this will send the RELEASE request, however if

View File

@ -164,17 +164,15 @@ enum {
};
struct fuse_conn;
struct fuse_release_args;
/** FUSE specific file data */
struct fuse_file {
/** Fuse connection for this file */
struct fuse_conn *fc;
/*
* Request reserved for flush and release.
* Modified under relative fuse_inode::lock.
*/
struct fuse_req *reserved_req;
/* Argument space reserved for release */
struct fuse_release_args *release_args;
/** Kernel file handle guaranteed to be unique */
u64 kh;