xref: /openbmc/linux/fs/fuse/dir.c (revision d2a85164aaa8d514ef5efbf5d05746e85dd13ddd)
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 			}
1668da5ff23SMiklos Szeredi 			spin_lock(&fc->lock);
1679e6268dbSMiklos Szeredi 			fi->nlookup ++;
1688da5ff23SMiklos Szeredi 			spin_unlock(&fc->lock);
1699e6268dbSMiklos Szeredi 		}
170e5e5558eSMiklos Szeredi 		fuse_put_request(fc, req);
1719e6268dbSMiklos Szeredi 		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
172e5e5558eSMiklos Szeredi 			return 0;
173e5e5558eSMiklos Szeredi 
174e5e5558eSMiklos Szeredi 		fuse_change_attributes(inode, &outarg.attr);
1750aa7c699SMiklos Szeredi 		fuse_change_timeout(entry, &outarg);
176e5e5558eSMiklos Szeredi 	}
177e5e5558eSMiklos Szeredi 	return 1;
178e5e5558eSMiklos Szeredi }
179e5e5558eSMiklos Szeredi 
1808bfc016dSMiklos Szeredi static int invalid_nodeid(u64 nodeid)
1812827d0b2SMiklos Szeredi {
1822827d0b2SMiklos Szeredi 	return !nodeid || nodeid == FUSE_ROOT_ID;
1832827d0b2SMiklos Szeredi }
1842827d0b2SMiklos Szeredi 
185e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = {
186e5e5558eSMiklos Szeredi 	.d_revalidate	= fuse_dentry_revalidate,
187e5e5558eSMiklos Szeredi };
188e5e5558eSMiklos Szeredi 
1898bfc016dSMiklos Szeredi static int valid_mode(int m)
19039ee059aSMiklos Szeredi {
19139ee059aSMiklos Szeredi 	return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
19239ee059aSMiklos Szeredi 		S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
19339ee059aSMiklos Szeredi }
19439ee059aSMiklos Szeredi 
195*d2a85164SMiklos Szeredi /*
196*d2a85164SMiklos Szeredi  * Add a directory inode to a dentry, ensuring that no other dentry
197*d2a85164SMiklos Szeredi  * refers to this inode.  Called with fc->inst_mutex.
198*d2a85164SMiklos Szeredi  */
199*d2a85164SMiklos Szeredi static int fuse_d_add_directory(struct dentry *entry, struct inode *inode)
200*d2a85164SMiklos Szeredi {
201*d2a85164SMiklos Szeredi 	struct dentry *alias = d_find_alias(inode);
202*d2a85164SMiklos Szeredi 	if (alias) {
203*d2a85164SMiklos Szeredi 		/* This tries to shrink the subtree below alias */
204*d2a85164SMiklos Szeredi 		fuse_invalidate_entry(alias);
205*d2a85164SMiklos Szeredi 		dput(alias);
206*d2a85164SMiklos Szeredi 		if (!list_empty(&inode->i_dentry))
207*d2a85164SMiklos Szeredi 			return -EBUSY;
208*d2a85164SMiklos Szeredi 	}
209*d2a85164SMiklos Szeredi 	d_add(entry, inode);
210*d2a85164SMiklos Szeredi 	return 0;
211*d2a85164SMiklos Szeredi }
212*d2a85164SMiklos Szeredi 
2130aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
2140aa7c699SMiklos Szeredi 				  struct nameidata *nd)
215e5e5558eSMiklos Szeredi {
216e5e5558eSMiklos Szeredi 	int err;
217e5e5558eSMiklos Szeredi 	struct fuse_entry_out outarg;
218e5e5558eSMiklos Szeredi 	struct inode *inode = NULL;
219e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
220e5e5558eSMiklos Szeredi 	struct fuse_req *req;
221e5e5558eSMiklos Szeredi 
222e5e5558eSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
2230aa7c699SMiklos Szeredi 		return ERR_PTR(-ENAMETOOLONG);
224e5e5558eSMiklos Szeredi 
225ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
226ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
227ce1d5a49SMiklos Szeredi 		return ERR_PTR(PTR_ERR(req));
228e5e5558eSMiklos Szeredi 
229e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
230e5e5558eSMiklos Szeredi 	request_send(fc, req);
231e5e5558eSMiklos Szeredi 	err = req->out.h.error;
23250322fe7SMiklos Szeredi 	/* Zero nodeid is same as -ENOENT, but with valid timeout */
23350322fe7SMiklos Szeredi 	if (!err && outarg.nodeid &&
23450322fe7SMiklos Szeredi 	    (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode)))
235ee4e5271SMiklos Szeredi 		err = -EIO;
2368cbdf1e6SMiklos Szeredi 	if (!err && outarg.nodeid) {
237e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
2389e6268dbSMiklos Szeredi 				  &outarg.attr);
239e5e5558eSMiklos Szeredi 		if (!inode) {
2409e6268dbSMiklos Szeredi 			fuse_send_forget(fc, req, outarg.nodeid, 1);
2410aa7c699SMiklos Szeredi 			return ERR_PTR(-ENOMEM);
242e5e5558eSMiklos Szeredi 		}
243e5e5558eSMiklos Szeredi 	}
244e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
245e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
2460aa7c699SMiklos Szeredi 		return ERR_PTR(err);
247e5e5558eSMiklos Szeredi 
248*d2a85164SMiklos Szeredi 	if (inode && S_ISDIR(inode->i_mode)) {
249*d2a85164SMiklos Szeredi 		mutex_lock(&fc->inst_mutex);
250*d2a85164SMiklos Szeredi 		err = fuse_d_add_directory(entry, inode);
251*d2a85164SMiklos Szeredi 		mutex_unlock(&fc->inst_mutex);
252*d2a85164SMiklos Szeredi 		if (err) {
2530aa7c699SMiklos Szeredi 			iput(inode);
254*d2a85164SMiklos Szeredi 			return ERR_PTR(err);
255e5e5558eSMiklos Szeredi 		}
256*d2a85164SMiklos Szeredi 	} else
2570aa7c699SMiklos Szeredi 		d_add(entry, inode);
258*d2a85164SMiklos Szeredi 
259e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
2608cbdf1e6SMiklos Szeredi 	if (!err)
2610aa7c699SMiklos Szeredi 		fuse_change_timeout(entry, &outarg);
2628cbdf1e6SMiklos Szeredi 	else
2638cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
2640aa7c699SMiklos Szeredi 	return NULL;
265e5e5558eSMiklos Szeredi }
266e5e5558eSMiklos Szeredi 
2676f9f1180SMiklos Szeredi /*
26851eb01e7SMiklos Szeredi  * Synchronous release for the case when something goes wrong in CREATE_OPEN
26951eb01e7SMiklos Szeredi  */
27051eb01e7SMiklos Szeredi static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
27151eb01e7SMiklos Szeredi 			      u64 nodeid, int flags)
27251eb01e7SMiklos Szeredi {
27351eb01e7SMiklos Szeredi 	struct fuse_req *req;
27451eb01e7SMiklos Szeredi 
27551eb01e7SMiklos Szeredi 	req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
27651eb01e7SMiklos Szeredi 	req->force = 1;
27751eb01e7SMiklos Szeredi 	request_send(fc, req);
27851eb01e7SMiklos Szeredi 	fuse_put_request(fc, req);
27951eb01e7SMiklos Szeredi }
28051eb01e7SMiklos Szeredi 
28151eb01e7SMiklos Szeredi /*
2826f9f1180SMiklos Szeredi  * Atomic create+open operation
2836f9f1180SMiklos Szeredi  *
2846f9f1180SMiklos Szeredi  * If the filesystem doesn't support this, then fall back to separate
2856f9f1180SMiklos Szeredi  * 'mknod' + 'open' requests.
2866f9f1180SMiklos Szeredi  */
287fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
288fd72faacSMiklos Szeredi 			    struct nameidata *nd)
289fd72faacSMiklos Szeredi {
290fd72faacSMiklos Szeredi 	int err;
291fd72faacSMiklos Szeredi 	struct inode *inode;
292fd72faacSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
293fd72faacSMiklos Szeredi 	struct fuse_req *req;
29451eb01e7SMiklos Szeredi 	struct fuse_req *forget_req;
295fd72faacSMiklos Szeredi 	struct fuse_open_in inarg;
296fd72faacSMiklos Szeredi 	struct fuse_open_out outopen;
297fd72faacSMiklos Szeredi 	struct fuse_entry_out outentry;
298fd72faacSMiklos Szeredi 	struct fuse_file *ff;
299fd72faacSMiklos Szeredi 	struct file *file;
300fd72faacSMiklos Szeredi 	int flags = nd->intent.open.flags - 1;
301fd72faacSMiklos Szeredi 
302fd72faacSMiklos Szeredi 	if (fc->no_create)
303ce1d5a49SMiklos Szeredi 		return -ENOSYS;
304fd72faacSMiklos Szeredi 
30551eb01e7SMiklos Szeredi 	forget_req = fuse_get_req(fc);
30651eb01e7SMiklos Szeredi 	if (IS_ERR(forget_req))
30751eb01e7SMiklos Szeredi 		return PTR_ERR(forget_req);
30851eb01e7SMiklos Szeredi 
309ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
31051eb01e7SMiklos Szeredi 	err = PTR_ERR(req);
311ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
31251eb01e7SMiklos Szeredi 		goto out_put_forget_req;
313fd72faacSMiklos Szeredi 
314ce1d5a49SMiklos Szeredi 	err = -ENOMEM;
315fd72faacSMiklos Szeredi 	ff = fuse_file_alloc();
316fd72faacSMiklos Szeredi 	if (!ff)
317fd72faacSMiklos Szeredi 		goto out_put_request;
318fd72faacSMiklos Szeredi 
319fd72faacSMiklos Szeredi 	flags &= ~O_NOCTTY;
320fd72faacSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
321fd72faacSMiklos Szeredi 	inarg.flags = flags;
322fd72faacSMiklos Szeredi 	inarg.mode = mode;
323fd72faacSMiklos Szeredi 	req->in.h.opcode = FUSE_CREATE;
324fd72faacSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
325fd72faacSMiklos Szeredi 	req->in.numargs = 2;
326fd72faacSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
327fd72faacSMiklos Szeredi 	req->in.args[0].value = &inarg;
328fd72faacSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
329fd72faacSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
330fd72faacSMiklos Szeredi 	req->out.numargs = 2;
331fd72faacSMiklos Szeredi 	req->out.args[0].size = sizeof(outentry);
332fd72faacSMiklos Szeredi 	req->out.args[0].value = &outentry;
333fd72faacSMiklos Szeredi 	req->out.args[1].size = sizeof(outopen);
334fd72faacSMiklos Szeredi 	req->out.args[1].value = &outopen;
335fd72faacSMiklos Szeredi 	request_send(fc, req);
336fd72faacSMiklos Szeredi 	err = req->out.h.error;
337fd72faacSMiklos Szeredi 	if (err) {
338fd72faacSMiklos Szeredi 		if (err == -ENOSYS)
339fd72faacSMiklos Szeredi 			fc->no_create = 1;
340fd72faacSMiklos Szeredi 		goto out_free_ff;
341fd72faacSMiklos Szeredi 	}
342fd72faacSMiklos Szeredi 
343fd72faacSMiklos Szeredi 	err = -EIO;
3442827d0b2SMiklos Szeredi 	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
345fd72faacSMiklos Szeredi 		goto out_free_ff;
346fd72faacSMiklos Szeredi 
34751eb01e7SMiklos Szeredi 	fuse_put_request(fc, req);
348fd72faacSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
349fd72faacSMiklos Szeredi 			  &outentry.attr);
350fd72faacSMiklos Szeredi 	if (!inode) {
351fd72faacSMiklos Szeredi 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
352fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
35351eb01e7SMiklos Szeredi 		fuse_sync_release(fc, ff, outentry.nodeid, flags);
35451eb01e7SMiklos Szeredi 		fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
35551eb01e7SMiklos Szeredi 		return -ENOMEM;
356fd72faacSMiklos Szeredi 	}
35751eb01e7SMiklos Szeredi 	fuse_put_request(fc, forget_req);
358fd72faacSMiklos Szeredi 	d_instantiate(entry, inode);
3590aa7c699SMiklos Szeredi 	fuse_change_timeout(entry, &outentry);
360fd72faacSMiklos Szeredi 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
361fd72faacSMiklos Szeredi 	if (IS_ERR(file)) {
362fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
36351eb01e7SMiklos Szeredi 		fuse_sync_release(fc, ff, outentry.nodeid, flags);
364fd72faacSMiklos Szeredi 		return PTR_ERR(file);
365fd72faacSMiklos Szeredi 	}
366fd72faacSMiklos Szeredi 	fuse_finish_open(inode, file, ff, &outopen);
367fd72faacSMiklos Szeredi 	return 0;
368fd72faacSMiklos Szeredi 
369fd72faacSMiklos Szeredi  out_free_ff:
370fd72faacSMiklos Szeredi 	fuse_file_free(ff);
371fd72faacSMiklos Szeredi  out_put_request:
372fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
37351eb01e7SMiklos Szeredi  out_put_forget_req:
37451eb01e7SMiklos Szeredi 	fuse_put_request(fc, forget_req);
375fd72faacSMiklos Szeredi 	return err;
376fd72faacSMiklos Szeredi }
377fd72faacSMiklos Szeredi 
3786f9f1180SMiklos Szeredi /*
3796f9f1180SMiklos Szeredi  * Code shared between mknod, mkdir, symlink and link
3806f9f1180SMiklos Szeredi  */
3819e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
3829e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
3839e6268dbSMiklos Szeredi 			    int mode)
3849e6268dbSMiklos Szeredi {
3859e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
3869e6268dbSMiklos Szeredi 	struct inode *inode;
3879e6268dbSMiklos Szeredi 	int err;
3889e6268dbSMiklos Szeredi 
3899e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
3909e6268dbSMiklos Szeredi 	req->out.numargs = 1;
3919e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
3929e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
3939e6268dbSMiklos Szeredi 	request_send(fc, req);
3949e6268dbSMiklos Szeredi 	err = req->out.h.error;
3959e6268dbSMiklos Szeredi 	if (err) {
3969e6268dbSMiklos Szeredi 		fuse_put_request(fc, req);
3979e6268dbSMiklos Szeredi 		return err;
3989e6268dbSMiklos Szeredi 	}
39939ee059aSMiklos Szeredi 	err = -EIO;
40039ee059aSMiklos Szeredi 	if (invalid_nodeid(outarg.nodeid))
40139ee059aSMiklos Szeredi 		goto out_put_request;
40239ee059aSMiklos Szeredi 
40339ee059aSMiklos Szeredi 	if ((outarg.attr.mode ^ mode) & S_IFMT)
40439ee059aSMiklos Szeredi 		goto out_put_request;
40539ee059aSMiklos Szeredi 
4069e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
4079e6268dbSMiklos Szeredi 			  &outarg.attr);
4089e6268dbSMiklos Szeredi 	if (!inode) {
4099e6268dbSMiklos Szeredi 		fuse_send_forget(fc, req, outarg.nodeid, 1);
4109e6268dbSMiklos Szeredi 		return -ENOMEM;
4119e6268dbSMiklos Szeredi 	}
4129e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4139e6268dbSMiklos Szeredi 
414*d2a85164SMiklos Szeredi 	if (S_ISDIR(inode->i_mode)) {
415*d2a85164SMiklos Szeredi 		struct dentry *alias;
416*d2a85164SMiklos Szeredi 		mutex_lock(&fc->inst_mutex);
417*d2a85164SMiklos Szeredi 		alias = d_find_alias(inode);
418*d2a85164SMiklos Szeredi 		if (alias) {
419*d2a85164SMiklos Szeredi 			/* New directory must have moved since mkdir */
420*d2a85164SMiklos Szeredi 			mutex_unlock(&fc->inst_mutex);
421*d2a85164SMiklos Szeredi 			dput(alias);
4229e6268dbSMiklos Szeredi 			iput(inode);
423*d2a85164SMiklos Szeredi 			return -EBUSY;
4249e6268dbSMiklos Szeredi 		}
4259e6268dbSMiklos Szeredi 		d_instantiate(entry, inode);
426*d2a85164SMiklos Szeredi 		mutex_unlock(&fc->inst_mutex);
427*d2a85164SMiklos Szeredi 	} else
428*d2a85164SMiklos Szeredi 		d_instantiate(entry, inode);
429*d2a85164SMiklos Szeredi 
4300aa7c699SMiklos Szeredi 	fuse_change_timeout(entry, &outarg);
4319e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
4329e6268dbSMiklos Szeredi 	return 0;
43339ee059aSMiklos Szeredi 
43439ee059aSMiklos Szeredi  out_put_request:
43539ee059aSMiklos Szeredi 	fuse_put_request(fc, req);
43639ee059aSMiklos Szeredi 	return err;
4379e6268dbSMiklos Szeredi }
4389e6268dbSMiklos Szeredi 
4399e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
4409e6268dbSMiklos Szeredi 		      dev_t rdev)
4419e6268dbSMiklos Szeredi {
4429e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
4439e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
444ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
445ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
446ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
4479e6268dbSMiklos Szeredi 
4489e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4499e6268dbSMiklos Szeredi 	inarg.mode = mode;
4509e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
4519e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
4529e6268dbSMiklos Szeredi 	req->in.numargs = 2;
4539e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4549e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4559e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
4569e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
4579e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
4589e6268dbSMiklos Szeredi }
4599e6268dbSMiklos Szeredi 
4609e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
4619e6268dbSMiklos Szeredi 		       struct nameidata *nd)
4629e6268dbSMiklos Szeredi {
463fd72faacSMiklos Szeredi 	if (nd && (nd->flags & LOOKUP_CREATE)) {
464fd72faacSMiklos Szeredi 		int err = fuse_create_open(dir, entry, mode, nd);
465fd72faacSMiklos Szeredi 		if (err != -ENOSYS)
466fd72faacSMiklos Szeredi 			return err;
467fd72faacSMiklos Szeredi 		/* Fall back on mknod */
468fd72faacSMiklos Szeredi 	}
4699e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
4709e6268dbSMiklos Szeredi }
4719e6268dbSMiklos Szeredi 
4729e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
4739e6268dbSMiklos Szeredi {
4749e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
4759e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
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 	memset(&inarg, 0, sizeof(inarg));
4819e6268dbSMiklos Szeredi 	inarg.mode = mode;
4829e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
4839e6268dbSMiklos Szeredi 	req->in.numargs = 2;
4849e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4859e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4869e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
4879e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
4889e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
4899e6268dbSMiklos Szeredi }
4909e6268dbSMiklos Szeredi 
4919e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
4929e6268dbSMiklos Szeredi 			const char *link)
4939e6268dbSMiklos Szeredi {
4949e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
4959e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
496ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
497ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
498ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
4999e6268dbSMiklos Szeredi 
5009e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SYMLINK;
5019e6268dbSMiklos Szeredi 	req->in.numargs = 2;
5029e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5039e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5049e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
5059e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
5069e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
5079e6268dbSMiklos Szeredi }
5089e6268dbSMiklos Szeredi 
5099e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
5109e6268dbSMiklos Szeredi {
5119e6268dbSMiklos Szeredi 	int err;
5129e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
513ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
514ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
515ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5169e6268dbSMiklos Szeredi 
5179e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
5189e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
5199e6268dbSMiklos Szeredi 	req->in.numargs = 1;
5209e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5219e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5229e6268dbSMiklos Szeredi 	request_send(fc, req);
5239e6268dbSMiklos Szeredi 	err = req->out.h.error;
5249e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
5259e6268dbSMiklos Szeredi 	if (!err) {
5269e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
5279e6268dbSMiklos Szeredi 
5289e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
5299e6268dbSMiklos Szeredi                    the inode does have more links this will be
5309e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
531ce71ec36SDave Hansen 		clear_nlink(inode);
5329e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
5339e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
5348cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
5359e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
5369e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
5379e6268dbSMiklos Szeredi 	return err;
5389e6268dbSMiklos Szeredi }
5399e6268dbSMiklos Szeredi 
5409e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
5419e6268dbSMiklos Szeredi {
5429e6268dbSMiklos Szeredi 	int err;
5439e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
544ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
545ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
546ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5479e6268dbSMiklos Szeredi 
5489e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
5499e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
5509e6268dbSMiklos Szeredi 	req->in.numargs = 1;
5519e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5529e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5539e6268dbSMiklos Szeredi 	request_send(fc, req);
5549e6268dbSMiklos Szeredi 	err = req->out.h.error;
5559e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
5569e6268dbSMiklos Szeredi 	if (!err) {
557ce71ec36SDave Hansen 		clear_nlink(entry->d_inode);
5589e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
5598cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
5609e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
5619e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
5629e6268dbSMiklos Szeredi 	return err;
5639e6268dbSMiklos Szeredi }
5649e6268dbSMiklos Szeredi 
5659e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
5669e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
5679e6268dbSMiklos Szeredi {
5689e6268dbSMiklos Szeredi 	int err;
5699e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
5709e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
571ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
572ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
573ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5749e6268dbSMiklos Szeredi 
5759e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
5769e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
5779e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
5789e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
5799e6268dbSMiklos Szeredi 	req->in.numargs = 3;
5809e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
5819e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
5829e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
5839e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
5849e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
5859e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
5869e6268dbSMiklos Szeredi 	request_send(fc, req);
5879e6268dbSMiklos Szeredi 	err = req->out.h.error;
5889e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
5899e6268dbSMiklos Szeredi 	if (!err) {
5909e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
5919e6268dbSMiklos Szeredi 		if (olddir != newdir)
5929e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
5938cbdf1e6SMiklos Szeredi 
5948cbdf1e6SMiklos Szeredi 		/* newent will end up negative */
5958cbdf1e6SMiklos Szeredi 		if (newent->d_inode)
5968cbdf1e6SMiklos Szeredi 			fuse_invalidate_entry_cache(newent);
5979e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
5989e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
5999e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
6009e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
6019e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
6029e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
6039e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
6049e6268dbSMiklos Szeredi 		if (newent->d_inode)
6059e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
6069e6268dbSMiklos Szeredi 	}
6079e6268dbSMiklos Szeredi 
6089e6268dbSMiklos Szeredi 	return err;
6099e6268dbSMiklos Szeredi }
6109e6268dbSMiklos Szeredi 
6119e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
6129e6268dbSMiklos Szeredi 		     struct dentry *newent)
6139e6268dbSMiklos Szeredi {
6149e6268dbSMiklos Szeredi 	int err;
6159e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
6169e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
6179e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
618ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
619ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
620ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
6219e6268dbSMiklos Szeredi 
6229e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
6239e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
6249e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
6259e6268dbSMiklos Szeredi 	req->in.numargs = 2;
6269e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
6279e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
6289e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
6299e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
6309e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
6319e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
6329e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
6339e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
6349e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
6359e6268dbSMiklos Szeredi 	   etc.)
6369e6268dbSMiklos Szeredi 	*/
6379e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
6389e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
6399e6268dbSMiklos Szeredi 	return err;
6409e6268dbSMiklos Szeredi }
6419e6268dbSMiklos Szeredi 
642e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode)
643e5e5558eSMiklos Szeredi {
644e5e5558eSMiklos Szeredi 	int err;
645e5e5558eSMiklos Szeredi 	struct fuse_attr_out arg;
646e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
647ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
648ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
649ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
650e5e5558eSMiklos Szeredi 
651e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
652e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
653e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
654e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(arg);
655e5e5558eSMiklos Szeredi 	req->out.args[0].value = &arg;
656e5e5558eSMiklos Szeredi 	request_send(fc, req);
657e5e5558eSMiklos Szeredi 	err = req->out.h.error;
658e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
659e5e5558eSMiklos Szeredi 	if (!err) {
660e5e5558eSMiklos Szeredi 		if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
661e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
662e5e5558eSMiklos Szeredi 			err = -EIO;
663e5e5558eSMiklos Szeredi 		} else {
664e5e5558eSMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
665e5e5558eSMiklos Szeredi 			fuse_change_attributes(inode, &arg.attr);
666e5e5558eSMiklos Szeredi 			fi->i_time = time_to_jiffies(arg.attr_valid,
667e5e5558eSMiklos Szeredi 						     arg.attr_valid_nsec);
668e5e5558eSMiklos Szeredi 		}
669e5e5558eSMiklos Szeredi 	}
670e5e5558eSMiklos Szeredi 	return err;
671e5e5558eSMiklos Szeredi }
672e5e5558eSMiklos Szeredi 
67387729a55SMiklos Szeredi /*
67487729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
67587729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
67687729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
67787729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
67887729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
67987729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
68087729a55SMiklos Szeredi  * DoS against the requester.
68187729a55SMiklos Szeredi  *
68287729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
68387729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
68487729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
68587729a55SMiklos Szeredi  */
68687729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
68787729a55SMiklos Szeredi {
68887729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
68987729a55SMiklos Szeredi 		return 1;
69087729a55SMiklos Szeredi 
69187729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
69287729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
69387729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
69487729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
69587729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
69687729a55SMiklos Szeredi 	    task->gid == fc->group_id)
69787729a55SMiklos Szeredi 		return 1;
69887729a55SMiklos Szeredi 
69987729a55SMiklos Szeredi 	return 0;
70087729a55SMiklos Szeredi }
70187729a55SMiklos Szeredi 
7026f9f1180SMiklos Szeredi /*
7036f9f1180SMiklos Szeredi  * Check whether the inode attributes are still valid
7046f9f1180SMiklos Szeredi  *
7056f9f1180SMiklos Szeredi  * If the attribute validity timeout has expired, then fetch the fresh
7066f9f1180SMiklos Szeredi  * attributes with a 'getattr' request
7076f9f1180SMiklos Szeredi  *
7086f9f1180SMiklos Szeredi  * I'm not sure why cached attributes are never returned for the root
7096f9f1180SMiklos Szeredi  * inode, this is probably being too cautious.
7106f9f1180SMiklos Szeredi  */
711e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry)
712e5e5558eSMiklos Szeredi {
713e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
714e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
715e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
716e5e5558eSMiklos Szeredi 
71787729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
718e5e5558eSMiklos Szeredi 		return -EACCES;
71987729a55SMiklos Szeredi 	if (get_node_id(inode) != FUSE_ROOT_ID &&
7200a0898cfSMiklos Szeredi 	    fi->i_time >= get_jiffies_64())
721e5e5558eSMiklos Szeredi 		return 0;
722e5e5558eSMiklos Szeredi 
723e5e5558eSMiklos Szeredi 	return fuse_do_getattr(inode);
724e5e5558eSMiklos Szeredi }
725e5e5558eSMiklos Szeredi 
72631d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask)
72731d40d74SMiklos Szeredi {
72831d40d74SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
72931d40d74SMiklos Szeredi 	struct fuse_req *req;
73031d40d74SMiklos Szeredi 	struct fuse_access_in inarg;
73131d40d74SMiklos Szeredi 	int err;
73231d40d74SMiklos Szeredi 
73331d40d74SMiklos Szeredi 	if (fc->no_access)
73431d40d74SMiklos Szeredi 		return 0;
73531d40d74SMiklos Szeredi 
736ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
737ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
738ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
73931d40d74SMiklos Szeredi 
74031d40d74SMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
74131d40d74SMiklos Szeredi 	inarg.mask = mask;
74231d40d74SMiklos Szeredi 	req->in.h.opcode = FUSE_ACCESS;
74331d40d74SMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
74431d40d74SMiklos Szeredi 	req->in.numargs = 1;
74531d40d74SMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
74631d40d74SMiklos Szeredi 	req->in.args[0].value = &inarg;
74731d40d74SMiklos Szeredi 	request_send(fc, req);
74831d40d74SMiklos Szeredi 	err = req->out.h.error;
74931d40d74SMiklos Szeredi 	fuse_put_request(fc, req);
75031d40d74SMiklos Szeredi 	if (err == -ENOSYS) {
75131d40d74SMiklos Szeredi 		fc->no_access = 1;
75231d40d74SMiklos Szeredi 		err = 0;
75331d40d74SMiklos Szeredi 	}
75431d40d74SMiklos Szeredi 	return err;
75531d40d74SMiklos Szeredi }
75631d40d74SMiklos Szeredi 
7576f9f1180SMiklos Szeredi /*
7586f9f1180SMiklos Szeredi  * Check permission.  The two basic access models of FUSE are:
7596f9f1180SMiklos Szeredi  *
7606f9f1180SMiklos Szeredi  * 1) Local access checking ('default_permissions' mount option) based
7616f9f1180SMiklos Szeredi  * on file mode.  This is the plain old disk filesystem permission
7626f9f1180SMiklos Szeredi  * modell.
7636f9f1180SMiklos Szeredi  *
7646f9f1180SMiklos Szeredi  * 2) "Remote" access checking, where server is responsible for
7656f9f1180SMiklos Szeredi  * checking permission in each inode operation.  An exception to this
7666f9f1180SMiklos Szeredi  * is if ->permission() was invoked from sys_access() in which case an
7676f9f1180SMiklos Szeredi  * access request is sent.  Execute permission is still checked
7686f9f1180SMiklos Szeredi  * locally based on file mode.
7696f9f1180SMiklos Szeredi  */
770e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
771e5e5558eSMiklos Szeredi {
772e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
773e5e5558eSMiklos Szeredi 
77487729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
775e5e5558eSMiklos Szeredi 		return -EACCES;
7761e9a4ed9SMiklos Szeredi 	else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
7771e9a4ed9SMiklos Szeredi 		int err = generic_permission(inode, mask, NULL);
7781e9a4ed9SMiklos Szeredi 
7791e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
7801e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
7811e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
7821e9a4ed9SMiklos Szeredi 		if (err == -EACCES) {
7831e9a4ed9SMiklos Szeredi 		 	err = fuse_do_getattr(inode);
7841e9a4ed9SMiklos Szeredi 			if (!err)
7851e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
7861e9a4ed9SMiklos Szeredi 		}
7871e9a4ed9SMiklos Szeredi 
7886f9f1180SMiklos Szeredi 		/* Note: the opposite of the above test does not
7896f9f1180SMiklos Szeredi 		   exist.  So if permissions are revoked this won't be
7906f9f1180SMiklos Szeredi 		   noticed immediately, only after the attribute
7916f9f1180SMiklos Szeredi 		   timeout has expired */
7921e9a4ed9SMiklos Szeredi 
7931e9a4ed9SMiklos Szeredi 		return err;
7941e9a4ed9SMiklos Szeredi 	} else {
795e5e5558eSMiklos Szeredi 		int mode = inode->i_mode;
796e5e5558eSMiklos Szeredi 		if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
797e5e5558eSMiklos Szeredi 			return -EACCES;
79831d40d74SMiklos Szeredi 
799650a8983SMiklos Szeredi 		if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR)))
80031d40d74SMiklos Szeredi 			return fuse_access(inode, mask);
801e5e5558eSMiklos Szeredi 		return 0;
802e5e5558eSMiklos Szeredi 	}
803e5e5558eSMiklos Szeredi }
804e5e5558eSMiklos Szeredi 
805e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
806e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
807e5e5558eSMiklos Szeredi {
808e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
809e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
810e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
811e5e5558eSMiklos Szeredi 		int over;
812e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
813e5e5558eSMiklos Szeredi 			return -EIO;
814e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
815e5e5558eSMiklos Szeredi 			break;
816e5e5558eSMiklos Szeredi 
817e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
818e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
819e5e5558eSMiklos Szeredi 		if (over)
820e5e5558eSMiklos Szeredi 			break;
821e5e5558eSMiklos Szeredi 
822e5e5558eSMiklos Szeredi 		buf += reclen;
823e5e5558eSMiklos Szeredi 		nbytes -= reclen;
824e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
825e5e5558eSMiklos Szeredi 	}
826e5e5558eSMiklos Szeredi 
827e5e5558eSMiklos Szeredi 	return 0;
828e5e5558eSMiklos Szeredi }
829e5e5558eSMiklos Szeredi 
830e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
831e5e5558eSMiklos Szeredi {
83204730fefSMiklos Szeredi 	int err;
83304730fefSMiklos Szeredi 	size_t nbytes;
83404730fefSMiklos Szeredi 	struct page *page;
83504730fefSMiklos Szeredi 	struct inode *inode = file->f_dentry->d_inode;
83604730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
837248d86e8SMiklos Szeredi 	struct fuse_req *req;
838248d86e8SMiklos Szeredi 
839248d86e8SMiklos Szeredi 	if (is_bad_inode(inode))
840248d86e8SMiklos Szeredi 		return -EIO;
841248d86e8SMiklos Szeredi 
842ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
843ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
844ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
845e5e5558eSMiklos Szeredi 
84604730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
84704730fefSMiklos Szeredi 	if (!page) {
84804730fefSMiklos Szeredi 		fuse_put_request(fc, req);
849e5e5558eSMiklos Szeredi 		return -ENOMEM;
85004730fefSMiklos Szeredi 	}
85104730fefSMiklos Szeredi 	req->num_pages = 1;
85204730fefSMiklos Szeredi 	req->pages[0] = page;
853361b1eb5SMiklos Szeredi 	fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
854361b1eb5SMiklos Szeredi 	request_send(fc, req);
855361b1eb5SMiklos Szeredi 	nbytes = req->out.args[0].size;
85604730fefSMiklos Szeredi 	err = req->out.h.error;
85704730fefSMiklos Szeredi 	fuse_put_request(fc, req);
85804730fefSMiklos Szeredi 	if (!err)
85904730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
86004730fefSMiklos Szeredi 				    filldir);
861e5e5558eSMiklos Szeredi 
86204730fefSMiklos Szeredi 	__free_page(page);
863b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
86404730fefSMiklos Szeredi 	return err;
865e5e5558eSMiklos Szeredi }
866e5e5558eSMiklos Szeredi 
867e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
868e5e5558eSMiklos Szeredi {
869e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
870e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
871ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
872e5e5558eSMiklos Szeredi 	char *link;
873e5e5558eSMiklos Szeredi 
874ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
875ce1d5a49SMiklos Szeredi 		return ERR_PTR(PTR_ERR(req));
876e5e5558eSMiklos Szeredi 
877e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
878e5e5558eSMiklos Szeredi 	if (!link) {
879e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
880e5e5558eSMiklos Szeredi 		goto out;
881e5e5558eSMiklos Szeredi 	}
882e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
883e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
884e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
885e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
886e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
887e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
888e5e5558eSMiklos Szeredi 	request_send(fc, req);
889e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
890e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
891e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
892e5e5558eSMiklos Szeredi 	} else
893e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
894e5e5558eSMiklos Szeredi  out:
895e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
896b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
897e5e5558eSMiklos Szeredi 	return link;
898e5e5558eSMiklos Szeredi }
899e5e5558eSMiklos Szeredi 
900e5e5558eSMiklos Szeredi static void free_link(char *link)
901e5e5558eSMiklos Szeredi {
902e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
903e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
904e5e5558eSMiklos Szeredi }
905e5e5558eSMiklos Szeredi 
906e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
907e5e5558eSMiklos Szeredi {
908e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
909e5e5558eSMiklos Szeredi 	return NULL;
910e5e5558eSMiklos Szeredi }
911e5e5558eSMiklos Szeredi 
912e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
913e5e5558eSMiklos Szeredi {
914e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
915e5e5558eSMiklos Szeredi }
916e5e5558eSMiklos Szeredi 
917e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
918e5e5558eSMiklos Szeredi {
91904730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
920e5e5558eSMiklos Szeredi }
921e5e5558eSMiklos Szeredi 
922e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
923e5e5558eSMiklos Szeredi {
92404730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
925e5e5558eSMiklos Szeredi }
926e5e5558eSMiklos Szeredi 
92782547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
92882547981SMiklos Szeredi {
92982547981SMiklos Szeredi 	/* nfsd can call this with no file */
93082547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
93182547981SMiklos Szeredi }
93282547981SMiklos Szeredi 
933befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
9349e6268dbSMiklos Szeredi {
9359e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
9369e6268dbSMiklos Szeredi 
9379e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
938befc649cSMiklos Szeredi 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
9399e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
940befc649cSMiklos Szeredi 		arg->valid |= FATTR_UID,    arg->uid = iattr->ia_uid;
9419e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
942befc649cSMiklos Szeredi 		arg->valid |= FATTR_GID,    arg->gid = iattr->ia_gid;
9439e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
944befc649cSMiklos Szeredi 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
9459e6268dbSMiklos Szeredi 	/* You can only _set_ these together (they may change by themselves) */
9469e6268dbSMiklos Szeredi 	if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
947befc649cSMiklos Szeredi 		arg->valid |= FATTR_ATIME | FATTR_MTIME;
948befc649cSMiklos Szeredi 		arg->atime = iattr->ia_atime.tv_sec;
949befc649cSMiklos Szeredi 		arg->mtime = iattr->ia_mtime.tv_sec;
9509e6268dbSMiklos Szeredi 	}
951befc649cSMiklos Szeredi 	if (ivalid & ATTR_FILE) {
952befc649cSMiklos Szeredi 		struct fuse_file *ff = iattr->ia_file->private_data;
953befc649cSMiklos Szeredi 		arg->valid |= FATTR_FH;
954befc649cSMiklos Szeredi 		arg->fh = ff->fh;
955befc649cSMiklos Szeredi 	}
9569e6268dbSMiklos Szeredi }
9579e6268dbSMiklos Szeredi 
9589ffbb916SMiklos Szeredi static void fuse_vmtruncate(struct inode *inode, loff_t offset)
9599ffbb916SMiklos Szeredi {
9609ffbb916SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
9619ffbb916SMiklos Szeredi 	int need_trunc;
9629ffbb916SMiklos Szeredi 
9639ffbb916SMiklos Szeredi 	spin_lock(&fc->lock);
9649ffbb916SMiklos Szeredi 	need_trunc = inode->i_size > offset;
9659ffbb916SMiklos Szeredi 	i_size_write(inode, offset);
9669ffbb916SMiklos Szeredi 	spin_unlock(&fc->lock);
9679ffbb916SMiklos Szeredi 
9689ffbb916SMiklos Szeredi 	if (need_trunc) {
9699ffbb916SMiklos Szeredi 		struct address_space *mapping = inode->i_mapping;
9709ffbb916SMiklos Szeredi 		unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
9719ffbb916SMiklos Szeredi 		truncate_inode_pages(mapping, offset);
9729ffbb916SMiklos Szeredi 	}
9739ffbb916SMiklos Szeredi }
9749ffbb916SMiklos Szeredi 
9756f9f1180SMiklos Szeredi /*
9766f9f1180SMiklos Szeredi  * Set attributes, and at the same time refresh them.
9776f9f1180SMiklos Szeredi  *
9786f9f1180SMiklos Szeredi  * Truncation is slightly complicated, because the 'truncate' request
9796f9f1180SMiklos Szeredi  * may fail, in which case we don't want to touch the mapping.
9809ffbb916SMiklos Szeredi  * vmtruncate() doesn't allow for this case, so do the rlimit checking
9819ffbb916SMiklos Szeredi  * and the actual truncation by hand.
9826f9f1180SMiklos Szeredi  */
9839e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
9849e6268dbSMiklos Szeredi {
9859e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
9869e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
9879e6268dbSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
9889e6268dbSMiklos Szeredi 	struct fuse_req *req;
9899e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
9909e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
9919e6268dbSMiklos Szeredi 	int err;
9929e6268dbSMiklos Szeredi 	int is_truncate = 0;
9939e6268dbSMiklos Szeredi 
9941e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
9951e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
9961e9a4ed9SMiklos Szeredi 		if (err)
9971e9a4ed9SMiklos Szeredi 			return err;
9981e9a4ed9SMiklos Szeredi 	}
9991e9a4ed9SMiklos Szeredi 
10009e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
10019e6268dbSMiklos Szeredi 		unsigned long limit;
10029e6268dbSMiklos Szeredi 		is_truncate = 1;
10039e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
10049e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
10059e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
10069e6268dbSMiklos Szeredi 			return -EFBIG;
10079e6268dbSMiklos Szeredi 		}
10089e6268dbSMiklos Szeredi 	}
10099e6268dbSMiklos Szeredi 
1010ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1011ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1012ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
10139e6268dbSMiklos Szeredi 
10149e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
1015befc649cSMiklos Szeredi 	iattr_to_fattr(attr, &inarg);
10169e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
10179e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
10189e6268dbSMiklos Szeredi 	req->in.numargs = 1;
10199e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
10209e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
10219e6268dbSMiklos Szeredi 	req->out.numargs = 1;
10229e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
10239e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
10249e6268dbSMiklos Szeredi 	request_send(fc, req);
10259e6268dbSMiklos Szeredi 	err = req->out.h.error;
10269e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
10279e6268dbSMiklos Szeredi 	if (!err) {
10289e6268dbSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
10299e6268dbSMiklos Szeredi 			make_bad_inode(inode);
10309e6268dbSMiklos Szeredi 			err = -EIO;
10319e6268dbSMiklos Szeredi 		} else {
10329ffbb916SMiklos Szeredi 			if (is_truncate)
10339ffbb916SMiklos Szeredi 				fuse_vmtruncate(inode, outarg.attr.size);
10349e6268dbSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr);
10359e6268dbSMiklos Szeredi 			fi->i_time = time_to_jiffies(outarg.attr_valid,
10369e6268dbSMiklos Szeredi 						     outarg.attr_valid_nsec);
10379e6268dbSMiklos Szeredi 		}
10389e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
10399e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
10409e6268dbSMiklos Szeredi 
10419e6268dbSMiklos Szeredi 	return err;
10429e6268dbSMiklos Szeredi }
10439e6268dbSMiklos Szeredi 
1044e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
1045e5e5558eSMiklos Szeredi 			struct kstat *stat)
1046e5e5558eSMiklos Szeredi {
1047e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
1048e5e5558eSMiklos Szeredi 	int err = fuse_revalidate(entry);
1049e5e5558eSMiklos Szeredi 	if (!err)
1050e5e5558eSMiklos Szeredi 		generic_fillattr(inode, stat);
1051e5e5558eSMiklos Szeredi 
1052e5e5558eSMiklos Szeredi 	return err;
1053e5e5558eSMiklos Szeredi }
1054e5e5558eSMiklos Szeredi 
105592a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
105692a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
105792a8780eSMiklos Szeredi {
105892a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
105992a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
106092a8780eSMiklos Szeredi 	struct fuse_req *req;
106192a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
106292a8780eSMiklos Szeredi 	int err;
106392a8780eSMiklos Szeredi 
106492a8780eSMiklos Szeredi 	if (fc->no_setxattr)
106592a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
106692a8780eSMiklos Szeredi 
1067ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1068ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1069ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
107092a8780eSMiklos Szeredi 
107192a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
107292a8780eSMiklos Szeredi 	inarg.size = size;
107392a8780eSMiklos Szeredi 	inarg.flags = flags;
107492a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
107592a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
107692a8780eSMiklos Szeredi 	req->in.numargs = 3;
107792a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
107892a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
107992a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
108092a8780eSMiklos Szeredi 	req->in.args[1].value = name;
108192a8780eSMiklos Szeredi 	req->in.args[2].size = size;
108292a8780eSMiklos Szeredi 	req->in.args[2].value = value;
108392a8780eSMiklos Szeredi 	request_send(fc, req);
108492a8780eSMiklos Szeredi 	err = req->out.h.error;
108592a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
108692a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
108792a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
108892a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
108992a8780eSMiklos Szeredi 	}
109092a8780eSMiklos Szeredi 	return err;
109192a8780eSMiklos Szeredi }
109292a8780eSMiklos Szeredi 
109392a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
109492a8780eSMiklos Szeredi 			     void *value, size_t size)
109592a8780eSMiklos Szeredi {
109692a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
109792a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
109892a8780eSMiklos Szeredi 	struct fuse_req *req;
109992a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
110092a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
110192a8780eSMiklos Szeredi 	ssize_t ret;
110292a8780eSMiklos Szeredi 
110392a8780eSMiklos Szeredi 	if (fc->no_getxattr)
110492a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
110592a8780eSMiklos Szeredi 
1106ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1107ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1108ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
110992a8780eSMiklos Szeredi 
111092a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
111192a8780eSMiklos Szeredi 	inarg.size = size;
111292a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
111392a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
111492a8780eSMiklos Szeredi 	req->in.numargs = 2;
111592a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
111692a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
111792a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
111892a8780eSMiklos Szeredi 	req->in.args[1].value = name;
111992a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
112092a8780eSMiklos Szeredi 	req->out.numargs = 1;
112192a8780eSMiklos Szeredi 	if (size) {
112292a8780eSMiklos Szeredi 		req->out.argvar = 1;
112392a8780eSMiklos Szeredi 		req->out.args[0].size = size;
112492a8780eSMiklos Szeredi 		req->out.args[0].value = value;
112592a8780eSMiklos Szeredi 	} else {
112692a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
112792a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
112892a8780eSMiklos Szeredi 	}
112992a8780eSMiklos Szeredi 	request_send(fc, req);
113092a8780eSMiklos Szeredi 	ret = req->out.h.error;
113192a8780eSMiklos Szeredi 	if (!ret)
113292a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
113392a8780eSMiklos Szeredi 	else {
113492a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
113592a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
113692a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
113792a8780eSMiklos Szeredi 		}
113892a8780eSMiklos Szeredi 	}
113992a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
114092a8780eSMiklos Szeredi 	return ret;
114192a8780eSMiklos Szeredi }
114292a8780eSMiklos Szeredi 
114392a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
114492a8780eSMiklos Szeredi {
114592a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
114692a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
114792a8780eSMiklos Szeredi 	struct fuse_req *req;
114892a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
114992a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
115092a8780eSMiklos Szeredi 	ssize_t ret;
115192a8780eSMiklos Szeredi 
115292a8780eSMiklos Szeredi 	if (fc->no_listxattr)
115392a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
115492a8780eSMiklos Szeredi 
1155ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1156ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1157ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
115892a8780eSMiklos Szeredi 
115992a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
116092a8780eSMiklos Szeredi 	inarg.size = size;
116192a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
116292a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
116392a8780eSMiklos Szeredi 	req->in.numargs = 1;
116492a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
116592a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
116692a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
116792a8780eSMiklos Szeredi 	req->out.numargs = 1;
116892a8780eSMiklos Szeredi 	if (size) {
116992a8780eSMiklos Szeredi 		req->out.argvar = 1;
117092a8780eSMiklos Szeredi 		req->out.args[0].size = size;
117192a8780eSMiklos Szeredi 		req->out.args[0].value = list;
117292a8780eSMiklos Szeredi 	} else {
117392a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
117492a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
117592a8780eSMiklos Szeredi 	}
117692a8780eSMiklos Szeredi 	request_send(fc, req);
117792a8780eSMiklos Szeredi 	ret = req->out.h.error;
117892a8780eSMiklos Szeredi 	if (!ret)
117992a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
118092a8780eSMiklos Szeredi 	else {
118192a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
118292a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
118392a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
118492a8780eSMiklos Szeredi 		}
118592a8780eSMiklos Szeredi 	}
118692a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
118792a8780eSMiklos Szeredi 	return ret;
118892a8780eSMiklos Szeredi }
118992a8780eSMiklos Szeredi 
119092a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
119192a8780eSMiklos Szeredi {
119292a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
119392a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
119492a8780eSMiklos Szeredi 	struct fuse_req *req;
119592a8780eSMiklos Szeredi 	int err;
119692a8780eSMiklos Szeredi 
119792a8780eSMiklos Szeredi 	if (fc->no_removexattr)
119892a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
119992a8780eSMiklos Szeredi 
1200ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1201ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1202ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
120392a8780eSMiklos Szeredi 
120492a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
120592a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
120692a8780eSMiklos Szeredi 	req->in.numargs = 1;
120792a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
120892a8780eSMiklos Szeredi 	req->in.args[0].value = name;
120992a8780eSMiklos Szeredi 	request_send(fc, req);
121092a8780eSMiklos Szeredi 	err = req->out.h.error;
121192a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
121292a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
121392a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
121492a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
121592a8780eSMiklos Szeredi 	}
121692a8780eSMiklos Szeredi 	return err;
121792a8780eSMiklos Szeredi }
121892a8780eSMiklos Szeredi 
1219e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = {
1220e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
12219e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
12229e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
12239e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
12249e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
12259e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
12269e6268dbSMiklos Szeredi 	.link		= fuse_link,
12279e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
12289e6268dbSMiklos Szeredi 	.create		= fuse_create,
12299e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
1230e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1231e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
123292a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
123392a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
123492a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
123592a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1236e5e5558eSMiklos Szeredi };
1237e5e5558eSMiklos Szeredi 
12384b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = {
1239b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
1240e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
1241e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
1242e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
1243e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
124482547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
1245e5e5558eSMiklos Szeredi };
1246e5e5558eSMiklos Szeredi 
1247e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = {
12489e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1249e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1250e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
125192a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
125292a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
125392a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
125492a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1255e5e5558eSMiklos Szeredi };
1256e5e5558eSMiklos Szeredi 
1257e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = {
12589e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1259e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
1260e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
1261e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
1262e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
126392a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
126492a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
126592a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
126692a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1267e5e5558eSMiklos Szeredi };
1268e5e5558eSMiklos Szeredi 
1269e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
1270e5e5558eSMiklos Szeredi {
1271e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
1272e5e5558eSMiklos Szeredi }
1273e5e5558eSMiklos Szeredi 
1274e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
1275e5e5558eSMiklos Szeredi {
1276e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
1277e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
1278e5e5558eSMiklos Szeredi }
1279e5e5558eSMiklos Szeredi 
1280e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
1281e5e5558eSMiklos Szeredi {
1282e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
1283e5e5558eSMiklos Szeredi }
1284