xref: /openbmc/linux/fs/fuse/dir.c (revision f007d5c961448170d0ec2998b1a80eef054b6235)
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>
16fd72faacSMiklos Szeredi #include <linux/mount.h>
17e5e5558eSMiklos Szeredi 
18e5e5558eSMiklos Szeredi static inline unsigned long time_to_jiffies(unsigned long sec,
19e5e5558eSMiklos Szeredi 					    unsigned long nsec)
20e5e5558eSMiklos Szeredi {
21e5e5558eSMiklos Szeredi 	struct timespec ts = {sec, nsec};
22e5e5558eSMiklos Szeredi 	return jiffies + timespec_to_jiffies(&ts);
23e5e5558eSMiklos Szeredi }
24e5e5558eSMiklos Szeredi 
25e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
26e5e5558eSMiklos Szeredi 			     struct dentry *entry,
27e5e5558eSMiklos Szeredi 			     struct fuse_entry_out *outarg)
28e5e5558eSMiklos Szeredi {
29e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_LOOKUP;
30e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
31e5e5558eSMiklos Szeredi 	req->inode = dir;
32e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
33e5e5558eSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
34e5e5558eSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
35e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
36e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(struct fuse_entry_out);
37e5e5558eSMiklos Szeredi 	req->out.args[0].value = outarg;
38e5e5558eSMiklos Szeredi }
39e5e5558eSMiklos Szeredi 
40e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
41e5e5558eSMiklos Szeredi {
42e5e5558eSMiklos Szeredi 	if (!entry->d_inode || is_bad_inode(entry->d_inode))
43e5e5558eSMiklos Szeredi 		return 0;
44e5e5558eSMiklos Szeredi 	else if (time_after(jiffies, entry->d_time)) {
45e5e5558eSMiklos Szeredi 		int err;
46e5e5558eSMiklos Szeredi 		struct fuse_entry_out outarg;
47e5e5558eSMiklos Szeredi 		struct inode *inode = entry->d_inode;
48e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
49e5e5558eSMiklos Szeredi 		struct fuse_conn *fc = get_fuse_conn(inode);
507c352bdfSMiklos Szeredi 		struct fuse_req *req = fuse_get_request(fc);
51e5e5558eSMiklos Szeredi 		if (!req)
52e5e5558eSMiklos Szeredi 			return 0;
53e5e5558eSMiklos Szeredi 
54e5e5558eSMiklos Szeredi 		fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
557c352bdfSMiklos Szeredi 		request_send(fc, req);
56e5e5558eSMiklos Szeredi 		err = req->out.h.error;
579e6268dbSMiklos Szeredi 		if (!err) {
589e6268dbSMiklos Szeredi 			if (outarg.nodeid != get_node_id(inode)) {
599e6268dbSMiklos Szeredi 				fuse_send_forget(fc, req, outarg.nodeid, 1);
609e6268dbSMiklos Szeredi 				return 0;
619e6268dbSMiklos Szeredi 			}
629e6268dbSMiklos Szeredi 			fi->nlookup ++;
639e6268dbSMiklos Szeredi 		}
64e5e5558eSMiklos Szeredi 		fuse_put_request(fc, req);
659e6268dbSMiklos Szeredi 		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
66e5e5558eSMiklos Szeredi 			return 0;
67e5e5558eSMiklos Szeredi 
68e5e5558eSMiklos Szeredi 		fuse_change_attributes(inode, &outarg.attr);
69e5e5558eSMiklos Szeredi 		entry->d_time = time_to_jiffies(outarg.entry_valid,
70e5e5558eSMiklos Szeredi 						outarg.entry_valid_nsec);
71e5e5558eSMiklos Szeredi 		fi->i_time = time_to_jiffies(outarg.attr_valid,
72e5e5558eSMiklos Szeredi 					     outarg.attr_valid_nsec);
73e5e5558eSMiklos Szeredi 	}
74e5e5558eSMiklos Szeredi 	return 1;
75e5e5558eSMiklos Szeredi }
76e5e5558eSMiklos Szeredi 
77*f007d5c9SMiklos Szeredi static int dir_alias(struct inode *inode)
78*f007d5c9SMiklos Szeredi {
79*f007d5c9SMiklos Szeredi 	if (S_ISDIR(inode->i_mode)) {
80*f007d5c9SMiklos Szeredi 		/* Don't allow creating an alias to a directory  */
81*f007d5c9SMiklos Szeredi 		struct dentry *alias = d_find_alias(inode);
82*f007d5c9SMiklos Szeredi 		if (alias) {
83*f007d5c9SMiklos Szeredi 			dput(alias);
84*f007d5c9SMiklos Szeredi 			return 1;
85*f007d5c9SMiklos Szeredi 		}
86*f007d5c9SMiklos Szeredi 	}
87*f007d5c9SMiklos Szeredi 	return 0;
88*f007d5c9SMiklos Szeredi }
89*f007d5c9SMiklos Szeredi 
90e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = {
91e5e5558eSMiklos Szeredi 	.d_revalidate	= fuse_dentry_revalidate,
92e5e5558eSMiklos Szeredi };
93e5e5558eSMiklos Szeredi 
94e5e5558eSMiklos Szeredi static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
95e5e5558eSMiklos Szeredi 			    struct inode **inodep)
96e5e5558eSMiklos Szeredi {
97e5e5558eSMiklos Szeredi 	int err;
98e5e5558eSMiklos Szeredi 	struct fuse_entry_out outarg;
99e5e5558eSMiklos Szeredi 	struct inode *inode = NULL;
100e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
101e5e5558eSMiklos Szeredi 	struct fuse_req *req;
102e5e5558eSMiklos Szeredi 
103e5e5558eSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
104e5e5558eSMiklos Szeredi 		return -ENAMETOOLONG;
105e5e5558eSMiklos Szeredi 
106e5e5558eSMiklos Szeredi 	req = fuse_get_request(fc);
107e5e5558eSMiklos Szeredi 	if (!req)
1087c352bdfSMiklos Szeredi 		return -EINTR;
109e5e5558eSMiklos Szeredi 
110e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
111e5e5558eSMiklos Szeredi 	request_send(fc, req);
112e5e5558eSMiklos Szeredi 	err = req->out.h.error;
113ee4e5271SMiklos Szeredi 	if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID))
114ee4e5271SMiklos Szeredi 		err = -EIO;
115e5e5558eSMiklos Szeredi 	if (!err) {
116e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
1179e6268dbSMiklos Szeredi 				  &outarg.attr);
118e5e5558eSMiklos Szeredi 		if (!inode) {
1199e6268dbSMiklos Szeredi 			fuse_send_forget(fc, req, outarg.nodeid, 1);
120e5e5558eSMiklos Szeredi 			return -ENOMEM;
121e5e5558eSMiklos Szeredi 		}
122e5e5558eSMiklos Szeredi 	}
123e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
124e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
125e5e5558eSMiklos Szeredi 		return err;
126e5e5558eSMiklos Szeredi 
127e5e5558eSMiklos Szeredi 	if (inode) {
128e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
129e5e5558eSMiklos Szeredi 		entry->d_time =	time_to_jiffies(outarg.entry_valid,
130e5e5558eSMiklos Szeredi 						outarg.entry_valid_nsec);
131e5e5558eSMiklos Szeredi 		fi->i_time = time_to_jiffies(outarg.attr_valid,
132e5e5558eSMiklos Szeredi 					     outarg.attr_valid_nsec);
133e5e5558eSMiklos Szeredi 	}
134e5e5558eSMiklos Szeredi 
135e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
136e5e5558eSMiklos Szeredi 	*inodep = inode;
137e5e5558eSMiklos Szeredi 	return 0;
138e5e5558eSMiklos Szeredi }
139e5e5558eSMiklos Szeredi 
1409e6268dbSMiklos Szeredi void fuse_invalidate_attr(struct inode *inode)
1419e6268dbSMiklos Szeredi {
1429e6268dbSMiklos Szeredi 	get_fuse_inode(inode)->i_time = jiffies - 1;
1439e6268dbSMiklos Szeredi }
1449e6268dbSMiklos Szeredi 
1459e6268dbSMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry)
1469e6268dbSMiklos Szeredi {
1479e6268dbSMiklos Szeredi 	d_invalidate(entry);
1489e6268dbSMiklos Szeredi 	entry->d_time = jiffies - 1;
1499e6268dbSMiklos Szeredi }
1509e6268dbSMiklos Szeredi 
151fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
152fd72faacSMiklos Szeredi 			    struct nameidata *nd)
153fd72faacSMiklos Szeredi {
154fd72faacSMiklos Szeredi 	int err;
155fd72faacSMiklos Szeredi 	struct inode *inode;
156fd72faacSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
157fd72faacSMiklos Szeredi 	struct fuse_req *req;
158fd72faacSMiklos Szeredi 	struct fuse_open_in inarg;
159fd72faacSMiklos Szeredi 	struct fuse_open_out outopen;
160fd72faacSMiklos Szeredi 	struct fuse_entry_out outentry;
161fd72faacSMiklos Szeredi 	struct fuse_inode *fi;
162fd72faacSMiklos Szeredi 	struct fuse_file *ff;
163fd72faacSMiklos Szeredi 	struct file *file;
164fd72faacSMiklos Szeredi 	int flags = nd->intent.open.flags - 1;
165fd72faacSMiklos Szeredi 
166fd72faacSMiklos Szeredi 	err = -ENOSYS;
167fd72faacSMiklos Szeredi 	if (fc->no_create)
168fd72faacSMiklos Szeredi 		goto out;
169fd72faacSMiklos Szeredi 
170fd72faacSMiklos Szeredi 	err = -ENAMETOOLONG;
171fd72faacSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
172fd72faacSMiklos Szeredi 		goto out;
173fd72faacSMiklos Szeredi 
174fd72faacSMiklos Szeredi 	err = -EINTR;
175fd72faacSMiklos Szeredi 	req = fuse_get_request(fc);
176fd72faacSMiklos Szeredi 	if (!req)
177fd72faacSMiklos Szeredi 		goto out;
178fd72faacSMiklos Szeredi 
179fd72faacSMiklos Szeredi 	ff = fuse_file_alloc();
180fd72faacSMiklos Szeredi 	if (!ff)
181fd72faacSMiklos Szeredi 		goto out_put_request;
182fd72faacSMiklos Szeredi 
183fd72faacSMiklos Szeredi 	flags &= ~O_NOCTTY;
184fd72faacSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
185fd72faacSMiklos Szeredi 	inarg.flags = flags;
186fd72faacSMiklos Szeredi 	inarg.mode = mode;
187fd72faacSMiklos Szeredi 	req->in.h.opcode = FUSE_CREATE;
188fd72faacSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
189fd72faacSMiklos Szeredi 	req->inode = dir;
190fd72faacSMiklos Szeredi 	req->in.numargs = 2;
191fd72faacSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
192fd72faacSMiklos Szeredi 	req->in.args[0].value = &inarg;
193fd72faacSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
194fd72faacSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
195fd72faacSMiklos Szeredi 	req->out.numargs = 2;
196fd72faacSMiklos Szeredi 	req->out.args[0].size = sizeof(outentry);
197fd72faacSMiklos Szeredi 	req->out.args[0].value = &outentry;
198fd72faacSMiklos Szeredi 	req->out.args[1].size = sizeof(outopen);
199fd72faacSMiklos Szeredi 	req->out.args[1].value = &outopen;
200fd72faacSMiklos Szeredi 	request_send(fc, req);
201fd72faacSMiklos Szeredi 	err = req->out.h.error;
202fd72faacSMiklos Szeredi 	if (err) {
203fd72faacSMiklos Szeredi 		if (err == -ENOSYS)
204fd72faacSMiklos Szeredi 			fc->no_create = 1;
205fd72faacSMiklos Szeredi 		goto out_free_ff;
206fd72faacSMiklos Szeredi 	}
207fd72faacSMiklos Szeredi 
208fd72faacSMiklos Szeredi 	err = -EIO;
209fd72faacSMiklos Szeredi 	if (!S_ISREG(outentry.attr.mode))
210fd72faacSMiklos Szeredi 		goto out_free_ff;
211fd72faacSMiklos Szeredi 
212fd72faacSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
213fd72faacSMiklos Szeredi 			  &outentry.attr);
214fd72faacSMiklos Szeredi 	err = -ENOMEM;
215fd72faacSMiklos Szeredi 	if (!inode) {
216fd72faacSMiklos Szeredi 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
217fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
218fd72faacSMiklos Szeredi 		fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
219fd72faacSMiklos Szeredi 		goto out_put_request;
220fd72faacSMiklos Szeredi 	}
221fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
222fd72faacSMiklos Szeredi 	entry->d_time =	time_to_jiffies(outentry.entry_valid,
223fd72faacSMiklos Szeredi 					outentry.entry_valid_nsec);
224fd72faacSMiklos Szeredi 	fi = get_fuse_inode(inode);
225fd72faacSMiklos Szeredi 	fi->i_time = time_to_jiffies(outentry.attr_valid,
226fd72faacSMiklos Szeredi 				     outentry.attr_valid_nsec);
227fd72faacSMiklos Szeredi 
228fd72faacSMiklos Szeredi 	d_instantiate(entry, inode);
229fd72faacSMiklos Szeredi 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
230fd72faacSMiklos Szeredi 	if (IS_ERR(file)) {
231fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
232fd72faacSMiklos Szeredi 		fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
233fd72faacSMiklos Szeredi 		return PTR_ERR(file);
234fd72faacSMiklos Szeredi 	}
235fd72faacSMiklos Szeredi 	fuse_finish_open(inode, file, ff, &outopen);
236fd72faacSMiklos Szeredi 	return 0;
237fd72faacSMiklos Szeredi 
238fd72faacSMiklos Szeredi  out_free_ff:
239fd72faacSMiklos Szeredi 	fuse_file_free(ff);
240fd72faacSMiklos Szeredi  out_put_request:
241fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
242fd72faacSMiklos Szeredi  out:
243fd72faacSMiklos Szeredi 	return err;
244fd72faacSMiklos Szeredi }
245fd72faacSMiklos Szeredi 
2469e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
2479e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
2489e6268dbSMiklos Szeredi 			    int mode)
2499e6268dbSMiklos Szeredi {
2509e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
2519e6268dbSMiklos Szeredi 	struct inode *inode;
2529e6268dbSMiklos Szeredi 	struct fuse_inode *fi;
2539e6268dbSMiklos Szeredi 	int err;
2549e6268dbSMiklos Szeredi 
2559e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
2569e6268dbSMiklos Szeredi 	req->inode = dir;
2579e6268dbSMiklos Szeredi 	req->out.numargs = 1;
2589e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
2599e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
2609e6268dbSMiklos Szeredi 	request_send(fc, req);
2619e6268dbSMiklos Szeredi 	err = req->out.h.error;
2629e6268dbSMiklos Szeredi 	if (err) {
2639e6268dbSMiklos Szeredi 		fuse_put_request(fc, req);
2649e6268dbSMiklos Szeredi 		return err;
2659e6268dbSMiklos Szeredi 	}
266ee4e5271SMiklos Szeredi 	if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
267ee4e5271SMiklos Szeredi 		fuse_put_request(fc, req);
268ee4e5271SMiklos Szeredi 		return -EIO;
269ee4e5271SMiklos Szeredi 	}
2709e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
2719e6268dbSMiklos Szeredi 			  &outarg.attr);
2729e6268dbSMiklos Szeredi 	if (!inode) {
2739e6268dbSMiklos Szeredi 		fuse_send_forget(fc, req, outarg.nodeid, 1);
2749e6268dbSMiklos Szeredi 		return -ENOMEM;
2759e6268dbSMiklos Szeredi 	}
2769e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
2779e6268dbSMiklos Szeredi 
2789e6268dbSMiklos Szeredi 	/* Don't allow userspace to do really stupid things... */
279*f007d5c9SMiklos Szeredi 	if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
2809e6268dbSMiklos Szeredi 		iput(inode);
2819e6268dbSMiklos Szeredi 		return -EIO;
2829e6268dbSMiklos Szeredi 	}
2839e6268dbSMiklos Szeredi 
2849e6268dbSMiklos Szeredi 	entry->d_time = time_to_jiffies(outarg.entry_valid,
2859e6268dbSMiklos Szeredi 					outarg.entry_valid_nsec);
2869e6268dbSMiklos Szeredi 
2879e6268dbSMiklos Szeredi 	fi = get_fuse_inode(inode);
2889e6268dbSMiklos Szeredi 	fi->i_time = time_to_jiffies(outarg.attr_valid,
2899e6268dbSMiklos Szeredi 				     outarg.attr_valid_nsec);
2909e6268dbSMiklos Szeredi 
2919e6268dbSMiklos Szeredi 	d_instantiate(entry, inode);
2929e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
2939e6268dbSMiklos Szeredi 	return 0;
2949e6268dbSMiklos Szeredi }
2959e6268dbSMiklos Szeredi 
2969e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
2979e6268dbSMiklos Szeredi 		      dev_t rdev)
2989e6268dbSMiklos Szeredi {
2999e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
3009e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3019e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3029e6268dbSMiklos Szeredi 	if (!req)
3037c352bdfSMiklos Szeredi 		return -EINTR;
3049e6268dbSMiklos Szeredi 
3059e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3069e6268dbSMiklos Szeredi 	inarg.mode = mode;
3079e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
3089e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
3099e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3109e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3119e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3129e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
3139e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
3149e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
3159e6268dbSMiklos Szeredi }
3169e6268dbSMiklos Szeredi 
3179e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
3189e6268dbSMiklos Szeredi 		       struct nameidata *nd)
3199e6268dbSMiklos Szeredi {
320fd72faacSMiklos Szeredi 	if (nd && (nd->flags & LOOKUP_CREATE)) {
321fd72faacSMiklos Szeredi 		int err = fuse_create_open(dir, entry, mode, nd);
322fd72faacSMiklos Szeredi 		if (err != -ENOSYS)
323fd72faacSMiklos Szeredi 			return err;
324fd72faacSMiklos Szeredi 		/* Fall back on mknod */
325fd72faacSMiklos Szeredi 	}
3269e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
3279e6268dbSMiklos Szeredi }
3289e6268dbSMiklos Szeredi 
3299e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
3309e6268dbSMiklos Szeredi {
3319e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
3329e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3339e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3349e6268dbSMiklos Szeredi 	if (!req)
3357c352bdfSMiklos Szeredi 		return -EINTR;
3369e6268dbSMiklos Szeredi 
3379e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3389e6268dbSMiklos Szeredi 	inarg.mode = mode;
3399e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
3409e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3419e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3429e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3439e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
3449e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
3459e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
3469e6268dbSMiklos Szeredi }
3479e6268dbSMiklos Szeredi 
3489e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
3499e6268dbSMiklos Szeredi 			const char *link)
3509e6268dbSMiklos Szeredi {
3519e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3529e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
3539e6268dbSMiklos Szeredi 	struct fuse_req *req;
3549e6268dbSMiklos Szeredi 
3559e6268dbSMiklos Szeredi 	if (len > FUSE_SYMLINK_MAX)
3569e6268dbSMiklos Szeredi 		return -ENAMETOOLONG;
3579e6268dbSMiklos Szeredi 
3589e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
3599e6268dbSMiklos Szeredi 	if (!req)
3607c352bdfSMiklos Szeredi 		return -EINTR;
3619e6268dbSMiklos Szeredi 
3629e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SYMLINK;
3639e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3649e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
3659e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
3669e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
3679e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
3689e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
3699e6268dbSMiklos Szeredi }
3709e6268dbSMiklos Szeredi 
3719e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
3729e6268dbSMiklos Szeredi {
3739e6268dbSMiklos Szeredi 	int err;
3749e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3759e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3769e6268dbSMiklos Szeredi 	if (!req)
3777c352bdfSMiklos Szeredi 		return -EINTR;
3789e6268dbSMiklos Szeredi 
3799e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
3809e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
3819e6268dbSMiklos Szeredi 	req->inode = dir;
3829e6268dbSMiklos Szeredi 	req->in.numargs = 1;
3839e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
3849e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
3859e6268dbSMiklos Szeredi 	request_send(fc, req);
3869e6268dbSMiklos Szeredi 	err = req->out.h.error;
3879e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
3889e6268dbSMiklos Szeredi 	if (!err) {
3899e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
3909e6268dbSMiklos Szeredi 
3919e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
3929e6268dbSMiklos Szeredi                    the inode does have more links this will be
3939e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
3949e6268dbSMiklos Szeredi 		inode->i_nlink = 0;
3959e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
3969e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
3979e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
3989e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
3999e6268dbSMiklos Szeredi 	return err;
4009e6268dbSMiklos Szeredi }
4019e6268dbSMiklos Szeredi 
4029e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
4039e6268dbSMiklos Szeredi {
4049e6268dbSMiklos Szeredi 	int err;
4059e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
4069e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
4079e6268dbSMiklos Szeredi 	if (!req)
4087c352bdfSMiklos Szeredi 		return -EINTR;
4099e6268dbSMiklos Szeredi 
4109e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
4119e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
4129e6268dbSMiklos Szeredi 	req->inode = dir;
4139e6268dbSMiklos Szeredi 	req->in.numargs = 1;
4149e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
4159e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
4169e6268dbSMiklos Szeredi 	request_send(fc, req);
4179e6268dbSMiklos Szeredi 	err = req->out.h.error;
4189e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4199e6268dbSMiklos Szeredi 	if (!err) {
4209e6268dbSMiklos Szeredi 		entry->d_inode->i_nlink = 0;
4219e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
4229e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
4239e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
4249e6268dbSMiklos Szeredi 	return err;
4259e6268dbSMiklos Szeredi }
4269e6268dbSMiklos Szeredi 
4279e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
4289e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
4299e6268dbSMiklos Szeredi {
4309e6268dbSMiklos Szeredi 	int err;
4319e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
4329e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
4339e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
4349e6268dbSMiklos Szeredi 	if (!req)
4357c352bdfSMiklos Szeredi 		return -EINTR;
4369e6268dbSMiklos Szeredi 
4379e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4389e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
4399e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
4409e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
4419e6268dbSMiklos Szeredi 	req->inode = olddir;
4429e6268dbSMiklos Szeredi 	req->inode2 = newdir;
4439e6268dbSMiklos Szeredi 	req->in.numargs = 3;
4449e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4459e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4469e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
4479e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
4489e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
4499e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
4509e6268dbSMiklos Szeredi 	request_send(fc, req);
4519e6268dbSMiklos Szeredi 	err = req->out.h.error;
4529e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4539e6268dbSMiklos Szeredi 	if (!err) {
4549e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
4559e6268dbSMiklos Szeredi 		if (olddir != newdir)
4569e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
4579e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
4589e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
4599e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
4609e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
4619e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
4629e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
4639e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
4649e6268dbSMiklos Szeredi 		if (newent->d_inode)
4659e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
4669e6268dbSMiklos Szeredi 	}
4679e6268dbSMiklos Szeredi 
4689e6268dbSMiklos Szeredi 	return err;
4699e6268dbSMiklos Szeredi }
4709e6268dbSMiklos Szeredi 
4719e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
4729e6268dbSMiklos Szeredi 		     struct dentry *newent)
4739e6268dbSMiklos Szeredi {
4749e6268dbSMiklos Szeredi 	int err;
4759e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
4769e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
4779e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
4789e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
4799e6268dbSMiklos Szeredi 	if (!req)
4807c352bdfSMiklos Szeredi 		return -EINTR;
4819e6268dbSMiklos Szeredi 
4829e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4839e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
4849e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
4859e6268dbSMiklos Szeredi 	req->inode2 = inode;
4869e6268dbSMiklos Szeredi 	req->in.numargs = 2;
4879e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4889e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4899e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
4909e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
4919e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
4929e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
4939e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
4949e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
4959e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
4969e6268dbSMiklos Szeredi 	   etc.)
4979e6268dbSMiklos Szeredi 	*/
4989e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
4999e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
5009e6268dbSMiklos Szeredi 	return err;
5019e6268dbSMiklos Szeredi }
5029e6268dbSMiklos Szeredi 
503e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode)
504e5e5558eSMiklos Szeredi {
505e5e5558eSMiklos Szeredi 	int err;
506e5e5558eSMiklos Szeredi 	struct fuse_attr_out arg;
507e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
508e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
509e5e5558eSMiklos Szeredi 	if (!req)
5107c352bdfSMiklos Szeredi 		return -EINTR;
511e5e5558eSMiklos Szeredi 
512e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
513e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
514e5e5558eSMiklos Szeredi 	req->inode = inode;
515e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
516e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(arg);
517e5e5558eSMiklos Szeredi 	req->out.args[0].value = &arg;
518e5e5558eSMiklos Szeredi 	request_send(fc, req);
519e5e5558eSMiklos Szeredi 	err = req->out.h.error;
520e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
521e5e5558eSMiklos Szeredi 	if (!err) {
522e5e5558eSMiklos Szeredi 		if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
523e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
524e5e5558eSMiklos Szeredi 			err = -EIO;
525e5e5558eSMiklos Szeredi 		} else {
526e5e5558eSMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
527e5e5558eSMiklos Szeredi 			fuse_change_attributes(inode, &arg.attr);
528e5e5558eSMiklos Szeredi 			fi->i_time = time_to_jiffies(arg.attr_valid,
529e5e5558eSMiklos Szeredi 						     arg.attr_valid_nsec);
530e5e5558eSMiklos Szeredi 		}
531e5e5558eSMiklos Szeredi 	}
532e5e5558eSMiklos Szeredi 	return err;
533e5e5558eSMiklos Szeredi }
534e5e5558eSMiklos Szeredi 
53587729a55SMiklos Szeredi /*
53687729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
53787729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
53887729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
53987729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
54087729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
54187729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
54287729a55SMiklos Szeredi  * DoS against the requester.
54387729a55SMiklos Szeredi  *
54487729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
54587729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
54687729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
54787729a55SMiklos Szeredi  */
54887729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
54987729a55SMiklos Szeredi {
55087729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
55187729a55SMiklos Szeredi 		return 1;
55287729a55SMiklos Szeredi 
55387729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
55487729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
55587729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
55687729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
55787729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
55887729a55SMiklos Szeredi 	    task->gid == fc->group_id)
55987729a55SMiklos Szeredi 		return 1;
56087729a55SMiklos Szeredi 
56187729a55SMiklos Szeredi 	return 0;
56287729a55SMiklos Szeredi }
56387729a55SMiklos Szeredi 
564e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry)
565e5e5558eSMiklos Szeredi {
566e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
567e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
568e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
569e5e5558eSMiklos Szeredi 
57087729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
571e5e5558eSMiklos Szeredi 		return -EACCES;
57287729a55SMiklos Szeredi 	if (get_node_id(inode) != FUSE_ROOT_ID &&
57387729a55SMiklos Szeredi 	    time_before_eq(jiffies, fi->i_time))
574e5e5558eSMiklos Szeredi 		return 0;
575e5e5558eSMiklos Szeredi 
576e5e5558eSMiklos Szeredi 	return fuse_do_getattr(inode);
577e5e5558eSMiklos Szeredi }
578e5e5558eSMiklos Szeredi 
57931d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask)
58031d40d74SMiklos Szeredi {
58131d40d74SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
58231d40d74SMiklos Szeredi 	struct fuse_req *req;
58331d40d74SMiklos Szeredi 	struct fuse_access_in inarg;
58431d40d74SMiklos Szeredi 	int err;
58531d40d74SMiklos Szeredi 
58631d40d74SMiklos Szeredi 	if (fc->no_access)
58731d40d74SMiklos Szeredi 		return 0;
58831d40d74SMiklos Szeredi 
58931d40d74SMiklos Szeredi 	req = fuse_get_request(fc);
59031d40d74SMiklos Szeredi 	if (!req)
59131d40d74SMiklos Szeredi 		return -EINTR;
59231d40d74SMiklos Szeredi 
59331d40d74SMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
59431d40d74SMiklos Szeredi 	inarg.mask = mask;
59531d40d74SMiklos Szeredi 	req->in.h.opcode = FUSE_ACCESS;
59631d40d74SMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
59731d40d74SMiklos Szeredi 	req->inode = inode;
59831d40d74SMiklos Szeredi 	req->in.numargs = 1;
59931d40d74SMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
60031d40d74SMiklos Szeredi 	req->in.args[0].value = &inarg;
60131d40d74SMiklos Szeredi 	request_send(fc, req);
60231d40d74SMiklos Szeredi 	err = req->out.h.error;
60331d40d74SMiklos Szeredi 	fuse_put_request(fc, req);
60431d40d74SMiklos Szeredi 	if (err == -ENOSYS) {
60531d40d74SMiklos Szeredi 		fc->no_access = 1;
60631d40d74SMiklos Szeredi 		err = 0;
60731d40d74SMiklos Szeredi 	}
60831d40d74SMiklos Szeredi 	return err;
60931d40d74SMiklos Szeredi }
61031d40d74SMiklos Szeredi 
611e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
612e5e5558eSMiklos Szeredi {
613e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
614e5e5558eSMiklos Szeredi 
61587729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
616e5e5558eSMiklos Szeredi 		return -EACCES;
6171e9a4ed9SMiklos Szeredi 	else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
6181e9a4ed9SMiklos Szeredi 		int err = generic_permission(inode, mask, NULL);
6191e9a4ed9SMiklos Szeredi 
6201e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
6211e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
6221e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
6231e9a4ed9SMiklos Szeredi 		if (err == -EACCES) {
6241e9a4ed9SMiklos Szeredi 		 	err = fuse_do_getattr(inode);
6251e9a4ed9SMiklos Szeredi 			if (!err)
6261e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
6271e9a4ed9SMiklos Szeredi 		}
6281e9a4ed9SMiklos Szeredi 
6291e9a4ed9SMiklos Szeredi 		/* FIXME: Need some mechanism to revoke permissions:
6301e9a4ed9SMiklos Szeredi 		   currently if the filesystem suddenly changes the
6311e9a4ed9SMiklos Szeredi 		   file mode, we will not be informed about it, and
6321e9a4ed9SMiklos Szeredi 		   continue to allow access to the file/directory.
6331e9a4ed9SMiklos Szeredi 
6341e9a4ed9SMiklos Szeredi 		   This is actually not so grave, since the user can
6351e9a4ed9SMiklos Szeredi 		   simply keep access to the file/directory anyway by
6361e9a4ed9SMiklos Szeredi 		   keeping it open... */
6371e9a4ed9SMiklos Szeredi 
6381e9a4ed9SMiklos Szeredi 		return err;
6391e9a4ed9SMiklos Szeredi 	} else {
640e5e5558eSMiklos Szeredi 		int mode = inode->i_mode;
641e5e5558eSMiklos Szeredi 		if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
642e5e5558eSMiklos Szeredi 			return -EACCES;
64331d40d74SMiklos Szeredi 
64431d40d74SMiklos Szeredi 		if (nd && (nd->flags & LOOKUP_ACCESS))
64531d40d74SMiklos Szeredi 			return fuse_access(inode, mask);
646e5e5558eSMiklos Szeredi 		return 0;
647e5e5558eSMiklos Szeredi 	}
648e5e5558eSMiklos Szeredi }
649e5e5558eSMiklos Szeredi 
650e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
651e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
652e5e5558eSMiklos Szeredi {
653e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
654e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
655e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
656e5e5558eSMiklos Szeredi 		int over;
657e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
658e5e5558eSMiklos Szeredi 			return -EIO;
659e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
660e5e5558eSMiklos Szeredi 			break;
661e5e5558eSMiklos Szeredi 
662e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
663e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
664e5e5558eSMiklos Szeredi 		if (over)
665e5e5558eSMiklos Szeredi 			break;
666e5e5558eSMiklos Szeredi 
667e5e5558eSMiklos Szeredi 		buf += reclen;
668e5e5558eSMiklos Szeredi 		nbytes -= reclen;
669e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
670e5e5558eSMiklos Szeredi 	}
671e5e5558eSMiklos Szeredi 
672e5e5558eSMiklos Szeredi 	return 0;
673e5e5558eSMiklos Szeredi }
674e5e5558eSMiklos Szeredi 
67504730fefSMiklos Szeredi static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
67604730fefSMiklos Szeredi 				       struct inode *inode, loff_t pos,
67704730fefSMiklos Szeredi 				       size_t count)
678e5e5558eSMiklos Szeredi {
67904730fefSMiklos Szeredi 	return fuse_send_read_common(req, file, inode, pos, count, 1);
680e5e5558eSMiklos Szeredi }
681e5e5558eSMiklos Szeredi 
682e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
683e5e5558eSMiklos Szeredi {
68404730fefSMiklos Szeredi 	int err;
68504730fefSMiklos Szeredi 	size_t nbytes;
68604730fefSMiklos Szeredi 	struct page *page;
68704730fefSMiklos Szeredi 	struct inode *inode = file->f_dentry->d_inode;
68804730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
6897c352bdfSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
69004730fefSMiklos Szeredi 	if (!req)
69104730fefSMiklos Szeredi 		return -EINTR;
692e5e5558eSMiklos Szeredi 
69304730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
69404730fefSMiklos Szeredi 	if (!page) {
69504730fefSMiklos Szeredi 		fuse_put_request(fc, req);
696e5e5558eSMiklos Szeredi 		return -ENOMEM;
69704730fefSMiklos Szeredi 	}
69804730fefSMiklos Szeredi 	req->num_pages = 1;
69904730fefSMiklos Szeredi 	req->pages[0] = page;
70004730fefSMiklos Szeredi 	nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
70104730fefSMiklos Szeredi 	err = req->out.h.error;
70204730fefSMiklos Szeredi 	fuse_put_request(fc, req);
70304730fefSMiklos Szeredi 	if (!err)
70404730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
70504730fefSMiklos Szeredi 				    filldir);
706e5e5558eSMiklos Szeredi 
70704730fefSMiklos Szeredi 	__free_page(page);
708b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
70904730fefSMiklos Szeredi 	return err;
710e5e5558eSMiklos Szeredi }
711e5e5558eSMiklos Szeredi 
712e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
713e5e5558eSMiklos Szeredi {
714e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
715e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
716e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
717e5e5558eSMiklos Szeredi 	char *link;
718e5e5558eSMiklos Szeredi 
719e5e5558eSMiklos Szeredi 	if (!req)
7207c352bdfSMiklos Szeredi 		return ERR_PTR(-EINTR);
721e5e5558eSMiklos Szeredi 
722e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
723e5e5558eSMiklos Szeredi 	if (!link) {
724e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
725e5e5558eSMiklos Szeredi 		goto out;
726e5e5558eSMiklos Szeredi 	}
727e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
728e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
729e5e5558eSMiklos Szeredi 	req->inode = inode;
730e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
731e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
732e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
733e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
734e5e5558eSMiklos Szeredi 	request_send(fc, req);
735e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
736e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
737e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
738e5e5558eSMiklos Szeredi 	} else
739e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
740e5e5558eSMiklos Szeredi  out:
741e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
742b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
743e5e5558eSMiklos Szeredi 	return link;
744e5e5558eSMiklos Szeredi }
745e5e5558eSMiklos Szeredi 
746e5e5558eSMiklos Szeredi static void free_link(char *link)
747e5e5558eSMiklos Szeredi {
748e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
749e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
750e5e5558eSMiklos Szeredi }
751e5e5558eSMiklos Szeredi 
752e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
753e5e5558eSMiklos Szeredi {
754e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
755e5e5558eSMiklos Szeredi 	return NULL;
756e5e5558eSMiklos Szeredi }
757e5e5558eSMiklos Szeredi 
758e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
759e5e5558eSMiklos Szeredi {
760e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
761e5e5558eSMiklos Szeredi }
762e5e5558eSMiklos Szeredi 
763e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
764e5e5558eSMiklos Szeredi {
76504730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
766e5e5558eSMiklos Szeredi }
767e5e5558eSMiklos Szeredi 
768e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
769e5e5558eSMiklos Szeredi {
77004730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
771e5e5558eSMiklos Szeredi }
772e5e5558eSMiklos Szeredi 
77382547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
77482547981SMiklos Szeredi {
77582547981SMiklos Szeredi 	/* nfsd can call this with no file */
77682547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
77782547981SMiklos Szeredi }
77882547981SMiklos Szeredi 
779befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
7809e6268dbSMiklos Szeredi {
7819e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
7829e6268dbSMiklos Szeredi 
7839e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
784befc649cSMiklos Szeredi 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
7859e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
786befc649cSMiklos Szeredi 		arg->valid |= FATTR_UID,    arg->uid = iattr->ia_uid;
7879e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
788befc649cSMiklos Szeredi 		arg->valid |= FATTR_GID,    arg->gid = iattr->ia_gid;
7899e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
790befc649cSMiklos Szeredi 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
7919e6268dbSMiklos Szeredi 	/* You can only _set_ these together (they may change by themselves) */
7929e6268dbSMiklos Szeredi 	if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
793befc649cSMiklos Szeredi 		arg->valid |= FATTR_ATIME | FATTR_MTIME;
794befc649cSMiklos Szeredi 		arg->atime = iattr->ia_atime.tv_sec;
795befc649cSMiklos Szeredi 		arg->mtime = iattr->ia_mtime.tv_sec;
7969e6268dbSMiklos Szeredi 	}
797befc649cSMiklos Szeredi 	if (ivalid & ATTR_FILE) {
798befc649cSMiklos Szeredi 		struct fuse_file *ff = iattr->ia_file->private_data;
799befc649cSMiklos Szeredi 		arg->valid |= FATTR_FH;
800befc649cSMiklos Szeredi 		arg->fh = ff->fh;
801befc649cSMiklos Szeredi 	}
8029e6268dbSMiklos Szeredi }
8039e6268dbSMiklos Szeredi 
8049e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
8059e6268dbSMiklos Szeredi {
8069e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
8079e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
8089e6268dbSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
8099e6268dbSMiklos Szeredi 	struct fuse_req *req;
8109e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
8119e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
8129e6268dbSMiklos Szeredi 	int err;
8139e6268dbSMiklos Szeredi 	int is_truncate = 0;
8149e6268dbSMiklos Szeredi 
8151e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
8161e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
8171e9a4ed9SMiklos Szeredi 		if (err)
8181e9a4ed9SMiklos Szeredi 			return err;
8191e9a4ed9SMiklos Szeredi 	}
8201e9a4ed9SMiklos Szeredi 
8219e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
8229e6268dbSMiklos Szeredi 		unsigned long limit;
8239e6268dbSMiklos Szeredi 		is_truncate = 1;
8249e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
8259e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
8269e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
8279e6268dbSMiklos Szeredi 			return -EFBIG;
8289e6268dbSMiklos Szeredi 		}
8299e6268dbSMiklos Szeredi 	}
8309e6268dbSMiklos Szeredi 
8319e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
8329e6268dbSMiklos Szeredi 	if (!req)
8337c352bdfSMiklos Szeredi 		return -EINTR;
8349e6268dbSMiklos Szeredi 
8359e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
836befc649cSMiklos Szeredi 	iattr_to_fattr(attr, &inarg);
8379e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
8389e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
8399e6268dbSMiklos Szeredi 	req->inode = inode;
8409e6268dbSMiklos Szeredi 	req->in.numargs = 1;
8419e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
8429e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
8439e6268dbSMiklos Szeredi 	req->out.numargs = 1;
8449e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
8459e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
8469e6268dbSMiklos Szeredi 	request_send(fc, req);
8479e6268dbSMiklos Szeredi 	err = req->out.h.error;
8489e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
8499e6268dbSMiklos Szeredi 	if (!err) {
8509e6268dbSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
8519e6268dbSMiklos Szeredi 			make_bad_inode(inode);
8529e6268dbSMiklos Szeredi 			err = -EIO;
8539e6268dbSMiklos Szeredi 		} else {
8549e6268dbSMiklos Szeredi 			if (is_truncate) {
8559e6268dbSMiklos Szeredi 				loff_t origsize = i_size_read(inode);
8569e6268dbSMiklos Szeredi 				i_size_write(inode, outarg.attr.size);
8579e6268dbSMiklos Szeredi 				if (origsize > outarg.attr.size)
8589e6268dbSMiklos Szeredi 					vmtruncate(inode, outarg.attr.size);
8599e6268dbSMiklos Szeredi 			}
8609e6268dbSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr);
8619e6268dbSMiklos Szeredi 			fi->i_time = time_to_jiffies(outarg.attr_valid,
8629e6268dbSMiklos Szeredi 						     outarg.attr_valid_nsec);
8639e6268dbSMiklos Szeredi 		}
8649e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
8659e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
8669e6268dbSMiklos Szeredi 
8679e6268dbSMiklos Szeredi 	return err;
8689e6268dbSMiklos Szeredi }
8699e6268dbSMiklos Szeredi 
870e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
871e5e5558eSMiklos Szeredi 			struct kstat *stat)
872e5e5558eSMiklos Szeredi {
873e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
874e5e5558eSMiklos Szeredi 	int err = fuse_revalidate(entry);
875e5e5558eSMiklos Szeredi 	if (!err)
876e5e5558eSMiklos Szeredi 		generic_fillattr(inode, stat);
877e5e5558eSMiklos Szeredi 
878e5e5558eSMiklos Szeredi 	return err;
879e5e5558eSMiklos Szeredi }
880e5e5558eSMiklos Szeredi 
881e5e5558eSMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
882e5e5558eSMiklos Szeredi 				  struct nameidata *nd)
883e5e5558eSMiklos Szeredi {
884e5e5558eSMiklos Szeredi 	struct inode *inode;
885fd72faacSMiklos Szeredi 	int err;
886fd72faacSMiklos Szeredi 
887fd72faacSMiklos Szeredi 	err = fuse_lookup_iget(dir, entry, &inode);
888e5e5558eSMiklos Szeredi 	if (err)
889e5e5558eSMiklos Szeredi 		return ERR_PTR(err);
890*f007d5c9SMiklos Szeredi 	if (inode && dir_alias(inode)) {
891e5e5558eSMiklos Szeredi 		iput(inode);
892e5e5558eSMiklos Szeredi 		return ERR_PTR(-EIO);
893e5e5558eSMiklos Szeredi 	}
894f12ec440SMiklos Szeredi 	d_add(entry, inode);
895f12ec440SMiklos Szeredi 	return NULL;
896e5e5558eSMiklos Szeredi }
897e5e5558eSMiklos Szeredi 
89892a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
89992a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
90092a8780eSMiklos Szeredi {
90192a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
90292a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
90392a8780eSMiklos Szeredi 	struct fuse_req *req;
90492a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
90592a8780eSMiklos Szeredi 	int err;
90692a8780eSMiklos Szeredi 
90792a8780eSMiklos Szeredi 	if (size > FUSE_XATTR_SIZE_MAX)
90892a8780eSMiklos Szeredi 		return -E2BIG;
90992a8780eSMiklos Szeredi 
91092a8780eSMiklos Szeredi 	if (fc->no_setxattr)
91192a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
91292a8780eSMiklos Szeredi 
91392a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
91492a8780eSMiklos Szeredi 	if (!req)
9157c352bdfSMiklos Szeredi 		return -EINTR;
91692a8780eSMiklos Szeredi 
91792a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
91892a8780eSMiklos Szeredi 	inarg.size = size;
91992a8780eSMiklos Szeredi 	inarg.flags = flags;
92092a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
92192a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
92292a8780eSMiklos Szeredi 	req->inode = inode;
92392a8780eSMiklos Szeredi 	req->in.numargs = 3;
92492a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
92592a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
92692a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
92792a8780eSMiklos Szeredi 	req->in.args[1].value = name;
92892a8780eSMiklos Szeredi 	req->in.args[2].size = size;
92992a8780eSMiklos Szeredi 	req->in.args[2].value = value;
93092a8780eSMiklos Szeredi 	request_send(fc, req);
93192a8780eSMiklos Szeredi 	err = req->out.h.error;
93292a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
93392a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
93492a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
93592a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
93692a8780eSMiklos Szeredi 	}
93792a8780eSMiklos Szeredi 	return err;
93892a8780eSMiklos Szeredi }
93992a8780eSMiklos Szeredi 
94092a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
94192a8780eSMiklos Szeredi 			     void *value, size_t size)
94292a8780eSMiklos Szeredi {
94392a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
94492a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
94592a8780eSMiklos Szeredi 	struct fuse_req *req;
94692a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
94792a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
94892a8780eSMiklos Szeredi 	ssize_t ret;
94992a8780eSMiklos Szeredi 
95092a8780eSMiklos Szeredi 	if (fc->no_getxattr)
95192a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
95292a8780eSMiklos Szeredi 
95392a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
95492a8780eSMiklos Szeredi 	if (!req)
9557c352bdfSMiklos Szeredi 		return -EINTR;
95692a8780eSMiklos Szeredi 
95792a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
95892a8780eSMiklos Szeredi 	inarg.size = size;
95992a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
96092a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
96192a8780eSMiklos Szeredi 	req->inode = inode;
96292a8780eSMiklos Szeredi 	req->in.numargs = 2;
96392a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
96492a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
96592a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
96692a8780eSMiklos Szeredi 	req->in.args[1].value = name;
96792a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
96892a8780eSMiklos Szeredi 	req->out.numargs = 1;
96992a8780eSMiklos Szeredi 	if (size) {
97092a8780eSMiklos Szeredi 		req->out.argvar = 1;
97192a8780eSMiklos Szeredi 		req->out.args[0].size = size;
97292a8780eSMiklos Szeredi 		req->out.args[0].value = value;
97392a8780eSMiklos Szeredi 	} else {
97492a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
97592a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
97692a8780eSMiklos Szeredi 	}
97792a8780eSMiklos Szeredi 	request_send(fc, req);
97892a8780eSMiklos Szeredi 	ret = req->out.h.error;
97992a8780eSMiklos Szeredi 	if (!ret)
98092a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
98192a8780eSMiklos Szeredi 	else {
98292a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
98392a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
98492a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
98592a8780eSMiklos Szeredi 		}
98692a8780eSMiklos Szeredi 	}
98792a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
98892a8780eSMiklos Szeredi 	return ret;
98992a8780eSMiklos Szeredi }
99092a8780eSMiklos Szeredi 
99192a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
99292a8780eSMiklos Szeredi {
99392a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
99492a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
99592a8780eSMiklos Szeredi 	struct fuse_req *req;
99692a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
99792a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
99892a8780eSMiklos Szeredi 	ssize_t ret;
99992a8780eSMiklos Szeredi 
100092a8780eSMiklos Szeredi 	if (fc->no_listxattr)
100192a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
100292a8780eSMiklos Szeredi 
100392a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
100492a8780eSMiklos Szeredi 	if (!req)
10057c352bdfSMiklos Szeredi 		return -EINTR;
100692a8780eSMiklos Szeredi 
100792a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
100892a8780eSMiklos Szeredi 	inarg.size = size;
100992a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
101092a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
101192a8780eSMiklos Szeredi 	req->inode = inode;
101292a8780eSMiklos Szeredi 	req->in.numargs = 1;
101392a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
101492a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
101592a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
101692a8780eSMiklos Szeredi 	req->out.numargs = 1;
101792a8780eSMiklos Szeredi 	if (size) {
101892a8780eSMiklos Szeredi 		req->out.argvar = 1;
101992a8780eSMiklos Szeredi 		req->out.args[0].size = size;
102092a8780eSMiklos Szeredi 		req->out.args[0].value = list;
102192a8780eSMiklos Szeredi 	} else {
102292a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
102392a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
102492a8780eSMiklos Szeredi 	}
102592a8780eSMiklos Szeredi 	request_send(fc, req);
102692a8780eSMiklos Szeredi 	ret = req->out.h.error;
102792a8780eSMiklos Szeredi 	if (!ret)
102892a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
102992a8780eSMiklos Szeredi 	else {
103092a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
103192a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
103292a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
103392a8780eSMiklos Szeredi 		}
103492a8780eSMiklos Szeredi 	}
103592a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
103692a8780eSMiklos Szeredi 	return ret;
103792a8780eSMiklos Szeredi }
103892a8780eSMiklos Szeredi 
103992a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
104092a8780eSMiklos Szeredi {
104192a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
104292a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
104392a8780eSMiklos Szeredi 	struct fuse_req *req;
104492a8780eSMiklos Szeredi 	int err;
104592a8780eSMiklos Szeredi 
104692a8780eSMiklos Szeredi 	if (fc->no_removexattr)
104792a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
104892a8780eSMiklos Szeredi 
104992a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
105092a8780eSMiklos Szeredi 	if (!req)
10517c352bdfSMiklos Szeredi 		return -EINTR;
105292a8780eSMiklos Szeredi 
105392a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
105492a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
105592a8780eSMiklos Szeredi 	req->inode = inode;
105692a8780eSMiklos Szeredi 	req->in.numargs = 1;
105792a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
105892a8780eSMiklos Szeredi 	req->in.args[0].value = name;
105992a8780eSMiklos Szeredi 	request_send(fc, req);
106092a8780eSMiklos Szeredi 	err = req->out.h.error;
106192a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
106292a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
106392a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
106492a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
106592a8780eSMiklos Szeredi 	}
106692a8780eSMiklos Szeredi 	return err;
106792a8780eSMiklos Szeredi }
106892a8780eSMiklos Szeredi 
1069e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = {
1070e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
10719e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
10729e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
10739e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
10749e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
10759e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
10769e6268dbSMiklos Szeredi 	.link		= fuse_link,
10779e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
10789e6268dbSMiklos Szeredi 	.create		= fuse_create,
10799e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
1080e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1081e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
108292a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
108392a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
108492a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
108592a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1086e5e5558eSMiklos Szeredi };
1087e5e5558eSMiklos Szeredi 
1088e5e5558eSMiklos Szeredi static struct file_operations fuse_dir_operations = {
1089b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
1090e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
1091e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
1092e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
1093e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
109482547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
1095e5e5558eSMiklos Szeredi };
1096e5e5558eSMiklos Szeredi 
1097e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = {
10989e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1099e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1100e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
110192a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
110292a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
110392a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
110492a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1105e5e5558eSMiklos Szeredi };
1106e5e5558eSMiklos Szeredi 
1107e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = {
11089e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1109e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
1110e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
1111e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
1112e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
111392a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
111492a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
111592a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
111692a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1117e5e5558eSMiklos Szeredi };
1118e5e5558eSMiklos Szeredi 
1119e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
1120e5e5558eSMiklos Szeredi {
1121e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
1122e5e5558eSMiklos Szeredi }
1123e5e5558eSMiklos Szeredi 
1124e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
1125e5e5558eSMiklos Szeredi {
1126e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
1127e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
1128e5e5558eSMiklos Szeredi }
1129e5e5558eSMiklos Szeredi 
1130e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
1131e5e5558eSMiklos Szeredi {
1132e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
1133e5e5558eSMiklos Szeredi }
1134