aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse')
-rw-r--r--fs/fuse/dir.c117
1 files changed, 77 insertions, 40 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index be5450dd6387..51d0035ff07e 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -112,18 +112,16 @@ static void fuse_invalidate_entry(struct dentry *entry)
112 fuse_invalidate_entry_cache(entry); 112 fuse_invalidate_entry_cache(entry);
113} 113}
114 114
115static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, 115static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_req *req,
116 struct dentry *entry, 116 u64 nodeid, struct qstr *name,
117 struct fuse_entry_out *outarg) 117 struct fuse_entry_out *outarg)
118{ 118{
119 struct fuse_conn *fc = get_fuse_conn(dir);
120
121 memset(outarg, 0, sizeof(struct fuse_entry_out)); 119 memset(outarg, 0, sizeof(struct fuse_entry_out));
122 req->in.h.opcode = FUSE_LOOKUP; 120 req->in.h.opcode = FUSE_LOOKUP;
123 req->in.h.nodeid = get_node_id(dir); 121 req->in.h.nodeid = nodeid;
124 req->in.numargs = 1; 122 req->in.numargs = 1;
125 req->in.args[0].size = entry->d_name.len + 1; 123 req->in.args[0].size = name->len + 1;
126 req->in.args[0].value = entry->d_name.name; 124 req->in.args[0].value = name->name;
127 req->out.numargs = 1; 125 req->out.numargs = 1;
128 if (fc->minor < 9) 126 if (fc->minor < 9)
129 req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; 127 req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
@@ -189,7 +187,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
189 attr_version = fuse_get_attr_version(fc); 187 attr_version = fuse_get_attr_version(fc);
190 188
191 parent = dget_parent(entry); 189 parent = dget_parent(entry);
192 fuse_lookup_init(req, parent->d_inode, entry, &outarg); 190 fuse_lookup_init(fc, req, get_node_id(parent->d_inode),
191 &entry->d_name, &outarg);
193 request_send(fc, req); 192 request_send(fc, req);
194 dput(parent); 193 dput(parent);
195 err = req->out.h.error; 194 err = req->out.h.error;
@@ -255,73 +254,111 @@ static struct dentry *fuse_d_add_directory(struct dentry *entry,
255 return d_splice_alias(inode, entry); 254 return d_splice_alias(inode, entry);
256} 255}
257 256
258static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 257int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
259 struct nameidata *nd) 258 struct fuse_entry_out *outarg, struct inode **inode)
260{ 259{
261 int err; 260 struct fuse_conn *fc = get_fuse_conn_super(sb);
262 struct fuse_entry_out outarg;
263 struct inode *inode = NULL;
264 struct dentry *newent;
265 struct fuse_conn *fc = get_fuse_conn(dir);
266 struct fuse_req *req; 261 struct fuse_req *req;
267 struct fuse_req *forget_req; 262 struct fuse_req *forget_req;
268 u64 attr_version; 263 u64 attr_version;
264 int err;
269 265
270 if (entry->d_name.len > FUSE_NAME_MAX) 266 *inode = NULL;
271 return ERR_PTR(-ENAMETOOLONG); 267 err = -ENAMETOOLONG;
268 if (name->len > FUSE_NAME_MAX)
269 goto out;
272 270
273 req = fuse_get_req(fc); 271 req = fuse_get_req(fc);
272 err = PTR_ERR(req);
274 if (IS_ERR(req)) 273 if (IS_ERR(req))
275 return ERR_CAST(req); 274 goto out;
276 275
277 forget_req = fuse_get_req(fc); 276 forget_req = fuse_get_req(fc);
277 err = PTR_ERR(forget_req);
278 if (IS_ERR(forget_req)) { 278 if (IS_ERR(forget_req)) {
279 fuse_put_request(fc, req); 279 fuse_put_request(fc, req);
280 return ERR_CAST(forget_req); 280 goto out;
281 } 281 }
282 282
283 attr_version = fuse_get_attr_version(fc); 283 attr_version = fuse_get_attr_version(fc);
284 284
285 fuse_lookup_init(req, dir, entry, &outarg); 285 fuse_lookup_init(fc, req, nodeid, name, outarg);
286 request_send(fc, req); 286 request_send(fc, req);
287 err = req->out.h.error; 287 err = req->out.h.error;
288 fuse_put_request(fc, req); 288 fuse_put_request(fc, req);
289 /* Zero nodeid is same as -ENOENT, but with valid timeout */ 289 /* Zero nodeid is same as -ENOENT, but with valid timeout */
290 if (!err && outarg.nodeid && 290 if (err || !outarg->nodeid)
291 (invalid_nodeid(outarg.nodeid) || 291 goto out_put_forget;
292 !fuse_valid_type(outarg.attr.mode))) 292
293 err = -EIO; 293 err = -EIO;
294 if (!err && outarg.nodeid) { 294 if (!outarg->nodeid)
295 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 295 goto out_put_forget;
296 &outarg.attr, entry_attr_timeout(&outarg), 296 if (!fuse_valid_type(outarg->attr.mode))
297 attr_version); 297 goto out_put_forget;
298 if (!inode) { 298
299 fuse_send_forget(fc, forget_req, outarg.nodeid, 1); 299 *inode = fuse_iget(sb, outarg->nodeid, outarg->generation,
300 return ERR_PTR(-ENOMEM); 300 &outarg->attr, entry_attr_timeout(outarg),
301 } 301 attr_version);
302 err = -ENOMEM;
303 if (!*inode) {
304 fuse_send_forget(fc, forget_req, outarg->nodeid, 1);
305 goto out;
302 } 306 }
307 err = 0;
308
309 out_put_forget:
303 fuse_put_request(fc, forget_req); 310 fuse_put_request(fc, forget_req);
304 if (err && err != -ENOENT) 311 out:
305 return ERR_PTR(err); 312 return err;
313}
314
315static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
316 struct nameidata *nd)
317{
318 int err;
319 struct fuse_entry_out outarg;
320 struct inode *inode;
321 struct dentry *newent;
322 struct fuse_conn *fc = get_fuse_conn(dir);
323 bool outarg_valid = true;
324
325 err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
326 &outarg, &inode);
327 if (err == -ENOENT) {
328 outarg_valid = false;
329 err = 0;
330 }
331 if (err)
332 goto out_err;
333
334 err = -EIO;
335 if (inode && get_node_id(inode) == FUSE_ROOT_ID)
336 goto out_iput;
306 337
307 if (inode && S_ISDIR(inode->i_mode)) { 338 if (inode && S_ISDIR(inode->i_mode)) {
308 mutex_lock(&fc->inst_mutex); 339 mutex_lock(&fc->inst_mutex);
309 newent = fuse_d_add_directory(entry, inode); 340 newent = fuse_d_add_directory(entry, inode);
310 mutex_unlock(&fc->inst_mutex); 341 mutex_unlock(&fc->inst_mutex);
311 if (IS_ERR(newent)) { 342 err = PTR_ERR(newent);
312 iput(inode); 343 if (IS_ERR(newent))
313 return newent; 344 goto out_iput;
314 } 345 } else {
315 } else
316 newent = d_splice_alias(inode, entry); 346 newent = d_splice_alias(inode, entry);
347 }
317 348
318 entry = newent ? newent : entry; 349 entry = newent ? newent : entry;
319 entry->d_op = &fuse_dentry_operations; 350 entry->d_op = &fuse_dentry_operations;
320 if (!err) 351 if (outarg_valid)
321 fuse_change_entry_timeout(entry, &outarg); 352 fuse_change_entry_timeout(entry, &outarg);
322 else 353 else
323 fuse_invalidate_entry_cache(entry); 354 fuse_invalidate_entry_cache(entry);
355
324 return newent; 356 return newent;
357
358 out_iput:
359 iput(inode);
360 out_err:
361 return ERR_PTR(err);
325} 362}
326 363
327/* 364/*