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:
parent
b50ef7c52a
commit
4cb548666e
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue