xref: /openbmc/linux/fs/fuse/dir.c (revision dbd561d236ff16f8143bc727d91758ddd190e8cb)
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  */
100*dbd561d2SMiklos Szeredi 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 
1355c5c5e51SMiklos Szeredi 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 
228*dbd561d2SMiklos Szeredi 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  */
2420de6256dSMiklos Szeredi static struct dentry *fuse_d_add_directory(struct dentry *entry,
2430de6256dSMiklos Szeredi 					   struct inode *inode)
244d2a85164SMiklos Szeredi {
245d2a85164SMiklos Szeredi 	struct dentry *alias = d_find_alias(inode);
2460de6256dSMiklos Szeredi 	if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
247d2a85164SMiklos Szeredi 		/* This tries to shrink the subtree below alias */
248d2a85164SMiklos Szeredi 		fuse_invalidate_entry(alias);
249d2a85164SMiklos Szeredi 		dput(alias);
250d2a85164SMiklos Szeredi 		if (!list_empty(&inode->i_dentry))
2510de6256dSMiklos Szeredi 			return ERR_PTR(-EBUSY);
2520de6256dSMiklos Szeredi 	} else {
2530de6256dSMiklos Szeredi 		dput(alias);
254d2a85164SMiklos Szeredi 	}
2550de6256dSMiklos Szeredi 	return d_splice_alias(inode, entry);
256d2a85164SMiklos Szeredi }
257d2a85164SMiklos Szeredi 
2580aa7c699SMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
2590aa7c699SMiklos Szeredi 				  struct nameidata *nd)
260e5e5558eSMiklos Szeredi {
261e5e5558eSMiklos Szeredi 	int err;
262e5e5558eSMiklos Szeredi 	struct fuse_entry_out outarg;
263e5e5558eSMiklos Szeredi 	struct inode *inode = NULL;
2640de6256dSMiklos Szeredi 	struct dentry *newent;
265e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
266e5e5558eSMiklos Szeredi 	struct fuse_req *req;
2672d51013eSMiklos Szeredi 	struct fuse_req *forget_req;
2681fb69e78SMiklos Szeredi 	u64 attr_version;
269e5e5558eSMiklos Szeredi 
270e5e5558eSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
2710aa7c699SMiklos Szeredi 		return ERR_PTR(-ENAMETOOLONG);
272e5e5558eSMiklos Szeredi 
273ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
274ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
275e231c2eeSDavid Howells 		return ERR_CAST(req);
276e5e5558eSMiklos Szeredi 
2772d51013eSMiklos Szeredi 	forget_req = fuse_get_req(fc);
2782d51013eSMiklos Szeredi 	if (IS_ERR(forget_req)) {
2792d51013eSMiklos Szeredi 		fuse_put_request(fc, req);
280e231c2eeSDavid Howells 		return ERR_CAST(forget_req);
2812d51013eSMiklos Szeredi 	}
2822d51013eSMiklos Szeredi 
2837dca9fd3SMiklos Szeredi 	attr_version = fuse_get_attr_version(fc);
2841fb69e78SMiklos Szeredi 
285e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
286e5e5558eSMiklos Szeredi 	request_send(fc, req);
287e5e5558eSMiklos Szeredi 	err = req->out.h.error;
2882d51013eSMiklos Szeredi 	fuse_put_request(fc, req);
28950322fe7SMiklos Szeredi 	/* Zero nodeid is same as -ENOENT, but with valid timeout */
29050322fe7SMiklos Szeredi 	if (!err && outarg.nodeid &&
291a5bfffacSTimo Savola 	    (invalid_nodeid(outarg.nodeid) ||
292a5bfffacSTimo Savola 	     !fuse_valid_type(outarg.attr.mode)))
293ee4e5271SMiklos Szeredi 		err = -EIO;
2948cbdf1e6SMiklos Szeredi 	if (!err && outarg.nodeid) {
295e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
2961fb69e78SMiklos Szeredi 				  &outarg.attr, entry_attr_timeout(&outarg),
2971fb69e78SMiklos Szeredi 				  attr_version);
298e5e5558eSMiklos Szeredi 		if (!inode) {
2992d51013eSMiklos Szeredi 			fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
3000aa7c699SMiklos Szeredi 			return ERR_PTR(-ENOMEM);
301e5e5558eSMiklos Szeredi 		}
302e5e5558eSMiklos Szeredi 	}
3032d51013eSMiklos Szeredi 	fuse_put_request(fc, forget_req);
304e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
3050aa7c699SMiklos Szeredi 		return ERR_PTR(err);
306e5e5558eSMiklos Szeredi 
307d2a85164SMiklos Szeredi 	if (inode && S_ISDIR(inode->i_mode)) {
308d2a85164SMiklos Szeredi 		mutex_lock(&fc->inst_mutex);
3090de6256dSMiklos Szeredi 		newent = fuse_d_add_directory(entry, inode);
310d2a85164SMiklos Szeredi 		mutex_unlock(&fc->inst_mutex);
3110de6256dSMiklos Szeredi 		if (IS_ERR(newent)) {
3120aa7c699SMiklos Szeredi 			iput(inode);
3130de6256dSMiklos Szeredi 			return newent;
314e5e5558eSMiklos Szeredi 		}
315d2a85164SMiklos Szeredi 	} else
3160de6256dSMiklos Szeredi 		newent = d_splice_alias(inode, entry);
317d2a85164SMiklos Szeredi 
3180de6256dSMiklos Szeredi 	entry = newent ? newent : entry;
319e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
3208cbdf1e6SMiklos Szeredi 	if (!err)
3211fb69e78SMiklos Szeredi 		fuse_change_entry_timeout(entry, &outarg);
3228cbdf1e6SMiklos Szeredi 	else
3238cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
3240de6256dSMiklos Szeredi 	return newent;
325e5e5558eSMiklos Szeredi }
326e5e5558eSMiklos Szeredi 
3276f9f1180SMiklos Szeredi /*
32851eb01e7SMiklos Szeredi  * Synchronous release for the case when something goes wrong in CREATE_OPEN
32951eb01e7SMiklos Szeredi  */
33051eb01e7SMiklos Szeredi static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
33151eb01e7SMiklos Szeredi 			      u64 nodeid, int flags)
33251eb01e7SMiklos Szeredi {
333c756e0a4SMiklos Szeredi 	fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
334c756e0a4SMiklos Szeredi 	ff->reserved_req->force = 1;
335c756e0a4SMiklos Szeredi 	request_send(fc, ff->reserved_req);
336c756e0a4SMiklos Szeredi 	fuse_put_request(fc, ff->reserved_req);
337c756e0a4SMiklos Szeredi 	kfree(ff);
33851eb01e7SMiklos Szeredi }
33951eb01e7SMiklos Szeredi 
34051eb01e7SMiklos Szeredi /*
3416f9f1180SMiklos Szeredi  * Atomic create+open operation
3426f9f1180SMiklos Szeredi  *
3436f9f1180SMiklos Szeredi  * If the filesystem doesn't support this, then fall back to separate
3446f9f1180SMiklos Szeredi  * 'mknod' + 'open' requests.
3456f9f1180SMiklos Szeredi  */
346fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
347fd72faacSMiklos Szeredi 			    struct nameidata *nd)
348fd72faacSMiklos Szeredi {
349fd72faacSMiklos Szeredi 	int err;
350fd72faacSMiklos Szeredi 	struct inode *inode;
351fd72faacSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
352fd72faacSMiklos Szeredi 	struct fuse_req *req;
35351eb01e7SMiklos Szeredi 	struct fuse_req *forget_req;
354fd72faacSMiklos Szeredi 	struct fuse_open_in inarg;
355fd72faacSMiklos Szeredi 	struct fuse_open_out outopen;
356fd72faacSMiklos Szeredi 	struct fuse_entry_out outentry;
357fd72faacSMiklos Szeredi 	struct fuse_file *ff;
358fd72faacSMiklos Szeredi 	struct file *file;
359fd72faacSMiklos Szeredi 	int flags = nd->intent.open.flags - 1;
360fd72faacSMiklos Szeredi 
361fd72faacSMiklos Szeredi 	if (fc->no_create)
362ce1d5a49SMiklos Szeredi 		return -ENOSYS;
363fd72faacSMiklos Szeredi 
36451eb01e7SMiklos Szeredi 	forget_req = fuse_get_req(fc);
36551eb01e7SMiklos Szeredi 	if (IS_ERR(forget_req))
36651eb01e7SMiklos Szeredi 		return PTR_ERR(forget_req);
36751eb01e7SMiklos Szeredi 
368ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
36951eb01e7SMiklos Szeredi 	err = PTR_ERR(req);
370ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
37151eb01e7SMiklos Szeredi 		goto out_put_forget_req;
372fd72faacSMiklos Szeredi 
373ce1d5a49SMiklos Szeredi 	err = -ENOMEM;
374fd72faacSMiklos Szeredi 	ff = fuse_file_alloc();
375fd72faacSMiklos Szeredi 	if (!ff)
376fd72faacSMiklos Szeredi 		goto out_put_request;
377fd72faacSMiklos Szeredi 
378fd72faacSMiklos Szeredi 	flags &= ~O_NOCTTY;
379fd72faacSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3800e9663eeSMiklos Szeredi 	memset(&outentry, 0, sizeof(outentry));
381fd72faacSMiklos Szeredi 	inarg.flags = flags;
382fd72faacSMiklos Szeredi 	inarg.mode = mode;
383fd72faacSMiklos Szeredi 	req->in.h.opcode = FUSE_CREATE;
384fd72faacSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
385fd72faacSMiklos Szeredi 	req->in.numargs = 2;
386fd72faacSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
387fd72faacSMiklos Szeredi 	req->in.args[0].value = &inarg;
388fd72faacSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
389fd72faacSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
390fd72faacSMiklos Szeredi 	req->out.numargs = 2;
3910e9663eeSMiklos Szeredi 	if (fc->minor < 9)
3920e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
3930e9663eeSMiklos Szeredi 	else
394fd72faacSMiklos Szeredi 		req->out.args[0].size = sizeof(outentry);
395fd72faacSMiklos Szeredi 	req->out.args[0].value = &outentry;
396fd72faacSMiklos Szeredi 	req->out.args[1].size = sizeof(outopen);
397fd72faacSMiklos Szeredi 	req->out.args[1].value = &outopen;
398fd72faacSMiklos Szeredi 	request_send(fc, req);
399fd72faacSMiklos Szeredi 	err = req->out.h.error;
400fd72faacSMiklos Szeredi 	if (err) {
401fd72faacSMiklos Szeredi 		if (err == -ENOSYS)
402fd72faacSMiklos Szeredi 			fc->no_create = 1;
403fd72faacSMiklos Szeredi 		goto out_free_ff;
404fd72faacSMiklos Szeredi 	}
405fd72faacSMiklos Szeredi 
406fd72faacSMiklos Szeredi 	err = -EIO;
4072827d0b2SMiklos Szeredi 	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
408fd72faacSMiklos Szeredi 		goto out_free_ff;
409fd72faacSMiklos Szeredi 
41051eb01e7SMiklos Szeredi 	fuse_put_request(fc, req);
411fd72faacSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
4121fb69e78SMiklos Szeredi 			  &outentry.attr, entry_attr_timeout(&outentry), 0);
413fd72faacSMiklos Szeredi 	if (!inode) {
414fd72faacSMiklos Szeredi 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
415fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
41651eb01e7SMiklos Szeredi 		fuse_sync_release(fc, ff, outentry.nodeid, flags);
41751eb01e7SMiklos Szeredi 		fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
41851eb01e7SMiklos Szeredi 		return -ENOMEM;
419fd72faacSMiklos Szeredi 	}
42051eb01e7SMiklos Szeredi 	fuse_put_request(fc, forget_req);
421fd72faacSMiklos Szeredi 	d_instantiate(entry, inode);
4221fb69e78SMiklos Szeredi 	fuse_change_entry_timeout(entry, &outentry);
4230952b2a4SMiklos Szeredi 	fuse_invalidate_attr(dir);
424fd72faacSMiklos Szeredi 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
425fd72faacSMiklos Szeredi 	if (IS_ERR(file)) {
426fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
42751eb01e7SMiklos Szeredi 		fuse_sync_release(fc, ff, outentry.nodeid, flags);
428fd72faacSMiklos Szeredi 		return PTR_ERR(file);
429fd72faacSMiklos Szeredi 	}
430fd72faacSMiklos Szeredi 	fuse_finish_open(inode, file, ff, &outopen);
431fd72faacSMiklos Szeredi 	return 0;
432fd72faacSMiklos Szeredi 
433fd72faacSMiklos Szeredi  out_free_ff:
434fd72faacSMiklos Szeredi 	fuse_file_free(ff);
435fd72faacSMiklos Szeredi  out_put_request:
436fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
43751eb01e7SMiklos Szeredi  out_put_forget_req:
43851eb01e7SMiklos Szeredi 	fuse_put_request(fc, forget_req);
439fd72faacSMiklos Szeredi 	return err;
440fd72faacSMiklos Szeredi }
441fd72faacSMiklos Szeredi 
4426f9f1180SMiklos Szeredi /*
4436f9f1180SMiklos Szeredi  * Code shared between mknod, mkdir, symlink and link
4446f9f1180SMiklos Szeredi  */
4459e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
4469e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
4479e6268dbSMiklos Szeredi 			    int mode)
4489e6268dbSMiklos Szeredi {
4499e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
4509e6268dbSMiklos Szeredi 	struct inode *inode;
4519e6268dbSMiklos Szeredi 	int err;
4522d51013eSMiklos Szeredi 	struct fuse_req *forget_req;
4532d51013eSMiklos Szeredi 
4542d51013eSMiklos Szeredi 	forget_req = fuse_get_req(fc);
4552d51013eSMiklos Szeredi 	if (IS_ERR(forget_req)) {
4562d51013eSMiklos Szeredi 		fuse_put_request(fc, req);
4572d51013eSMiklos Szeredi 		return PTR_ERR(forget_req);
4582d51013eSMiklos Szeredi 	}
4599e6268dbSMiklos Szeredi 
4600e9663eeSMiklos Szeredi 	memset(&outarg, 0, sizeof(outarg));
4619e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
4629e6268dbSMiklos Szeredi 	req->out.numargs = 1;
4630e9663eeSMiklos Szeredi 	if (fc->minor < 9)
4640e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
4650e9663eeSMiklos Szeredi 	else
4669e6268dbSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
4679e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
4689e6268dbSMiklos Szeredi 	request_send(fc, req);
4699e6268dbSMiklos Szeredi 	err = req->out.h.error;
4709e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4712d51013eSMiklos Szeredi 	if (err)
4722d51013eSMiklos Szeredi 		goto out_put_forget_req;
4732d51013eSMiklos Szeredi 
47439ee059aSMiklos Szeredi 	err = -EIO;
47539ee059aSMiklos Szeredi 	if (invalid_nodeid(outarg.nodeid))
4762d51013eSMiklos Szeredi 		goto out_put_forget_req;
47739ee059aSMiklos Szeredi 
47839ee059aSMiklos Szeredi 	if ((outarg.attr.mode ^ mode) & S_IFMT)
4792d51013eSMiklos Szeredi 		goto out_put_forget_req;
48039ee059aSMiklos Szeredi 
4819e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
4821fb69e78SMiklos Szeredi 			  &outarg.attr, entry_attr_timeout(&outarg), 0);
4839e6268dbSMiklos Szeredi 	if (!inode) {
4842d51013eSMiklos Szeredi 		fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
4859e6268dbSMiklos Szeredi 		return -ENOMEM;
4869e6268dbSMiklos Szeredi 	}
4872d51013eSMiklos Szeredi 	fuse_put_request(fc, forget_req);
4889e6268dbSMiklos Szeredi 
489d2a85164SMiklos Szeredi 	if (S_ISDIR(inode->i_mode)) {
490d2a85164SMiklos Szeredi 		struct dentry *alias;
491d2a85164SMiklos Szeredi 		mutex_lock(&fc->inst_mutex);
492d2a85164SMiklos Szeredi 		alias = d_find_alias(inode);
493d2a85164SMiklos Szeredi 		if (alias) {
494d2a85164SMiklos Szeredi 			/* New directory must have moved since mkdir */
495d2a85164SMiklos Szeredi 			mutex_unlock(&fc->inst_mutex);
496d2a85164SMiklos Szeredi 			dput(alias);
4979e6268dbSMiklos Szeredi 			iput(inode);
498d2a85164SMiklos Szeredi 			return -EBUSY;
4999e6268dbSMiklos Szeredi 		}
5009e6268dbSMiklos Szeredi 		d_instantiate(entry, inode);
501d2a85164SMiklos Szeredi 		mutex_unlock(&fc->inst_mutex);
502d2a85164SMiklos Szeredi 	} else
503d2a85164SMiklos Szeredi 		d_instantiate(entry, inode);
504d2a85164SMiklos Szeredi 
5051fb69e78SMiklos Szeredi 	fuse_change_entry_timeout(entry, &outarg);
5069e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
5079e6268dbSMiklos Szeredi 	return 0;
50839ee059aSMiklos Szeredi 
5092d51013eSMiklos Szeredi  out_put_forget_req:
5102d51013eSMiklos Szeredi 	fuse_put_request(fc, forget_req);
51139ee059aSMiklos Szeredi 	return err;
5129e6268dbSMiklos Szeredi }
5139e6268dbSMiklos Szeredi 
5149e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
5159e6268dbSMiklos Szeredi 		      dev_t rdev)
5169e6268dbSMiklos Szeredi {
5179e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
5189e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
519ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
520ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
521ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5229e6268dbSMiklos Szeredi 
5239e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
5249e6268dbSMiklos Szeredi 	inarg.mode = mode;
5259e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
5269e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
5279e6268dbSMiklos Szeredi 	req->in.numargs = 2;
5289e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
5299e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
5309e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
5319e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
5329e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
5339e6268dbSMiklos Szeredi }
5349e6268dbSMiklos Szeredi 
5359e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
5369e6268dbSMiklos Szeredi 		       struct nameidata *nd)
5379e6268dbSMiklos Szeredi {
538b9ba347fSMiklos Szeredi 	if (nd && (nd->flags & LOOKUP_OPEN)) {
539fd72faacSMiklos Szeredi 		int err = fuse_create_open(dir, entry, mode, nd);
540fd72faacSMiklos Szeredi 		if (err != -ENOSYS)
541fd72faacSMiklos Szeredi 			return err;
542fd72faacSMiklos Szeredi 		/* Fall back on mknod */
543fd72faacSMiklos Szeredi 	}
5449e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
5459e6268dbSMiklos Szeredi }
5469e6268dbSMiklos Szeredi 
5479e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
5489e6268dbSMiklos Szeredi {
5499e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
5509e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
551ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
552ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
553ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5549e6268dbSMiklos Szeredi 
5559e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
5569e6268dbSMiklos Szeredi 	inarg.mode = mode;
5579e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
5589e6268dbSMiklos Szeredi 	req->in.numargs = 2;
5599e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
5609e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
5619e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
5629e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
5639e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
5649e6268dbSMiklos Szeredi }
5659e6268dbSMiklos Szeredi 
5669e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
5679e6268dbSMiklos Szeredi 			const char *link)
5689e6268dbSMiklos Szeredi {
5699e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
5709e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
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 	req->in.h.opcode = FUSE_SYMLINK;
5769e6268dbSMiklos Szeredi 	req->in.numargs = 2;
5779e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5789e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5799e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
5809e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
5819e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
5829e6268dbSMiklos Szeredi }
5839e6268dbSMiklos Szeredi 
5849e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
5859e6268dbSMiklos Szeredi {
5869e6268dbSMiklos Szeredi 	int err;
5879e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
588ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
589ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
590ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
5919e6268dbSMiklos Szeredi 
5929e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
5939e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
5949e6268dbSMiklos Szeredi 	req->in.numargs = 1;
5959e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
5969e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
5979e6268dbSMiklos Szeredi 	request_send(fc, req);
5989e6268dbSMiklos Szeredi 	err = req->out.h.error;
5999e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
6009e6268dbSMiklos Szeredi 	if (!err) {
6019e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
6029e6268dbSMiklos Szeredi 
6039e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
6049e6268dbSMiklos Szeredi                    the inode does have more links this will be
6059e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
606ce71ec36SDave Hansen 		clear_nlink(inode);
6079e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
6089e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
6098cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
6109e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
6119e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
6129e6268dbSMiklos Szeredi 	return err;
6139e6268dbSMiklos Szeredi }
6149e6268dbSMiklos Szeredi 
6159e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
6169e6268dbSMiklos Szeredi {
6179e6268dbSMiklos Szeredi 	int err;
6189e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
619ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
620ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
621ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
6229e6268dbSMiklos Szeredi 
6239e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
6249e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
6259e6268dbSMiklos Szeredi 	req->in.numargs = 1;
6269e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
6279e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
6289e6268dbSMiklos Szeredi 	request_send(fc, req);
6299e6268dbSMiklos Szeredi 	err = req->out.h.error;
6309e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
6319e6268dbSMiklos Szeredi 	if (!err) {
632ce71ec36SDave Hansen 		clear_nlink(entry->d_inode);
6339e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
6348cbdf1e6SMiklos Szeredi 		fuse_invalidate_entry_cache(entry);
6359e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
6369e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
6379e6268dbSMiklos Szeredi 	return err;
6389e6268dbSMiklos Szeredi }
6399e6268dbSMiklos Szeredi 
6409e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
6419e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
6429e6268dbSMiklos Szeredi {
6439e6268dbSMiklos Szeredi 	int err;
6449e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
6459e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
646ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
647ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
648ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
6499e6268dbSMiklos Szeredi 
6509e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
6519e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
6529e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
6539e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
6549e6268dbSMiklos Szeredi 	req->in.numargs = 3;
6559e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
6569e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
6579e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
6589e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
6599e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
6609e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
6619e6268dbSMiklos Szeredi 	request_send(fc, req);
6629e6268dbSMiklos Szeredi 	err = req->out.h.error;
6639e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
6649e6268dbSMiklos Szeredi 	if (!err) {
66508b63307SMiklos Szeredi 		/* ctime changes */
66608b63307SMiklos Szeredi 		fuse_invalidate_attr(oldent->d_inode);
66708b63307SMiklos Szeredi 
6689e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
6699e6268dbSMiklos Szeredi 		if (olddir != newdir)
6709e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
6718cbdf1e6SMiklos Szeredi 
6728cbdf1e6SMiklos Szeredi 		/* newent will end up negative */
6738cbdf1e6SMiklos Szeredi 		if (newent->d_inode)
6748cbdf1e6SMiklos Szeredi 			fuse_invalidate_entry_cache(newent);
6759e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
6769e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
6779e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
6789e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
6799e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
6809e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
6819e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
6829e6268dbSMiklos Szeredi 		if (newent->d_inode)
6839e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
6849e6268dbSMiklos Szeredi 	}
6859e6268dbSMiklos Szeredi 
6869e6268dbSMiklos Szeredi 	return err;
6879e6268dbSMiklos Szeredi }
6889e6268dbSMiklos Szeredi 
6899e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
6909e6268dbSMiklos Szeredi 		     struct dentry *newent)
6919e6268dbSMiklos Szeredi {
6929e6268dbSMiklos Szeredi 	int err;
6939e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
6949e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
6959e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
696ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
697ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
698ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
6999e6268dbSMiklos Szeredi 
7009e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
7019e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
7029e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
7039e6268dbSMiklos Szeredi 	req->in.numargs = 2;
7049e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
7059e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
7069e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
7079e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
7089e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
7099e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
7109e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
7119e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
7129e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
7139e6268dbSMiklos Szeredi 	   etc.)
7149e6268dbSMiklos Szeredi 	*/
7159e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
7169e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
7179e6268dbSMiklos Szeredi 	return err;
7189e6268dbSMiklos Szeredi }
7199e6268dbSMiklos Szeredi 
7201fb69e78SMiklos Szeredi static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
7211fb69e78SMiklos Szeredi 			  struct kstat *stat)
7221fb69e78SMiklos Szeredi {
7231fb69e78SMiklos Szeredi 	stat->dev = inode->i_sb->s_dev;
7241fb69e78SMiklos Szeredi 	stat->ino = attr->ino;
7251fb69e78SMiklos Szeredi 	stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
7261fb69e78SMiklos Szeredi 	stat->nlink = attr->nlink;
7271fb69e78SMiklos Szeredi 	stat->uid = attr->uid;
7281fb69e78SMiklos Szeredi 	stat->gid = attr->gid;
7291fb69e78SMiklos Szeredi 	stat->rdev = inode->i_rdev;
7301fb69e78SMiklos Szeredi 	stat->atime.tv_sec = attr->atime;
7311fb69e78SMiklos Szeredi 	stat->atime.tv_nsec = attr->atimensec;
7321fb69e78SMiklos Szeredi 	stat->mtime.tv_sec = attr->mtime;
7331fb69e78SMiklos Szeredi 	stat->mtime.tv_nsec = attr->mtimensec;
7341fb69e78SMiklos Szeredi 	stat->ctime.tv_sec = attr->ctime;
7351fb69e78SMiklos Szeredi 	stat->ctime.tv_nsec = attr->ctimensec;
7361fb69e78SMiklos Szeredi 	stat->size = attr->size;
7371fb69e78SMiklos Szeredi 	stat->blocks = attr->blocks;
7381fb69e78SMiklos Szeredi 	stat->blksize = (1 << inode->i_blkbits);
7391fb69e78SMiklos Szeredi }
7401fb69e78SMiklos Szeredi 
741c79e322fSMiklos Szeredi static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
742c79e322fSMiklos Szeredi 			   struct file *file)
743e5e5558eSMiklos Szeredi {
744e5e5558eSMiklos Szeredi 	int err;
745c79e322fSMiklos Szeredi 	struct fuse_getattr_in inarg;
746c79e322fSMiklos Szeredi 	struct fuse_attr_out outarg;
747e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
7481fb69e78SMiklos Szeredi 	struct fuse_req *req;
7491fb69e78SMiklos Szeredi 	u64 attr_version;
7501fb69e78SMiklos Szeredi 
7511fb69e78SMiklos Szeredi 	req = fuse_get_req(fc);
752ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
753ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
754e5e5558eSMiklos Szeredi 
7557dca9fd3SMiklos Szeredi 	attr_version = fuse_get_attr_version(fc);
7561fb69e78SMiklos Szeredi 
757c79e322fSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
7580e9663eeSMiklos Szeredi 	memset(&outarg, 0, sizeof(outarg));
759c79e322fSMiklos Szeredi 	/* Directories have separate file-handle space */
760c79e322fSMiklos Szeredi 	if (file && S_ISREG(inode->i_mode)) {
761c79e322fSMiklos Szeredi 		struct fuse_file *ff = file->private_data;
762c79e322fSMiklos Szeredi 
763c79e322fSMiklos Szeredi 		inarg.getattr_flags |= FUSE_GETATTR_FH;
764c79e322fSMiklos Szeredi 		inarg.fh = ff->fh;
765c79e322fSMiklos Szeredi 	}
766e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
767e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
768c79e322fSMiklos Szeredi 	req->in.numargs = 1;
769c79e322fSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
770c79e322fSMiklos Szeredi 	req->in.args[0].value = &inarg;
771e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
7720e9663eeSMiklos Szeredi 	if (fc->minor < 9)
7730e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
7740e9663eeSMiklos Szeredi 	else
775c79e322fSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
776c79e322fSMiklos Szeredi 	req->out.args[0].value = &outarg;
777e5e5558eSMiklos Szeredi 	request_send(fc, req);
778e5e5558eSMiklos Szeredi 	err = req->out.h.error;
779e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
780e5e5558eSMiklos Szeredi 	if (!err) {
781c79e322fSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
782e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
783e5e5558eSMiklos Szeredi 			err = -EIO;
784e5e5558eSMiklos Szeredi 		} else {
785c79e322fSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr,
786c79e322fSMiklos Szeredi 					       attr_timeout(&outarg),
7871fb69e78SMiklos Szeredi 					       attr_version);
7881fb69e78SMiklos Szeredi 			if (stat)
789c79e322fSMiklos Szeredi 				fuse_fillattr(inode, &outarg.attr, stat);
790e5e5558eSMiklos Szeredi 		}
791e5e5558eSMiklos Szeredi 	}
792e5e5558eSMiklos Szeredi 	return err;
793e5e5558eSMiklos Szeredi }
794e5e5558eSMiklos Szeredi 
795bcb4be80SMiklos Szeredi int fuse_update_attributes(struct inode *inode, struct kstat *stat,
796bcb4be80SMiklos Szeredi 			   struct file *file, bool *refreshed)
797bcb4be80SMiklos Szeredi {
798bcb4be80SMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
799bcb4be80SMiklos Szeredi 	int err;
800bcb4be80SMiklos Szeredi 	bool r;
801bcb4be80SMiklos Szeredi 
802bcb4be80SMiklos Szeredi 	if (fi->i_time < get_jiffies_64()) {
803bcb4be80SMiklos Szeredi 		r = true;
804bcb4be80SMiklos Szeredi 		err = fuse_do_getattr(inode, stat, file);
805bcb4be80SMiklos Szeredi 	} else {
806bcb4be80SMiklos Szeredi 		r = false;
807bcb4be80SMiklos Szeredi 		err = 0;
808bcb4be80SMiklos Szeredi 		if (stat) {
809bcb4be80SMiklos Szeredi 			generic_fillattr(inode, stat);
810bcb4be80SMiklos Szeredi 			stat->mode = fi->orig_i_mode;
811bcb4be80SMiklos Szeredi 		}
812bcb4be80SMiklos Szeredi 	}
813bcb4be80SMiklos Szeredi 
814bcb4be80SMiklos Szeredi 	if (refreshed != NULL)
815bcb4be80SMiklos Szeredi 		*refreshed = r;
816bcb4be80SMiklos Szeredi 
817bcb4be80SMiklos Szeredi 	return err;
818bcb4be80SMiklos Szeredi }
819bcb4be80SMiklos Szeredi 
82087729a55SMiklos Szeredi /*
82187729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
82287729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
82387729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
82487729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
82587729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
82687729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
82787729a55SMiklos Szeredi  * DoS against the requester.
82887729a55SMiklos Szeredi  *
82987729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
83087729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
83187729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
83287729a55SMiklos Szeredi  */
833e57ac683SMiklos Szeredi int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
83487729a55SMiklos Szeredi {
83587729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
83687729a55SMiklos Szeredi 		return 1;
83787729a55SMiklos Szeredi 
83887729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
83987729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
84087729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
84187729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
84287729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
84387729a55SMiklos Szeredi 	    task->gid == fc->group_id)
84487729a55SMiklos Szeredi 		return 1;
84587729a55SMiklos Szeredi 
84687729a55SMiklos Szeredi 	return 0;
84787729a55SMiklos Szeredi }
84887729a55SMiklos Szeredi 
84931d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask)
85031d40d74SMiklos Szeredi {
85131d40d74SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
85231d40d74SMiklos Szeredi 	struct fuse_req *req;
85331d40d74SMiklos Szeredi 	struct fuse_access_in inarg;
85431d40d74SMiklos Szeredi 	int err;
85531d40d74SMiklos Szeredi 
85631d40d74SMiklos Szeredi 	if (fc->no_access)
85731d40d74SMiklos Szeredi 		return 0;
85831d40d74SMiklos Szeredi 
859ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
860ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
861ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
86231d40d74SMiklos Szeredi 
86331d40d74SMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
86431d40d74SMiklos Szeredi 	inarg.mask = mask;
86531d40d74SMiklos Szeredi 	req->in.h.opcode = FUSE_ACCESS;
86631d40d74SMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
86731d40d74SMiklos Szeredi 	req->in.numargs = 1;
86831d40d74SMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
86931d40d74SMiklos Szeredi 	req->in.args[0].value = &inarg;
87031d40d74SMiklos Szeredi 	request_send(fc, req);
87131d40d74SMiklos Szeredi 	err = req->out.h.error;
87231d40d74SMiklos Szeredi 	fuse_put_request(fc, req);
87331d40d74SMiklos Szeredi 	if (err == -ENOSYS) {
87431d40d74SMiklos Szeredi 		fc->no_access = 1;
87531d40d74SMiklos Szeredi 		err = 0;
87631d40d74SMiklos Szeredi 	}
87731d40d74SMiklos Szeredi 	return err;
87831d40d74SMiklos Szeredi }
87931d40d74SMiklos Szeredi 
8806f9f1180SMiklos Szeredi /*
8816f9f1180SMiklos Szeredi  * Check permission.  The two basic access models of FUSE are:
8826f9f1180SMiklos Szeredi  *
8836f9f1180SMiklos Szeredi  * 1) Local access checking ('default_permissions' mount option) based
8846f9f1180SMiklos Szeredi  * on file mode.  This is the plain old disk filesystem permission
8856f9f1180SMiklos Szeredi  * modell.
8866f9f1180SMiklos Szeredi  *
8876f9f1180SMiklos Szeredi  * 2) "Remote" access checking, where server is responsible for
8886f9f1180SMiklos Szeredi  * checking permission in each inode operation.  An exception to this
8896f9f1180SMiklos Szeredi  * is if ->permission() was invoked from sys_access() in which case an
8906f9f1180SMiklos Szeredi  * access request is sent.  Execute permission is still checked
8916f9f1180SMiklos Szeredi  * locally based on file mode.
8926f9f1180SMiklos Szeredi  */
893e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
894e5e5558eSMiklos Szeredi {
895e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
896244f6385SMiklos Szeredi 	bool refreshed = false;
897244f6385SMiklos Szeredi 	int err = 0;
898e5e5558eSMiklos Szeredi 
89987729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
900e5e5558eSMiklos Szeredi 		return -EACCES;
901244f6385SMiklos Szeredi 
902244f6385SMiklos Szeredi 	/*
903e8e96157SMiklos Szeredi 	 * If attributes are needed, refresh them before proceeding
904244f6385SMiklos Szeredi 	 */
905e8e96157SMiklos Szeredi 	if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) ||
906e8e96157SMiklos Szeredi 	    ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) {
907bcb4be80SMiklos Szeredi 		err = fuse_update_attributes(inode, NULL, NULL, &refreshed);
908244f6385SMiklos Szeredi 		if (err)
909244f6385SMiklos Szeredi 			return err;
9101fb69e78SMiklos Szeredi 	}
911244f6385SMiklos Szeredi 
912244f6385SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
9131a823ac9SMiklos Szeredi 		err = generic_permission(inode, mask, NULL);
9141e9a4ed9SMiklos Szeredi 
9151e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
9161e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
9171e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
918244f6385SMiklos Szeredi 		if (err == -EACCES && !refreshed) {
919c79e322fSMiklos Szeredi 			err = fuse_do_getattr(inode, NULL, NULL);
9201e9a4ed9SMiklos Szeredi 			if (!err)
9211e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
9221e9a4ed9SMiklos Szeredi 		}
9231e9a4ed9SMiklos Szeredi 
9246f9f1180SMiklos Szeredi 		/* Note: the opposite of the above test does not
9256f9f1180SMiklos Szeredi 		   exist.  So if permissions are revoked this won't be
9266f9f1180SMiklos Szeredi 		   noticed immediately, only after the attribute
9276f9f1180SMiklos Szeredi 		   timeout has expired */
928e8e96157SMiklos Szeredi 	} else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) {
929e8e96157SMiklos Szeredi 		err = fuse_access(inode, mask);
930e8e96157SMiklos Szeredi 	} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
931e8e96157SMiklos Szeredi 		if (!(inode->i_mode & S_IXUGO)) {
932e8e96157SMiklos Szeredi 			if (refreshed)
933e5e5558eSMiklos Szeredi 				return -EACCES;
93431d40d74SMiklos Szeredi 
935c79e322fSMiklos Szeredi 			err = fuse_do_getattr(inode, NULL, NULL);
936e8e96157SMiklos Szeredi 			if (!err && !(inode->i_mode & S_IXUGO))
937e8e96157SMiklos Szeredi 				return -EACCES;
938e8e96157SMiklos Szeredi 		}
939e5e5558eSMiklos Szeredi 	}
940244f6385SMiklos Szeredi 	return err;
941e5e5558eSMiklos Szeredi }
942e5e5558eSMiklos Szeredi 
943e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
944e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
945e5e5558eSMiklos Szeredi {
946e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
947e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
948e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
949e5e5558eSMiklos Szeredi 		int over;
950e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
951e5e5558eSMiklos Szeredi 			return -EIO;
952e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
953e5e5558eSMiklos Szeredi 			break;
954e5e5558eSMiklos Szeredi 
955e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
956e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
957e5e5558eSMiklos Szeredi 		if (over)
958e5e5558eSMiklos Szeredi 			break;
959e5e5558eSMiklos Szeredi 
960e5e5558eSMiklos Szeredi 		buf += reclen;
961e5e5558eSMiklos Szeredi 		nbytes -= reclen;
962e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
963e5e5558eSMiklos Szeredi 	}
964e5e5558eSMiklos Szeredi 
965e5e5558eSMiklos Szeredi 	return 0;
966e5e5558eSMiklos Szeredi }
967e5e5558eSMiklos Szeredi 
968e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
969e5e5558eSMiklos Szeredi {
97004730fefSMiklos Szeredi 	int err;
97104730fefSMiklos Szeredi 	size_t nbytes;
97204730fefSMiklos Szeredi 	struct page *page;
9737706a9d6SJosef Sipek 	struct inode *inode = file->f_path.dentry->d_inode;
97404730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
975248d86e8SMiklos Szeredi 	struct fuse_req *req;
976248d86e8SMiklos Szeredi 
977248d86e8SMiklos Szeredi 	if (is_bad_inode(inode))
978248d86e8SMiklos Szeredi 		return -EIO;
979248d86e8SMiklos Szeredi 
980ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
981ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
982ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
983e5e5558eSMiklos Szeredi 
98404730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
98504730fefSMiklos Szeredi 	if (!page) {
98604730fefSMiklos Szeredi 		fuse_put_request(fc, req);
987e5e5558eSMiklos Szeredi 		return -ENOMEM;
98804730fefSMiklos Szeredi 	}
98904730fefSMiklos Szeredi 	req->num_pages = 1;
99004730fefSMiklos Szeredi 	req->pages[0] = page;
991a6643094SMiklos Szeredi 	fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
992361b1eb5SMiklos Szeredi 	request_send(fc, req);
993361b1eb5SMiklos Szeredi 	nbytes = req->out.args[0].size;
99404730fefSMiklos Szeredi 	err = req->out.h.error;
99504730fefSMiklos Szeredi 	fuse_put_request(fc, req);
99604730fefSMiklos Szeredi 	if (!err)
99704730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
99804730fefSMiklos Szeredi 				    filldir);
999e5e5558eSMiklos Szeredi 
100004730fefSMiklos Szeredi 	__free_page(page);
1001b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
100204730fefSMiklos Szeredi 	return err;
1003e5e5558eSMiklos Szeredi }
1004e5e5558eSMiklos Szeredi 
1005e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
1006e5e5558eSMiklos Szeredi {
1007e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
1008e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
1009ce1d5a49SMiklos Szeredi 	struct fuse_req *req = fuse_get_req(fc);
1010e5e5558eSMiklos Szeredi 	char *link;
1011e5e5558eSMiklos Szeredi 
1012ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1013e231c2eeSDavid Howells 		return ERR_CAST(req);
1014e5e5558eSMiklos Szeredi 
1015e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
1016e5e5558eSMiklos Szeredi 	if (!link) {
1017e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
1018e5e5558eSMiklos Szeredi 		goto out;
1019e5e5558eSMiklos Szeredi 	}
1020e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
1021e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
1022e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
1023e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
1024e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
1025e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
1026e5e5558eSMiklos Szeredi 	request_send(fc, req);
1027e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
1028e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
1029e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
1030e5e5558eSMiklos Szeredi 	} else
1031e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
1032e5e5558eSMiklos Szeredi  out:
1033e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
1034b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
1035e5e5558eSMiklos Szeredi 	return link;
1036e5e5558eSMiklos Szeredi }
1037e5e5558eSMiklos Szeredi 
1038e5e5558eSMiklos Szeredi static void free_link(char *link)
1039e5e5558eSMiklos Szeredi {
1040e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
1041e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
1042e5e5558eSMiklos Szeredi }
1043e5e5558eSMiklos Szeredi 
1044e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
1045e5e5558eSMiklos Szeredi {
1046e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
1047e5e5558eSMiklos Szeredi 	return NULL;
1048e5e5558eSMiklos Szeredi }
1049e5e5558eSMiklos Szeredi 
1050e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
1051e5e5558eSMiklos Szeredi {
1052e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
1053e5e5558eSMiklos Szeredi }
1054e5e5558eSMiklos Szeredi 
1055e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
1056e5e5558eSMiklos Szeredi {
105704730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
1058e5e5558eSMiklos Szeredi }
1059e5e5558eSMiklos Szeredi 
1060e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
1061e5e5558eSMiklos Szeredi {
106204730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
1063e5e5558eSMiklos Szeredi }
1064e5e5558eSMiklos Szeredi 
106582547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
106682547981SMiklos Szeredi {
106782547981SMiklos Szeredi 	/* nfsd can call this with no file */
106882547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
106982547981SMiklos Szeredi }
107082547981SMiklos Szeredi 
107117637cbaSMiklos Szeredi static bool update_mtime(unsigned ivalid)
107217637cbaSMiklos Szeredi {
107317637cbaSMiklos Szeredi 	/* Always update if mtime is explicitly set  */
107417637cbaSMiklos Szeredi 	if (ivalid & ATTR_MTIME_SET)
107517637cbaSMiklos Szeredi 		return true;
107617637cbaSMiklos Szeredi 
107717637cbaSMiklos Szeredi 	/* If it's an open(O_TRUNC) or an ftruncate(), don't update */
107817637cbaSMiklos Szeredi 	if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
107917637cbaSMiklos Szeredi 		return false;
108017637cbaSMiklos Szeredi 
108117637cbaSMiklos Szeredi 	/* In all other cases update */
108217637cbaSMiklos Szeredi 	return true;
108317637cbaSMiklos Szeredi }
108417637cbaSMiklos Szeredi 
1085befc649cSMiklos Szeredi static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
10869e6268dbSMiklos Szeredi {
10879e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
10889e6268dbSMiklos Szeredi 
10899e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
1090befc649cSMiklos Szeredi 		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
10919e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
1092befc649cSMiklos Szeredi 		arg->valid |= FATTR_UID,    arg->uid = iattr->ia_uid;
10939e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
1094befc649cSMiklos Szeredi 		arg->valid |= FATTR_GID,    arg->gid = iattr->ia_gid;
10959e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
1096befc649cSMiklos Szeredi 		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
109717637cbaSMiklos Szeredi 	if (ivalid & ATTR_ATIME) {
109817637cbaSMiklos Szeredi 		arg->valid |= FATTR_ATIME;
1099befc649cSMiklos Szeredi 		arg->atime = iattr->ia_atime.tv_sec;
110017637cbaSMiklos Szeredi 		arg->atimensec = iattr->ia_atime.tv_nsec;
110117637cbaSMiklos Szeredi 		if (!(ivalid & ATTR_ATIME_SET))
110217637cbaSMiklos Szeredi 			arg->valid |= FATTR_ATIME_NOW;
110317637cbaSMiklos Szeredi 	}
110417637cbaSMiklos Szeredi 	if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) {
110517637cbaSMiklos Szeredi 		arg->valid |= FATTR_MTIME;
1106befc649cSMiklos Szeredi 		arg->mtime = iattr->ia_mtime.tv_sec;
110717637cbaSMiklos Szeredi 		arg->mtimensec = iattr->ia_mtime.tv_nsec;
110817637cbaSMiklos Szeredi 		if (!(ivalid & ATTR_MTIME_SET))
110917637cbaSMiklos Szeredi 			arg->valid |= FATTR_MTIME_NOW;
11109e6268dbSMiklos Szeredi 	}
11119e6268dbSMiklos Szeredi }
11129e6268dbSMiklos Szeredi 
11136f9f1180SMiklos Szeredi /*
11143be5a52bSMiklos Szeredi  * Prevent concurrent writepages on inode
11153be5a52bSMiklos Szeredi  *
11163be5a52bSMiklos Szeredi  * This is done by adding a negative bias to the inode write counter
11173be5a52bSMiklos Szeredi  * and waiting for all pending writes to finish.
11183be5a52bSMiklos Szeredi  */
11193be5a52bSMiklos Szeredi void fuse_set_nowrite(struct inode *inode)
11203be5a52bSMiklos Szeredi {
11213be5a52bSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
11223be5a52bSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
11233be5a52bSMiklos Szeredi 
11243be5a52bSMiklos Szeredi 	BUG_ON(!mutex_is_locked(&inode->i_mutex));
11253be5a52bSMiklos Szeredi 
11263be5a52bSMiklos Szeredi 	spin_lock(&fc->lock);
11273be5a52bSMiklos Szeredi 	BUG_ON(fi->writectr < 0);
11283be5a52bSMiklos Szeredi 	fi->writectr += FUSE_NOWRITE;
11293be5a52bSMiklos Szeredi 	spin_unlock(&fc->lock);
11303be5a52bSMiklos Szeredi 	wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE);
11313be5a52bSMiklos Szeredi }
11323be5a52bSMiklos Szeredi 
11333be5a52bSMiklos Szeredi /*
11343be5a52bSMiklos Szeredi  * Allow writepages on inode
11353be5a52bSMiklos Szeredi  *
11363be5a52bSMiklos Szeredi  * Remove the bias from the writecounter and send any queued
11373be5a52bSMiklos Szeredi  * writepages.
11383be5a52bSMiklos Szeredi  */
11393be5a52bSMiklos Szeredi static void __fuse_release_nowrite(struct inode *inode)
11403be5a52bSMiklos Szeredi {
11413be5a52bSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
11423be5a52bSMiklos Szeredi 
11433be5a52bSMiklos Szeredi 	BUG_ON(fi->writectr != FUSE_NOWRITE);
11443be5a52bSMiklos Szeredi 	fi->writectr = 0;
11453be5a52bSMiklos Szeredi 	fuse_flush_writepages(inode);
11463be5a52bSMiklos Szeredi }
11473be5a52bSMiklos Szeredi 
11483be5a52bSMiklos Szeredi void fuse_release_nowrite(struct inode *inode)
11493be5a52bSMiklos Szeredi {
11503be5a52bSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
11513be5a52bSMiklos Szeredi 
11523be5a52bSMiklos Szeredi 	spin_lock(&fc->lock);
11533be5a52bSMiklos Szeredi 	__fuse_release_nowrite(inode);
11543be5a52bSMiklos Szeredi 	spin_unlock(&fc->lock);
11553be5a52bSMiklos Szeredi }
11563be5a52bSMiklos Szeredi 
11573be5a52bSMiklos Szeredi /*
11586f9f1180SMiklos Szeredi  * Set attributes, and at the same time refresh them.
11596f9f1180SMiklos Szeredi  *
11606f9f1180SMiklos Szeredi  * Truncation is slightly complicated, because the 'truncate' request
11616f9f1180SMiklos Szeredi  * may fail, in which case we don't want to touch the mapping.
11629ffbb916SMiklos Szeredi  * vmtruncate() doesn't allow for this case, so do the rlimit checking
11639ffbb916SMiklos Szeredi  * and the actual truncation by hand.
11646f9f1180SMiklos Szeredi  */
116549d4914fSMiklos Szeredi static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
116649d4914fSMiklos Szeredi 			   struct file *file)
11679e6268dbSMiklos Szeredi {
11689e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
11699e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
11709e6268dbSMiklos Szeredi 	struct fuse_req *req;
11719e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
11729e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
11733be5a52bSMiklos Szeredi 	bool is_truncate = false;
11743be5a52bSMiklos Szeredi 	loff_t oldsize;
11759e6268dbSMiklos Szeredi 	int err;
11769e6268dbSMiklos Szeredi 
1177e57ac683SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
1178e57ac683SMiklos Szeredi 		return -EACCES;
1179e57ac683SMiklos Szeredi 
11801e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
11811e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
11821e9a4ed9SMiklos Szeredi 		if (err)
11831e9a4ed9SMiklos Szeredi 			return err;
11841e9a4ed9SMiklos Szeredi 	}
11851e9a4ed9SMiklos Szeredi 
11866ff958edSMiklos Szeredi 	if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
11876ff958edSMiklos Szeredi 		return 0;
11886ff958edSMiklos Szeredi 
11899e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
11909e6268dbSMiklos Szeredi 		unsigned long limit;
1191b2d2272fSMiklos Szeredi 		if (IS_SWAPFILE(inode))
1192b2d2272fSMiklos Szeredi 			return -ETXTBSY;
11939e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
11949e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
11959e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
11969e6268dbSMiklos Szeredi 			return -EFBIG;
11979e6268dbSMiklos Szeredi 		}
11983be5a52bSMiklos Szeredi 		is_truncate = true;
11999e6268dbSMiklos Szeredi 	}
12009e6268dbSMiklos Szeredi 
1201ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1202ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1203ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
12049e6268dbSMiklos Szeredi 
12053be5a52bSMiklos Szeredi 	if (is_truncate)
12063be5a52bSMiklos Szeredi 		fuse_set_nowrite(inode);
12073be5a52bSMiklos Szeredi 
12089e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
12090e9663eeSMiklos Szeredi 	memset(&outarg, 0, sizeof(outarg));
1210befc649cSMiklos Szeredi 	iattr_to_fattr(attr, &inarg);
121149d4914fSMiklos Szeredi 	if (file) {
121249d4914fSMiklos Szeredi 		struct fuse_file *ff = file->private_data;
121349d4914fSMiklos Szeredi 		inarg.valid |= FATTR_FH;
121449d4914fSMiklos Szeredi 		inarg.fh = ff->fh;
121549d4914fSMiklos Szeredi 	}
1216f3332114SMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
1217f3332114SMiklos Szeredi 		/* For mandatory locking in truncate */
1218f3332114SMiklos Szeredi 		inarg.valid |= FATTR_LOCKOWNER;
1219f3332114SMiklos Szeredi 		inarg.lock_owner = fuse_lock_owner_id(fc, current->files);
1220f3332114SMiklos Szeredi 	}
12219e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
12229e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
12239e6268dbSMiklos Szeredi 	req->in.numargs = 1;
12249e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
12259e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
12269e6268dbSMiklos Szeredi 	req->out.numargs = 1;
12270e9663eeSMiklos Szeredi 	if (fc->minor < 9)
12280e9663eeSMiklos Szeredi 		req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
12290e9663eeSMiklos Szeredi 	else
12309e6268dbSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
12319e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
12329e6268dbSMiklos Szeredi 	request_send(fc, req);
12339e6268dbSMiklos Szeredi 	err = req->out.h.error;
12349e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
1235e00d2c2dSMiklos Szeredi 	if (err) {
1236e00d2c2dSMiklos Szeredi 		if (err == -EINTR)
1237e00d2c2dSMiklos Szeredi 			fuse_invalidate_attr(inode);
12383be5a52bSMiklos Szeredi 		goto error;
1239e00d2c2dSMiklos Szeredi 	}
1240e00d2c2dSMiklos Szeredi 
12419e6268dbSMiklos Szeredi 	if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
12429e6268dbSMiklos Szeredi 		make_bad_inode(inode);
12433be5a52bSMiklos Szeredi 		err = -EIO;
12443be5a52bSMiklos Szeredi 		goto error;
12459e6268dbSMiklos Szeredi 	}
12469e6268dbSMiklos Szeredi 
12473be5a52bSMiklos Szeredi 	spin_lock(&fc->lock);
12483be5a52bSMiklos Szeredi 	fuse_change_attributes_common(inode, &outarg.attr,
12493be5a52bSMiklos Szeredi 				      attr_timeout(&outarg));
12503be5a52bSMiklos Szeredi 	oldsize = inode->i_size;
12513be5a52bSMiklos Szeredi 	i_size_write(inode, outarg.attr.size);
12523be5a52bSMiklos Szeredi 
12533be5a52bSMiklos Szeredi 	if (is_truncate) {
12543be5a52bSMiklos Szeredi 		/* NOTE: this may release/reacquire fc->lock */
12553be5a52bSMiklos Szeredi 		__fuse_release_nowrite(inode);
12563be5a52bSMiklos Szeredi 	}
12573be5a52bSMiklos Szeredi 	spin_unlock(&fc->lock);
12583be5a52bSMiklos Szeredi 
12593be5a52bSMiklos Szeredi 	/*
12603be5a52bSMiklos Szeredi 	 * Only call invalidate_inode_pages2() after removing
12613be5a52bSMiklos Szeredi 	 * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.
12623be5a52bSMiklos Szeredi 	 */
12633be5a52bSMiklos Szeredi 	if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
12643be5a52bSMiklos Szeredi 		if (outarg.attr.size < oldsize)
12653be5a52bSMiklos Szeredi 			fuse_truncate(inode->i_mapping, outarg.attr.size);
12663be5a52bSMiklos Szeredi 		invalidate_inode_pages2(inode->i_mapping);
12673be5a52bSMiklos Szeredi 	}
12683be5a52bSMiklos Szeredi 
1269e00d2c2dSMiklos Szeredi 	return 0;
12703be5a52bSMiklos Szeredi 
12713be5a52bSMiklos Szeredi error:
12723be5a52bSMiklos Szeredi 	if (is_truncate)
12733be5a52bSMiklos Szeredi 		fuse_release_nowrite(inode);
12743be5a52bSMiklos Szeredi 
12753be5a52bSMiklos Szeredi 	return err;
12769e6268dbSMiklos Szeredi }
12779e6268dbSMiklos Szeredi 
127849d4914fSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
127949d4914fSMiklos Szeredi {
128049d4914fSMiklos Szeredi 	if (attr->ia_valid & ATTR_FILE)
128149d4914fSMiklos Szeredi 		return fuse_do_setattr(entry, attr, attr->ia_file);
128249d4914fSMiklos Szeredi 	else
128349d4914fSMiklos Szeredi 		return fuse_do_setattr(entry, attr, NULL);
128449d4914fSMiklos Szeredi }
128549d4914fSMiklos Szeredi 
1286e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
1287e5e5558eSMiklos Szeredi 			struct kstat *stat)
1288e5e5558eSMiklos Szeredi {
1289e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
1290244f6385SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
1291244f6385SMiklos Szeredi 
1292244f6385SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
1293244f6385SMiklos Szeredi 		return -EACCES;
1294244f6385SMiklos Szeredi 
1295bcb4be80SMiklos Szeredi 	return fuse_update_attributes(inode, stat, NULL, NULL);
1296e5e5558eSMiklos Szeredi }
1297e5e5558eSMiklos Szeredi 
129892a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
129992a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
130092a8780eSMiklos Szeredi {
130192a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
130292a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
130392a8780eSMiklos Szeredi 	struct fuse_req *req;
130492a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
130592a8780eSMiklos Szeredi 	int err;
130692a8780eSMiklos Szeredi 
130792a8780eSMiklos Szeredi 	if (fc->no_setxattr)
130892a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
130992a8780eSMiklos Szeredi 
1310ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1311ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1312ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
131392a8780eSMiklos Szeredi 
131492a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
131592a8780eSMiklos Szeredi 	inarg.size = size;
131692a8780eSMiklos Szeredi 	inarg.flags = flags;
131792a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
131892a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
131992a8780eSMiklos Szeredi 	req->in.numargs = 3;
132092a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
132192a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
132292a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
132392a8780eSMiklos Szeredi 	req->in.args[1].value = name;
132492a8780eSMiklos Szeredi 	req->in.args[2].size = size;
132592a8780eSMiklos Szeredi 	req->in.args[2].value = value;
132692a8780eSMiklos Szeredi 	request_send(fc, req);
132792a8780eSMiklos Szeredi 	err = req->out.h.error;
132892a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
132992a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
133092a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
133192a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
133292a8780eSMiklos Szeredi 	}
133392a8780eSMiklos Szeredi 	return err;
133492a8780eSMiklos Szeredi }
133592a8780eSMiklos Szeredi 
133692a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
133792a8780eSMiklos Szeredi 			     void *value, size_t size)
133892a8780eSMiklos Szeredi {
133992a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
134092a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
134192a8780eSMiklos Szeredi 	struct fuse_req *req;
134292a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
134392a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
134492a8780eSMiklos Szeredi 	ssize_t ret;
134592a8780eSMiklos Szeredi 
134692a8780eSMiklos Szeredi 	if (fc->no_getxattr)
134792a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
134892a8780eSMiklos Szeredi 
1349ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1350ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1351ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
135292a8780eSMiklos Szeredi 
135392a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
135492a8780eSMiklos Szeredi 	inarg.size = size;
135592a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
135692a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
135792a8780eSMiklos Szeredi 	req->in.numargs = 2;
135892a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
135992a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
136092a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
136192a8780eSMiklos Szeredi 	req->in.args[1].value = name;
136292a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
136392a8780eSMiklos Szeredi 	req->out.numargs = 1;
136492a8780eSMiklos Szeredi 	if (size) {
136592a8780eSMiklos Szeredi 		req->out.argvar = 1;
136692a8780eSMiklos Szeredi 		req->out.args[0].size = size;
136792a8780eSMiklos Szeredi 		req->out.args[0].value = value;
136892a8780eSMiklos Szeredi 	} else {
136992a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
137092a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
137192a8780eSMiklos Szeredi 	}
137292a8780eSMiklos Szeredi 	request_send(fc, req);
137392a8780eSMiklos Szeredi 	ret = req->out.h.error;
137492a8780eSMiklos Szeredi 	if (!ret)
137592a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
137692a8780eSMiklos Szeredi 	else {
137792a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
137892a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
137992a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
138092a8780eSMiklos Szeredi 		}
138192a8780eSMiklos Szeredi 	}
138292a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
138392a8780eSMiklos Szeredi 	return ret;
138492a8780eSMiklos Szeredi }
138592a8780eSMiklos Szeredi 
138692a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
138792a8780eSMiklos Szeredi {
138892a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
138992a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
139092a8780eSMiklos Szeredi 	struct fuse_req *req;
139192a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
139292a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
139392a8780eSMiklos Szeredi 	ssize_t ret;
139492a8780eSMiklos Szeredi 
1395e57ac683SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
1396e57ac683SMiklos Szeredi 		return -EACCES;
1397e57ac683SMiklos Szeredi 
139892a8780eSMiklos Szeredi 	if (fc->no_listxattr)
139992a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
140092a8780eSMiklos Szeredi 
1401ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1402ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1403ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
140492a8780eSMiklos Szeredi 
140592a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
140692a8780eSMiklos Szeredi 	inarg.size = size;
140792a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
140892a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
140992a8780eSMiklos Szeredi 	req->in.numargs = 1;
141092a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
141192a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
141292a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
141392a8780eSMiklos Szeredi 	req->out.numargs = 1;
141492a8780eSMiklos Szeredi 	if (size) {
141592a8780eSMiklos Szeredi 		req->out.argvar = 1;
141692a8780eSMiklos Szeredi 		req->out.args[0].size = size;
141792a8780eSMiklos Szeredi 		req->out.args[0].value = list;
141892a8780eSMiklos Szeredi 	} else {
141992a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
142092a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
142192a8780eSMiklos Szeredi 	}
142292a8780eSMiklos Szeredi 	request_send(fc, req);
142392a8780eSMiklos Szeredi 	ret = req->out.h.error;
142492a8780eSMiklos Szeredi 	if (!ret)
142592a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
142692a8780eSMiklos Szeredi 	else {
142792a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
142892a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
142992a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
143092a8780eSMiklos Szeredi 		}
143192a8780eSMiklos Szeredi 	}
143292a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
143392a8780eSMiklos Szeredi 	return ret;
143492a8780eSMiklos Szeredi }
143592a8780eSMiklos Szeredi 
143692a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
143792a8780eSMiklos Szeredi {
143892a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
143992a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
144092a8780eSMiklos Szeredi 	struct fuse_req *req;
144192a8780eSMiklos Szeredi 	int err;
144292a8780eSMiklos Szeredi 
144392a8780eSMiklos Szeredi 	if (fc->no_removexattr)
144492a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
144592a8780eSMiklos Szeredi 
1446ce1d5a49SMiklos Szeredi 	req = fuse_get_req(fc);
1447ce1d5a49SMiklos Szeredi 	if (IS_ERR(req))
1448ce1d5a49SMiklos Szeredi 		return PTR_ERR(req);
144992a8780eSMiklos Szeredi 
145092a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
145192a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
145292a8780eSMiklos Szeredi 	req->in.numargs = 1;
145392a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
145492a8780eSMiklos Szeredi 	req->in.args[0].value = name;
145592a8780eSMiklos Szeredi 	request_send(fc, req);
145692a8780eSMiklos Szeredi 	err = req->out.h.error;
145792a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
145892a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
145992a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
146092a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
146192a8780eSMiklos Szeredi 	}
146292a8780eSMiklos Szeredi 	return err;
146392a8780eSMiklos Szeredi }
146492a8780eSMiklos Szeredi 
1465754661f1SArjan van de Ven static const struct inode_operations fuse_dir_inode_operations = {
1466e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
14679e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
14689e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
14699e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
14709e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
14719e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
14729e6268dbSMiklos Szeredi 	.link		= fuse_link,
14739e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
14749e6268dbSMiklos Szeredi 	.create		= fuse_create,
14759e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
1476e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1477e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
147892a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
147992a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
148092a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
148192a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1482e5e5558eSMiklos Szeredi };
1483e5e5558eSMiklos Szeredi 
14844b6f5d20SArjan van de Ven static const struct file_operations fuse_dir_operations = {
1485b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
1486e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
1487e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
1488e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
1489e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
149082547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
1491e5e5558eSMiklos Szeredi };
1492e5e5558eSMiklos Szeredi 
1493754661f1SArjan van de Ven static const struct inode_operations fuse_common_inode_operations = {
14949e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1495e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1496e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
149792a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
149892a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
149992a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
150092a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1501e5e5558eSMiklos Szeredi };
1502e5e5558eSMiklos Szeredi 
1503754661f1SArjan van de Ven static const struct inode_operations fuse_symlink_inode_operations = {
15049e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1505e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
1506e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
1507e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
1508e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
150992a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
151092a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
151192a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
151292a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1513e5e5558eSMiklos Szeredi };
1514e5e5558eSMiklos Szeredi 
1515e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
1516e5e5558eSMiklos Szeredi {
1517e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
1518e5e5558eSMiklos Szeredi }
1519e5e5558eSMiklos Szeredi 
1520e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
1521e5e5558eSMiklos Szeredi {
1522e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
1523e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
1524e5e5558eSMiklos Szeredi }
1525e5e5558eSMiklos Szeredi 
1526e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
1527e5e5558eSMiklos Szeredi {
1528e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
1529e5e5558eSMiklos Szeredi }
1530