summaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2019-09-10 09:04:10 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2019-09-10 10:29:50 -0400
commit4cb548666e4c13699904a063f6909b169d3f900c (patch)
tree8a49d640133a82335f1cd3901834b5303a47574b /fs/fuse
parentb50ef7c52ad7c954b743cd1cb181e9bf03537bab (diff)
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>
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/file.c75
-rw-r--r--fs/fuse/fuse_i.h8
2 files changed, 42 insertions, 41 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 399b89b29bb4..56ed45ef3058 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -53,6 +53,12 @@ static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
53 return fuse_simple_request(fc, &args); 53 return fuse_simple_request(fc, &args);
54} 54}
55 55
56struct fuse_release_args {
57 struct fuse_args args;
58 struct fuse_release_in inarg;
59 struct inode *inode;
60};
61
56struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) 62struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
57{ 63{
58 struct fuse_file *ff; 64 struct fuse_file *ff;
@@ -62,8 +68,8 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
62 return NULL; 68 return NULL;
63 69
64 ff->fc = fc; 70 ff->fc = fc;
65 ff->reserved_req = fuse_request_alloc(0); 71 ff->release_args = kzalloc(sizeof(*ff->release_args), GFP_KERNEL);
66 if (unlikely(!ff->reserved_req)) { 72 if (!ff->release_args) {
67 kfree(ff); 73 kfree(ff);
68 return NULL; 74 return NULL;
69 } 75 }
@@ -81,7 +87,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
81 87
82void fuse_file_free(struct fuse_file *ff) 88void fuse_file_free(struct fuse_file *ff)
83{ 89{
84 fuse_request_free(ff->reserved_req); 90 kfree(ff->release_args);
85 mutex_destroy(&ff->readdir.lock); 91 mutex_destroy(&ff->readdir.lock);
86 kfree(ff); 92 kfree(ff);
87} 93}
@@ -92,34 +98,31 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff)
92 return ff; 98 return ff;
93} 99}
94 100
95static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) 101static void fuse_release_end(struct fuse_conn *fc, struct fuse_args *args,
102 int error)
96{ 103{
97 iput(req->misc.release.inode); 104 struct fuse_release_args *ra = container_of(args, typeof(*ra), args);
105
106 iput(ra->inode);
107 kfree(ra);
98} 108}
99 109
100static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) 110static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir)
101{ 111{
102 if (refcount_dec_and_test(&ff->count)) { 112 if (refcount_dec_and_test(&ff->count)) {
103 struct fuse_req *req = ff->reserved_req; 113 struct fuse_args *args = &ff->release_args->args;
104 114
105 if (isdir ? ff->fc->no_opendir : ff->fc->no_open) { 115 if (isdir ? ff->fc->no_opendir : ff->fc->no_open) {
106 /* 116 /* Do nothing when client does not implement 'open' */
107 * Drop the release request when client does not 117 fuse_release_end(ff->fc, args, 0);
108 * implement 'open'
109 */
110 __clear_bit(FR_BACKGROUND, &req->flags);
111 iput(req->misc.release.inode);
112 fuse_put_request(ff->fc, req);
113 } else if (sync) { 118 } else if (sync) {
114 __set_bit(FR_FORCE, &req->flags); 119 fuse_simple_request(ff->fc, args);
115 __clear_bit(FR_BACKGROUND, &req->flags); 120 fuse_release_end(ff->fc, args, 0);
116 fuse_request_send(ff->fc, req);
117 iput(req->misc.release.inode);
118 fuse_put_request(ff->fc, req);
119 } else { 121 } else {
120 req->end = fuse_release_end; 122 args->end = fuse_release_end;
121 __set_bit(FR_BACKGROUND, &req->flags); 123 if (fuse_simple_background(ff->fc, args,
122 fuse_request_send_background(ff->fc, req); 124 GFP_KERNEL | __GFP_NOFAIL))
125 fuse_release_end(ff->fc, args, -ENOTCONN);
123 } 126 }
124 kfree(ff); 127 kfree(ff);
125 } 128 }
@@ -239,8 +242,7 @@ static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff,
239 int flags, int opcode) 242 int flags, int opcode)
240{ 243{
241 struct fuse_conn *fc = ff->fc; 244 struct fuse_conn *fc = ff->fc;
242 struct fuse_req *req = ff->reserved_req; 245 struct fuse_release_args *ra = ff->release_args;
243 struct fuse_release_in *inarg = &req->misc.release.in;
244 246
245 /* Inode is NULL on error path of fuse_create_open() */ 247 /* Inode is NULL on error path of fuse_create_open() */
246 if (likely(fi)) { 248 if (likely(fi)) {
@@ -255,32 +257,33 @@ static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff,
255 257
256 wake_up_interruptible_all(&ff->poll_wait); 258 wake_up_interruptible_all(&ff->poll_wait);
257 259
258 inarg->fh = ff->fh; 260 ra->inarg.fh = ff->fh;
259 inarg->flags = flags; 261 ra->inarg.flags = flags;
260 req->in.h.opcode = opcode; 262 ra->args.in_numargs = 1;
261 req->in.h.nodeid = ff->nodeid; 263 ra->args.in_args[0].size = sizeof(struct fuse_release_in);
262 req->in.numargs = 1; 264 ra->args.in_args[0].value = &ra->inarg;
263 req->in.args[0].size = sizeof(struct fuse_release_in); 265 ra->args.opcode = opcode;
264 req->in.args[0].value = inarg; 266 ra->args.nodeid = ff->nodeid;
267 ra->args.force = true;
268 ra->args.nocreds = true;
265} 269}
266 270
267void fuse_release_common(struct file *file, bool isdir) 271void fuse_release_common(struct file *file, bool isdir)
268{ 272{
269 struct fuse_inode *fi = get_fuse_inode(file_inode(file)); 273 struct fuse_inode *fi = get_fuse_inode(file_inode(file));
270 struct fuse_file *ff = file->private_data; 274 struct fuse_file *ff = file->private_data;
271 struct fuse_req *req = ff->reserved_req; 275 struct fuse_release_args *ra = ff->release_args;
272 int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; 276 int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE;
273 277
274 fuse_prepare_release(fi, ff, file->f_flags, opcode); 278 fuse_prepare_release(fi, ff, file->f_flags, opcode);
275 279
276 if (ff->flock) { 280 if (ff->flock) {
277 struct fuse_release_in *inarg = &req->misc.release.in; 281 ra->inarg.release_flags |= FUSE_RELEASE_FLOCK_UNLOCK;
278 inarg->release_flags |= FUSE_RELEASE_FLOCK_UNLOCK; 282 ra->inarg.lock_owner = fuse_lock_owner_id(ff->fc,
279 inarg->lock_owner = fuse_lock_owner_id(ff->fc, 283 (fl_owner_t) file);
280 (fl_owner_t) file);
281 } 284 }
282 /* Hold inode until release is finished */ 285 /* Hold inode until release is finished */
283 req->misc.release.inode = igrab(file_inode(file)); 286 ra->inode = igrab(file_inode(file));
284 287
285 /* 288 /*
286 * Normally this will send the RELEASE request, however if 289 * Normally this will send the RELEASE request, however if
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index a9d707bf2e69..a055a45361ef 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -164,17 +164,15 @@ enum {
164}; 164};
165 165
166struct fuse_conn; 166struct fuse_conn;
167struct fuse_release_args;
167 168
168/** FUSE specific file data */ 169/** FUSE specific file data */
169struct fuse_file { 170struct fuse_file {
170 /** Fuse connection for this file */ 171 /** Fuse connection for this file */
171 struct fuse_conn *fc; 172 struct fuse_conn *fc;
172 173
173 /* 174 /* Argument space reserved for release */
174 * Request reserved for flush and release. 175 struct fuse_release_args *release_args;
175 * Modified under relative fuse_inode::lock.
176 */
177 struct fuse_req *reserved_req;
178 176
179 /** Kernel file handle guaranteed to be unique */ 177 /** Kernel file handle guaranteed to be unique */
180 u64 kh; 178 u64 kh;