xref: /openbmc/linux/fs/fuse/dir.c (revision ce71ec36840368b877fb63bd14c8e67ab62d08b1)
1e5e5558eSMiklos Szeredi /*
2e5e5558eSMiklos Szeredi   FUSE: Filesystem in Userspace
351eb01e7SMiklos Szeredi   Copyright (C) 2001-2006  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 
170a0898cfSMiklos Szeredi #if BITS_PER_LONG >= 64
180a0898cfSMiklos Szeredi static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
190a0898cfSMiklos Szeredi {
200a0898cfSMiklos Szeredi 	entry->d_time = time;
210a0898cfSMiklos Szeredi }
220a0898cfSMiklos Szeredi 
230a0898cfSMiklos Szeredi static inline u64 fuse_dentry_time(struct dentry *entry)
240a0898cfSMiklos Szeredi {
250a0898cfSMiklos Szeredi 	return entry->d_time;
260a0898cfSMiklos Szeredi }
270a0898cfSMiklos Szeredi #else
280a0898cfSMiklos Szeredi /*
290a0898cfSMiklos Szeredi  * On 32 bit archs store the high 32 bits of time in d_fsdata
300a0898cfSMiklos Szeredi  */
310a0898cfSMiklos Szeredi static void fuse_dentry_settime(struct dentry *entry, u64 time)
320a0898cfSMiklos Szeredi {
330a0898cfSMiklos Szeredi 	entry->d_time = time;
340a0898cfSMiklos Szeredi 	entry->d_fsdata = (void *) (unsigned long) (time >> 32);
350a0898cfSMiklos Szeredi }
360a0898cfSMiklos Szeredi 
370a0898cfSMiklos Szeredi static u64 fuse_dentry_time(struct dentry *entry)
380a0898cfSMiklos Szeredi {
390a0898cfSMiklos Szeredi 	return (u64) entry->d_time +
400a0898cfSMiklos Szeredi 		((u64) (unsigned long) entry->d_fsdata << 32);
410a0898cfSMiklos Szeredi }
420a0898cfSMiklos Szeredi #endif
430a0898cfSMiklos Szeredi 
446f9f1180SMiklos Szeredi /*
456f9f1180SMiklos Szeredi  * FUSE caches dentries and attributes with separate timeout.  The
466f9f1180SMiklos Szeredi  * time in jiffies until the dentry/attributes are valid is stored in
476f9f1180SMiklos Szeredi  * dentry->d_time and fuse_inode->i_time respectively.
486f9f1180SMiklos Szeredi  */
496f9f1180SMiklos Szeredi 
506f9f1180SMiklos Szeredi /*
516f9f1180SMiklos Szeredi  * Calculate the time in jiffies until a dentry/attributes are valid
526f9f1180SMiklos Szeredi  */
530a0898cfSMiklos Szeredi static u64 time_to_jiffies(unsigned long sec, unsigned long nsec)
54e5e5558eSMiklos Szeredi {
55685d16ddSMiklos Szeredi 	if (sec || nsec) {
56e5e5558eSMiklos Szeredi 		struct timespec ts = {sec, nsec};
570a0898cfSMiklos Szeredi 		return get_jiffies_64() + timespec_to_jiffies(&ts);
58685d16ddSMiklos Szeredi 	} else
590a0898cfSMiklos Szeredi 		return 0;
60e5e5558eSMiklos Szeredi }
61e5e5558eSMiklos Szeredi 
626f9f1180SMiklos Szeredi /*
636f9f1180SMiklos Szeredi  * Set dentry and possibly attribute timeouts from the lookup/mk*
646f9f1180SMiklos Szeredi  * replies
656f9f1180SMiklos Szeredi  */
660aa7c699SMiklos Szeredi static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
670aa7c699SMiklos Szeredi {
680a0898cfSMiklos Szeredi 	fuse_dentry_settime(entry,
690a0898cfSMiklos Szeredi 		time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
708cbdf1e6SMiklos Szeredi 	if (entry->d_inode)
718cbdf1e6SMiklos Szeredi 		get_fuse_inode(entry->d_inode)->i_time =
728cbdf1e6SMiklos Szeredi 			time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
738cbdf1e6SMiklos Szeredi }
748cbdf1e6SMiklos Szeredi 
756f9f1180SMiklos Szeredi /*
766f9f1180SMiklos Szeredi  * Mark the attributes as stale, so that at the next call to
776f9f1180SMiklos Szeredi  * ->getattr() they will be fetched from userspace
786f9f1180SMiklos Szeredi  */
798cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode)
808cbdf1e6SMiklos Szeredi {
810a0898cfSMiklos Szeredi 	get_fuse_inode(inode)->i_time = 0;
828cbdf1e6SMiklos Szeredi }
838cbdf1e6SMiklos Szeredi 
846f9f1180SMiklos Szeredi /*
856f9f1180SMiklos Szeredi  * Just mark the entry as stale, so that a next attempt to look it up
866f9f1180SMiklos Szeredi  * will result in a new lookup call to userspace
876f9f1180SMiklos Szeredi  *
886f9f1180SMiklos Szeredi  * This is called when a dentry is about to become negative and the
896f9f1180SMiklos Szeredi  * timeout is unknown (unlink, rmdir, rename and in some cases
906f9f1180SMiklos Szeredi  * lookup)
916f9f1180SMiklos Szeredi  */
928cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry_cache(struct dentry *entry)
938cbdf1e6SMiklos Szeredi {
940a0898cfSMiklos Szeredi 	fuse_dentry_settime(entry, 0);
958cbdf1e6SMiklos Szeredi }
968cbdf1e6SMiklos Szeredi 
976f9f1180SMiklos Szeredi /*
986f9f1180SMiklos Szeredi  * Same as fuse_invalidate_entry_cache(), but also try to remove the
996f9f1180SMiklos Szeredi  * dentry from the hash
1006f9f1180SMiklos Szeredi  */
1018cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry)
1028cbdf1e6SMiklos Szeredi {
1038cbdf1e6SMiklos Szeredi 	d_invalidate(entry);
1048cbdf1e6SMiklos Szeredi 	fuse_invalidate_entry_cache(entry);
1050aa7c699SMiklos Szeredi }
1060aa7c699SMiklos Szeredi 
107e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
108e5e5558eSMiklos Szeredi 			     struct dentry *entry,
109e5e5558eSMiklos Szeredi 			     struct fuse_entry_out *outarg)
110e5e5558eSMiklos Szeredi {
111e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_LOOKUP;
112e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
113e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
114e5e5558eSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
115e5e5558eSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
116e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
117e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(struct fuse_entry_out);
118e5e5558eSMiklos Szeredi 	req->out.args[0].value = outarg;
119e5e5558eSMiklos Szeredi }
120e5e5558eSMiklos Szeredi 
1216f9f1180SMiklos Szeredi /*
1226f9f1180SMiklos Szeredi  * Check whether the dentry is still valid
1236f9f1180SMiklos Szeredi  *
1246f9f1180SMiklos Szeredi  * If the entry validity timeout has expired and the dentry is
1256f9f1180SMiklos Szeredi  * positive, try to redo the lookup.  If the lookup results in a
1266f9f1180SMiklos Szeredi  * different inode, then let the VFS invalidate the dentry and redo
1276f9f1180SMiklos Szeredi  * the lookup once more.  If the lookup results in the same inode,
1286f9f1180SMiklos Szeredi  * then refresh the attributes, timeouts and mark the dentry valid.
1296f9f1180SMiklos Szeredi  */
130e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
131e5e5558eSMiklos Szeredi {
1328cbdf1e6SMiklos Szeredi 	struct inode *inode = entry->d_inode;
1338cbdf1e6SMiklos Szeredi 
1348cbdf1e6SMiklos Szeredi 	if (inode && is_bad_inode(inode))
135e5e5558eSMiklos Szeredi 		return 0;
1360a0898cfSMiklos Szeredi 	else if (fuse_dentry_time(entry) < get_jiffies_64()) {
137e5e5558eSMiklos Szeredi 		int err;
138e5e5558eSMiklos Szeredi 		struct fuse_entry_out outarg;
1398cbdf1e6SMiklos Szeredi 		struct fuse_conn *fc;
1408cbdf1e6SMiklos Szeredi 		struct fuse_req *req;
1418cbdf1e6SMiklos Szeredi 
1426f9f1180SMiklos Szeredi 		/* Doesn't hurt to "reset" the validity timeout */
1438cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
14450322fe7SMiklos Szeredi 
14550322fe7SMiklos Szeredi 		/* For negative dentries, always do a fresh lookup */
1468cbdf1e6SMiklos Szeredi 		if (!inode)
1478cbdf1e6SMiklos Szeredi 			return 0;
1488cbdf1e6SMiklos Szeredi 
1498cbdf1e6SMiklos Szeredi 		fc = get_fuse_conn(inode);
150ce1d5a49SMiklos Szeredi 		req = fuse_get_req(fc);
151ce1d5a49SMiklos Szeredi 		if (IS_ERR(req))
152e5e5558eSMiklos Szeredi 			return 0;
153e5e5558eSMiklos Szeredi 
154e5e5558eSMiklos Szeredi 		fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
1557c352bdfSMiklos Szeredi 		request_send(fc, req);
156e5e5558eSMiklos Szeredi 		err = req->out.h.error;
15750322fe7SMiklos Szeredi 		/* Zero nodeid is same as -ENOENT */
15850322fe7SMiklos Szeredi 		if (!err && !outarg.nodeid)
15950322fe7SMiklos Szeredi 			err = -ENOENT;
1609e6268dbSMiklos Szeredi 		if (!err) {
1618cbdf1e6SMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
1629e6268dbSMiklos Szeredi 			if (outarg.nodeid != get_node_id(inode)) {
1639e6268dbSMiklos Szeredi 				fuse_send_forget(fc, req, outarg.nodeid, 1);
1649e6268dbSMiklos Szeredi 				return 0;
1659e6268dbSMiklos Szeredi 			}
1669e6268dbSMiklos Szeredi 			fi->nlookup ++;
1679e6268dbSMiklos Szeredi 		}
168e5e5558eSMiklos Szeredi 		fuse_put_request(fc, req);
1699e6268dbSMiklos Szeredi 		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
170e5e5558eSMiklos Szeredi 			return 0;
171e5e5558eSMiklos Szeredi 
172e5e5558eSMiklos Szeredi 		fuse_change_attributes(inode, &outarg.attr);
1730aa7c699SMiklos Szeredi 		fuse_change_timeout(entry, &outarg);
174e5e5558eSMiklos Szeredi 	}
175e5e5558eSMiklos Szeredi 	return 1;
176e5e5558eSMiklos Szeredi }
177e5e5558eSMiklos Szeredi 
1786f9f1180SMiklos Szeredi /*
1796f9f1180SMiklos Szeredi  * Check if there's already a hashed alias of this directory inode.
1806f9f1180SMiklos Szeredi  * If yes, then lookup and mkdir must not create a new alias.
1816f9f1180SMiklos Szeredi  */
182f007d5c9SMiklos Szeredi static int dir_alias(struct inode *inode)
183f007d5c9SMiklos Szeredi {
184f007d5c9SMiklos Szeredi 	if (S_ISDIR(inode->i_mode)) {
185f007d5c9SMiklos Szeredi 		struct dentry *alias = d_find_alias(inode);
186f007d5c9SMiklos Szeredi 		if (alias) {
187f007d5c9SMiklos Szeredi 			dput(alias);
188f007d5c9SMiklos Szeredi 			return 1;
189f007d5c9SMiklos Szeredi 		}
190f007d5c9SMiklos Szeredi 	}
191f007d5c9SMiklos Szeredi 	return 0;
192f007d5c9SMiklos Szeredi }
193f007d5c9SMiklos Szeredi 
1948bfc016dSMiklos Szeredi static int invalid_nodeid(u64 nodeid)
1952827d0b2SMiklos Szeredi {
1962827d0b2SMiklos Szeredi 	return !nodeid || nodeid == FUSE_ROOT_ID;
1972827d0b2SMiklos Szeredi }
1982827d0b2SMiklos Szeredi 
199e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = {
200e5e5558eSMiklos Szeredi 	.d_revalidate	= fuse_dentry_revalidate,
201e5e5558eSMiklos Szeredi };
202e5e5558eSMiklos Szeredi 
2038bfc016dSMiklos Szeredi static int valid_mode(int m)
20439ee059aSMiklos Szeredi {
20539ee059aSMiklos Szeredi 	return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
20639ee059aSMiklos Szeredi 		S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
20739ee059aSMiklos Szeredi }
20839ee059aSMiklos Szeredi 
2090aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
2100aa7c699SMiklos Szeredi 				  struct nameidata *nd)
211e5e5558eSMiklos Szeredi {
212e5e5558eSMiklos Szeredi 	int err;
213e5e5558eSMiklos Szeredi 	struct fuse_entry_out outarg;
214e5e5558eSMiklos Szeredi 	struct inode *inode = NULL;
215e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
216e5e5558eSMiklos Szeredi 	struct fuse_req *req;
217e5e5558eSMiklos Szeredi 
218e5e5558eSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
2190aa7c699SMiklos Szeredi 		return ERR_PTR(-ENAMETOOLONG);
220e5e5558eSMiklos Szeredi 
221ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
222ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
223ce1d5a49SMiklos Szeredi 		return ERR_PTR(PTR_ERR(req));
224e5e5558eSMiklos Szeredi 
225e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
226e5e5558eSMiklos Szeredi 	request_send(fc, req);
227e5e5558eSMiklos Szeredi 	err = req->out.h.error;
22850322fe7SMiklos Szeredi 	/* Zero nodeid is same as -ENOENT, but with valid timeout */
22950322fe7SMiklos Szeredi 	if (!err && outarg.nodeid &&
23050322fe7SMiklos Szeredi 	    (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode)))
231ee4e5271SMiklos Szeredi 		err = -EIO;
2328cbdf1e6SMiklos Szeredi 	if (!err && outarg.nodeid) {
233e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
2349e6268dbSMiklos Szeredi 				  &outarg.attr);
235e5e5558eSMiklos Szeredi 		if (!inode) {
2369e6268dbSMiklos Szeredi 			fuse_send_forget(fc, req, outarg.nodeid, 1);
2370aa7c699SMiklos Szeredi 			return ERR_PTR(-ENOMEM);
238e5e5558eSMiklos Szeredi 		}
239e5e5558eSMiklos Szeredi 	}
240e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
241e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
2420aa7c699SMiklos Szeredi 		return ERR_PTR(err);
243e5e5558eSMiklos Szeredi 
2440aa7c699SMiklos Szeredi 	if (inode && dir_alias(inode)) {
2450aa7c699SMiklos Szeredi 		iput(inode);
2460aa7c699SMiklos Szeredi 		return ERR_PTR(-EIO);
247e5e5558eSMiklos Szeredi 	}
2480aa7c699SMiklos Szeredi 	d_add(entry, inode);
249e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
2508cbdf1e6SMiklos Szeredi 	if (!err)
2510aa7c699SMiklos Szeredi 		fuse_change_timeout(entry, &outarg);
2528cbdf1e6SMiklos Szeredi 	else
2538cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
2540aa7c699SMiklos Szeredi 	return NULL;
255e5e5558eSMiklos Szeredi }
256e5e5558eSMiklos Szeredi 
2576f9f1180SMiklos Szeredi /*
25851eb01e7SMiklos Szeredi  * Synchronous release for the case when something goes wrong in CREATE_OPEN
25951eb01e7SMiklos Szeredi  */
26051eb01e7SMiklos Szeredi static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
26151eb01e7SMiklos Szeredi 			      u64 nodeid, int flags)
26251eb01e7SMiklos Szeredi {
26351eb01e7SMiklos Szeredi 	struct fuse_req *req;
26451eb01e7SMiklos Szeredi 
26551eb01e7SMiklos Szeredi 	req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
26651eb01e7SMiklos Szeredi 	req->force = 1;
26751eb01e7SMiklos Szeredi 	request_send(fc, req);
26851eb01e7SMiklos Szeredi 	fuse_put_request(fc, req);
26951eb01e7SMiklos Szeredi }
27051eb01e7SMiklos Szeredi 
27151eb01e7SMiklos Szeredi /*
2726f9f1180SMiklos Szeredi  * Atomic create+open operation
2736f9f1180SMiklos Szeredi  *
2746f9f1180SMiklos Szeredi  * If the filesystem doesn't support this, then fall back to separate
2756f9f1180SMiklos Szeredi  * 'mknod' + 'open' requests.
2766f9f1180SMiklos Szeredi  */
277fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
278fd72faacSMiklos Szeredi 			    struct nameidata *nd)
279fd72faacSMiklos Szeredi {
280fd72faacSMiklos Szeredi 	int err;
281fd72faacSMiklos Szeredi 	struct inode *inode;
282fd72faacSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
283fd72faacSMiklos Szeredi 	struct fuse_req *req;
28451eb01e7SMiklos Szeredi 	struct fuse_req *forget_req;
285fd72faacSMiklos Szeredi 	struct fuse_open_in inarg;
286fd72faacSMiklos Szeredi 	struct fuse_open_out outopen;
287fd72faacSMiklos Szeredi 	struct fuse_entry_out outentry;
288fd72faacSMiklos Szeredi 	struct fuse_file *ff;
289fd72faacSMiklos Szeredi 	struct file *file;
290fd72faacSMiklos Szeredi 	int flags = nd->intent.open.flags - 1;
291fd72faacSMiklos Szeredi 
292fd72faacSMiklos Szeredi 	if (fc->no_create)
293ce1d5a49SMiklos Szeredi 		return -ENOSYS;
294fd72faacSMiklos Szeredi 
29551eb01e7SMiklos Szeredi 	forget_req = fuse_get_req(fc);
29651eb01e7SMiklos Szeredi 	if (IS_ERR(forget_req))
29751eb01e7SMiklos Szeredi 		return PTR_ERR(forget_req);
29851eb01e7SMiklos Szeredi 
299ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
30051eb01e7SMiklos Szeredi 	err = PTR_ERR(req);
301ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
30251eb01e7SMiklos Szeredi 		goto out_put_forget_req;
303fd72faacSMiklos Szeredi 
304ce1d5a49SMiklos Szeredi 	err = -ENOMEM;
305fd72faacSMiklos Szeredi 	ff = fuse_file_alloc();
306fd72faacSMiklos Szeredi 	if (!ff)
307fd72faacSMiklos Szeredi 		goto out_put_request;
308fd72faacSMiklos Szeredi 
309fd72faacSMiklos Szeredi 	flags &= ~O_NOCTTY;
310fd72faacSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
311fd72faacSMiklos Szeredi 	inarg.flags = flags;
312fd72faacSMiklos Szeredi 	inarg.mode = mode;
313fd72faacSMiklos Szeredi 	req->in.h.opcode = FUSE_CREATE;
314fd72faacSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
315fd72faacSMiklos Szeredi 	req->in.numargs = 2;
316fd72faacSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
317fd72faacSMiklos Szeredi 	req->in.args[0].value = &inarg;
318fd72faacSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
319fd72faacSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
320fd72faacSMiklos Szeredi 	req->out.numargs = 2;
321fd72faacSMiklos Szeredi 	req->out.args[0].size = sizeof(outentry);
322fd72faacSMiklos Szeredi 	req->out.args[0].value = &outentry;
323fd72faacSMiklos Szeredi 	req->out.args[1].size = sizeof(outopen);
324fd72faacSMiklos Szeredi 	req->out.args[1].value = &outopen;
325fd72faacSMiklos Szeredi 	request_send(fc, req);
326fd72faacSMiklos Szeredi 	err = req->out.h.error;
327fd72faacSMiklos Szeredi 	if (err) {
328fd72faacSMiklos Szeredi 		if (err == -ENOSYS)
329fd72faacSMiklos Szeredi 			fc->no_create = 1;
330fd72faacSMiklos Szeredi 		goto out_free_ff;
331fd72faacSMiklos Szeredi 	}
332fd72faacSMiklos Szeredi 
333fd72faacSMiklos Szeredi 	err = -EIO;
3342827d0b2SMiklos Szeredi 	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
335fd72faacSMiklos Szeredi 		goto out_free_ff;
336fd72faacSMiklos Szeredi 
33751eb01e7SMiklos Szeredi 	fuse_put_request(fc, req);
338fd72faacSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
339fd72faacSMiklos Szeredi 			  &outentry.attr);
340fd72faacSMiklos Szeredi 	if (!inode) {
341fd72faacSMiklos Szeredi 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
342fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
34351eb01e7SMiklos Szeredi 		fuse_sync_release(fc, ff, outentry.nodeid, flags);
34451eb01e7SMiklos Szeredi 		fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
34551eb01e7SMiklos Szeredi 		return -ENOMEM;
346fd72faacSMiklos Szeredi 	}
34751eb01e7SMiklos Szeredi 	fuse_put_request(fc, forget_req);
348fd72faacSMiklos Szeredi 	d_instantiate(entry, inode);
3490aa7c699SMiklos Szeredi 	fuse_change_timeout(entry, &outentry);
350fd72faacSMiklos Szeredi 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
351fd72faacSMiklos Szeredi 	if (IS_ERR(file)) {
352fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
35351eb01e7SMiklos Szeredi 		fuse_sync_release(fc, ff, outentry.nodeid, flags);
354fd72faacSMiklos Szeredi 		return PTR_ERR(file);
355fd72faacSMiklos Szeredi 	}
356fd72faacSMiklos Szeredi 	fuse_finish_open(inode, file, ff, &outopen);
357fd72faacSMiklos Szeredi 	return 0;
358fd72faacSMiklos Szeredi 
359fd72faacSMiklos Szeredi  out_free_ff:
360fd72faacSMiklos Szeredi 	fuse_file_free(ff);
361fd72faacSMiklos Szeredi  out_put_request:
362fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
36351eb01e7SMiklos Szeredi  out_put_forget_req:
36451eb01e7SMiklos Szeredi 	fuse_put_request(fc, forget_req);
365fd72faacSMiklos Szeredi 	return err;
366fd72faacSMiklos Szeredi }
367fd72faacSMiklos Szeredi 
3686f9f1180SMiklos Szeredi /*
3696f9f1180SMiklos Szeredi  * Code shared between mknod, mkdir, symlink and link
3706f9f1180SMiklos Szeredi  */
3719e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
3729e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
3739e6268dbSMiklos Szeredi 			    int mode)
3749e6268dbSMiklos Szeredi {
3759e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
3769e6268dbSMiklos Szeredi 	struct inode *inode;
3779e6268dbSMiklos Szeredi 	int err;
3789e6268dbSMiklos Szeredi 
3799e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
3809e6268dbSMiklos Szeredi 	req->out.numargs = 1;
3819e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
3829e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
3839e6268dbSMiklos Szeredi 	request_send(fc, req);
3849e6268dbSMiklos Szeredi 	err = req->out.h.error;
3859e6268dbSMiklos Szeredi 	if (err) {
3869e6268dbSMiklos Szeredi 		fuse_put_request(fc, req);
3879e6268dbSMiklos Szeredi 		return err;
3889e6268dbSMiklos Szeredi 	}
38939ee059aSMiklos Szeredi 	err = -EIO;
39039ee059aSMiklos Szeredi 	if (invalid_nodeid(outarg.nodeid))
39139ee059aSMiklos Szeredi 		goto out_put_request;
39239ee059aSMiklos Szeredi 
39339ee059aSMiklos Szeredi 	if ((outarg.attr.mode ^ mode) & S_IFMT)
39439ee059aSMiklos Szeredi 		goto out_put_request;
39539ee059aSMiklos Szeredi 
3969e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
3979e6268dbSMiklos Szeredi 			  &outarg.attr);
3989e6268dbSMiklos Szeredi 	if (!inode) {
3999e6268dbSMiklos Szeredi 		fuse_send_forget(fc, req, outarg.nodeid, 1);
4009e6268dbSMiklos Szeredi 		return -ENOMEM;
4019e6268dbSMiklos Szeredi 	}
4029e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4039e6268dbSMiklos Szeredi 
40439ee059aSMiklos Szeredi 	if (dir_alias(inode)) {
4059e6268dbSMiklos Szeredi 		iput(inode);
4069e6268dbSMiklos Szeredi 		return -EIO;
4079e6268dbSMiklos Szeredi 	}
4089e6268dbSMiklos Szeredi 
4099e6268dbSMiklos Szeredi 	d_instantiate(entry, inode);
4100aa7c699SMiklos Szeredi 	fuse_change_timeout(entry, &outarg);
4119e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
4129e6268dbSMiklos Szeredi 	return 0;
41339ee059aSMiklos Szeredi 
41439ee059aSMiklos Szeredi  out_put_request:
41539ee059aSMiklos Szeredi 	fuse_put_request(fc, req);
41639ee059aSMiklos Szeredi 	return err;
4179e6268dbSMiklos Szeredi }
4189e6268dbSMiklos Szeredi 
4199e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
4209e6268dbSMiklos Szeredi 		      dev_t rdev)
4219e6268dbSMiklos Szeredi {
4229e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
4239e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
424ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
425ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
426ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
4279e6268dbSMiklos Szeredi 
4289e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4299e6268dbSMiklos Szeredi 	inarg.mode = mode;
4309e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
4319e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
4329e6268dbSMiklos Szeredi 	req->in.numargs = 2;
4339e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4349e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4359e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
4369e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
4379e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
4389e6268dbSMiklos Szeredi }
4399e6268dbSMiklos Szeredi 
4409e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
4419e6268dbSMiklos Szeredi 		       struct nameidata *nd)
4429e6268dbSMiklos Szeredi {
443fd72faacSMiklos Szeredi 	if (nd && (nd->flags & LOOKUP_CREATE)) {
444fd72faacSMiklos Szeredi 		int err = fuse_create_open(dir, entry, mode, nd);
445fd72faacSMiklos Szeredi 		if (err != -ENOSYS)
446fd72faacSMiklos Szeredi 			return err;
447fd72faacSMiklos Szeredi 		/* Fall back on mknod */
448fd72faacSMiklos Szeredi 	}
4499e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
4509e6268dbSMiklos Szeredi }
4519e6268dbSMiklos Szeredi 
4529e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
4539e6268dbSMiklos Szeredi {
4549e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
4559e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
456ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
457ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
458ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
4599e6268dbSMiklos Szeredi 
4609e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4619e6268dbSMiklos Szeredi 	inarg.mode = mode;
4629e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
4639e6268dbSMiklos Szeredi 	req->in.numargs = 2;
4649e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4659e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4669e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
4679e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
4689e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
4699e6268dbSMiklos Szeredi }
4709e6268dbSMiklos Szeredi 
4719e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
4729e6268dbSMiklos Szeredi 			const char *link)
4739e6268dbSMiklos Szeredi {
4749e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
4759e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
476ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
477ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
478ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
4799e6268dbSMiklos Szeredi 
4809e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SYMLINK;
4819e6268dbSMiklos Szeredi 	req->in.numargs = 2;
4829e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
4839e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
4849e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
4859e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
4869e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
4879e6268dbSMiklos Szeredi }
4889e6268dbSMiklos Szeredi 
4899e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
4909e6268dbSMiklos Szeredi {
4919e6268dbSMiklos Szeredi 	int err;
4929e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
493ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
494ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
495ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
4969e6268dbSMiklos Szeredi 
4979e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
4989e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
4999e6268dbSMiklos Szeredi 	req->in.numargs = 1;
5009e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5019e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5029e6268dbSMiklos Szeredi 	request_send(fc, req);
5039e6268dbSMiklos Szeredi 	err = req->out.h.error;
5049e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
5059e6268dbSMiklos Szeredi 	if (!err) {
5069e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
5079e6268dbSMiklos Szeredi 
5089e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
5099e6268dbSMiklos Szeredi                    the inode does have more links this will be
5109e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
511*ce71ec36SDave Hansen 		clear_nlink(inode);
5129e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
5139e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
5148cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
5159e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
5169e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
5179e6268dbSMiklos Szeredi 	return err;
5189e6268dbSMiklos Szeredi }
5199e6268dbSMiklos Szeredi 
5209e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
5219e6268dbSMiklos Szeredi {
5229e6268dbSMiklos Szeredi 	int err;
5239e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
524ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
525ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
526ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5279e6268dbSMiklos Szeredi 
5289e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
5299e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
5309e6268dbSMiklos Szeredi 	req->in.numargs = 1;
5319e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5329e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5339e6268dbSMiklos Szeredi 	request_send(fc, req);
5349e6268dbSMiklos Szeredi 	err = req->out.h.error;
5359e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
5369e6268dbSMiklos Szeredi 	if (!err) {
537*ce71ec36SDave Hansen 		clear_nlink(entry->d_inode);
5389e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
5398cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
5409e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
5419e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
5429e6268dbSMiklos Szeredi 	return err;
5439e6268dbSMiklos Szeredi }
5449e6268dbSMiklos Szeredi 
5459e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
5469e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
5479e6268dbSMiklos Szeredi {
5489e6268dbSMiklos Szeredi 	int err;
5499e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
5509e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
551ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
552ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
553ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5549e6268dbSMiklos Szeredi 
5559e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
5569e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
5579e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
5589e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
5599e6268dbSMiklos Szeredi 	req->in.numargs = 3;
5609e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
5619e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
5629e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
5639e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
5649e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
5659e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
5669e6268dbSMiklos Szeredi 	request_send(fc, req);
5679e6268dbSMiklos Szeredi 	err = req->out.h.error;
5689e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
5699e6268dbSMiklos Szeredi 	if (!err) {
5709e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
5719e6268dbSMiklos Szeredi 		if (olddir != newdir)
5729e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
5738cbdf1e6SMiklos Szeredi 
5748cbdf1e6SMiklos Szeredi 		/* newent will end up negative */
5758cbdf1e6SMiklos Szeredi 		if (newent->d_inode)
5768cbdf1e6SMiklos Szeredi 			fuse_invalidate_entry_cache(newent);
5779e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
5789e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
5799e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
5809e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
5819e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
5829e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
5839e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
5849e6268dbSMiklos Szeredi 		if (newent->d_inode)
5859e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
5869e6268dbSMiklos Szeredi 	}
5879e6268dbSMiklos Szeredi 
5889e6268dbSMiklos Szeredi 	return err;
5899e6268dbSMiklos Szeredi }
5909e6268dbSMiklos Szeredi 
5919e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
5929e6268dbSMiklos Szeredi 		     struct dentry *newent)
5939e6268dbSMiklos Szeredi {
5949e6268dbSMiklos Szeredi 	int err;
5959e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
5969e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
5979e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
598ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
599ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
600ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
6019e6268dbSMiklos Szeredi 
6029e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
6039e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
6049e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
6059e6268dbSMiklos Szeredi 	req->in.numargs = 2;
6069e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
6079e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
6089e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
6099e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
6109e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
6119e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
6129e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
6139e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
6149e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
6159e6268dbSMiklos Szeredi 	   etc.)
6169e6268dbSMiklos Szeredi 	*/
6179e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
6189e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
6199e6268dbSMiklos Szeredi 	return err;
6209e6268dbSMiklos Szeredi }
6219e6268dbSMiklos Szeredi 
622e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode)
623e5e5558eSMiklos Szeredi {
624e5e5558eSMiklos Szeredi 	int err;
625e5e5558eSMiklos Szeredi 	struct fuse_attr_out arg;
626e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
627ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
628ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
629ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
630e5e5558eSMiklos Szeredi 
631e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
632e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
633e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
634e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(arg);
635e5e5558eSMiklos Szeredi 	req->out.args[0].value = &arg;
636e5e5558eSMiklos Szeredi 	request_send(fc, req);
637e5e5558eSMiklos Szeredi 	err = req->out.h.error;
638e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
639e5e5558eSMiklos Szeredi 	if (!err) {
640e5e5558eSMiklos Szeredi 		if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
641e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
642e5e5558eSMiklos Szeredi 			err = -EIO;
643e5e5558eSMiklos Szeredi 		} else {
644e5e5558eSMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
645e5e5558eSMiklos Szeredi 			fuse_change_attributes(inode, &arg.attr);
646e5e5558eSMiklos Szeredi 			fi->i_time = time_to_jiffies(arg.attr_valid,
647e5e5558eSMiklos Szeredi 						     arg.attr_valid_nsec);
648e5e5558eSMiklos Szeredi 		}
649e5e5558eSMiklos Szeredi 	}
650e5e5558eSMiklos Szeredi 	return err;
651e5e5558eSMiklos Szeredi }
652e5e5558eSMiklos Szeredi 
65387729a55SMiklos Szeredi /*
65487729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
65587729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
65687729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
65787729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
65887729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
65987729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
66087729a55SMiklos Szeredi  * DoS against the requester.
66187729a55SMiklos Szeredi  *
66287729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
66387729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
66487729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
66587729a55SMiklos Szeredi  */
66687729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
66787729a55SMiklos Szeredi {
66887729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
66987729a55SMiklos Szeredi 		return 1;
67087729a55SMiklos Szeredi 
67187729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
67287729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
67387729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
67487729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
67587729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
67687729a55SMiklos Szeredi 	    task->gid == fc->group_id)
67787729a55SMiklos Szeredi 		return 1;
67887729a55SMiklos Szeredi 
67987729a55SMiklos Szeredi 	return 0;
68087729a55SMiklos Szeredi }
68187729a55SMiklos Szeredi 
6826f9f1180SMiklos Szeredi /*
6836f9f1180SMiklos Szeredi  * Check whether the inode attributes are still valid
6846f9f1180SMiklos Szeredi  *
6856f9f1180SMiklos Szeredi  * If the attribute validity timeout has expired, then fetch the fresh
6866f9f1180SMiklos Szeredi  * attributes with a 'getattr' request
6876f9f1180SMiklos Szeredi  *
6886f9f1180SMiklos Szeredi  * I'm not sure why cached attributes are never returned for the root
6896f9f1180SMiklos Szeredi  * inode, this is probably being too cautious.
6906f9f1180SMiklos Szeredi  */
691e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry)
692e5e5558eSMiklos Szeredi {
693e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
694e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
695e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
696e5e5558eSMiklos Szeredi 
69787729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
698e5e5558eSMiklos Szeredi 		return -EACCES;
69987729a55SMiklos Szeredi 	if (get_node_id(inode) != FUSE_ROOT_ID &&
7000a0898cfSMiklos Szeredi 	    fi->i_time >= get_jiffies_64())
701e5e5558eSMiklos Szeredi 		return 0;
702e5e5558eSMiklos Szeredi 
703e5e5558eSMiklos Szeredi 	return fuse_do_getattr(inode);
704e5e5558eSMiklos Szeredi }
705e5e5558eSMiklos Szeredi 
70631d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask)
70731d40d74SMiklos Szeredi {
70831d40d74SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
70931d40d74SMiklos Szeredi 	struct fuse_req *req;
71031d40d74SMiklos Szeredi 	struct fuse_access_in inarg;
71131d40d74SMiklos Szeredi 	int err;
71231d40d74SMiklos Szeredi 
71331d40d74SMiklos Szeredi 	if (fc->no_access)
71431d40d74SMiklos Szeredi 		return 0;
71531d40d74SMiklos Szeredi 
716ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
717ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
718ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
71931d40d74SMiklos Szeredi 
72031d40d74SMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
72131d40d74SMiklos Szeredi 	inarg.mask = mask;
72231d40d74SMiklos Szeredi 	req->in.h.opcode = FUSE_ACCESS;
72331d40d74SMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
72431d40d74SMiklos Szeredi 	req->in.numargs = 1;
72531d40d74SMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
72631d40d74SMiklos Szeredi 	req->in.args[0].value = &inarg;
72731d40d74SMiklos Szeredi 	request_send(fc, req);
72831d40d74SMiklos Szeredi 	err = req->out.h.error;
72931d40d74SMiklos Szeredi 	fuse_put_request(fc, req);
73031d40d74SMiklos Szeredi 	if (err == -ENOSYS) {
73131d40d74SMiklos Szeredi 		fc->no_access = 1;
73231d40d74SMiklos Szeredi 		err = 0;
73331d40d74SMiklos Szeredi 	}
73431d40d74SMiklos Szeredi 	return err;
73531d40d74SMiklos Szeredi }
73631d40d74SMiklos Szeredi 
7376f9f1180SMiklos Szeredi /*
7386f9f1180SMiklos Szeredi  * Check permission.  The two basic access models of FUSE are:
7396f9f1180SMiklos Szeredi  *
7406f9f1180SMiklos Szeredi  * 1) Local access checking ('default_permissions' mount option) based
7416f9f1180SMiklos Szeredi  * on file mode.  This is the plain old disk filesystem permission
7426f9f1180SMiklos Szeredi  * modell.
7436f9f1180SMiklos Szeredi  *
7446f9f1180SMiklos Szeredi  * 2) "Remote" access checking, where server is responsible for
7456f9f1180SMiklos Szeredi  * checking permission in each inode operation.  An exception to this
7466f9f1180SMiklos Szeredi  * is if ->permission() was invoked from sys_access() in which case an
7476f9f1180SMiklos Szeredi  * access request is sent.  Execute permission is still checked
7486f9f1180SMiklos Szeredi  * locally based on file mode.
7496f9f1180SMiklos Szeredi  */
750e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
751e5e5558eSMiklos Szeredi {
752e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
753e5e5558eSMiklos Szeredi 
75487729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
755e5e5558eSMiklos Szeredi 		return -EACCES;
7561e9a4ed9SMiklos Szeredi 	else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
7571e9a4ed9SMiklos Szeredi 		int err = generic_permission(inode, mask, NULL);
7581e9a4ed9SMiklos Szeredi 
7591e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
7601e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
7611e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
7621e9a4ed9SMiklos Szeredi 		if (err == -EACCES) {
7631e9a4ed9SMiklos Szeredi 		 	err = fuse_do_getattr(inode);
7641e9a4ed9SMiklos Szeredi 			if (!err)
7651e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
7661e9a4ed9SMiklos Szeredi 		}
7671e9a4ed9SMiklos Szeredi 
7686f9f1180SMiklos Szeredi 		/* Note: the opposite of the above test does not
7696f9f1180SMiklos Szeredi 		   exist.  So if permissions are revoked this won't be
7706f9f1180SMiklos Szeredi 		   noticed immediately, only after the attribute
7716f9f1180SMiklos Szeredi 		   timeout has expired */
7721e9a4ed9SMiklos Szeredi 
7731e9a4ed9SMiklos Szeredi 		return err;
7741e9a4ed9SMiklos Szeredi 	} else {
775e5e5558eSMiklos Szeredi 		int mode = inode->i_mode;
776e5e5558eSMiklos Szeredi 		if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
777e5e5558eSMiklos Szeredi 			return -EACCES;
77831d40d74SMiklos Szeredi 
779650a8983SMiklos Szeredi 		if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR)))
78031d40d74SMiklos Szeredi 			return fuse_access(inode, mask);
781e5e5558eSMiklos Szeredi 		return 0;
782e5e5558eSMiklos Szeredi 	}
783e5e5558eSMiklos Szeredi }
784e5e5558eSMiklos Szeredi 
785e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
786e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
787e5e5558eSMiklos Szeredi {
788e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
789e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
790e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
791e5e5558eSMiklos Szeredi 		int over;
792e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
793e5e5558eSMiklos Szeredi 			return -EIO;
794e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
795e5e5558eSMiklos Szeredi 			break;
796e5e5558eSMiklos Szeredi 
797e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
798e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
799e5e5558eSMiklos Szeredi 		if (over)
800e5e5558eSMiklos Szeredi 			break;
801e5e5558eSMiklos Szeredi 
802e5e5558eSMiklos Szeredi 		buf += reclen;
803e5e5558eSMiklos Szeredi 		nbytes -= reclen;
804e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
805e5e5558eSMiklos Szeredi 	}
806e5e5558eSMiklos Szeredi 
807e5e5558eSMiklos Szeredi 	return 0;
808e5e5558eSMiklos Szeredi }
809e5e5558eSMiklos Szeredi 
810e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
811e5e5558eSMiklos Szeredi {
81204730fefSMiklos Szeredi 	int err;
81304730fefSMiklos Szeredi 	size_t nbytes;
81404730fefSMiklos Szeredi 	struct page *page;
81504730fefSMiklos Szeredi 	struct inode *inode = file->f_dentry->d_inode;
81604730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
817248d86e8SMiklos Szeredi 	struct fuse_req *req;
818248d86e8SMiklos Szeredi 
819248d86e8SMiklos Szeredi 	if (is_bad_inode(inode))
820248d86e8SMiklos Szeredi 		return -EIO;
821248d86e8SMiklos Szeredi 
822ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
823ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
824ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
825e5e5558eSMiklos Szeredi 
82604730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
82704730fefSMiklos Szeredi 	if (!page) {
82804730fefSMiklos Szeredi 		fuse_put_request(fc, req);
829e5e5558eSMiklos Szeredi 		return -ENOMEM;
83004730fefSMiklos Szeredi 	}
83104730fefSMiklos Szeredi 	req->num_pages = 1;
83204730fefSMiklos Szeredi 	req->pages[0] = page;
833361b1eb5SMiklos Szeredi 	fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
834361b1eb5SMiklos Szeredi 	request_send(fc, req);
835361b1eb5SMiklos Szeredi 	nbytes = req->out.args[0].size;
83604730fefSMiklos Szeredi 	err = req->out.h.error;
83704730fefSMiklos Szeredi 	fuse_put_request(fc, req);
83804730fefSMiklos Szeredi 	if (!err)
83904730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
84004730fefSMiklos Szeredi 				    filldir);
841e5e5558eSMiklos Szeredi 
84204730fefSMiklos Szeredi 	__free_page(page);
843b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
84404730fefSMiklos Szeredi 	return err;
845e5e5558eSMiklos Szeredi }
846e5e5558eSMiklos Szeredi 
847e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
848e5e5558eSMiklos Szeredi {
849e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
850e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
851ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
852e5e5558eSMiklos Szeredi 	char *link;
853e5e5558eSMiklos Szeredi 
854ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
855ce1d5a49SMiklos Szeredi 		return ERR_PTR(PTR_ERR(req));
856e5e5558eSMiklos Szeredi 
857e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
858e5e5558eSMiklos Szeredi 	if (!link) {
859e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
860e5e5558eSMiklos Szeredi 		goto out;
861e5e5558eSMiklos Szeredi 	}
862e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
863e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
864e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
865e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
866e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
867e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
868e5e5558eSMiklos Szeredi 	request_send(fc, req);
869e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
870e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
871e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
872e5e5558eSMiklos Szeredi 	} else
873e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
874e5e5558eSMiklos Szeredi  out:
875e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
876b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
877e5e5558eSMiklos Szeredi 	return link;
878e5e5558eSMiklos Szeredi }
879e5e5558eSMiklos Szeredi 
880e5e5558eSMiklos Szeredi static void free_link(char *link)
881e5e5558eSMiklos Szeredi {
882e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
883e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
884e5e5558eSMiklos Szeredi }
885e5e5558eSMiklos Szeredi 
886e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
887e5e5558eSMiklos Szeredi {
888e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
889e5e5558eSMiklos Szeredi 	return NULL;
890e5e5558eSMiklos Szeredi }
891e5e5558eSMiklos Szeredi 
892e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
893e5e5558eSMiklos Szeredi {
894e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
895e5e5558eSMiklos Szeredi }
896e5e5558eSMiklos Szeredi 
897e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
898e5e5558eSMiklos Szeredi {
89904730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
900e5e5558eSMiklos Szeredi }
901e5e5558eSMiklos Szeredi 
902e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
903e5e5558eSMiklos Szeredi {
90404730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
905e5e5558eSMiklos Szeredi }
906e5e5558eSMiklos Szeredi 
90782547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
90882547981SMiklos Szeredi {
90982547981SMiklos Szeredi 	/* nfsd can call this with no file */
91082547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
91182547981SMiklos Szeredi }
91282547981SMiklos Szeredi 
913befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
9149e6268dbSMiklos Szeredi {
9159e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
9169e6268dbSMiklos Szeredi 
9179e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
918befc649cSMiklos Szeredi 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
9199e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
920befc649cSMiklos Szeredi 		arg->valid |= FATTR_UID,    arg->uid = iattr->ia_uid;
9219e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
922befc649cSMiklos Szeredi 		arg->valid |= FATTR_GID,    arg->gid = iattr->ia_gid;
9239e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
924befc649cSMiklos Szeredi 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
9259e6268dbSMiklos Szeredi 	/* You can only _set_ these together (they may change by themselves) */
9269e6268dbSMiklos Szeredi 	if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
927befc649cSMiklos Szeredi 		arg->valid |= FATTR_ATIME | FATTR_MTIME;
928befc649cSMiklos Szeredi 		arg->atime = iattr->ia_atime.tv_sec;
929befc649cSMiklos Szeredi 		arg->mtime = iattr->ia_mtime.tv_sec;
9309e6268dbSMiklos Szeredi 	}
931befc649cSMiklos Szeredi 	if (ivalid & ATTR_FILE) {
932befc649cSMiklos Szeredi 		struct fuse_file *ff = iattr->ia_file->private_data;
933befc649cSMiklos Szeredi 		arg->valid |= FATTR_FH;
934befc649cSMiklos Szeredi 		arg->fh = ff->fh;
935befc649cSMiklos Szeredi 	}
9369e6268dbSMiklos Szeredi }
9379e6268dbSMiklos Szeredi 
9386f9f1180SMiklos Szeredi /*
9396f9f1180SMiklos Szeredi  * Set attributes, and at the same time refresh them.
9406f9f1180SMiklos Szeredi  *
9416f9f1180SMiklos Szeredi  * Truncation is slightly complicated, because the 'truncate' request
9426f9f1180SMiklos Szeredi  * may fail, in which case we don't want to touch the mapping.
9436f9f1180SMiklos Szeredi  * vmtruncate() doesn't allow for this case.  So do the rlimit
9446f9f1180SMiklos Szeredi  * checking by hand and call vmtruncate() only after the file has
9456f9f1180SMiklos Szeredi  * actually been truncated.
9466f9f1180SMiklos Szeredi  */
9479e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
9489e6268dbSMiklos Szeredi {
9499e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
9509e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
9519e6268dbSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
9529e6268dbSMiklos Szeredi 	struct fuse_req *req;
9539e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
9549e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
9559e6268dbSMiklos Szeredi 	int err;
9569e6268dbSMiklos Szeredi 	int is_truncate = 0;
9579e6268dbSMiklos Szeredi 
9581e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
9591e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
9601e9a4ed9SMiklos Szeredi 		if (err)
9611e9a4ed9SMiklos Szeredi 			return err;
9621e9a4ed9SMiklos Szeredi 	}
9631e9a4ed9SMiklos Szeredi 
9649e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
9659e6268dbSMiklos Szeredi 		unsigned long limit;
9669e6268dbSMiklos Szeredi 		is_truncate = 1;
9679e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
9689e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
9699e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
9709e6268dbSMiklos Szeredi 			return -EFBIG;
9719e6268dbSMiklos Szeredi 		}
9729e6268dbSMiklos Szeredi 	}
9739e6268dbSMiklos Szeredi 
974ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
975ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
976ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
9779e6268dbSMiklos Szeredi 
9789e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
979befc649cSMiklos Szeredi 	iattr_to_fattr(attr, &inarg);
9809e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
9819e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
9829e6268dbSMiklos Szeredi 	req->in.numargs = 1;
9839e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
9849e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
9859e6268dbSMiklos Szeredi 	req->out.numargs = 1;
9869e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
9879e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
9889e6268dbSMiklos Szeredi 	request_send(fc, req);
9899e6268dbSMiklos Szeredi 	err = req->out.h.error;
9909e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
9919e6268dbSMiklos Szeredi 	if (!err) {
9929e6268dbSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
9939e6268dbSMiklos Szeredi 			make_bad_inode(inode);
9949e6268dbSMiklos Szeredi 			err = -EIO;
9959e6268dbSMiklos Szeredi 		} else {
9969e6268dbSMiklos Szeredi 			if (is_truncate) {
9979e6268dbSMiklos Szeredi 				loff_t origsize = i_size_read(inode);
9989e6268dbSMiklos Szeredi 				i_size_write(inode, outarg.attr.size);
9999e6268dbSMiklos Szeredi 				if (origsize > outarg.attr.size)
10009e6268dbSMiklos Szeredi 					vmtruncate(inode, outarg.attr.size);
10019e6268dbSMiklos Szeredi 			}
10029e6268dbSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr);
10039e6268dbSMiklos Szeredi 			fi->i_time = time_to_jiffies(outarg.attr_valid,
10049e6268dbSMiklos Szeredi 						     outarg.attr_valid_nsec);
10059e6268dbSMiklos Szeredi 		}
10069e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
10079e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
10089e6268dbSMiklos Szeredi 
10099e6268dbSMiklos Szeredi 	return err;
10109e6268dbSMiklos Szeredi }
10119e6268dbSMiklos Szeredi 
1012e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
1013e5e5558eSMiklos Szeredi 			struct kstat *stat)
1014e5e5558eSMiklos Szeredi {
1015e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
1016e5e5558eSMiklos Szeredi 	int err = fuse_revalidate(entry);
1017e5e5558eSMiklos Szeredi 	if (!err)
1018e5e5558eSMiklos Szeredi 		generic_fillattr(inode, stat);
1019e5e5558eSMiklos Szeredi 
1020e5e5558eSMiklos Szeredi 	return err;
1021e5e5558eSMiklos Szeredi }
1022e5e5558eSMiklos Szeredi 
102392a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
102492a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
102592a8780eSMiklos Szeredi {
102692a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
102792a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
102892a8780eSMiklos Szeredi 	struct fuse_req *req;
102992a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
103092a8780eSMiklos Szeredi 	int err;
103192a8780eSMiklos Szeredi 
103292a8780eSMiklos Szeredi 	if (fc->no_setxattr)
103392a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
103492a8780eSMiklos Szeredi 
1035ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1036ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1037ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
103892a8780eSMiklos Szeredi 
103992a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
104092a8780eSMiklos Szeredi 	inarg.size = size;
104192a8780eSMiklos Szeredi 	inarg.flags = flags;
104292a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
104392a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
104492a8780eSMiklos Szeredi 	req->in.numargs = 3;
104592a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
104692a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
104792a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
104892a8780eSMiklos Szeredi 	req->in.args[1].value = name;
104992a8780eSMiklos Szeredi 	req->in.args[2].size = size;
105092a8780eSMiklos Szeredi 	req->in.args[2].value = value;
105192a8780eSMiklos Szeredi 	request_send(fc, req);
105292a8780eSMiklos Szeredi 	err = req->out.h.error;
105392a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
105492a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
105592a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
105692a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
105792a8780eSMiklos Szeredi 	}
105892a8780eSMiklos Szeredi 	return err;
105992a8780eSMiklos Szeredi }
106092a8780eSMiklos Szeredi 
106192a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
106292a8780eSMiklos Szeredi 			     void *value, size_t size)
106392a8780eSMiklos Szeredi {
106492a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
106592a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
106692a8780eSMiklos Szeredi 	struct fuse_req *req;
106792a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
106892a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
106992a8780eSMiklos Szeredi 	ssize_t ret;
107092a8780eSMiklos Szeredi 
107192a8780eSMiklos Szeredi 	if (fc->no_getxattr)
107292a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
107392a8780eSMiklos Szeredi 
1074ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1075ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1076ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
107792a8780eSMiklos Szeredi 
107892a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
107992a8780eSMiklos Szeredi 	inarg.size = size;
108092a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
108192a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
108292a8780eSMiklos Szeredi 	req->in.numargs = 2;
108392a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
108492a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
108592a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
108692a8780eSMiklos Szeredi 	req->in.args[1].value = name;
108792a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
108892a8780eSMiklos Szeredi 	req->out.numargs = 1;
108992a8780eSMiklos Szeredi 	if (size) {
109092a8780eSMiklos Szeredi 		req->out.argvar = 1;
109192a8780eSMiklos Szeredi 		req->out.args[0].size = size;
109292a8780eSMiklos Szeredi 		req->out.args[0].value = value;
109392a8780eSMiklos Szeredi 	} else {
109492a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
109592a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
109692a8780eSMiklos Szeredi 	}
109792a8780eSMiklos Szeredi 	request_send(fc, req);
109892a8780eSMiklos Szeredi 	ret = req->out.h.error;
109992a8780eSMiklos Szeredi 	if (!ret)
110092a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
110192a8780eSMiklos Szeredi 	else {
110292a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
110392a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
110492a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
110592a8780eSMiklos Szeredi 		}
110692a8780eSMiklos Szeredi 	}
110792a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
110892a8780eSMiklos Szeredi 	return ret;
110992a8780eSMiklos Szeredi }
111092a8780eSMiklos Szeredi 
111192a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
111292a8780eSMiklos Szeredi {
111392a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
111492a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
111592a8780eSMiklos Szeredi 	struct fuse_req *req;
111692a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
111792a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
111892a8780eSMiklos Szeredi 	ssize_t ret;
111992a8780eSMiklos Szeredi 
112092a8780eSMiklos Szeredi 	if (fc->no_listxattr)
112192a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
112292a8780eSMiklos Szeredi 
1123ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1124ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1125ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
112692a8780eSMiklos Szeredi 
112792a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
112892a8780eSMiklos Szeredi 	inarg.size = size;
112992a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
113092a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
113192a8780eSMiklos Szeredi 	req->in.numargs = 1;
113292a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
113392a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
113492a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
113592a8780eSMiklos Szeredi 	req->out.numargs = 1;
113692a8780eSMiklos Szeredi 	if (size) {
113792a8780eSMiklos Szeredi 		req->out.argvar = 1;
113892a8780eSMiklos Szeredi 		req->out.args[0].size = size;
113992a8780eSMiklos Szeredi 		req->out.args[0].value = list;
114092a8780eSMiklos Szeredi 	} else {
114192a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
114292a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
114392a8780eSMiklos Szeredi 	}
114492a8780eSMiklos Szeredi 	request_send(fc, req);
114592a8780eSMiklos Szeredi 	ret = req->out.h.error;
114692a8780eSMiklos Szeredi 	if (!ret)
114792a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
114892a8780eSMiklos Szeredi 	else {
114992a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
115092a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
115192a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
115292a8780eSMiklos Szeredi 		}
115392a8780eSMiklos Szeredi 	}
115492a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
115592a8780eSMiklos Szeredi 	return ret;
115692a8780eSMiklos Szeredi }
115792a8780eSMiklos Szeredi 
115892a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
115992a8780eSMiklos Szeredi {
116092a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
116192a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
116292a8780eSMiklos Szeredi 	struct fuse_req *req;
116392a8780eSMiklos Szeredi 	int err;
116492a8780eSMiklos Szeredi 
116592a8780eSMiklos Szeredi 	if (fc->no_removexattr)
116692a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
116792a8780eSMiklos Szeredi 
1168ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1169ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1170ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
117192a8780eSMiklos Szeredi 
117292a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
117392a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
117492a8780eSMiklos Szeredi 	req->in.numargs = 1;
117592a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
117692a8780eSMiklos Szeredi 	req->in.args[0].value = name;
117792a8780eSMiklos Szeredi 	request_send(fc, req);
117892a8780eSMiklos Szeredi 	err = req->out.h.error;
117992a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
118092a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
118192a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
118292a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
118392a8780eSMiklos Szeredi 	}
118492a8780eSMiklos Szeredi 	return err;
118592a8780eSMiklos Szeredi }
118692a8780eSMiklos Szeredi 
1187e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = {
1188e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
11899e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
11909e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
11919e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
11929e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
11939e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
11949e6268dbSMiklos Szeredi 	.link		= fuse_link,
11959e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
11969e6268dbSMiklos Szeredi 	.create		= fuse_create,
11979e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
1198e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1199e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
120092a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
120192a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
120292a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
120392a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1204e5e5558eSMiklos Szeredi };
1205e5e5558eSMiklos Szeredi 
12064b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = {
1207b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
1208e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
1209e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
1210e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
1211e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
121282547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
1213e5e5558eSMiklos Szeredi };
1214e5e5558eSMiklos Szeredi 
1215e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = {
12169e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1217e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1218e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
121992a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
122092a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
122192a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
122292a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1223e5e5558eSMiklos Szeredi };
1224e5e5558eSMiklos Szeredi 
1225e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = {
12269e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1227e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
1228e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
1229e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
1230e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
123192a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
123292a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
123392a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
123492a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1235e5e5558eSMiklos Szeredi };
1236e5e5558eSMiklos Szeredi 
1237e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
1238e5e5558eSMiklos Szeredi {
1239e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
1240e5e5558eSMiklos Szeredi }
1241e5e5558eSMiklos Szeredi 
1242e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
1243e5e5558eSMiklos Szeredi {
1244e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
1245e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
1246e5e5558eSMiklos Szeredi }
1247e5e5558eSMiklos Szeredi 
1248e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
1249e5e5558eSMiklos Szeredi {
1250e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
1251e5e5558eSMiklos Szeredi }
1252