xref: /openbmc/linux/fs/fuse/dir.c (revision a6643094e73247c1ebd36816f494f631fa7be348)
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  */
661fb69e78SMiklos Szeredi static void fuse_change_entry_timeout(struct dentry *entry,
671fb69e78SMiklos Szeredi 				      struct fuse_entry_out *o)
680aa7c699SMiklos Szeredi {
690a0898cfSMiklos Szeredi 	fuse_dentry_settime(entry,
700a0898cfSMiklos Szeredi 		time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
711fb69e78SMiklos Szeredi }
721fb69e78SMiklos Szeredi 
731fb69e78SMiklos Szeredi static u64 attr_timeout(struct fuse_attr_out *o)
741fb69e78SMiklos Szeredi {
751fb69e78SMiklos Szeredi 	return time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
761fb69e78SMiklos Szeredi }
771fb69e78SMiklos Szeredi 
781fb69e78SMiklos Szeredi static u64 entry_attr_timeout(struct fuse_entry_out *o)
791fb69e78SMiklos Szeredi {
801fb69e78SMiklos Szeredi 	return time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
818cbdf1e6SMiklos Szeredi }
828cbdf1e6SMiklos Szeredi 
836f9f1180SMiklos Szeredi /*
846f9f1180SMiklos Szeredi  * Mark the attributes as stale, so that at the next call to
856f9f1180SMiklos Szeredi  * ->getattr() they will be fetched from userspace
866f9f1180SMiklos Szeredi  */
878cbdf1e6SMiklos Szeredi void fuse_invalidate_attr(struct inode *inode)
888cbdf1e6SMiklos Szeredi {
890a0898cfSMiklos Szeredi 	get_fuse_inode(inode)->i_time = 0;
908cbdf1e6SMiklos Szeredi }
918cbdf1e6SMiklos Szeredi 
926f9f1180SMiklos Szeredi /*
936f9f1180SMiklos Szeredi  * Just mark the entry as stale, so that a next attempt to look it up
946f9f1180SMiklos Szeredi  * will result in a new lookup call to userspace
956f9f1180SMiklos Szeredi  *
966f9f1180SMiklos Szeredi  * This is called when a dentry is about to become negative and the
976f9f1180SMiklos Szeredi  * timeout is unknown (unlink, rmdir, rename and in some cases
986f9f1180SMiklos Szeredi  * lookup)
996f9f1180SMiklos Szeredi  */
1008cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry_cache(struct dentry *entry)
1018cbdf1e6SMiklos Szeredi {
1020a0898cfSMiklos Szeredi 	fuse_dentry_settime(entry, 0);
1038cbdf1e6SMiklos Szeredi }
1048cbdf1e6SMiklos Szeredi 
1056f9f1180SMiklos Szeredi /*
1066f9f1180SMiklos Szeredi  * Same as fuse_invalidate_entry_cache(), but also try to remove the
1076f9f1180SMiklos Szeredi  * dentry from the hash
1086f9f1180SMiklos Szeredi  */
1098cbdf1e6SMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry)
1108cbdf1e6SMiklos Szeredi {
1118cbdf1e6SMiklos Szeredi 	d_invalidate(entry);
1128cbdf1e6SMiklos Szeredi 	fuse_invalidate_entry_cache(entry);
1130aa7c699SMiklos Szeredi }
1140aa7c699SMiklos Szeredi 
115e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
116e5e5558eSMiklos Szeredi 			     struct dentry *entry,
117e5e5558eSMiklos Szeredi 			     struct fuse_entry_out *outarg)
118e5e5558eSMiklos Szeredi {
1190e9663eeSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
1200e9663eeSMiklos Szeredi 
1210e9663eeSMiklos Szeredi 	memset(outarg, 0, sizeof(struct fuse_entry_out));
122e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_LOOKUP;
123e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
124e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
125e5e5558eSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
126e5e5558eSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
127e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
1280e9663eeSMiklos Szeredi 	if (fc->minor < 9)
1290e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
1300e9663eeSMiklos Szeredi 	else
131e5e5558eSMiklos Szeredi 		req->out.args[0].size = sizeof(struct fuse_entry_out);
132e5e5558eSMiklos Szeredi 	req->out.args[0].value = outarg;
133e5e5558eSMiklos Szeredi }
134e5e5558eSMiklos Szeredi 
1357dca9fd3SMiklos Szeredi static u64 fuse_get_attr_version(struct fuse_conn *fc)
1367dca9fd3SMiklos Szeredi {
1377dca9fd3SMiklos Szeredi 	u64 curr_version;
1387dca9fd3SMiklos Szeredi 
1397dca9fd3SMiklos Szeredi 	/*
1407dca9fd3SMiklos Szeredi 	 * The spin lock isn't actually needed on 64bit archs, but we
1417dca9fd3SMiklos Szeredi 	 * don't yet care too much about such optimizations.
1427dca9fd3SMiklos Szeredi 	 */
1437dca9fd3SMiklos Szeredi 	spin_lock(&fc->lock);
1447dca9fd3SMiklos Szeredi 	curr_version = fc->attr_version;
1457dca9fd3SMiklos Szeredi 	spin_unlock(&fc->lock);
1467dca9fd3SMiklos Szeredi 
1477dca9fd3SMiklos Szeredi 	return curr_version;
1487dca9fd3SMiklos Szeredi }
1497dca9fd3SMiklos Szeredi 
1506f9f1180SMiklos Szeredi /*
1516f9f1180SMiklos Szeredi  * Check whether the dentry is still valid
1526f9f1180SMiklos Szeredi  *
1536f9f1180SMiklos Szeredi  * If the entry validity timeout has expired and the dentry is
1546f9f1180SMiklos Szeredi  * positive, try to redo the lookup.  If the lookup results in a
1556f9f1180SMiklos Szeredi  * different inode, then let the VFS invalidate the dentry and redo
1566f9f1180SMiklos Szeredi  * the lookup once more.  If the lookup results in the same inode,
1576f9f1180SMiklos Szeredi  * then refresh the attributes, timeouts and mark the dentry valid.
1586f9f1180SMiklos Szeredi  */
159e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
160e5e5558eSMiklos Szeredi {
1618cbdf1e6SMiklos Szeredi 	struct inode *inode = entry->d_inode;
1628cbdf1e6SMiklos Szeredi 
1638cbdf1e6SMiklos Szeredi 	if (inode && is_bad_inode(inode))
164e5e5558eSMiklos Szeredi 		return 0;
1650a0898cfSMiklos Szeredi 	else if (fuse_dentry_time(entry) < get_jiffies_64()) {
166e5e5558eSMiklos Szeredi 		int err;
167e5e5558eSMiklos Szeredi 		struct fuse_entry_out outarg;
1688cbdf1e6SMiklos Szeredi 		struct fuse_conn *fc;
1698cbdf1e6SMiklos Szeredi 		struct fuse_req *req;
1702d51013eSMiklos Szeredi 		struct fuse_req *forget_req;
171e956edd0SMiklos Szeredi 		struct dentry *parent;
1721fb69e78SMiklos Szeredi 		u64 attr_version;
1738cbdf1e6SMiklos Szeredi 
17450322fe7SMiklos Szeredi 		/* For negative dentries, always do a fresh lookup */
1758cbdf1e6SMiklos Szeredi 		if (!inode)
1768cbdf1e6SMiklos Szeredi 			return 0;
1778cbdf1e6SMiklos Szeredi 
1788cbdf1e6SMiklos Szeredi 		fc = get_fuse_conn(inode);
179ce1d5a49SMiklos Szeredi 		req = fuse_get_req(fc);
180ce1d5a49SMiklos Szeredi 		if (IS_ERR(req))
181e5e5558eSMiklos Szeredi 			return 0;
182e5e5558eSMiklos Szeredi 
1832d51013eSMiklos Szeredi 		forget_req = fuse_get_req(fc);
1842d51013eSMiklos Szeredi 		if (IS_ERR(forget_req)) {
1852d51013eSMiklos Szeredi 			fuse_put_request(fc, req);
1862d51013eSMiklos Szeredi 			return 0;
1872d51013eSMiklos Szeredi 		}
1882d51013eSMiklos Szeredi 
1897dca9fd3SMiklos Szeredi 		attr_version = fuse_get_attr_version(fc);
1901fb69e78SMiklos Szeredi 
191e956edd0SMiklos Szeredi 		parent = dget_parent(entry);
192e956edd0SMiklos Szeredi 		fuse_lookup_init(req, parent->d_inode, entry, &outarg);
1937c352bdfSMiklos Szeredi 		request_send(fc, req);
194e956edd0SMiklos Szeredi 		dput(parent);
195e5e5558eSMiklos Szeredi 		err = req->out.h.error;
1962d51013eSMiklos Szeredi 		fuse_put_request(fc, req);
19750322fe7SMiklos Szeredi 		/* Zero nodeid is same as -ENOENT */
19850322fe7SMiklos Szeredi 		if (!err && !outarg.nodeid)
19950322fe7SMiklos Szeredi 			err = -ENOENT;
2009e6268dbSMiklos Szeredi 		if (!err) {
2018cbdf1e6SMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
2029e6268dbSMiklos Szeredi 			if (outarg.nodeid != get_node_id(inode)) {
2032d51013eSMiklos Szeredi 				fuse_send_forget(fc, forget_req,
2042d51013eSMiklos Szeredi 						 outarg.nodeid, 1);
2059e6268dbSMiklos Szeredi 				return 0;
2069e6268dbSMiklos Szeredi 			}
2078da5ff23SMiklos Szeredi 			spin_lock(&fc->lock);
2089e6268dbSMiklos Szeredi 			fi->nlookup ++;
2098da5ff23SMiklos Szeredi 			spin_unlock(&fc->lock);
2109e6268dbSMiklos Szeredi 		}
2112d51013eSMiklos Szeredi 		fuse_put_request(fc, forget_req);
2129e6268dbSMiklos Szeredi 		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
213e5e5558eSMiklos Szeredi 			return 0;
214e5e5558eSMiklos Szeredi 
2151fb69e78SMiklos Szeredi 		fuse_change_attributes(inode, &outarg.attr,
2161fb69e78SMiklos Szeredi 				       entry_attr_timeout(&outarg),
2171fb69e78SMiklos Szeredi 				       attr_version);
2181fb69e78SMiklos Szeredi 		fuse_change_entry_timeout(entry, &outarg);
219e5e5558eSMiklos Szeredi 	}
220e5e5558eSMiklos Szeredi 	return 1;
221e5e5558eSMiklos Szeredi }
222e5e5558eSMiklos Szeredi 
2238bfc016dSMiklos Szeredi static int invalid_nodeid(u64 nodeid)
2242827d0b2SMiklos Szeredi {
2252827d0b2SMiklos Szeredi 	return !nodeid || nodeid == FUSE_ROOT_ID;
2262827d0b2SMiklos Szeredi }
2272827d0b2SMiklos Szeredi 
228e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = {
229e5e5558eSMiklos Szeredi 	.d_revalidate	= fuse_dentry_revalidate,
230e5e5558eSMiklos Szeredi };
231e5e5558eSMiklos Szeredi 
232a5bfffacSTimo Savola int fuse_valid_type(int m)
23339ee059aSMiklos Szeredi {
23439ee059aSMiklos Szeredi 	return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
23539ee059aSMiklos Szeredi 		S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
23639ee059aSMiklos Szeredi }
23739ee059aSMiklos Szeredi 
238d2a85164SMiklos Szeredi /*
239d2a85164SMiklos Szeredi  * Add a directory inode to a dentry, ensuring that no other dentry
240d2a85164SMiklos Szeredi  * refers to this inode.  Called with fc->inst_mutex.
241d2a85164SMiklos Szeredi  */
242d2a85164SMiklos Szeredi static int fuse_d_add_directory(struct dentry *entry, struct inode *inode)
243d2a85164SMiklos Szeredi {
244d2a85164SMiklos Szeredi 	struct dentry *alias = d_find_alias(inode);
245d2a85164SMiklos Szeredi 	if (alias) {
246d2a85164SMiklos Szeredi 		/* This tries to shrink the subtree below alias */
247d2a85164SMiklos Szeredi 		fuse_invalidate_entry(alias);
248d2a85164SMiklos Szeredi 		dput(alias);
249d2a85164SMiklos Szeredi 		if (!list_empty(&inode->i_dentry))
250d2a85164SMiklos Szeredi 			return -EBUSY;
251d2a85164SMiklos Szeredi 	}
252d2a85164SMiklos Szeredi 	d_add(entry, inode);
253d2a85164SMiklos Szeredi 	return 0;
254d2a85164SMiklos Szeredi }
255d2a85164SMiklos Szeredi 
2560aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
2570aa7c699SMiklos Szeredi 				  struct nameidata *nd)
258e5e5558eSMiklos Szeredi {
259e5e5558eSMiklos Szeredi 	int err;
260e5e5558eSMiklos Szeredi 	struct fuse_entry_out outarg;
261e5e5558eSMiklos Szeredi 	struct inode *inode = NULL;
262e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
263e5e5558eSMiklos Szeredi 	struct fuse_req *req;
2642d51013eSMiklos Szeredi 	struct fuse_req *forget_req;
2651fb69e78SMiklos Szeredi 	u64 attr_version;
266e5e5558eSMiklos Szeredi 
267e5e5558eSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
2680aa7c699SMiklos Szeredi 		return ERR_PTR(-ENAMETOOLONG);
269e5e5558eSMiklos Szeredi 
270ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
271ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
272ce1d5a49SMiklos Szeredi 		return ERR_PTR(PTR_ERR(req));
273e5e5558eSMiklos Szeredi 
2742d51013eSMiklos Szeredi 	forget_req = fuse_get_req(fc);
2752d51013eSMiklos Szeredi 	if (IS_ERR(forget_req)) {
2762d51013eSMiklos Szeredi 		fuse_put_request(fc, req);
2772d51013eSMiklos Szeredi 		return ERR_PTR(PTR_ERR(forget_req));
2782d51013eSMiklos Szeredi 	}
2792d51013eSMiklos Szeredi 
2807dca9fd3SMiklos Szeredi 	attr_version = fuse_get_attr_version(fc);
2811fb69e78SMiklos Szeredi 
282e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
283e5e5558eSMiklos Szeredi 	request_send(fc, req);
284e5e5558eSMiklos Szeredi 	err = req->out.h.error;
2852d51013eSMiklos Szeredi 	fuse_put_request(fc, req);
28650322fe7SMiklos Szeredi 	/* Zero nodeid is same as -ENOENT, but with valid timeout */
28750322fe7SMiklos Szeredi 	if (!err && outarg.nodeid &&
288a5bfffacSTimo Savola 	    (invalid_nodeid(outarg.nodeid) ||
289a5bfffacSTimo Savola 	     !fuse_valid_type(outarg.attr.mode)))
290ee4e5271SMiklos Szeredi 		err = -EIO;
2918cbdf1e6SMiklos Szeredi 	if (!err && outarg.nodeid) {
292e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
2931fb69e78SMiklos Szeredi 				  &outarg.attr, entry_attr_timeout(&outarg),
2941fb69e78SMiklos Szeredi 				  attr_version);
295e5e5558eSMiklos Szeredi 		if (!inode) {
2962d51013eSMiklos Szeredi 			fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
2970aa7c699SMiklos Szeredi 			return ERR_PTR(-ENOMEM);
298e5e5558eSMiklos Szeredi 		}
299e5e5558eSMiklos Szeredi 	}
3002d51013eSMiklos Szeredi 	fuse_put_request(fc, forget_req);
301e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
3020aa7c699SMiklos Szeredi 		return ERR_PTR(err);
303e5e5558eSMiklos Szeredi 
304d2a85164SMiklos Szeredi 	if (inode && S_ISDIR(inode->i_mode)) {
305d2a85164SMiklos Szeredi 		mutex_lock(&fc->inst_mutex);
306d2a85164SMiklos Szeredi 		err = fuse_d_add_directory(entry, inode);
307d2a85164SMiklos Szeredi 		mutex_unlock(&fc->inst_mutex);
308d2a85164SMiklos Szeredi 		if (err) {
3090aa7c699SMiklos Szeredi 			iput(inode);
310d2a85164SMiklos Szeredi 			return ERR_PTR(err);
311e5e5558eSMiklos Szeredi 		}
312d2a85164SMiklos Szeredi 	} else
3130aa7c699SMiklos Szeredi 		d_add(entry, inode);
314d2a85164SMiklos Szeredi 
315e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
3168cbdf1e6SMiklos Szeredi 	if (!err)
3171fb69e78SMiklos Szeredi 		fuse_change_entry_timeout(entry, &outarg);
3188cbdf1e6SMiklos Szeredi 	else
3198cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
3200aa7c699SMiklos Szeredi 	return NULL;
321e5e5558eSMiklos Szeredi }
322e5e5558eSMiklos Szeredi 
3236f9f1180SMiklos Szeredi /*
32451eb01e7SMiklos Szeredi  * Synchronous release for the case when something goes wrong in CREATE_OPEN
32551eb01e7SMiklos Szeredi  */
32651eb01e7SMiklos Szeredi static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
32751eb01e7SMiklos Szeredi 			      u64 nodeid, int flags)
32851eb01e7SMiklos Szeredi {
329c756e0a4SMiklos Szeredi 	fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
330c756e0a4SMiklos Szeredi 	ff->reserved_req->force = 1;
331c756e0a4SMiklos Szeredi 	request_send(fc, ff->reserved_req);
332c756e0a4SMiklos Szeredi 	fuse_put_request(fc, ff->reserved_req);
333c756e0a4SMiklos Szeredi 	kfree(ff);
33451eb01e7SMiklos Szeredi }
33551eb01e7SMiklos Szeredi 
33651eb01e7SMiklos Szeredi /*
3376f9f1180SMiklos Szeredi  * Atomic create+open operation
3386f9f1180SMiklos Szeredi  *
3396f9f1180SMiklos Szeredi  * If the filesystem doesn't support this, then fall back to separate
3406f9f1180SMiklos Szeredi  * 'mknod' + 'open' requests.
3416f9f1180SMiklos Szeredi  */
342fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
343fd72faacSMiklos Szeredi 			    struct nameidata *nd)
344fd72faacSMiklos Szeredi {
345fd72faacSMiklos Szeredi 	int err;
346fd72faacSMiklos Szeredi 	struct inode *inode;
347fd72faacSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
348fd72faacSMiklos Szeredi 	struct fuse_req *req;
34951eb01e7SMiklos Szeredi 	struct fuse_req *forget_req;
350fd72faacSMiklos Szeredi 	struct fuse_open_in inarg;
351fd72faacSMiklos Szeredi 	struct fuse_open_out outopen;
352fd72faacSMiklos Szeredi 	struct fuse_entry_out outentry;
353fd72faacSMiklos Szeredi 	struct fuse_file *ff;
354fd72faacSMiklos Szeredi 	struct file *file;
355fd72faacSMiklos Szeredi 	int flags = nd->intent.open.flags - 1;
356fd72faacSMiklos Szeredi 
357fd72faacSMiklos Szeredi 	if (fc->no_create)
358ce1d5a49SMiklos Szeredi 		return -ENOSYS;
359fd72faacSMiklos Szeredi 
36051eb01e7SMiklos Szeredi 	forget_req = fuse_get_req(fc);
36151eb01e7SMiklos Szeredi 	if (IS_ERR(forget_req))
36251eb01e7SMiklos Szeredi 		return PTR_ERR(forget_req);
36351eb01e7SMiklos Szeredi 
364ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
36551eb01e7SMiklos Szeredi 	err = PTR_ERR(req);
366ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
36751eb01e7SMiklos Szeredi 		goto out_put_forget_req;
368fd72faacSMiklos Szeredi 
369ce1d5a49SMiklos Szeredi 	err = -ENOMEM;
370fd72faacSMiklos Szeredi 	ff = fuse_file_alloc();
371fd72faacSMiklos Szeredi 	if (!ff)
372fd72faacSMiklos Szeredi 		goto out_put_request;
373fd72faacSMiklos Szeredi 
374fd72faacSMiklos Szeredi 	flags &= ~O_NOCTTY;
375fd72faacSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3760e9663eeSMiklos Szeredi 	memset(&outentry, 0, sizeof(outentry));
377fd72faacSMiklos Szeredi 	inarg.flags = flags;
378fd72faacSMiklos Szeredi 	inarg.mode = mode;
379fd72faacSMiklos Szeredi 	req->in.h.opcode = FUSE_CREATE;
380fd72faacSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
381fd72faacSMiklos Szeredi 	req->in.numargs = 2;
382fd72faacSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
383fd72faacSMiklos Szeredi 	req->in.args[0].value = &inarg;
384fd72faacSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
385fd72faacSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
386fd72faacSMiklos Szeredi 	req->out.numargs = 2;
3870e9663eeSMiklos Szeredi 	if (fc->minor < 9)
3880e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
3890e9663eeSMiklos Szeredi 	else
390fd72faacSMiklos Szeredi 		req->out.args[0].size = sizeof(outentry);
391fd72faacSMiklos Szeredi 	req->out.args[0].value = &outentry;
392fd72faacSMiklos Szeredi 	req->out.args[1].size = sizeof(outopen);
393fd72faacSMiklos Szeredi 	req->out.args[1].value = &outopen;
394fd72faacSMiklos Szeredi 	request_send(fc, req);
395fd72faacSMiklos Szeredi 	err = req->out.h.error;
396fd72faacSMiklos Szeredi 	if (err) {
397fd72faacSMiklos Szeredi 		if (err == -ENOSYS)
398fd72faacSMiklos Szeredi 			fc->no_create = 1;
399fd72faacSMiklos Szeredi 		goto out_free_ff;
400fd72faacSMiklos Szeredi 	}
401fd72faacSMiklos Szeredi 
402fd72faacSMiklos Szeredi 	err = -EIO;
4032827d0b2SMiklos Szeredi 	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
404fd72faacSMiklos Szeredi 		goto out_free_ff;
405fd72faacSMiklos Szeredi 
40651eb01e7SMiklos Szeredi 	fuse_put_request(fc, req);
407fd72faacSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
4081fb69e78SMiklos Szeredi 			  &outentry.attr, entry_attr_timeout(&outentry), 0);
409fd72faacSMiklos Szeredi 	if (!inode) {
410fd72faacSMiklos Szeredi 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
411fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
41251eb01e7SMiklos Szeredi 		fuse_sync_release(fc, ff, outentry.nodeid, flags);
41351eb01e7SMiklos Szeredi 		fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
41451eb01e7SMiklos Szeredi 		return -ENOMEM;
415fd72faacSMiklos Szeredi 	}
41651eb01e7SMiklos Szeredi 	fuse_put_request(fc, forget_req);
417fd72faacSMiklos Szeredi 	d_instantiate(entry, inode);
4181fb69e78SMiklos Szeredi 	fuse_change_entry_timeout(entry, &outentry);
419fd72faacSMiklos Szeredi 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
420fd72faacSMiklos Szeredi 	if (IS_ERR(file)) {
421fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
42251eb01e7SMiklos Szeredi 		fuse_sync_release(fc, ff, outentry.nodeid, flags);
423fd72faacSMiklos Szeredi 		return PTR_ERR(file);
424fd72faacSMiklos Szeredi 	}
425fd72faacSMiklos Szeredi 	fuse_finish_open(inode, file, ff, &outopen);
426fd72faacSMiklos Szeredi 	return 0;
427fd72faacSMiklos Szeredi 
428fd72faacSMiklos Szeredi  out_free_ff:
429fd72faacSMiklos Szeredi 	fuse_file_free(ff);
430fd72faacSMiklos Szeredi  out_put_request:
431fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
43251eb01e7SMiklos Szeredi  out_put_forget_req:
43351eb01e7SMiklos Szeredi 	fuse_put_request(fc, forget_req);
434fd72faacSMiklos Szeredi 	return err;
435fd72faacSMiklos Szeredi }
436fd72faacSMiklos Szeredi 
4376f9f1180SMiklos Szeredi /*
4386f9f1180SMiklos Szeredi  * Code shared between mknod, mkdir, symlink and link
4396f9f1180SMiklos Szeredi  */
4409e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
4419e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
4429e6268dbSMiklos Szeredi 			    int mode)
4439e6268dbSMiklos Szeredi {
4449e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
4459e6268dbSMiklos Szeredi 	struct inode *inode;
4469e6268dbSMiklos Szeredi 	int err;
4472d51013eSMiklos Szeredi 	struct fuse_req *forget_req;
4482d51013eSMiklos Szeredi 
4492d51013eSMiklos Szeredi 	forget_req = fuse_get_req(fc);
4502d51013eSMiklos Szeredi 	if (IS_ERR(forget_req)) {
4512d51013eSMiklos Szeredi 		fuse_put_request(fc, req);
4522d51013eSMiklos Szeredi 		return PTR_ERR(forget_req);
4532d51013eSMiklos Szeredi 	}
4549e6268dbSMiklos Szeredi 
4550e9663eeSMiklos Szeredi 	memset(&outarg, 0, sizeof(outarg));
4569e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
4579e6268dbSMiklos Szeredi 	req->out.numargs = 1;
4580e9663eeSMiklos Szeredi 	if (fc->minor < 9)
4590e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
4600e9663eeSMiklos Szeredi 	else
4619e6268dbSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
4629e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
4639e6268dbSMiklos Szeredi 	request_send(fc, req);
4649e6268dbSMiklos Szeredi 	err = req->out.h.error;
4659e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4662d51013eSMiklos Szeredi 	if (err)
4672d51013eSMiklos Szeredi 		goto out_put_forget_req;
4682d51013eSMiklos Szeredi 
46939ee059aSMiklos Szeredi 	err = -EIO;
47039ee059aSMiklos Szeredi 	if (invalid_nodeid(outarg.nodeid))
4712d51013eSMiklos Szeredi 		goto out_put_forget_req;
47239ee059aSMiklos Szeredi 
47339ee059aSMiklos Szeredi 	if ((outarg.attr.mode ^ mode) & S_IFMT)
4742d51013eSMiklos Szeredi 		goto out_put_forget_req;
47539ee059aSMiklos Szeredi 
4769e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
4771fb69e78SMiklos Szeredi 			  &outarg.attr, entry_attr_timeout(&outarg), 0);
4789e6268dbSMiklos Szeredi 	if (!inode) {
4792d51013eSMiklos Szeredi 		fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
4809e6268dbSMiklos Szeredi 		return -ENOMEM;
4819e6268dbSMiklos Szeredi 	}
4822d51013eSMiklos Szeredi 	fuse_put_request(fc, forget_req);
4839e6268dbSMiklos Szeredi 
484d2a85164SMiklos Szeredi 	if (S_ISDIR(inode->i_mode)) {
485d2a85164SMiklos Szeredi 		struct dentry *alias;
486d2a85164SMiklos Szeredi 		mutex_lock(&fc->inst_mutex);
487d2a85164SMiklos Szeredi 		alias = d_find_alias(inode);
488d2a85164SMiklos Szeredi 		if (alias) {
489d2a85164SMiklos Szeredi 			/* New directory must have moved since mkdir */
490d2a85164SMiklos Szeredi 			mutex_unlock(&fc->inst_mutex);
491d2a85164SMiklos Szeredi 			dput(alias);
4929e6268dbSMiklos Szeredi 			iput(inode);
493d2a85164SMiklos Szeredi 			return -EBUSY;
4949e6268dbSMiklos Szeredi 		}
4959e6268dbSMiklos Szeredi 		d_instantiate(entry, inode);
496d2a85164SMiklos Szeredi 		mutex_unlock(&fc->inst_mutex);
497d2a85164SMiklos Szeredi 	} else
498d2a85164SMiklos Szeredi 		d_instantiate(entry, inode);
499d2a85164SMiklos Szeredi 
5001fb69e78SMiklos Szeredi 	fuse_change_entry_timeout(entry, &outarg);
5019e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
5029e6268dbSMiklos Szeredi 	return 0;
50339ee059aSMiklos Szeredi 
5042d51013eSMiklos Szeredi  out_put_forget_req:
5052d51013eSMiklos Szeredi 	fuse_put_request(fc, forget_req);
50639ee059aSMiklos Szeredi 	return err;
5079e6268dbSMiklos Szeredi }
5089e6268dbSMiklos Szeredi 
5099e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
5109e6268dbSMiklos Szeredi 		      dev_t rdev)
5119e6268dbSMiklos Szeredi {
5129e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
5139e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
514ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
515ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
516ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5179e6268dbSMiklos Szeredi 
5189e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
5199e6268dbSMiklos Szeredi 	inarg.mode = mode;
5209e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
5219e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
5229e6268dbSMiklos Szeredi 	req->in.numargs = 2;
5239e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
5249e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
5259e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
5269e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
5279e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
5289e6268dbSMiklos Szeredi }
5299e6268dbSMiklos Szeredi 
5309e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
5319e6268dbSMiklos Szeredi 		       struct nameidata *nd)
5329e6268dbSMiklos Szeredi {
533b9ba347fSMiklos Szeredi 	if (nd && (nd->flags & LOOKUP_OPEN)) {
534fd72faacSMiklos Szeredi 		int err = fuse_create_open(dir, entry, mode, nd);
535fd72faacSMiklos Szeredi 		if (err != -ENOSYS)
536fd72faacSMiklos Szeredi 			return err;
537fd72faacSMiklos Szeredi 		/* Fall back on mknod */
538fd72faacSMiklos Szeredi 	}
5399e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
5409e6268dbSMiklos Szeredi }
5419e6268dbSMiklos Szeredi 
5429e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
5439e6268dbSMiklos Szeredi {
5449e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
5459e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
546ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
547ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
548ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5499e6268dbSMiklos Szeredi 
5509e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
5519e6268dbSMiklos Szeredi 	inarg.mode = mode;
5529e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
5539e6268dbSMiklos Szeredi 	req->in.numargs = 2;
5549e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
5559e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
5569e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
5579e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
5589e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
5599e6268dbSMiklos Szeredi }
5609e6268dbSMiklos Szeredi 
5619e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
5629e6268dbSMiklos Szeredi 			const char *link)
5639e6268dbSMiklos Szeredi {
5649e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
5659e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
566ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
567ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
568ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5699e6268dbSMiklos Szeredi 
5709e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SYMLINK;
5719e6268dbSMiklos Szeredi 	req->in.numargs = 2;
5729e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5739e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5749e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
5759e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
5769e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
5779e6268dbSMiklos Szeredi }
5789e6268dbSMiklos Szeredi 
5799e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
5809e6268dbSMiklos Szeredi {
5819e6268dbSMiklos Szeredi 	int err;
5829e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
583ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
584ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
585ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5869e6268dbSMiklos Szeredi 
5879e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
5889e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
5899e6268dbSMiklos Szeredi 	req->in.numargs = 1;
5909e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5919e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5929e6268dbSMiklos Szeredi 	request_send(fc, req);
5939e6268dbSMiklos Szeredi 	err = req->out.h.error;
5949e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
5959e6268dbSMiklos Szeredi 	if (!err) {
5969e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
5979e6268dbSMiklos Szeredi 
5989e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
5999e6268dbSMiklos Szeredi                    the inode does have more links this will be
6009e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
601ce71ec36SDave Hansen 		clear_nlink(inode);
6029e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
6039e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
6048cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
6059e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
6069e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
6079e6268dbSMiklos Szeredi 	return err;
6089e6268dbSMiklos Szeredi }
6099e6268dbSMiklos Szeredi 
6109e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
6119e6268dbSMiklos Szeredi {
6129e6268dbSMiklos Szeredi 	int err;
6139e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
614ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
615ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
616ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
6179e6268dbSMiklos Szeredi 
6189e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
6199e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
6209e6268dbSMiklos Szeredi 	req->in.numargs = 1;
6219e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
6229e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
6239e6268dbSMiklos Szeredi 	request_send(fc, req);
6249e6268dbSMiklos Szeredi 	err = req->out.h.error;
6259e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
6269e6268dbSMiklos Szeredi 	if (!err) {
627ce71ec36SDave Hansen 		clear_nlink(entry->d_inode);
6289e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
6298cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
6309e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
6319e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
6329e6268dbSMiklos Szeredi 	return err;
6339e6268dbSMiklos Szeredi }
6349e6268dbSMiklos Szeredi 
6359e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
6369e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
6379e6268dbSMiklos Szeredi {
6389e6268dbSMiklos Szeredi 	int err;
6399e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
6409e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
641ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
642ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
643ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
6449e6268dbSMiklos Szeredi 
6459e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
6469e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
6479e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
6489e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
6499e6268dbSMiklos Szeredi 	req->in.numargs = 3;
6509e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
6519e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
6529e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
6539e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
6549e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
6559e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
6569e6268dbSMiklos Szeredi 	request_send(fc, req);
6579e6268dbSMiklos Szeredi 	err = req->out.h.error;
6589e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
6599e6268dbSMiklos Szeredi 	if (!err) {
6609e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
6619e6268dbSMiklos Szeredi 		if (olddir != newdir)
6629e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
6638cbdf1e6SMiklos Szeredi 
6648cbdf1e6SMiklos Szeredi 		/* newent will end up negative */
6658cbdf1e6SMiklos Szeredi 		if (newent->d_inode)
6668cbdf1e6SMiklos Szeredi 			fuse_invalidate_entry_cache(newent);
6679e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
6689e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
6699e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
6709e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
6719e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
6729e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
6739e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
6749e6268dbSMiklos Szeredi 		if (newent->d_inode)
6759e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
6769e6268dbSMiklos Szeredi 	}
6779e6268dbSMiklos Szeredi 
6789e6268dbSMiklos Szeredi 	return err;
6799e6268dbSMiklos Szeredi }
6809e6268dbSMiklos Szeredi 
6819e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
6829e6268dbSMiklos Szeredi 		     struct dentry *newent)
6839e6268dbSMiklos Szeredi {
6849e6268dbSMiklos Szeredi 	int err;
6859e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
6869e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
6879e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
688ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
689ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
690ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
6919e6268dbSMiklos Szeredi 
6929e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
6939e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
6949e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
6959e6268dbSMiklos Szeredi 	req->in.numargs = 2;
6969e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
6979e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
6989e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
6999e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
7009e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
7019e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
7029e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
7039e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
7049e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
7059e6268dbSMiklos Szeredi 	   etc.)
7069e6268dbSMiklos Szeredi 	*/
7079e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
7089e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
7099e6268dbSMiklos Szeredi 	return err;
7109e6268dbSMiklos Szeredi }
7119e6268dbSMiklos Szeredi 
7121fb69e78SMiklos Szeredi static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
7131fb69e78SMiklos Szeredi 			  struct kstat *stat)
7141fb69e78SMiklos Szeredi {
7151fb69e78SMiklos Szeredi 	stat->dev = inode->i_sb->s_dev;
7161fb69e78SMiklos Szeredi 	stat->ino = attr->ino;
7171fb69e78SMiklos Szeredi 	stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
7181fb69e78SMiklos Szeredi 	stat->nlink = attr->nlink;
7191fb69e78SMiklos Szeredi 	stat->uid = attr->uid;
7201fb69e78SMiklos Szeredi 	stat->gid = attr->gid;
7211fb69e78SMiklos Szeredi 	stat->rdev = inode->i_rdev;
7221fb69e78SMiklos Szeredi 	stat->atime.tv_sec = attr->atime;
7231fb69e78SMiklos Szeredi 	stat->atime.tv_nsec = attr->atimensec;
7241fb69e78SMiklos Szeredi 	stat->mtime.tv_sec = attr->mtime;
7251fb69e78SMiklos Szeredi 	stat->mtime.tv_nsec = attr->mtimensec;
7261fb69e78SMiklos Szeredi 	stat->ctime.tv_sec = attr->ctime;
7271fb69e78SMiklos Szeredi 	stat->ctime.tv_nsec = attr->ctimensec;
7281fb69e78SMiklos Szeredi 	stat->size = attr->size;
7291fb69e78SMiklos Szeredi 	stat->blocks = attr->blocks;
7301fb69e78SMiklos Szeredi 	stat->blksize = (1 << inode->i_blkbits);
7311fb69e78SMiklos Szeredi }
7321fb69e78SMiklos Szeredi 
733c79e322fSMiklos Szeredi static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
734c79e322fSMiklos Szeredi 			   struct file *file)
735e5e5558eSMiklos Szeredi {
736e5e5558eSMiklos Szeredi 	int err;
737c79e322fSMiklos Szeredi 	struct fuse_getattr_in inarg;
738c79e322fSMiklos Szeredi 	struct fuse_attr_out outarg;
739e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
7401fb69e78SMiklos Szeredi 	struct fuse_req *req;
7411fb69e78SMiklos Szeredi 	u64 attr_version;
7421fb69e78SMiklos Szeredi 
7431fb69e78SMiklos Szeredi 	req = fuse_get_req(fc);
744ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
745ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
746e5e5558eSMiklos Szeredi 
7477dca9fd3SMiklos Szeredi 	attr_version = fuse_get_attr_version(fc);
7481fb69e78SMiklos Szeredi 
749c79e322fSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
7500e9663eeSMiklos Szeredi 	memset(&outarg, 0, sizeof(outarg));
751c79e322fSMiklos Szeredi 	/* Directories have separate file-handle space */
752c79e322fSMiklos Szeredi 	if (file && S_ISREG(inode->i_mode)) {
753c79e322fSMiklos Szeredi 		struct fuse_file *ff = file->private_data;
754c79e322fSMiklos Szeredi 
755c79e322fSMiklos Szeredi 		inarg.getattr_flags |= FUSE_GETATTR_FH;
756c79e322fSMiklos Szeredi 		inarg.fh = ff->fh;
757c79e322fSMiklos Szeredi 	}
758e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
759e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
760c79e322fSMiklos Szeredi 	req->in.numargs = 1;
761c79e322fSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
762c79e322fSMiklos Szeredi 	req->in.args[0].value = &inarg;
763e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
7640e9663eeSMiklos Szeredi 	if (fc->minor < 9)
7650e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
7660e9663eeSMiklos Szeredi 	else
767c79e322fSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
768c79e322fSMiklos Szeredi 	req->out.args[0].value = &outarg;
769e5e5558eSMiklos Szeredi 	request_send(fc, req);
770e5e5558eSMiklos Szeredi 	err = req->out.h.error;
771e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
772e5e5558eSMiklos Szeredi 	if (!err) {
773c79e322fSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
774e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
775e5e5558eSMiklos Szeredi 			err = -EIO;
776e5e5558eSMiklos Szeredi 		} else {
777c79e322fSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr,
778c79e322fSMiklos Szeredi 					       attr_timeout(&outarg),
7791fb69e78SMiklos Szeredi 					       attr_version);
7801fb69e78SMiklos Szeredi 			if (stat)
781c79e322fSMiklos Szeredi 				fuse_fillattr(inode, &outarg.attr, stat);
782e5e5558eSMiklos Szeredi 		}
783e5e5558eSMiklos Szeredi 	}
784e5e5558eSMiklos Szeredi 	return err;
785e5e5558eSMiklos Szeredi }
786e5e5558eSMiklos Szeredi 
787bcb4be80SMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct kstat *stat,
788bcb4be80SMiklos Szeredi 			   struct file *file, bool *refreshed)
789bcb4be80SMiklos Szeredi {
790bcb4be80SMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
791bcb4be80SMiklos Szeredi 	int err;
792bcb4be80SMiklos Szeredi 	bool r;
793bcb4be80SMiklos Szeredi 
794bcb4be80SMiklos Szeredi 	if (fi->i_time < get_jiffies_64()) {
795bcb4be80SMiklos Szeredi 		r = true;
796bcb4be80SMiklos Szeredi 		err = fuse_do_getattr(inode, stat, file);
797bcb4be80SMiklos Szeredi 	} else {
798bcb4be80SMiklos Szeredi 		r = false;
799bcb4be80SMiklos Szeredi 		err = 0;
800bcb4be80SMiklos Szeredi 		if (stat) {
801bcb4be80SMiklos Szeredi 			generic_fillattr(inode, stat);
802bcb4be80SMiklos Szeredi 			stat->mode = fi->orig_i_mode;
803bcb4be80SMiklos Szeredi 		}
804bcb4be80SMiklos Szeredi 	}
805bcb4be80SMiklos Szeredi 
806bcb4be80SMiklos Szeredi 	if (refreshed != NULL)
807bcb4be80SMiklos Szeredi 		*refreshed = r;
808bcb4be80SMiklos Szeredi 
809bcb4be80SMiklos Szeredi 	return err;
810bcb4be80SMiklos Szeredi }
811bcb4be80SMiklos Szeredi 
81287729a55SMiklos Szeredi /*
81387729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
81487729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
81587729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
81687729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
81787729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
81887729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
81987729a55SMiklos Szeredi  * DoS against the requester.
82087729a55SMiklos Szeredi  *
82187729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
82287729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
82387729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
82487729a55SMiklos Szeredi  */
825e57ac683SMiklos Szeredi int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
82687729a55SMiklos Szeredi {
82787729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
82887729a55SMiklos Szeredi 		return 1;
82987729a55SMiklos Szeredi 
83087729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
83187729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
83287729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
83387729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
83487729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
83587729a55SMiklos Szeredi 	    task->gid == fc->group_id)
83687729a55SMiklos Szeredi 		return 1;
83787729a55SMiklos Szeredi 
83887729a55SMiklos Szeredi 	return 0;
83987729a55SMiklos Szeredi }
84087729a55SMiklos Szeredi 
84131d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask)
84231d40d74SMiklos Szeredi {
84331d40d74SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
84431d40d74SMiklos Szeredi 	struct fuse_req *req;
84531d40d74SMiklos Szeredi 	struct fuse_access_in inarg;
84631d40d74SMiklos Szeredi 	int err;
84731d40d74SMiklos Szeredi 
84831d40d74SMiklos Szeredi 	if (fc->no_access)
84931d40d74SMiklos Szeredi 		return 0;
85031d40d74SMiklos Szeredi 
851ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
852ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
853ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
85431d40d74SMiklos Szeredi 
85531d40d74SMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
85631d40d74SMiklos Szeredi 	inarg.mask = mask;
85731d40d74SMiklos Szeredi 	req->in.h.opcode = FUSE_ACCESS;
85831d40d74SMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
85931d40d74SMiklos Szeredi 	req->in.numargs = 1;
86031d40d74SMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
86131d40d74SMiklos Szeredi 	req->in.args[0].value = &inarg;
86231d40d74SMiklos Szeredi 	request_send(fc, req);
86331d40d74SMiklos Szeredi 	err = req->out.h.error;
86431d40d74SMiklos Szeredi 	fuse_put_request(fc, req);
86531d40d74SMiklos Szeredi 	if (err == -ENOSYS) {
86631d40d74SMiklos Szeredi 		fc->no_access = 1;
86731d40d74SMiklos Szeredi 		err = 0;
86831d40d74SMiklos Szeredi 	}
86931d40d74SMiklos Szeredi 	return err;
87031d40d74SMiklos Szeredi }
87131d40d74SMiklos Szeredi 
8726f9f1180SMiklos Szeredi /*
8736f9f1180SMiklos Szeredi  * Check permission.  The two basic access models of FUSE are:
8746f9f1180SMiklos Szeredi  *
8756f9f1180SMiklos Szeredi  * 1) Local access checking ('default_permissions' mount option) based
8766f9f1180SMiklos Szeredi  * on file mode.  This is the plain old disk filesystem permission
8776f9f1180SMiklos Szeredi  * modell.
8786f9f1180SMiklos Szeredi  *
8796f9f1180SMiklos Szeredi  * 2) "Remote" access checking, where server is responsible for
8806f9f1180SMiklos Szeredi  * checking permission in each inode operation.  An exception to this
8816f9f1180SMiklos Szeredi  * is if ->permission() was invoked from sys_access() in which case an
8826f9f1180SMiklos Szeredi  * access request is sent.  Execute permission is still checked
8836f9f1180SMiklos Szeredi  * locally based on file mode.
8846f9f1180SMiklos Szeredi  */
885e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
886e5e5558eSMiklos Szeredi {
887e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
888244f6385SMiklos Szeredi 	bool refreshed = false;
889244f6385SMiklos Szeredi 	int err = 0;
890e5e5558eSMiklos Szeredi 
89187729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
892e5e5558eSMiklos Szeredi 		return -EACCES;
893244f6385SMiklos Szeredi 
894244f6385SMiklos Szeredi 	/*
895e8e96157SMiklos Szeredi 	 * If attributes are needed, refresh them before proceeding
896244f6385SMiklos Szeredi 	 */
897e8e96157SMiklos Szeredi 	if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) ||
898e8e96157SMiklos Szeredi 	    ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) {
899bcb4be80SMiklos Szeredi 		err = fuse_update_attributes(inode, NULL, NULL, &refreshed);
900244f6385SMiklos Szeredi 		if (err)
901244f6385SMiklos Szeredi 			return err;
9021fb69e78SMiklos Szeredi 	}
903244f6385SMiklos Szeredi 
904244f6385SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
9051e9a4ed9SMiklos Szeredi 		int err = generic_permission(inode, mask, NULL);
9061e9a4ed9SMiklos Szeredi 
9071e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
9081e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
9091e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
910244f6385SMiklos Szeredi 		if (err == -EACCES && !refreshed) {
911c79e322fSMiklos Szeredi 			err = fuse_do_getattr(inode, NULL, NULL);
9121e9a4ed9SMiklos Szeredi 			if (!err)
9131e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
9141e9a4ed9SMiklos Szeredi 		}
9151e9a4ed9SMiklos Szeredi 
9166f9f1180SMiklos Szeredi 		/* Note: the opposite of the above test does not
9176f9f1180SMiklos Szeredi 		   exist.  So if permissions are revoked this won't be
9186f9f1180SMiklos Szeredi 		   noticed immediately, only after the attribute
9196f9f1180SMiklos Szeredi 		   timeout has expired */
920e8e96157SMiklos Szeredi 	} else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) {
921e8e96157SMiklos Szeredi 		err = fuse_access(inode, mask);
922e8e96157SMiklos Szeredi 	} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
923e8e96157SMiklos Szeredi 		if (!(inode->i_mode & S_IXUGO)) {
924e8e96157SMiklos Szeredi 			if (refreshed)
925e5e5558eSMiklos Szeredi 				return -EACCES;
92631d40d74SMiklos Szeredi 
927c79e322fSMiklos Szeredi 			err = fuse_do_getattr(inode, NULL, NULL);
928e8e96157SMiklos Szeredi 			if (!err && !(inode->i_mode & S_IXUGO))
929e8e96157SMiklos Szeredi 				return -EACCES;
930e8e96157SMiklos Szeredi 		}
931e5e5558eSMiklos Szeredi 	}
932244f6385SMiklos Szeredi 	return err;
933e5e5558eSMiklos Szeredi }
934e5e5558eSMiklos Szeredi 
935e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
936e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
937e5e5558eSMiklos Szeredi {
938e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
939e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
940e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
941e5e5558eSMiklos Szeredi 		int over;
942e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
943e5e5558eSMiklos Szeredi 			return -EIO;
944e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
945e5e5558eSMiklos Szeredi 			break;
946e5e5558eSMiklos Szeredi 
947e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
948e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
949e5e5558eSMiklos Szeredi 		if (over)
950e5e5558eSMiklos Szeredi 			break;
951e5e5558eSMiklos Szeredi 
952e5e5558eSMiklos Szeredi 		buf += reclen;
953e5e5558eSMiklos Szeredi 		nbytes -= reclen;
954e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
955e5e5558eSMiklos Szeredi 	}
956e5e5558eSMiklos Szeredi 
957e5e5558eSMiklos Szeredi 	return 0;
958e5e5558eSMiklos Szeredi }
959e5e5558eSMiklos Szeredi 
960e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
961e5e5558eSMiklos Szeredi {
96204730fefSMiklos Szeredi 	int err;
96304730fefSMiklos Szeredi 	size_t nbytes;
96404730fefSMiklos Szeredi 	struct page *page;
9657706a9d6SJosef Sipek 	struct inode *inode = file->f_path.dentry->d_inode;
96604730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
967248d86e8SMiklos Szeredi 	struct fuse_req *req;
968248d86e8SMiklos Szeredi 
969248d86e8SMiklos Szeredi 	if (is_bad_inode(inode))
970248d86e8SMiklos Szeredi 		return -EIO;
971248d86e8SMiklos Szeredi 
972ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
973ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
974ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
975e5e5558eSMiklos Szeredi 
97604730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
97704730fefSMiklos Szeredi 	if (!page) {
97804730fefSMiklos Szeredi 		fuse_put_request(fc, req);
979e5e5558eSMiklos Szeredi 		return -ENOMEM;
98004730fefSMiklos Szeredi 	}
98104730fefSMiklos Szeredi 	req->num_pages = 1;
98204730fefSMiklos Szeredi 	req->pages[0] = page;
983*a6643094SMiklos Szeredi 	fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
984361b1eb5SMiklos Szeredi 	request_send(fc, req);
985361b1eb5SMiklos Szeredi 	nbytes = req->out.args[0].size;
98604730fefSMiklos Szeredi 	err = req->out.h.error;
98704730fefSMiklos Szeredi 	fuse_put_request(fc, req);
98804730fefSMiklos Szeredi 	if (!err)
98904730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
99004730fefSMiklos Szeredi 				    filldir);
991e5e5558eSMiklos Szeredi 
99204730fefSMiklos Szeredi 	__free_page(page);
993b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
99404730fefSMiklos Szeredi 	return err;
995e5e5558eSMiklos Szeredi }
996e5e5558eSMiklos Szeredi 
997e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
998e5e5558eSMiklos Szeredi {
999e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
1000e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
1001ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
1002e5e5558eSMiklos Szeredi 	char *link;
1003e5e5558eSMiklos Szeredi 
1004ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1005ce1d5a49SMiklos Szeredi 		return ERR_PTR(PTR_ERR(req));
1006e5e5558eSMiklos Szeredi 
1007e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
1008e5e5558eSMiklos Szeredi 	if (!link) {
1009e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
1010e5e5558eSMiklos Szeredi 		goto out;
1011e5e5558eSMiklos Szeredi 	}
1012e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
1013e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
1014e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
1015e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
1016e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
1017e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
1018e5e5558eSMiklos Szeredi 	request_send(fc, req);
1019e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
1020e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
1021e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
1022e5e5558eSMiklos Szeredi 	} else
1023e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
1024e5e5558eSMiklos Szeredi  out:
1025e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
1026b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
1027e5e5558eSMiklos Szeredi 	return link;
1028e5e5558eSMiklos Szeredi }
1029e5e5558eSMiklos Szeredi 
1030e5e5558eSMiklos Szeredi static void free_link(char *link)
1031e5e5558eSMiklos Szeredi {
1032e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
1033e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
1034e5e5558eSMiklos Szeredi }
1035e5e5558eSMiklos Szeredi 
1036e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
1037e5e5558eSMiklos Szeredi {
1038e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
1039e5e5558eSMiklos Szeredi 	return NULL;
1040e5e5558eSMiklos Szeredi }
1041e5e5558eSMiklos Szeredi 
1042e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
1043e5e5558eSMiklos Szeredi {
1044e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
1045e5e5558eSMiklos Szeredi }
1046e5e5558eSMiklos Szeredi 
1047e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
1048e5e5558eSMiklos Szeredi {
104904730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
1050e5e5558eSMiklos Szeredi }
1051e5e5558eSMiklos Szeredi 
1052e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
1053e5e5558eSMiklos Szeredi {
105404730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
1055e5e5558eSMiklos Szeredi }
1056e5e5558eSMiklos Szeredi 
105782547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
105882547981SMiklos Szeredi {
105982547981SMiklos Szeredi 	/* nfsd can call this with no file */
106082547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
106182547981SMiklos Szeredi }
106282547981SMiklos Szeredi 
106317637cbaSMiklos Szeredi static bool update_mtime(unsigned ivalid)
106417637cbaSMiklos Szeredi {
106517637cbaSMiklos Szeredi 	/* Always update if mtime is explicitly set  */
106617637cbaSMiklos Szeredi 	if (ivalid & ATTR_MTIME_SET)
106717637cbaSMiklos Szeredi 		return true;
106817637cbaSMiklos Szeredi 
106917637cbaSMiklos Szeredi 	/* If it's an open(O_TRUNC) or an ftruncate(), don't update */
107017637cbaSMiklos Szeredi 	if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
107117637cbaSMiklos Szeredi 		return false;
107217637cbaSMiklos Szeredi 
107317637cbaSMiklos Szeredi 	/* In all other cases update */
107417637cbaSMiklos Szeredi 	return true;
107517637cbaSMiklos Szeredi }
107617637cbaSMiklos Szeredi 
1077befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
10789e6268dbSMiklos Szeredi {
10799e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
10809e6268dbSMiklos Szeredi 
10819e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
1082befc649cSMiklos Szeredi 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
10839e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
1084befc649cSMiklos Szeredi 		arg->valid |= FATTR_UID,    arg->uid = iattr->ia_uid;
10859e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
1086befc649cSMiklos Szeredi 		arg->valid |= FATTR_GID,    arg->gid = iattr->ia_gid;
10879e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
1088befc649cSMiklos Szeredi 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
108917637cbaSMiklos Szeredi 	if (ivalid & ATTR_ATIME) {
109017637cbaSMiklos Szeredi 		arg->valid |= FATTR_ATIME;
1091befc649cSMiklos Szeredi 		arg->atime = iattr->ia_atime.tv_sec;
109217637cbaSMiklos Szeredi 		arg->atimensec = iattr->ia_atime.tv_nsec;
109317637cbaSMiklos Szeredi 		if (!(ivalid & ATTR_ATIME_SET))
109417637cbaSMiklos Szeredi 			arg->valid |= FATTR_ATIME_NOW;
109517637cbaSMiklos Szeredi 	}
109617637cbaSMiklos Szeredi 	if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) {
109717637cbaSMiklos Szeredi 		arg->valid |= FATTR_MTIME;
1098befc649cSMiklos Szeredi 		arg->mtime = iattr->ia_mtime.tv_sec;
109917637cbaSMiklos Szeredi 		arg->mtimensec = iattr->ia_mtime.tv_nsec;
110017637cbaSMiklos Szeredi 		if (!(ivalid & ATTR_MTIME_SET))
110117637cbaSMiklos Szeredi 			arg->valid |= FATTR_MTIME_NOW;
11029e6268dbSMiklos Szeredi 	}
11039e6268dbSMiklos Szeredi }
11049e6268dbSMiklos Szeredi 
11056f9f1180SMiklos Szeredi /*
11066f9f1180SMiklos Szeredi  * Set attributes, and at the same time refresh them.
11076f9f1180SMiklos Szeredi  *
11086f9f1180SMiklos Szeredi  * Truncation is slightly complicated, because the 'truncate' request
11096f9f1180SMiklos Szeredi  * may fail, in which case we don't want to touch the mapping.
11109ffbb916SMiklos Szeredi  * vmtruncate() doesn't allow for this case, so do the rlimit checking
11119ffbb916SMiklos Szeredi  * and the actual truncation by hand.
11126f9f1180SMiklos Szeredi  */
111349d4914fSMiklos Szeredi static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
111449d4914fSMiklos Szeredi 			   struct file *file)
11159e6268dbSMiklos Szeredi {
11169e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
11179e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
11189e6268dbSMiklos Szeredi 	struct fuse_req *req;
11199e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
11209e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
11219e6268dbSMiklos Szeredi 	int err;
11229e6268dbSMiklos Szeredi 
1123e57ac683SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
1124e57ac683SMiklos Szeredi 		return -EACCES;
1125e57ac683SMiklos Szeredi 
11261e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
11271e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
11281e9a4ed9SMiklos Szeredi 		if (err)
11291e9a4ed9SMiklos Szeredi 			return err;
11301e9a4ed9SMiklos Szeredi 	}
11311e9a4ed9SMiklos Szeredi 
11326ff958edSMiklos Szeredi 	if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
11336ff958edSMiklos Szeredi 		return 0;
11346ff958edSMiklos Szeredi 
11359e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
11369e6268dbSMiklos Szeredi 		unsigned long limit;
1137b2d2272fSMiklos Szeredi 		if (IS_SWAPFILE(inode))
1138b2d2272fSMiklos Szeredi 			return -ETXTBSY;
11399e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
11409e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
11419e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
11429e6268dbSMiklos Szeredi 			return -EFBIG;
11439e6268dbSMiklos Szeredi 		}
11449e6268dbSMiklos Szeredi 	}
11459e6268dbSMiklos Szeredi 
1146ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1147ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1148ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
11499e6268dbSMiklos Szeredi 
11509e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
11510e9663eeSMiklos Szeredi 	memset(&outarg, 0, sizeof(outarg));
1152befc649cSMiklos Szeredi 	iattr_to_fattr(attr, &inarg);
115349d4914fSMiklos Szeredi 	if (file) {
115449d4914fSMiklos Szeredi 		struct fuse_file *ff = file->private_data;
115549d4914fSMiklos Szeredi 		inarg.valid |= FATTR_FH;
115649d4914fSMiklos Szeredi 		inarg.fh = ff->fh;
115749d4914fSMiklos Szeredi 	}
1158f3332114SMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
1159f3332114SMiklos Szeredi 		/* For mandatory locking in truncate */
1160f3332114SMiklos Szeredi 		inarg.valid |= FATTR_LOCKOWNER;
1161f3332114SMiklos Szeredi 		inarg.lock_owner = fuse_lock_owner_id(fc, current->files);
1162f3332114SMiklos Szeredi 	}
11639e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
11649e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
11659e6268dbSMiklos Szeredi 	req->in.numargs = 1;
11669e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
11679e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
11689e6268dbSMiklos Szeredi 	req->out.numargs = 1;
11690e9663eeSMiklos Szeredi 	if (fc->minor < 9)
11700e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
11710e9663eeSMiklos Szeredi 	else
11729e6268dbSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
11739e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
11749e6268dbSMiklos Szeredi 	request_send(fc, req);
11759e6268dbSMiklos Szeredi 	err = req->out.h.error;
11769e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
1177e00d2c2dSMiklos Szeredi 	if (err) {
1178e00d2c2dSMiklos Szeredi 		if (err == -EINTR)
1179e00d2c2dSMiklos Szeredi 			fuse_invalidate_attr(inode);
1180e00d2c2dSMiklos Szeredi 		return err;
1181e00d2c2dSMiklos Szeredi 	}
1182e00d2c2dSMiklos Szeredi 
11839e6268dbSMiklos Szeredi 	if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
11849e6268dbSMiklos Szeredi 		make_bad_inode(inode);
1185e00d2c2dSMiklos Szeredi 		return -EIO;
11869e6268dbSMiklos Szeredi 	}
11879e6268dbSMiklos Szeredi 
11881fb69e78SMiklos Szeredi 	fuse_change_attributes(inode, &outarg.attr, attr_timeout(&outarg), 0);
1189e00d2c2dSMiklos Szeredi 	return 0;
11909e6268dbSMiklos Szeredi }
11919e6268dbSMiklos Szeredi 
119249d4914fSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
119349d4914fSMiklos Szeredi {
119449d4914fSMiklos Szeredi 	if (attr->ia_valid & ATTR_FILE)
119549d4914fSMiklos Szeredi 		return fuse_do_setattr(entry, attr, attr->ia_file);
119649d4914fSMiklos Szeredi 	else
119749d4914fSMiklos Szeredi 		return fuse_do_setattr(entry, attr, NULL);
119849d4914fSMiklos Szeredi }
119949d4914fSMiklos Szeredi 
1200e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
1201e5e5558eSMiklos Szeredi 			struct kstat *stat)
1202e5e5558eSMiklos Szeredi {
1203e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
1204244f6385SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
1205244f6385SMiklos Szeredi 
1206244f6385SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
1207244f6385SMiklos Szeredi 		return -EACCES;
1208244f6385SMiklos Szeredi 
1209bcb4be80SMiklos Szeredi 	return fuse_update_attributes(inode, stat, NULL, NULL);
1210e5e5558eSMiklos Szeredi }
1211e5e5558eSMiklos Szeredi 
121292a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
121392a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
121492a8780eSMiklos Szeredi {
121592a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
121692a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
121792a8780eSMiklos Szeredi 	struct fuse_req *req;
121892a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
121992a8780eSMiklos Szeredi 	int err;
122092a8780eSMiklos Szeredi 
122192a8780eSMiklos Szeredi 	if (fc->no_setxattr)
122292a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
122392a8780eSMiklos Szeredi 
1224ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1225ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1226ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
122792a8780eSMiklos Szeredi 
122892a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
122992a8780eSMiklos Szeredi 	inarg.size = size;
123092a8780eSMiklos Szeredi 	inarg.flags = flags;
123192a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
123292a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
123392a8780eSMiklos Szeredi 	req->in.numargs = 3;
123492a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
123592a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
123692a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
123792a8780eSMiklos Szeredi 	req->in.args[1].value = name;
123892a8780eSMiklos Szeredi 	req->in.args[2].size = size;
123992a8780eSMiklos Szeredi 	req->in.args[2].value = value;
124092a8780eSMiklos Szeredi 	request_send(fc, req);
124192a8780eSMiklos Szeredi 	err = req->out.h.error;
124292a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
124392a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
124492a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
124592a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
124692a8780eSMiklos Szeredi 	}
124792a8780eSMiklos Szeredi 	return err;
124892a8780eSMiklos Szeredi }
124992a8780eSMiklos Szeredi 
125092a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
125192a8780eSMiklos Szeredi 			     void *value, size_t size)
125292a8780eSMiklos Szeredi {
125392a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
125492a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
125592a8780eSMiklos Szeredi 	struct fuse_req *req;
125692a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
125792a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
125892a8780eSMiklos Szeredi 	ssize_t ret;
125992a8780eSMiklos Szeredi 
126092a8780eSMiklos Szeredi 	if (fc->no_getxattr)
126192a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
126292a8780eSMiklos Szeredi 
1263ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1264ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1265ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
126692a8780eSMiklos Szeredi 
126792a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
126892a8780eSMiklos Szeredi 	inarg.size = size;
126992a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
127092a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
127192a8780eSMiklos Szeredi 	req->in.numargs = 2;
127292a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
127392a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
127492a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
127592a8780eSMiklos Szeredi 	req->in.args[1].value = name;
127692a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
127792a8780eSMiklos Szeredi 	req->out.numargs = 1;
127892a8780eSMiklos Szeredi 	if (size) {
127992a8780eSMiklos Szeredi 		req->out.argvar = 1;
128092a8780eSMiklos Szeredi 		req->out.args[0].size = size;
128192a8780eSMiklos Szeredi 		req->out.args[0].value = value;
128292a8780eSMiklos Szeredi 	} else {
128392a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
128492a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
128592a8780eSMiklos Szeredi 	}
128692a8780eSMiklos Szeredi 	request_send(fc, req);
128792a8780eSMiklos Szeredi 	ret = req->out.h.error;
128892a8780eSMiklos Szeredi 	if (!ret)
128992a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
129092a8780eSMiklos Szeredi 	else {
129192a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
129292a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
129392a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
129492a8780eSMiklos Szeredi 		}
129592a8780eSMiklos Szeredi 	}
129692a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
129792a8780eSMiklos Szeredi 	return ret;
129892a8780eSMiklos Szeredi }
129992a8780eSMiklos Szeredi 
130092a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
130192a8780eSMiklos Szeredi {
130292a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
130392a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
130492a8780eSMiklos Szeredi 	struct fuse_req *req;
130592a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
130692a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
130792a8780eSMiklos Szeredi 	ssize_t ret;
130892a8780eSMiklos Szeredi 
1309e57ac683SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
1310e57ac683SMiklos Szeredi 		return -EACCES;
1311e57ac683SMiklos Szeredi 
131292a8780eSMiklos Szeredi 	if (fc->no_listxattr)
131392a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
131492a8780eSMiklos Szeredi 
1315ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1316ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1317ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
131892a8780eSMiklos Szeredi 
131992a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
132092a8780eSMiklos Szeredi 	inarg.size = size;
132192a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
132292a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
132392a8780eSMiklos Szeredi 	req->in.numargs = 1;
132492a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
132592a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
132692a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
132792a8780eSMiklos Szeredi 	req->out.numargs = 1;
132892a8780eSMiklos Szeredi 	if (size) {
132992a8780eSMiklos Szeredi 		req->out.argvar = 1;
133092a8780eSMiklos Szeredi 		req->out.args[0].size = size;
133192a8780eSMiklos Szeredi 		req->out.args[0].value = list;
133292a8780eSMiklos Szeredi 	} else {
133392a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
133492a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
133592a8780eSMiklos Szeredi 	}
133692a8780eSMiklos Szeredi 	request_send(fc, req);
133792a8780eSMiklos Szeredi 	ret = req->out.h.error;
133892a8780eSMiklos Szeredi 	if (!ret)
133992a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
134092a8780eSMiklos Szeredi 	else {
134192a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
134292a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
134392a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
134492a8780eSMiklos Szeredi 		}
134592a8780eSMiklos Szeredi 	}
134692a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
134792a8780eSMiklos Szeredi 	return ret;
134892a8780eSMiklos Szeredi }
134992a8780eSMiklos Szeredi 
135092a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
135192a8780eSMiklos Szeredi {
135292a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
135392a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
135492a8780eSMiklos Szeredi 	struct fuse_req *req;
135592a8780eSMiklos Szeredi 	int err;
135692a8780eSMiklos Szeredi 
135792a8780eSMiklos Szeredi 	if (fc->no_removexattr)
135892a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
135992a8780eSMiklos Szeredi 
1360ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1361ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1362ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
136392a8780eSMiklos Szeredi 
136492a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
136592a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
136692a8780eSMiklos Szeredi 	req->in.numargs = 1;
136792a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
136892a8780eSMiklos Szeredi 	req->in.args[0].value = name;
136992a8780eSMiklos Szeredi 	request_send(fc, req);
137092a8780eSMiklos Szeredi 	err = req->out.h.error;
137192a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
137292a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
137392a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
137492a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
137592a8780eSMiklos Szeredi 	}
137692a8780eSMiklos Szeredi 	return err;
137792a8780eSMiklos Szeredi }
137892a8780eSMiklos Szeredi 
1379754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = {
1380e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
13819e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
13829e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
13839e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
13849e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
13859e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
13869e6268dbSMiklos Szeredi 	.link		= fuse_link,
13879e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
13889e6268dbSMiklos Szeredi 	.create		= fuse_create,
13899e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
1390e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1391e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
139292a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
139392a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
139492a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
139592a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1396e5e5558eSMiklos Szeredi };
1397e5e5558eSMiklos Szeredi 
13984b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = {
1399b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
1400e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
1401e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
1402e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
1403e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
140482547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
1405e5e5558eSMiklos Szeredi };
1406e5e5558eSMiklos Szeredi 
1407754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = {
14089e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1409e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1410e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
141192a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
141292a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
141392a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
141492a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1415e5e5558eSMiklos Szeredi };
1416e5e5558eSMiklos Szeredi 
1417754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = {
14189e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1419e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
1420e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
1421e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
1422e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
142392a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
142492a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
142592a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
142692a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1427e5e5558eSMiklos Szeredi };
1428e5e5558eSMiklos Szeredi 
1429e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
1430e5e5558eSMiklos Szeredi {
1431e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
1432e5e5558eSMiklos Szeredi }
1433e5e5558eSMiklos Szeredi 
1434e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
1435e5e5558eSMiklos Szeredi {
1436e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
1437e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
1438e5e5558eSMiklos Szeredi }
1439e5e5558eSMiklos Szeredi 
1440e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
1441e5e5558eSMiklos Szeredi {
1442e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
1443e5e5558eSMiklos Szeredi }
1444