xref: /openbmc/linux/fs/fuse/dir.c (revision 8cbdf1e6f6876b37d2a0d96fd15ea9f90f7d51c1)
1e5e5558eSMiklos Szeredi /*
2e5e5558eSMiklos Szeredi   FUSE: Filesystem in Userspace
3e5e5558eSMiklos Szeredi   Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
4e5e5558eSMiklos Szeredi 
5e5e5558eSMiklos Szeredi   This program can be distributed under the terms of the GNU GPL.
6e5e5558eSMiklos Szeredi   See the file COPYING.
7e5e5558eSMiklos Szeredi */
8e5e5558eSMiklos Szeredi 
9e5e5558eSMiklos Szeredi #include "fuse_i.h"
10e5e5558eSMiklos Szeredi 
11e5e5558eSMiklos Szeredi #include <linux/pagemap.h>
12e5e5558eSMiklos Szeredi #include <linux/file.h>
13e5e5558eSMiklos Szeredi #include <linux/gfp.h>
14e5e5558eSMiklos Szeredi #include <linux/sched.h>
15e5e5558eSMiklos Szeredi #include <linux/namei.h>
16e5e5558eSMiklos Szeredi 
17e5e5558eSMiklos Szeredi static inline unsigned long time_to_jiffies(unsigned long sec,
18e5e5558eSMiklos Szeredi 					    unsigned long nsec)
19e5e5558eSMiklos Szeredi {
20e5e5558eSMiklos Szeredi 	struct timespec ts = {sec, nsec};
21e5e5558eSMiklos Szeredi 	return jiffies + timespec_to_jiffies(&ts);
22e5e5558eSMiklos Szeredi }
23e5e5558eSMiklos Szeredi 
240aa7c699SMiklos Szeredi static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
250aa7c699SMiklos Szeredi {
260aa7c699SMiklos Szeredi 	entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
27*8cbdf1e6SMiklos Szeredi 	if (entry->d_inode)
28*8cbdf1e6SMiklos Szeredi 		get_fuse_inode(entry->d_inode)->i_time =
29*8cbdf1e6SMiklos Szeredi 			time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
30*8cbdf1e6SMiklos Szeredi }
31*8cbdf1e6SMiklos Szeredi 
32*8cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode)
33*8cbdf1e6SMiklos Szeredi {
34*8cbdf1e6SMiklos Szeredi 	get_fuse_inode(inode)->i_time = jiffies - 1;
35*8cbdf1e6SMiklos Szeredi }
36*8cbdf1e6SMiklos Szeredi 
37*8cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry_cache(struct dentry *entry)
38*8cbdf1e6SMiklos Szeredi {
39*8cbdf1e6SMiklos Szeredi 	entry->d_time = jiffies - 1;
40*8cbdf1e6SMiklos Szeredi }
41*8cbdf1e6SMiklos Szeredi 
42*8cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry)
43*8cbdf1e6SMiklos Szeredi {
44*8cbdf1e6SMiklos Szeredi 	d_invalidate(entry);
45*8cbdf1e6SMiklos Szeredi 	fuse_invalidate_entry_cache(entry);
460aa7c699SMiklos Szeredi }
470aa7c699SMiklos Szeredi 
48e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
49e5e5558eSMiklos Szeredi 			     struct dentry *entry,
50e5e5558eSMiklos Szeredi 			     struct fuse_entry_out *outarg)
51e5e5558eSMiklos Szeredi {
52e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_LOOKUP;
53e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
54e5e5558eSMiklos Szeredi 	req->inode = dir;
55e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
56e5e5558eSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
57e5e5558eSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
58e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
59e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(struct fuse_entry_out);
60e5e5558eSMiklos Szeredi 	req->out.args[0].value = outarg;
61e5e5558eSMiklos Szeredi }
62e5e5558eSMiklos Szeredi 
63e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
64e5e5558eSMiklos Szeredi {
65*8cbdf1e6SMiklos Szeredi 	struct inode *inode = entry->d_inode;
66*8cbdf1e6SMiklos Szeredi 
67*8cbdf1e6SMiklos Szeredi 	if (inode && is_bad_inode(inode))
68e5e5558eSMiklos Szeredi 		return 0;
69e5e5558eSMiklos Szeredi 	else if (time_after(jiffies, entry->d_time)) {
70e5e5558eSMiklos Szeredi 		int err;
71e5e5558eSMiklos Szeredi 		struct fuse_entry_out outarg;
72*8cbdf1e6SMiklos Szeredi 		struct fuse_conn *fc;
73*8cbdf1e6SMiklos Szeredi 		struct fuse_req *req;
74*8cbdf1e6SMiklos Szeredi 
75*8cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
76*8cbdf1e6SMiklos Szeredi 		if (!inode)
77*8cbdf1e6SMiklos Szeredi 			return 0;
78*8cbdf1e6SMiklos Szeredi 
79*8cbdf1e6SMiklos Szeredi 		fc = get_fuse_conn(inode);
80*8cbdf1e6SMiklos Szeredi 		req = fuse_get_request(fc);
81e5e5558eSMiklos Szeredi 		if (!req)
82e5e5558eSMiklos Szeredi 			return 0;
83e5e5558eSMiklos Szeredi 
84e5e5558eSMiklos Szeredi 		fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
857c352bdfSMiklos Szeredi 		request_send(fc, req);
86e5e5558eSMiklos Szeredi 		err = req->out.h.error;
879e6268dbSMiklos Szeredi 		if (!err) {
88*8cbdf1e6SMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
899e6268dbSMiklos Szeredi 			if (outarg.nodeid != get_node_id(inode)) {
909e6268dbSMiklos Szeredi 				fuse_send_forget(fc, req, outarg.nodeid, 1);
919e6268dbSMiklos Szeredi 				return 0;
929e6268dbSMiklos Szeredi 			}
939e6268dbSMiklos Szeredi 			fi->nlookup ++;
949e6268dbSMiklos Szeredi 		}
95e5e5558eSMiklos Szeredi 		fuse_put_request(fc, req);
969e6268dbSMiklos Szeredi 		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
97e5e5558eSMiklos Szeredi 			return 0;
98e5e5558eSMiklos Szeredi 
99e5e5558eSMiklos Szeredi 		fuse_change_attributes(inode, &outarg.attr);
1000aa7c699SMiklos Szeredi 		fuse_change_timeout(entry, &outarg);
101e5e5558eSMiklos Szeredi 	}
102e5e5558eSMiklos Szeredi 	return 1;
103e5e5558eSMiklos Szeredi }
104e5e5558eSMiklos Szeredi 
105f007d5c9SMiklos Szeredi static int dir_alias(struct inode *inode)
106f007d5c9SMiklos Szeredi {
107f007d5c9SMiklos Szeredi 	if (S_ISDIR(inode->i_mode)) {
108f007d5c9SMiklos Szeredi 		/* Don't allow creating an alias to a directory  */
109f007d5c9SMiklos Szeredi 		struct dentry *alias = d_find_alias(inode);
110f007d5c9SMiklos Szeredi 		if (alias) {
111f007d5c9SMiklos Szeredi 			dput(alias);
112f007d5c9SMiklos Szeredi 			return 1;
113f007d5c9SMiklos Szeredi 		}
114f007d5c9SMiklos Szeredi 	}
115f007d5c9SMiklos Szeredi 	return 0;
116f007d5c9SMiklos Szeredi }
117f007d5c9SMiklos Szeredi 
1182827d0b2SMiklos Szeredi static inline int invalid_nodeid(u64 nodeid)
1192827d0b2SMiklos Szeredi {
1202827d0b2SMiklos Szeredi 	return !nodeid || nodeid == FUSE_ROOT_ID;
1212827d0b2SMiklos Szeredi }
1222827d0b2SMiklos Szeredi 
123e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = {
124e5e5558eSMiklos Szeredi 	.d_revalidate	= fuse_dentry_revalidate,
125e5e5558eSMiklos Szeredi };
126e5e5558eSMiklos Szeredi 
1270aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
1280aa7c699SMiklos Szeredi 				  struct nameidata *nd)
129e5e5558eSMiklos Szeredi {
130e5e5558eSMiklos Szeredi 	int err;
131e5e5558eSMiklos Szeredi 	struct fuse_entry_out outarg;
132e5e5558eSMiklos Szeredi 	struct inode *inode = NULL;
133e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
134e5e5558eSMiklos Szeredi 	struct fuse_req *req;
135e5e5558eSMiklos Szeredi 
136e5e5558eSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
1370aa7c699SMiklos Szeredi 		return ERR_PTR(-ENAMETOOLONG);
138e5e5558eSMiklos Szeredi 
139e5e5558eSMiklos Szeredi 	req = fuse_get_request(fc);
140e5e5558eSMiklos Szeredi 	if (!req)
1410aa7c699SMiklos Szeredi 		return ERR_PTR(-EINTR);
142e5e5558eSMiklos Szeredi 
143e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
144e5e5558eSMiklos Szeredi 	request_send(fc, req);
145e5e5558eSMiklos Szeredi 	err = req->out.h.error;
146*8cbdf1e6SMiklos Szeredi 	if (!err && outarg.nodeid && invalid_nodeid(outarg.nodeid))
147ee4e5271SMiklos Szeredi 		err = -EIO;
148*8cbdf1e6SMiklos Szeredi 	if (!err && outarg.nodeid) {
149e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
1509e6268dbSMiklos Szeredi 				  &outarg.attr);
151e5e5558eSMiklos Szeredi 		if (!inode) {
1529e6268dbSMiklos Szeredi 			fuse_send_forget(fc, req, outarg.nodeid, 1);
1530aa7c699SMiklos Szeredi 			return ERR_PTR(-ENOMEM);
154e5e5558eSMiklos Szeredi 		}
155e5e5558eSMiklos Szeredi 	}
156e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
157e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
1580aa7c699SMiklos Szeredi 		return ERR_PTR(err);
159e5e5558eSMiklos Szeredi 
1600aa7c699SMiklos Szeredi 	if (inode && dir_alias(inode)) {
1610aa7c699SMiklos Szeredi 		iput(inode);
1620aa7c699SMiklos Szeredi 		return ERR_PTR(-EIO);
163e5e5558eSMiklos Szeredi 	}
1640aa7c699SMiklos Szeredi 	d_add(entry, inode);
165e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
166*8cbdf1e6SMiklos Szeredi 	if (!err)
1670aa7c699SMiklos Szeredi 		fuse_change_timeout(entry, &outarg);
168*8cbdf1e6SMiklos Szeredi 	else
169*8cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
1700aa7c699SMiklos Szeredi 	return NULL;
171e5e5558eSMiklos Szeredi }
172e5e5558eSMiklos Szeredi 
173fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
174fd72faacSMiklos Szeredi 			    struct nameidata *nd)
175fd72faacSMiklos Szeredi {
176fd72faacSMiklos Szeredi 	int err;
177fd72faacSMiklos Szeredi 	struct inode *inode;
178fd72faacSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
179fd72faacSMiklos Szeredi 	struct fuse_req *req;
180fd72faacSMiklos Szeredi 	struct fuse_open_in inarg;
181fd72faacSMiklos Szeredi 	struct fuse_open_out outopen;
182fd72faacSMiklos Szeredi 	struct fuse_entry_out outentry;
183fd72faacSMiklos Szeredi 	struct fuse_file *ff;
184fd72faacSMiklos Szeredi 	struct file *file;
185fd72faacSMiklos Szeredi 	int flags = nd->intent.open.flags - 1;
186fd72faacSMiklos Szeredi 
187fd72faacSMiklos Szeredi 	err = -ENOSYS;
188fd72faacSMiklos Szeredi 	if (fc->no_create)
189fd72faacSMiklos Szeredi 		goto out;
190fd72faacSMiklos Szeredi 
191fd72faacSMiklos Szeredi 	err = -ENAMETOOLONG;
192fd72faacSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
193fd72faacSMiklos Szeredi 		goto out;
194fd72faacSMiklos Szeredi 
195fd72faacSMiklos Szeredi 	err = -EINTR;
196fd72faacSMiklos Szeredi 	req = fuse_get_request(fc);
197fd72faacSMiklos Szeredi 	if (!req)
198fd72faacSMiklos Szeredi 		goto out;
199fd72faacSMiklos Szeredi 
200fd72faacSMiklos Szeredi 	ff = fuse_file_alloc();
201fd72faacSMiklos Szeredi 	if (!ff)
202fd72faacSMiklos Szeredi 		goto out_put_request;
203fd72faacSMiklos Szeredi 
204fd72faacSMiklos Szeredi 	flags &= ~O_NOCTTY;
205fd72faacSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
206fd72faacSMiklos Szeredi 	inarg.flags = flags;
207fd72faacSMiklos Szeredi 	inarg.mode = mode;
208fd72faacSMiklos Szeredi 	req->in.h.opcode = FUSE_CREATE;
209fd72faacSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
210fd72faacSMiklos Szeredi 	req->inode = dir;
211fd72faacSMiklos Szeredi 	req->in.numargs = 2;
212fd72faacSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
213fd72faacSMiklos Szeredi 	req->in.args[0].value = &inarg;
214fd72faacSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
215fd72faacSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
216fd72faacSMiklos Szeredi 	req->out.numargs = 2;
217fd72faacSMiklos Szeredi 	req->out.args[0].size = sizeof(outentry);
218fd72faacSMiklos Szeredi 	req->out.args[0].value = &outentry;
219fd72faacSMiklos Szeredi 	req->out.args[1].size = sizeof(outopen);
220fd72faacSMiklos Szeredi 	req->out.args[1].value = &outopen;
221fd72faacSMiklos Szeredi 	request_send(fc, req);
222fd72faacSMiklos Szeredi 	err = req->out.h.error;
223fd72faacSMiklos Szeredi 	if (err) {
224fd72faacSMiklos Szeredi 		if (err == -ENOSYS)
225fd72faacSMiklos Szeredi 			fc->no_create = 1;
226fd72faacSMiklos Szeredi 		goto out_free_ff;
227fd72faacSMiklos Szeredi 	}
228fd72faacSMiklos Szeredi 
229fd72faacSMiklos Szeredi 	err = -EIO;
2302827d0b2SMiklos Szeredi 	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
231fd72faacSMiklos Szeredi 		goto out_free_ff;
232fd72faacSMiklos Szeredi 
233fd72faacSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
234fd72faacSMiklos Szeredi 			  &outentry.attr);
235fd72faacSMiklos Szeredi 	err = -ENOMEM;
236fd72faacSMiklos Szeredi 	if (!inode) {
237fd72faacSMiklos Szeredi 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
238fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
239fd72faacSMiklos Szeredi 		fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
240fd72faacSMiklos Szeredi 		goto out_put_request;
241fd72faacSMiklos Szeredi 	}
242fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
243fd72faacSMiklos Szeredi 	d_instantiate(entry, inode);
2440aa7c699SMiklos Szeredi 	fuse_change_timeout(entry, &outentry);
245fd72faacSMiklos Szeredi 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
246fd72faacSMiklos Szeredi 	if (IS_ERR(file)) {
247fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
248fd72faacSMiklos Szeredi 		fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
249fd72faacSMiklos Szeredi 		return PTR_ERR(file);
250fd72faacSMiklos Szeredi 	}
251fd72faacSMiklos Szeredi 	fuse_finish_open(inode, file, ff, &outopen);
252fd72faacSMiklos Szeredi 	return 0;
253fd72faacSMiklos Szeredi 
254fd72faacSMiklos Szeredi  out_free_ff:
255fd72faacSMiklos Szeredi 	fuse_file_free(ff);
256fd72faacSMiklos Szeredi  out_put_request:
257fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
258fd72faacSMiklos Szeredi  out:
259fd72faacSMiklos Szeredi 	return err;
260fd72faacSMiklos Szeredi }
261fd72faacSMiklos Szeredi 
2629e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
2639e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
2649e6268dbSMiklos Szeredi 			    int mode)
2659e6268dbSMiklos Szeredi {
2669e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
2679e6268dbSMiklos Szeredi 	struct inode *inode;
2689e6268dbSMiklos Szeredi 	int err;
2699e6268dbSMiklos Szeredi 
2709e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
2719e6268dbSMiklos Szeredi 	req->inode = dir;
2729e6268dbSMiklos Szeredi 	req->out.numargs = 1;
2739e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
2749e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
2759e6268dbSMiklos Szeredi 	request_send(fc, req);
2769e6268dbSMiklos Szeredi 	err = req->out.h.error;
2779e6268dbSMiklos Szeredi 	if (err) {
2789e6268dbSMiklos Szeredi 		fuse_put_request(fc, req);
2799e6268dbSMiklos Szeredi 		return err;
2809e6268dbSMiklos Szeredi 	}
2812827d0b2SMiklos Szeredi 	if (invalid_nodeid(outarg.nodeid)) {
282ee4e5271SMiklos Szeredi 		fuse_put_request(fc, req);
283ee4e5271SMiklos Szeredi 		return -EIO;
284ee4e5271SMiklos Szeredi 	}
2859e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
2869e6268dbSMiklos Szeredi 			  &outarg.attr);
2879e6268dbSMiklos Szeredi 	if (!inode) {
2889e6268dbSMiklos Szeredi 		fuse_send_forget(fc, req, outarg.nodeid, 1);
2899e6268dbSMiklos Szeredi 		return -ENOMEM;
2909e6268dbSMiklos Szeredi 	}
2919e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
2929e6268dbSMiklos Szeredi 
2939e6268dbSMiklos Szeredi 	/* Don't allow userspace to do really stupid things... */
294f007d5c9SMiklos Szeredi 	if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
2959e6268dbSMiklos Szeredi 		iput(inode);
2969e6268dbSMiklos Szeredi 		return -EIO;
2979e6268dbSMiklos Szeredi 	}
2989e6268dbSMiklos Szeredi 
2999e6268dbSMiklos Szeredi 	d_instantiate(entry, inode);
3000aa7c699SMiklos Szeredi 	fuse_change_timeout(entry, &outarg);
3019e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
3029e6268dbSMiklos Szeredi 	return 0;
3039e6268dbSMiklos Szeredi }
3049e6268dbSMiklos Szeredi 
3059e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
3069e6268dbSMiklos Szeredi 		      dev_t rdev)
3079e6268dbSMiklos Szeredi {
3089e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
3099e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3109e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3119e6268dbSMiklos Szeredi 	if (!req)
3127c352bdfSMiklos Szeredi 		return -EINTR;
3139e6268dbSMiklos Szeredi 
3149e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3159e6268dbSMiklos Szeredi 	inarg.mode = mode;
3169e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
3179e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
3189e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3199e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3209e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3219e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
3229e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
3239e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
3249e6268dbSMiklos Szeredi }
3259e6268dbSMiklos Szeredi 
3269e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
3279e6268dbSMiklos Szeredi 		       struct nameidata *nd)
3289e6268dbSMiklos Szeredi {
329fd72faacSMiklos Szeredi 	if (nd && (nd->flags & LOOKUP_CREATE)) {
330fd72faacSMiklos Szeredi 		int err = fuse_create_open(dir, entry, mode, nd);
331fd72faacSMiklos Szeredi 		if (err != -ENOSYS)
332fd72faacSMiklos Szeredi 			return err;
333fd72faacSMiklos Szeredi 		/* Fall back on mknod */
334fd72faacSMiklos Szeredi 	}
3359e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
3369e6268dbSMiklos Szeredi }
3379e6268dbSMiklos Szeredi 
3389e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
3399e6268dbSMiklos Szeredi {
3409e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
3419e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3429e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3439e6268dbSMiklos Szeredi 	if (!req)
3447c352bdfSMiklos Szeredi 		return -EINTR;
3459e6268dbSMiklos Szeredi 
3469e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3479e6268dbSMiklos Szeredi 	inarg.mode = mode;
3489e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
3499e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3509e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3519e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3529e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
3539e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
3549e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
3559e6268dbSMiklos Szeredi }
3569e6268dbSMiklos Szeredi 
3579e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
3589e6268dbSMiklos Szeredi 			const char *link)
3599e6268dbSMiklos Szeredi {
3609e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3619e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
3629e6268dbSMiklos Szeredi 	struct fuse_req *req;
3639e6268dbSMiklos Szeredi 
3649e6268dbSMiklos Szeredi 	if (len > FUSE_SYMLINK_MAX)
3659e6268dbSMiklos Szeredi 		return -ENAMETOOLONG;
3669e6268dbSMiklos Szeredi 
3679e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
3689e6268dbSMiklos Szeredi 	if (!req)
3697c352bdfSMiklos Szeredi 		return -EINTR;
3709e6268dbSMiklos Szeredi 
3719e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SYMLINK;
3729e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3739e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
3749e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
3759e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
3769e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
3779e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
3789e6268dbSMiklos Szeredi }
3799e6268dbSMiklos Szeredi 
3809e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
3819e6268dbSMiklos Szeredi {
3829e6268dbSMiklos Szeredi 	int err;
3839e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3849e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3859e6268dbSMiklos Szeredi 	if (!req)
3867c352bdfSMiklos Szeredi 		return -EINTR;
3879e6268dbSMiklos Szeredi 
3889e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
3899e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
3909e6268dbSMiklos Szeredi 	req->inode = dir;
3919e6268dbSMiklos Szeredi 	req->in.numargs = 1;
3929e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
3939e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
3949e6268dbSMiklos Szeredi 	request_send(fc, req);
3959e6268dbSMiklos Szeredi 	err = req->out.h.error;
3969e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
3979e6268dbSMiklos Szeredi 	if (!err) {
3989e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
3999e6268dbSMiklos Szeredi 
4009e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
4019e6268dbSMiklos Szeredi                    the inode does have more links this will be
4029e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
4039e6268dbSMiklos Szeredi 		inode->i_nlink = 0;
4049e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
4059e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
406*8cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
4079e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
4089e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
4099e6268dbSMiklos Szeredi 	return err;
4109e6268dbSMiklos Szeredi }
4119e6268dbSMiklos Szeredi 
4129e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
4139e6268dbSMiklos Szeredi {
4149e6268dbSMiklos Szeredi 	int err;
4159e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
4169e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
4179e6268dbSMiklos Szeredi 	if (!req)
4187c352bdfSMiklos Szeredi 		return -EINTR;
4199e6268dbSMiklos Szeredi 
4209e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
4219e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
4229e6268dbSMiklos Szeredi 	req->inode = dir;
4239e6268dbSMiklos Szeredi 	req->in.numargs = 1;
4249e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
4259e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
4269e6268dbSMiklos Szeredi 	request_send(fc, req);
4279e6268dbSMiklos Szeredi 	err = req->out.h.error;
4289e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4299e6268dbSMiklos Szeredi 	if (!err) {
4309e6268dbSMiklos Szeredi 		entry->d_inode->i_nlink = 0;
4319e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
432*8cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
4339e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
4349e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
4359e6268dbSMiklos Szeredi 	return err;
4369e6268dbSMiklos Szeredi }
4379e6268dbSMiklos Szeredi 
4389e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
4399e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
4409e6268dbSMiklos Szeredi {
4419e6268dbSMiklos Szeredi 	int err;
4429e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
4439e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
4449e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
4459e6268dbSMiklos Szeredi 	if (!req)
4467c352bdfSMiklos Szeredi 		return -EINTR;
4479e6268dbSMiklos Szeredi 
4489e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4499e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
4509e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
4519e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
4529e6268dbSMiklos Szeredi 	req->inode = olddir;
4539e6268dbSMiklos Szeredi 	req->inode2 = newdir;
4549e6268dbSMiklos Szeredi 	req->in.numargs = 3;
4559e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4569e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4579e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
4589e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
4599e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
4609e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
4619e6268dbSMiklos Szeredi 	request_send(fc, req);
4629e6268dbSMiklos Szeredi 	err = req->out.h.error;
4639e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4649e6268dbSMiklos Szeredi 	if (!err) {
4659e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
4669e6268dbSMiklos Szeredi 		if (olddir != newdir)
4679e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
468*8cbdf1e6SMiklos Szeredi 
469*8cbdf1e6SMiklos Szeredi 		/* newent will end up negative */
470*8cbdf1e6SMiklos Szeredi 		if (newent->d_inode)
471*8cbdf1e6SMiklos Szeredi 			fuse_invalidate_entry_cache(newent);
4729e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
4739e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
4749e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
4759e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
4769e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
4779e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
4789e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
4799e6268dbSMiklos Szeredi 		if (newent->d_inode)
4809e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
4819e6268dbSMiklos Szeredi 	}
4829e6268dbSMiklos Szeredi 
4839e6268dbSMiklos Szeredi 	return err;
4849e6268dbSMiklos Szeredi }
4859e6268dbSMiklos Szeredi 
4869e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
4879e6268dbSMiklos Szeredi 		     struct dentry *newent)
4889e6268dbSMiklos Szeredi {
4899e6268dbSMiklos Szeredi 	int err;
4909e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
4919e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
4929e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
4939e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
4949e6268dbSMiklos Szeredi 	if (!req)
4957c352bdfSMiklos Szeredi 		return -EINTR;
4969e6268dbSMiklos Szeredi 
4979e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4989e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
4999e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
5009e6268dbSMiklos Szeredi 	req->inode2 = inode;
5019e6268dbSMiklos Szeredi 	req->in.numargs = 2;
5029e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
5039e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
5049e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
5059e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
5069e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
5079e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
5089e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
5099e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
5109e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
5119e6268dbSMiklos Szeredi 	   etc.)
5129e6268dbSMiklos Szeredi 	*/
5139e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
5149e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
5159e6268dbSMiklos Szeredi 	return err;
5169e6268dbSMiklos Szeredi }
5179e6268dbSMiklos Szeredi 
518e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode)
519e5e5558eSMiklos Szeredi {
520e5e5558eSMiklos Szeredi 	int err;
521e5e5558eSMiklos Szeredi 	struct fuse_attr_out arg;
522e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
523e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
524e5e5558eSMiklos Szeredi 	if (!req)
5257c352bdfSMiklos Szeredi 		return -EINTR;
526e5e5558eSMiklos Szeredi 
527e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
528e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
529e5e5558eSMiklos Szeredi 	req->inode = inode;
530e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
531e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(arg);
532e5e5558eSMiklos Szeredi 	req->out.args[0].value = &arg;
533e5e5558eSMiklos Szeredi 	request_send(fc, req);
534e5e5558eSMiklos Szeredi 	err = req->out.h.error;
535e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
536e5e5558eSMiklos Szeredi 	if (!err) {
537e5e5558eSMiklos Szeredi 		if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
538e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
539e5e5558eSMiklos Szeredi 			err = -EIO;
540e5e5558eSMiklos Szeredi 		} else {
541e5e5558eSMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
542e5e5558eSMiklos Szeredi 			fuse_change_attributes(inode, &arg.attr);
543e5e5558eSMiklos Szeredi 			fi->i_time = time_to_jiffies(arg.attr_valid,
544e5e5558eSMiklos Szeredi 						     arg.attr_valid_nsec);
545e5e5558eSMiklos Szeredi 		}
546e5e5558eSMiklos Szeredi 	}
547e5e5558eSMiklos Szeredi 	return err;
548e5e5558eSMiklos Szeredi }
549e5e5558eSMiklos Szeredi 
55087729a55SMiklos Szeredi /*
55187729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
55287729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
55387729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
55487729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
55587729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
55687729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
55787729a55SMiklos Szeredi  * DoS against the requester.
55887729a55SMiklos Szeredi  *
55987729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
56087729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
56187729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
56287729a55SMiklos Szeredi  */
56387729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
56487729a55SMiklos Szeredi {
56587729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
56687729a55SMiklos Szeredi 		return 1;
56787729a55SMiklos Szeredi 
56887729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
56987729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
57087729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
57187729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
57287729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
57387729a55SMiklos Szeredi 	    task->gid == fc->group_id)
57487729a55SMiklos Szeredi 		return 1;
57587729a55SMiklos Szeredi 
57687729a55SMiklos Szeredi 	return 0;
57787729a55SMiklos Szeredi }
57887729a55SMiklos Szeredi 
579e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry)
580e5e5558eSMiklos Szeredi {
581e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
582e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
583e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
584e5e5558eSMiklos Szeredi 
58587729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
586e5e5558eSMiklos Szeredi 		return -EACCES;
58787729a55SMiklos Szeredi 	if (get_node_id(inode) != FUSE_ROOT_ID &&
58887729a55SMiklos Szeredi 	    time_before_eq(jiffies, fi->i_time))
589e5e5558eSMiklos Szeredi 		return 0;
590e5e5558eSMiklos Szeredi 
591e5e5558eSMiklos Szeredi 	return fuse_do_getattr(inode);
592e5e5558eSMiklos Szeredi }
593e5e5558eSMiklos Szeredi 
59431d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask)
59531d40d74SMiklos Szeredi {
59631d40d74SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
59731d40d74SMiklos Szeredi 	struct fuse_req *req;
59831d40d74SMiklos Szeredi 	struct fuse_access_in inarg;
59931d40d74SMiklos Szeredi 	int err;
60031d40d74SMiklos Szeredi 
60131d40d74SMiklos Szeredi 	if (fc->no_access)
60231d40d74SMiklos Szeredi 		return 0;
60331d40d74SMiklos Szeredi 
60431d40d74SMiklos Szeredi 	req = fuse_get_request(fc);
60531d40d74SMiklos Szeredi 	if (!req)
60631d40d74SMiklos Szeredi 		return -EINTR;
60731d40d74SMiklos Szeredi 
60831d40d74SMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
60931d40d74SMiklos Szeredi 	inarg.mask = mask;
61031d40d74SMiklos Szeredi 	req->in.h.opcode = FUSE_ACCESS;
61131d40d74SMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
61231d40d74SMiklos Szeredi 	req->inode = inode;
61331d40d74SMiklos Szeredi 	req->in.numargs = 1;
61431d40d74SMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
61531d40d74SMiklos Szeredi 	req->in.args[0].value = &inarg;
61631d40d74SMiklos Szeredi 	request_send(fc, req);
61731d40d74SMiklos Szeredi 	err = req->out.h.error;
61831d40d74SMiklos Szeredi 	fuse_put_request(fc, req);
61931d40d74SMiklos Szeredi 	if (err == -ENOSYS) {
62031d40d74SMiklos Szeredi 		fc->no_access = 1;
62131d40d74SMiklos Szeredi 		err = 0;
62231d40d74SMiklos Szeredi 	}
62331d40d74SMiklos Szeredi 	return err;
62431d40d74SMiklos Szeredi }
62531d40d74SMiklos Szeredi 
626e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
627e5e5558eSMiklos Szeredi {
628e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
629e5e5558eSMiklos Szeredi 
63087729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
631e5e5558eSMiklos Szeredi 		return -EACCES;
6321e9a4ed9SMiklos Szeredi 	else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
6331e9a4ed9SMiklos Szeredi 		int err = generic_permission(inode, mask, NULL);
6341e9a4ed9SMiklos Szeredi 
6351e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
6361e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
6371e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
6381e9a4ed9SMiklos Szeredi 		if (err == -EACCES) {
6391e9a4ed9SMiklos Szeredi 		 	err = fuse_do_getattr(inode);
6401e9a4ed9SMiklos Szeredi 			if (!err)
6411e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
6421e9a4ed9SMiklos Szeredi 		}
6431e9a4ed9SMiklos Szeredi 
6441e9a4ed9SMiklos Szeredi 		/* FIXME: Need some mechanism to revoke permissions:
6451e9a4ed9SMiklos Szeredi 		   currently if the filesystem suddenly changes the
6461e9a4ed9SMiklos Szeredi 		   file mode, we will not be informed about it, and
6471e9a4ed9SMiklos Szeredi 		   continue to allow access to the file/directory.
6481e9a4ed9SMiklos Szeredi 
6491e9a4ed9SMiklos Szeredi 		   This is actually not so grave, since the user can
6501e9a4ed9SMiklos Szeredi 		   simply keep access to the file/directory anyway by
6511e9a4ed9SMiklos Szeredi 		   keeping it open... */
6521e9a4ed9SMiklos Szeredi 
6531e9a4ed9SMiklos Szeredi 		return err;
6541e9a4ed9SMiklos Szeredi 	} else {
655e5e5558eSMiklos Szeredi 		int mode = inode->i_mode;
656e5e5558eSMiklos Szeredi 		if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
657e5e5558eSMiklos Szeredi 			return -EACCES;
65831d40d74SMiklos Szeredi 
65931d40d74SMiklos Szeredi 		if (nd && (nd->flags & LOOKUP_ACCESS))
66031d40d74SMiklos Szeredi 			return fuse_access(inode, mask);
661e5e5558eSMiklos Szeredi 		return 0;
662e5e5558eSMiklos Szeredi 	}
663e5e5558eSMiklos Szeredi }
664e5e5558eSMiklos Szeredi 
665e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
666e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
667e5e5558eSMiklos Szeredi {
668e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
669e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
670e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
671e5e5558eSMiklos Szeredi 		int over;
672e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
673e5e5558eSMiklos Szeredi 			return -EIO;
674e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
675e5e5558eSMiklos Szeredi 			break;
676e5e5558eSMiklos Szeredi 
677e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
678e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
679e5e5558eSMiklos Szeredi 		if (over)
680e5e5558eSMiklos Szeredi 			break;
681e5e5558eSMiklos Szeredi 
682e5e5558eSMiklos Szeredi 		buf += reclen;
683e5e5558eSMiklos Szeredi 		nbytes -= reclen;
684e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
685e5e5558eSMiklos Szeredi 	}
686e5e5558eSMiklos Szeredi 
687e5e5558eSMiklos Szeredi 	return 0;
688e5e5558eSMiklos Szeredi }
689e5e5558eSMiklos Szeredi 
69004730fefSMiklos Szeredi static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
69104730fefSMiklos Szeredi 				       struct inode *inode, loff_t pos,
69204730fefSMiklos Szeredi 				       size_t count)
693e5e5558eSMiklos Szeredi {
69404730fefSMiklos Szeredi 	return fuse_send_read_common(req, file, inode, pos, count, 1);
695e5e5558eSMiklos Szeredi }
696e5e5558eSMiklos Szeredi 
697e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
698e5e5558eSMiklos Szeredi {
69904730fefSMiklos Szeredi 	int err;
70004730fefSMiklos Szeredi 	size_t nbytes;
70104730fefSMiklos Szeredi 	struct page *page;
70204730fefSMiklos Szeredi 	struct inode *inode = file->f_dentry->d_inode;
70304730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
7047c352bdfSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
70504730fefSMiklos Szeredi 	if (!req)
70604730fefSMiklos Szeredi 		return -EINTR;
707e5e5558eSMiklos Szeredi 
70804730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
70904730fefSMiklos Szeredi 	if (!page) {
71004730fefSMiklos Szeredi 		fuse_put_request(fc, req);
711e5e5558eSMiklos Szeredi 		return -ENOMEM;
71204730fefSMiklos Szeredi 	}
71304730fefSMiklos Szeredi 	req->num_pages = 1;
71404730fefSMiklos Szeredi 	req->pages[0] = page;
71504730fefSMiklos Szeredi 	nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
71604730fefSMiklos Szeredi 	err = req->out.h.error;
71704730fefSMiklos Szeredi 	fuse_put_request(fc, req);
71804730fefSMiklos Szeredi 	if (!err)
71904730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
72004730fefSMiklos Szeredi 				    filldir);
721e5e5558eSMiklos Szeredi 
72204730fefSMiklos Szeredi 	__free_page(page);
723b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
72404730fefSMiklos Szeredi 	return err;
725e5e5558eSMiklos Szeredi }
726e5e5558eSMiklos Szeredi 
727e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
728e5e5558eSMiklos Szeredi {
729e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
730e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
731e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
732e5e5558eSMiklos Szeredi 	char *link;
733e5e5558eSMiklos Szeredi 
734e5e5558eSMiklos Szeredi 	if (!req)
7357c352bdfSMiklos Szeredi 		return ERR_PTR(-EINTR);
736e5e5558eSMiklos Szeredi 
737e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
738e5e5558eSMiklos Szeredi 	if (!link) {
739e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
740e5e5558eSMiklos Szeredi 		goto out;
741e5e5558eSMiklos Szeredi 	}
742e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
743e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
744e5e5558eSMiklos Szeredi 	req->inode = inode;
745e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
746e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
747e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
748e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
749e5e5558eSMiklos Szeredi 	request_send(fc, req);
750e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
751e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
752e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
753e5e5558eSMiklos Szeredi 	} else
754e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
755e5e5558eSMiklos Szeredi  out:
756e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
757b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
758e5e5558eSMiklos Szeredi 	return link;
759e5e5558eSMiklos Szeredi }
760e5e5558eSMiklos Szeredi 
761e5e5558eSMiklos Szeredi static void free_link(char *link)
762e5e5558eSMiklos Szeredi {
763e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
764e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
765e5e5558eSMiklos Szeredi }
766e5e5558eSMiklos Szeredi 
767e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
768e5e5558eSMiklos Szeredi {
769e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
770e5e5558eSMiklos Szeredi 	return NULL;
771e5e5558eSMiklos Szeredi }
772e5e5558eSMiklos Szeredi 
773e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
774e5e5558eSMiklos Szeredi {
775e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
776e5e5558eSMiklos Szeredi }
777e5e5558eSMiklos Szeredi 
778e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
779e5e5558eSMiklos Szeredi {
78004730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
781e5e5558eSMiklos Szeredi }
782e5e5558eSMiklos Szeredi 
783e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
784e5e5558eSMiklos Szeredi {
78504730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
786e5e5558eSMiklos Szeredi }
787e5e5558eSMiklos Szeredi 
78882547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
78982547981SMiklos Szeredi {
79082547981SMiklos Szeredi 	/* nfsd can call this with no file */
79182547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
79282547981SMiklos Szeredi }
79382547981SMiklos Szeredi 
794befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
7959e6268dbSMiklos Szeredi {
7969e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
7979e6268dbSMiklos Szeredi 
7989e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
799befc649cSMiklos Szeredi 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
8009e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
801befc649cSMiklos Szeredi 		arg->valid |= FATTR_UID,    arg->uid = iattr->ia_uid;
8029e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
803befc649cSMiklos Szeredi 		arg->valid |= FATTR_GID,    arg->gid = iattr->ia_gid;
8049e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
805befc649cSMiklos Szeredi 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
8069e6268dbSMiklos Szeredi 	/* You can only _set_ these together (they may change by themselves) */
8079e6268dbSMiklos Szeredi 	if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
808befc649cSMiklos Szeredi 		arg->valid |= FATTR_ATIME | FATTR_MTIME;
809befc649cSMiklos Szeredi 		arg->atime = iattr->ia_atime.tv_sec;
810befc649cSMiklos Szeredi 		arg->mtime = iattr->ia_mtime.tv_sec;
8119e6268dbSMiklos Szeredi 	}
812befc649cSMiklos Szeredi 	if (ivalid & ATTR_FILE) {
813befc649cSMiklos Szeredi 		struct fuse_file *ff = iattr->ia_file->private_data;
814befc649cSMiklos Szeredi 		arg->valid |= FATTR_FH;
815befc649cSMiklos Szeredi 		arg->fh = ff->fh;
816befc649cSMiklos Szeredi 	}
8179e6268dbSMiklos Szeredi }
8189e6268dbSMiklos Szeredi 
8199e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
8209e6268dbSMiklos Szeredi {
8219e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
8229e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
8239e6268dbSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
8249e6268dbSMiklos Szeredi 	struct fuse_req *req;
8259e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
8269e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
8279e6268dbSMiklos Szeredi 	int err;
8289e6268dbSMiklos Szeredi 	int is_truncate = 0;
8299e6268dbSMiklos Szeredi 
8301e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
8311e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
8321e9a4ed9SMiklos Szeredi 		if (err)
8331e9a4ed9SMiklos Szeredi 			return err;
8341e9a4ed9SMiklos Szeredi 	}
8351e9a4ed9SMiklos Szeredi 
8369e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
8379e6268dbSMiklos Szeredi 		unsigned long limit;
8389e6268dbSMiklos Szeredi 		is_truncate = 1;
8399e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
8409e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
8419e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
8429e6268dbSMiklos Szeredi 			return -EFBIG;
8439e6268dbSMiklos Szeredi 		}
8449e6268dbSMiklos Szeredi 	}
8459e6268dbSMiklos Szeredi 
8469e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
8479e6268dbSMiklos Szeredi 	if (!req)
8487c352bdfSMiklos Szeredi 		return -EINTR;
8499e6268dbSMiklos Szeredi 
8509e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
851befc649cSMiklos Szeredi 	iattr_to_fattr(attr, &inarg);
8529e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
8539e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
8549e6268dbSMiklos Szeredi 	req->inode = inode;
8559e6268dbSMiklos Szeredi 	req->in.numargs = 1;
8569e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
8579e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
8589e6268dbSMiklos Szeredi 	req->out.numargs = 1;
8599e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
8609e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
8619e6268dbSMiklos Szeredi 	request_send(fc, req);
8629e6268dbSMiklos Szeredi 	err = req->out.h.error;
8639e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
8649e6268dbSMiklos Szeredi 	if (!err) {
8659e6268dbSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
8669e6268dbSMiklos Szeredi 			make_bad_inode(inode);
8679e6268dbSMiklos Szeredi 			err = -EIO;
8689e6268dbSMiklos Szeredi 		} else {
8699e6268dbSMiklos Szeredi 			if (is_truncate) {
8709e6268dbSMiklos Szeredi 				loff_t origsize = i_size_read(inode);
8719e6268dbSMiklos Szeredi 				i_size_write(inode, outarg.attr.size);
8729e6268dbSMiklos Szeredi 				if (origsize > outarg.attr.size)
8739e6268dbSMiklos Szeredi 					vmtruncate(inode, outarg.attr.size);
8749e6268dbSMiklos Szeredi 			}
8759e6268dbSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr);
8769e6268dbSMiklos Szeredi 			fi->i_time = time_to_jiffies(outarg.attr_valid,
8779e6268dbSMiklos Szeredi 						     outarg.attr_valid_nsec);
8789e6268dbSMiklos Szeredi 		}
8799e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
8809e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
8819e6268dbSMiklos Szeredi 
8829e6268dbSMiklos Szeredi 	return err;
8839e6268dbSMiklos Szeredi }
8849e6268dbSMiklos Szeredi 
885e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
886e5e5558eSMiklos Szeredi 			struct kstat *stat)
887e5e5558eSMiklos Szeredi {
888e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
889e5e5558eSMiklos Szeredi 	int err = fuse_revalidate(entry);
890e5e5558eSMiklos Szeredi 	if (!err)
891e5e5558eSMiklos Szeredi 		generic_fillattr(inode, stat);
892e5e5558eSMiklos Szeredi 
893e5e5558eSMiklos Szeredi 	return err;
894e5e5558eSMiklos Szeredi }
895e5e5558eSMiklos Szeredi 
89692a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
89792a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
89892a8780eSMiklos Szeredi {
89992a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
90092a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
90192a8780eSMiklos Szeredi 	struct fuse_req *req;
90292a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
90392a8780eSMiklos Szeredi 	int err;
90492a8780eSMiklos Szeredi 
90592a8780eSMiklos Szeredi 	if (size > FUSE_XATTR_SIZE_MAX)
90692a8780eSMiklos Szeredi 		return -E2BIG;
90792a8780eSMiklos Szeredi 
90892a8780eSMiklos Szeredi 	if (fc->no_setxattr)
90992a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
91092a8780eSMiklos Szeredi 
91192a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
91292a8780eSMiklos Szeredi 	if (!req)
9137c352bdfSMiklos Szeredi 		return -EINTR;
91492a8780eSMiklos Szeredi 
91592a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
91692a8780eSMiklos Szeredi 	inarg.size = size;
91792a8780eSMiklos Szeredi 	inarg.flags = flags;
91892a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
91992a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
92092a8780eSMiklos Szeredi 	req->inode = inode;
92192a8780eSMiklos Szeredi 	req->in.numargs = 3;
92292a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
92392a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
92492a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
92592a8780eSMiklos Szeredi 	req->in.args[1].value = name;
92692a8780eSMiklos Szeredi 	req->in.args[2].size = size;
92792a8780eSMiklos Szeredi 	req->in.args[2].value = value;
92892a8780eSMiklos Szeredi 	request_send(fc, req);
92992a8780eSMiklos Szeredi 	err = req->out.h.error;
93092a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
93192a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
93292a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
93392a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
93492a8780eSMiklos Szeredi 	}
93592a8780eSMiklos Szeredi 	return err;
93692a8780eSMiklos Szeredi }
93792a8780eSMiklos Szeredi 
93892a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
93992a8780eSMiklos Szeredi 			     void *value, size_t size)
94092a8780eSMiklos Szeredi {
94192a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
94292a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
94392a8780eSMiklos Szeredi 	struct fuse_req *req;
94492a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
94592a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
94692a8780eSMiklos Szeredi 	ssize_t ret;
94792a8780eSMiklos Szeredi 
94892a8780eSMiklos Szeredi 	if (fc->no_getxattr)
94992a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
95092a8780eSMiklos Szeredi 
95192a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
95292a8780eSMiklos Szeredi 	if (!req)
9537c352bdfSMiklos Szeredi 		return -EINTR;
95492a8780eSMiklos Szeredi 
95592a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
95692a8780eSMiklos Szeredi 	inarg.size = size;
95792a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
95892a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
95992a8780eSMiklos Szeredi 	req->inode = inode;
96092a8780eSMiklos Szeredi 	req->in.numargs = 2;
96192a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
96292a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
96392a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
96492a8780eSMiklos Szeredi 	req->in.args[1].value = name;
96592a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
96692a8780eSMiklos Szeredi 	req->out.numargs = 1;
96792a8780eSMiklos Szeredi 	if (size) {
96892a8780eSMiklos Szeredi 		req->out.argvar = 1;
96992a8780eSMiklos Szeredi 		req->out.args[0].size = size;
97092a8780eSMiklos Szeredi 		req->out.args[0].value = value;
97192a8780eSMiklos Szeredi 	} else {
97292a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
97392a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
97492a8780eSMiklos Szeredi 	}
97592a8780eSMiklos Szeredi 	request_send(fc, req);
97692a8780eSMiklos Szeredi 	ret = req->out.h.error;
97792a8780eSMiklos Szeredi 	if (!ret)
97892a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
97992a8780eSMiklos Szeredi 	else {
98092a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
98192a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
98292a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
98392a8780eSMiklos Szeredi 		}
98492a8780eSMiklos Szeredi 	}
98592a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
98692a8780eSMiklos Szeredi 	return ret;
98792a8780eSMiklos Szeredi }
98892a8780eSMiklos Szeredi 
98992a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
99092a8780eSMiklos Szeredi {
99192a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
99292a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
99392a8780eSMiklos Szeredi 	struct fuse_req *req;
99492a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
99592a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
99692a8780eSMiklos Szeredi 	ssize_t ret;
99792a8780eSMiklos Szeredi 
99892a8780eSMiklos Szeredi 	if (fc->no_listxattr)
99992a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
100092a8780eSMiklos Szeredi 
100192a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
100292a8780eSMiklos Szeredi 	if (!req)
10037c352bdfSMiklos Szeredi 		return -EINTR;
100492a8780eSMiklos Szeredi 
100592a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
100692a8780eSMiklos Szeredi 	inarg.size = size;
100792a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
100892a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
100992a8780eSMiklos Szeredi 	req->inode = inode;
101092a8780eSMiklos Szeredi 	req->in.numargs = 1;
101192a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
101292a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
101392a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
101492a8780eSMiklos Szeredi 	req->out.numargs = 1;
101592a8780eSMiklos Szeredi 	if (size) {
101692a8780eSMiklos Szeredi 		req->out.argvar = 1;
101792a8780eSMiklos Szeredi 		req->out.args[0].size = size;
101892a8780eSMiklos Szeredi 		req->out.args[0].value = list;
101992a8780eSMiklos Szeredi 	} else {
102092a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
102192a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
102292a8780eSMiklos Szeredi 	}
102392a8780eSMiklos Szeredi 	request_send(fc, req);
102492a8780eSMiklos Szeredi 	ret = req->out.h.error;
102592a8780eSMiklos Szeredi 	if (!ret)
102692a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
102792a8780eSMiklos Szeredi 	else {
102892a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
102992a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
103092a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
103192a8780eSMiklos Szeredi 		}
103292a8780eSMiklos Szeredi 	}
103392a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
103492a8780eSMiklos Szeredi 	return ret;
103592a8780eSMiklos Szeredi }
103692a8780eSMiklos Szeredi 
103792a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
103892a8780eSMiklos Szeredi {
103992a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
104092a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
104192a8780eSMiklos Szeredi 	struct fuse_req *req;
104292a8780eSMiklos Szeredi 	int err;
104392a8780eSMiklos Szeredi 
104492a8780eSMiklos Szeredi 	if (fc->no_removexattr)
104592a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
104692a8780eSMiklos Szeredi 
104792a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
104892a8780eSMiklos Szeredi 	if (!req)
10497c352bdfSMiklos Szeredi 		return -EINTR;
105092a8780eSMiklos Szeredi 
105192a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
105292a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
105392a8780eSMiklos Szeredi 	req->inode = inode;
105492a8780eSMiklos Szeredi 	req->in.numargs = 1;
105592a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
105692a8780eSMiklos Szeredi 	req->in.args[0].value = name;
105792a8780eSMiklos Szeredi 	request_send(fc, req);
105892a8780eSMiklos Szeredi 	err = req->out.h.error;
105992a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
106092a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
106192a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
106292a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
106392a8780eSMiklos Szeredi 	}
106492a8780eSMiklos Szeredi 	return err;
106592a8780eSMiklos Szeredi }
106692a8780eSMiklos Szeredi 
1067e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = {
1068e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
10699e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
10709e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
10719e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
10729e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
10739e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
10749e6268dbSMiklos Szeredi 	.link		= fuse_link,
10759e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
10769e6268dbSMiklos Szeredi 	.create		= fuse_create,
10779e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
1078e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1079e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
108092a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
108192a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
108292a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
108392a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1084e5e5558eSMiklos Szeredi };
1085e5e5558eSMiklos Szeredi 
1086e5e5558eSMiklos Szeredi static struct file_operations fuse_dir_operations = {
1087b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
1088e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
1089e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
1090e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
1091e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
109282547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
1093e5e5558eSMiklos Szeredi };
1094e5e5558eSMiklos Szeredi 
1095e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = {
10969e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1097e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1098e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
109992a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
110092a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
110192a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
110292a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1103e5e5558eSMiklos Szeredi };
1104e5e5558eSMiklos Szeredi 
1105e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = {
11069e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1107e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
1108e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
1109e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
1110e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
111192a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
111292a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
111392a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
111492a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1115e5e5558eSMiklos Szeredi };
1116e5e5558eSMiklos Szeredi 
1117e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
1118e5e5558eSMiklos Szeredi {
1119e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
1120e5e5558eSMiklos Szeredi }
1121e5e5558eSMiklos Szeredi 
1122e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
1123e5e5558eSMiklos Szeredi {
1124e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
1125e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
1126e5e5558eSMiklos Szeredi }
1127e5e5558eSMiklos Szeredi 
1128e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
1129e5e5558eSMiklos Szeredi {
1130e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
1131e5e5558eSMiklos Szeredi }
1132