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

View File

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