xref: /openbmc/linux/fs/fuse/dir.c (revision f12ec44070f6b4d1a3911fcf9917cf8f872a4daf)
1e5e5558eSMiklos Szeredi /*
2e5e5558eSMiklos Szeredi   FUSE: Filesystem in Userspace
3e5e5558eSMiklos Szeredi   Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
4e5e5558eSMiklos Szeredi 
5e5e5558eSMiklos Szeredi   This program can be distributed under the terms of the GNU GPL.
6e5e5558eSMiklos Szeredi   See the file COPYING.
7e5e5558eSMiklos Szeredi */
8e5e5558eSMiklos Szeredi 
9e5e5558eSMiklos Szeredi #include "fuse_i.h"
10e5e5558eSMiklos Szeredi 
11e5e5558eSMiklos Szeredi #include <linux/pagemap.h>
12e5e5558eSMiklos Szeredi #include <linux/file.h>
13e5e5558eSMiklos Szeredi #include <linux/gfp.h>
14e5e5558eSMiklos Szeredi #include <linux/sched.h>
15e5e5558eSMiklos Szeredi #include <linux/namei.h>
16e5e5558eSMiklos Szeredi 
17e5e5558eSMiklos Szeredi static inline unsigned long time_to_jiffies(unsigned long sec,
18e5e5558eSMiklos Szeredi 					    unsigned long nsec)
19e5e5558eSMiklos Szeredi {
20e5e5558eSMiklos Szeredi 	struct timespec ts = {sec, nsec};
21e5e5558eSMiklos Szeredi 	return jiffies + timespec_to_jiffies(&ts);
22e5e5558eSMiklos Szeredi }
23e5e5558eSMiklos Szeredi 
24e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
25e5e5558eSMiklos Szeredi 			     struct dentry *entry,
26e5e5558eSMiklos Szeredi 			     struct fuse_entry_out *outarg)
27e5e5558eSMiklos Szeredi {
28e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_LOOKUP;
29e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
30e5e5558eSMiklos Szeredi 	req->inode = dir;
31e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
32e5e5558eSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
33e5e5558eSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
34e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
35e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(struct fuse_entry_out);
36e5e5558eSMiklos Szeredi 	req->out.args[0].value = outarg;
37e5e5558eSMiklos Szeredi }
38e5e5558eSMiklos Szeredi 
39e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
40e5e5558eSMiklos Szeredi {
41e5e5558eSMiklos Szeredi 	if (!entry->d_inode || is_bad_inode(entry->d_inode))
42e5e5558eSMiklos Szeredi 		return 0;
43e5e5558eSMiklos Szeredi 	else if (time_after(jiffies, entry->d_time)) {
44e5e5558eSMiklos Szeredi 		int err;
45e5e5558eSMiklos Szeredi 		struct fuse_entry_out outarg;
46e5e5558eSMiklos Szeredi 		struct inode *inode = entry->d_inode;
47e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
48e5e5558eSMiklos Szeredi 		struct fuse_conn *fc = get_fuse_conn(inode);
497c352bdfSMiklos Szeredi 		struct fuse_req *req = fuse_get_request(fc);
50e5e5558eSMiklos Szeredi 		if (!req)
51e5e5558eSMiklos Szeredi 			return 0;
52e5e5558eSMiklos Szeredi 
53e5e5558eSMiklos Szeredi 		fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
547c352bdfSMiklos Szeredi 		request_send(fc, req);
55e5e5558eSMiklos Szeredi 		err = req->out.h.error;
569e6268dbSMiklos Szeredi 		if (!err) {
579e6268dbSMiklos Szeredi 			if (outarg.nodeid != get_node_id(inode)) {
589e6268dbSMiklos Szeredi 				fuse_send_forget(fc, req, outarg.nodeid, 1);
599e6268dbSMiklos Szeredi 				return 0;
609e6268dbSMiklos Szeredi 			}
619e6268dbSMiklos Szeredi 			fi->nlookup ++;
629e6268dbSMiklos Szeredi 		}
63e5e5558eSMiklos Szeredi 		fuse_put_request(fc, req);
649e6268dbSMiklos Szeredi 		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
65e5e5558eSMiklos Szeredi 			return 0;
66e5e5558eSMiklos Szeredi 
67e5e5558eSMiklos Szeredi 		fuse_change_attributes(inode, &outarg.attr);
68e5e5558eSMiklos Szeredi 		entry->d_time = time_to_jiffies(outarg.entry_valid,
69e5e5558eSMiklos Szeredi 						outarg.entry_valid_nsec);
70e5e5558eSMiklos Szeredi 		fi->i_time = time_to_jiffies(outarg.attr_valid,
71e5e5558eSMiklos Szeredi 					     outarg.attr_valid_nsec);
72e5e5558eSMiklos Szeredi 	}
73e5e5558eSMiklos Szeredi 	return 1;
74e5e5558eSMiklos Szeredi }
75e5e5558eSMiklos Szeredi 
76e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = {
77e5e5558eSMiklos Szeredi 	.d_revalidate	= fuse_dentry_revalidate,
78e5e5558eSMiklos Szeredi };
79e5e5558eSMiklos Szeredi 
80e5e5558eSMiklos Szeredi static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
81e5e5558eSMiklos Szeredi 			    struct inode **inodep)
82e5e5558eSMiklos Szeredi {
83e5e5558eSMiklos Szeredi 	int err;
84e5e5558eSMiklos Szeredi 	struct fuse_entry_out outarg;
85e5e5558eSMiklos Szeredi 	struct inode *inode = NULL;
86e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
87e5e5558eSMiklos Szeredi 	struct fuse_req *req;
88e5e5558eSMiklos Szeredi 
89e5e5558eSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
90e5e5558eSMiklos Szeredi 		return -ENAMETOOLONG;
91e5e5558eSMiklos Szeredi 
92e5e5558eSMiklos Szeredi 	req = fuse_get_request(fc);
93e5e5558eSMiklos Szeredi 	if (!req)
947c352bdfSMiklos Szeredi 		return -EINTR;
95e5e5558eSMiklos Szeredi 
96e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
97e5e5558eSMiklos Szeredi 	request_send(fc, req);
98e5e5558eSMiklos Szeredi 	err = req->out.h.error;
99ee4e5271SMiklos Szeredi 	if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID))
100ee4e5271SMiklos Szeredi 		err = -EIO;
101e5e5558eSMiklos Szeredi 	if (!err) {
102e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
1039e6268dbSMiklos Szeredi 				  &outarg.attr);
104e5e5558eSMiklos Szeredi 		if (!inode) {
1059e6268dbSMiklos Szeredi 			fuse_send_forget(fc, req, outarg.nodeid, 1);
106e5e5558eSMiklos Szeredi 			return -ENOMEM;
107e5e5558eSMiklos Szeredi 		}
108e5e5558eSMiklos Szeredi 	}
109e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
110e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
111e5e5558eSMiklos Szeredi 		return err;
112e5e5558eSMiklos Szeredi 
113e5e5558eSMiklos Szeredi 	if (inode) {
114e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
115e5e5558eSMiklos Szeredi 		entry->d_time =	time_to_jiffies(outarg.entry_valid,
116e5e5558eSMiklos Szeredi 						outarg.entry_valid_nsec);
117e5e5558eSMiklos Szeredi 		fi->i_time = time_to_jiffies(outarg.attr_valid,
118e5e5558eSMiklos Szeredi 					     outarg.attr_valid_nsec);
119e5e5558eSMiklos Szeredi 	}
120e5e5558eSMiklos Szeredi 
121e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
122e5e5558eSMiklos Szeredi 	*inodep = inode;
123e5e5558eSMiklos Szeredi 	return 0;
124e5e5558eSMiklos Szeredi }
125e5e5558eSMiklos Szeredi 
1269e6268dbSMiklos Szeredi void fuse_invalidate_attr(struct inode *inode)
1279e6268dbSMiklos Szeredi {
1289e6268dbSMiklos Szeredi 	get_fuse_inode(inode)->i_time = jiffies - 1;
1299e6268dbSMiklos Szeredi }
1309e6268dbSMiklos Szeredi 
1319e6268dbSMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry)
1329e6268dbSMiklos Szeredi {
1339e6268dbSMiklos Szeredi 	d_invalidate(entry);
1349e6268dbSMiklos Szeredi 	entry->d_time = jiffies - 1;
1359e6268dbSMiklos Szeredi }
1369e6268dbSMiklos Szeredi 
1379e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
1389e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
1399e6268dbSMiklos Szeredi 			    int mode)
1409e6268dbSMiklos Szeredi {
1419e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
1429e6268dbSMiklos Szeredi 	struct inode *inode;
1439e6268dbSMiklos Szeredi 	struct fuse_inode *fi;
1449e6268dbSMiklos Szeredi 	int err;
1459e6268dbSMiklos Szeredi 
1469e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
1479e6268dbSMiklos Szeredi 	req->inode = dir;
1489e6268dbSMiklos Szeredi 	req->out.numargs = 1;
1499e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
1509e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
1519e6268dbSMiklos Szeredi 	request_send(fc, req);
1529e6268dbSMiklos Szeredi 	err = req->out.h.error;
1539e6268dbSMiklos Szeredi 	if (err) {
1549e6268dbSMiklos Szeredi 		fuse_put_request(fc, req);
1559e6268dbSMiklos Szeredi 		return err;
1569e6268dbSMiklos Szeredi 	}
157ee4e5271SMiklos Szeredi 	if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
158ee4e5271SMiklos Szeredi 		fuse_put_request(fc, req);
159ee4e5271SMiklos Szeredi 		return -EIO;
160ee4e5271SMiklos Szeredi 	}
1619e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
1629e6268dbSMiklos Szeredi 			  &outarg.attr);
1639e6268dbSMiklos Szeredi 	if (!inode) {
1649e6268dbSMiklos Szeredi 		fuse_send_forget(fc, req, outarg.nodeid, 1);
1659e6268dbSMiklos Szeredi 		return -ENOMEM;
1669e6268dbSMiklos Szeredi 	}
1679e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
1689e6268dbSMiklos Szeredi 
1699e6268dbSMiklos Szeredi 	/* Don't allow userspace to do really stupid things... */
1709e6268dbSMiklos Szeredi 	if ((inode->i_mode ^ mode) & S_IFMT) {
1719e6268dbSMiklos Szeredi 		iput(inode);
1729e6268dbSMiklos Szeredi 		return -EIO;
1739e6268dbSMiklos Szeredi 	}
1749e6268dbSMiklos Szeredi 
1759e6268dbSMiklos Szeredi 	entry->d_time = time_to_jiffies(outarg.entry_valid,
1769e6268dbSMiklos Szeredi 					outarg.entry_valid_nsec);
1779e6268dbSMiklos Szeredi 
1789e6268dbSMiklos Szeredi 	fi = get_fuse_inode(inode);
1799e6268dbSMiklos Szeredi 	fi->i_time = time_to_jiffies(outarg.attr_valid,
1809e6268dbSMiklos Szeredi 				     outarg.attr_valid_nsec);
1819e6268dbSMiklos Szeredi 
1829e6268dbSMiklos Szeredi 	d_instantiate(entry, inode);
1839e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
1849e6268dbSMiklos Szeredi 	return 0;
1859e6268dbSMiklos Szeredi }
1869e6268dbSMiklos Szeredi 
1879e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
1889e6268dbSMiklos Szeredi 		      dev_t rdev)
1899e6268dbSMiklos Szeredi {
1909e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
1919e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
1929e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
1939e6268dbSMiklos Szeredi 	if (!req)
1947c352bdfSMiklos Szeredi 		return -EINTR;
1959e6268dbSMiklos Szeredi 
1969e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
1979e6268dbSMiklos Szeredi 	inarg.mode = mode;
1989e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
1999e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
2009e6268dbSMiklos Szeredi 	req->in.numargs = 2;
2019e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
2029e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
2039e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
2049e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
2059e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
2069e6268dbSMiklos Szeredi }
2079e6268dbSMiklos Szeredi 
2089e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
2099e6268dbSMiklos Szeredi 		       struct nameidata *nd)
2109e6268dbSMiklos Szeredi {
2119e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
2129e6268dbSMiklos Szeredi }
2139e6268dbSMiklos Szeredi 
2149e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
2159e6268dbSMiklos Szeredi {
2169e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
2179e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2189e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
2199e6268dbSMiklos Szeredi 	if (!req)
2207c352bdfSMiklos Szeredi 		return -EINTR;
2219e6268dbSMiklos Szeredi 
2229e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
2239e6268dbSMiklos Szeredi 	inarg.mode = mode;
2249e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
2259e6268dbSMiklos Szeredi 	req->in.numargs = 2;
2269e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
2279e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
2289e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
2299e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
2309e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
2319e6268dbSMiklos Szeredi }
2329e6268dbSMiklos Szeredi 
2339e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
2349e6268dbSMiklos Szeredi 			const char *link)
2359e6268dbSMiklos Szeredi {
2369e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2379e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
2389e6268dbSMiklos Szeredi 	struct fuse_req *req;
2399e6268dbSMiklos Szeredi 
2409e6268dbSMiklos Szeredi 	if (len > FUSE_SYMLINK_MAX)
2419e6268dbSMiklos Szeredi 		return -ENAMETOOLONG;
2429e6268dbSMiklos Szeredi 
2439e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
2449e6268dbSMiklos Szeredi 	if (!req)
2457c352bdfSMiklos Szeredi 		return -EINTR;
2469e6268dbSMiklos Szeredi 
2479e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SYMLINK;
2489e6268dbSMiklos Szeredi 	req->in.numargs = 2;
2499e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
2509e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
2519e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
2529e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
2539e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
2549e6268dbSMiklos Szeredi }
2559e6268dbSMiklos Szeredi 
2569e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
2579e6268dbSMiklos Szeredi {
2589e6268dbSMiklos Szeredi 	int err;
2599e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2609e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
2619e6268dbSMiklos Szeredi 	if (!req)
2627c352bdfSMiklos Szeredi 		return -EINTR;
2639e6268dbSMiklos Szeredi 
2649e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
2659e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
2669e6268dbSMiklos Szeredi 	req->inode = dir;
2679e6268dbSMiklos Szeredi 	req->in.numargs = 1;
2689e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
2699e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
2709e6268dbSMiklos Szeredi 	request_send(fc, req);
2719e6268dbSMiklos Szeredi 	err = req->out.h.error;
2729e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
2739e6268dbSMiklos Szeredi 	if (!err) {
2749e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
2759e6268dbSMiklos Szeredi 
2769e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
2779e6268dbSMiklos Szeredi                    the inode does have more links this will be
2789e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
2799e6268dbSMiklos Szeredi 		inode->i_nlink = 0;
2809e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
2819e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
2829e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
2839e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
2849e6268dbSMiklos Szeredi 	return err;
2859e6268dbSMiklos Szeredi }
2869e6268dbSMiklos Szeredi 
2879e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
2889e6268dbSMiklos Szeredi {
2899e6268dbSMiklos Szeredi 	int err;
2909e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2919e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
2929e6268dbSMiklos Szeredi 	if (!req)
2937c352bdfSMiklos Szeredi 		return -EINTR;
2949e6268dbSMiklos Szeredi 
2959e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
2969e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
2979e6268dbSMiklos Szeredi 	req->inode = dir;
2989e6268dbSMiklos Szeredi 	req->in.numargs = 1;
2999e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
3009e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
3019e6268dbSMiklos Szeredi 	request_send(fc, req);
3029e6268dbSMiklos Szeredi 	err = req->out.h.error;
3039e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
3049e6268dbSMiklos Szeredi 	if (!err) {
3059e6268dbSMiklos Szeredi 		entry->d_inode->i_nlink = 0;
3069e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
3079e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
3089e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
3099e6268dbSMiklos Szeredi 	return err;
3109e6268dbSMiklos Szeredi }
3119e6268dbSMiklos Szeredi 
3129e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
3139e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
3149e6268dbSMiklos Szeredi {
3159e6268dbSMiklos Szeredi 	int err;
3169e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
3179e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
3189e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3199e6268dbSMiklos Szeredi 	if (!req)
3207c352bdfSMiklos Szeredi 		return -EINTR;
3219e6268dbSMiklos Szeredi 
3229e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3239e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
3249e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
3259e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
3269e6268dbSMiklos Szeredi 	req->inode = olddir;
3279e6268dbSMiklos Szeredi 	req->inode2 = newdir;
3289e6268dbSMiklos Szeredi 	req->in.numargs = 3;
3299e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3309e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3319e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
3329e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
3339e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
3349e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
3359e6268dbSMiklos Szeredi 	request_send(fc, req);
3369e6268dbSMiklos Szeredi 	err = req->out.h.error;
3379e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
3389e6268dbSMiklos Szeredi 	if (!err) {
3399e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
3409e6268dbSMiklos Szeredi 		if (olddir != newdir)
3419e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
3429e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
3439e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
3449e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
3459e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
3469e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
3479e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
3489e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
3499e6268dbSMiklos Szeredi 		if (newent->d_inode)
3509e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
3519e6268dbSMiklos Szeredi 	}
3529e6268dbSMiklos Szeredi 
3539e6268dbSMiklos Szeredi 	return err;
3549e6268dbSMiklos Szeredi }
3559e6268dbSMiklos Szeredi 
3569e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
3579e6268dbSMiklos Szeredi 		     struct dentry *newent)
3589e6268dbSMiklos Szeredi {
3599e6268dbSMiklos Szeredi 	int err;
3609e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
3619e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
3629e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
3639e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3649e6268dbSMiklos Szeredi 	if (!req)
3657c352bdfSMiklos Szeredi 		return -EINTR;
3669e6268dbSMiklos Szeredi 
3679e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3689e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
3699e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
3709e6268dbSMiklos Szeredi 	req->inode2 = inode;
3719e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3729e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3739e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3749e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
3759e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
3769e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
3779e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
3789e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
3799e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
3809e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
3819e6268dbSMiklos Szeredi 	   etc.)
3829e6268dbSMiklos Szeredi 	*/
3839e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
3849e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
3859e6268dbSMiklos Szeredi 	return err;
3869e6268dbSMiklos Szeredi }
3879e6268dbSMiklos Szeredi 
388e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode)
389e5e5558eSMiklos Szeredi {
390e5e5558eSMiklos Szeredi 	int err;
391e5e5558eSMiklos Szeredi 	struct fuse_attr_out arg;
392e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
393e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
394e5e5558eSMiklos Szeredi 	if (!req)
3957c352bdfSMiklos Szeredi 		return -EINTR;
396e5e5558eSMiklos Szeredi 
397e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
398e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
399e5e5558eSMiklos Szeredi 	req->inode = inode;
400e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
401e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(arg);
402e5e5558eSMiklos Szeredi 	req->out.args[0].value = &arg;
403e5e5558eSMiklos Szeredi 	request_send(fc, req);
404e5e5558eSMiklos Szeredi 	err = req->out.h.error;
405e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
406e5e5558eSMiklos Szeredi 	if (!err) {
407e5e5558eSMiklos Szeredi 		if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
408e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
409e5e5558eSMiklos Szeredi 			err = -EIO;
410e5e5558eSMiklos Szeredi 		} else {
411e5e5558eSMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
412e5e5558eSMiklos Szeredi 			fuse_change_attributes(inode, &arg.attr);
413e5e5558eSMiklos Szeredi 			fi->i_time = time_to_jiffies(arg.attr_valid,
414e5e5558eSMiklos Szeredi 						     arg.attr_valid_nsec);
415e5e5558eSMiklos Szeredi 		}
416e5e5558eSMiklos Szeredi 	}
417e5e5558eSMiklos Szeredi 	return err;
418e5e5558eSMiklos Szeredi }
419e5e5558eSMiklos Szeredi 
42087729a55SMiklos Szeredi /*
42187729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
42287729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
42387729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
42487729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
42587729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
42687729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
42787729a55SMiklos Szeredi  * DoS against the requester.
42887729a55SMiklos Szeredi  *
42987729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
43087729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
43187729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
43287729a55SMiklos Szeredi  */
43387729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
43487729a55SMiklos Szeredi {
43587729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
43687729a55SMiklos Szeredi 		return 1;
43787729a55SMiklos Szeredi 
43887729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
43987729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
44087729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
44187729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
44287729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
44387729a55SMiklos Szeredi 	    task->gid == fc->group_id)
44487729a55SMiklos Szeredi 		return 1;
44587729a55SMiklos Szeredi 
44687729a55SMiklos Szeredi 	return 0;
44787729a55SMiklos Szeredi }
44887729a55SMiklos Szeredi 
449e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry)
450e5e5558eSMiklos Szeredi {
451e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
452e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
453e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
454e5e5558eSMiklos Szeredi 
45587729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
456e5e5558eSMiklos Szeredi 		return -EACCES;
45787729a55SMiklos Szeredi 	if (get_node_id(inode) != FUSE_ROOT_ID &&
45887729a55SMiklos Szeredi 	    time_before_eq(jiffies, fi->i_time))
459e5e5558eSMiklos Szeredi 		return 0;
460e5e5558eSMiklos Szeredi 
461e5e5558eSMiklos Szeredi 	return fuse_do_getattr(inode);
462e5e5558eSMiklos Szeredi }
463e5e5558eSMiklos Szeredi 
464e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
465e5e5558eSMiklos Szeredi {
466e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
467e5e5558eSMiklos Szeredi 
46887729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
469e5e5558eSMiklos Szeredi 		return -EACCES;
4701e9a4ed9SMiklos Szeredi 	else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
4711e9a4ed9SMiklos Szeredi 		int err = generic_permission(inode, mask, NULL);
4721e9a4ed9SMiklos Szeredi 
4731e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
4741e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
4751e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
4761e9a4ed9SMiklos Szeredi 		if (err == -EACCES) {
4771e9a4ed9SMiklos Szeredi 		 	err = fuse_do_getattr(inode);
4781e9a4ed9SMiklos Szeredi 			if (!err)
4791e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
4801e9a4ed9SMiklos Szeredi 		}
4811e9a4ed9SMiklos Szeredi 
4821e9a4ed9SMiklos Szeredi 		/* FIXME: Need some mechanism to revoke permissions:
4831e9a4ed9SMiklos Szeredi 		   currently if the filesystem suddenly changes the
4841e9a4ed9SMiklos Szeredi 		   file mode, we will not be informed about it, and
4851e9a4ed9SMiklos Szeredi 		   continue to allow access to the file/directory.
4861e9a4ed9SMiklos Szeredi 
4871e9a4ed9SMiklos Szeredi 		   This is actually not so grave, since the user can
4881e9a4ed9SMiklos Szeredi 		   simply keep access to the file/directory anyway by
4891e9a4ed9SMiklos Szeredi 		   keeping it open... */
4901e9a4ed9SMiklos Szeredi 
4911e9a4ed9SMiklos Szeredi 		return err;
4921e9a4ed9SMiklos Szeredi 	} else {
493e5e5558eSMiklos Szeredi 		int mode = inode->i_mode;
494e5e5558eSMiklos Szeredi 		if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
495e5e5558eSMiklos Szeredi                     (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
496e5e5558eSMiklos Szeredi                         return -EROFS;
497e5e5558eSMiklos Szeredi 		if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
498e5e5558eSMiklos Szeredi 			return -EACCES;
499e5e5558eSMiklos Szeredi 		return 0;
500e5e5558eSMiklos Szeredi 	}
501e5e5558eSMiklos Szeredi }
502e5e5558eSMiklos Szeredi 
503e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
504e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
505e5e5558eSMiklos Szeredi {
506e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
507e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
508e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
509e5e5558eSMiklos Szeredi 		int over;
510e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
511e5e5558eSMiklos Szeredi 			return -EIO;
512e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
513e5e5558eSMiklos Szeredi 			break;
514e5e5558eSMiklos Szeredi 
515e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
516e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
517e5e5558eSMiklos Szeredi 		if (over)
518e5e5558eSMiklos Szeredi 			break;
519e5e5558eSMiklos Szeredi 
520e5e5558eSMiklos Szeredi 		buf += reclen;
521e5e5558eSMiklos Szeredi 		nbytes -= reclen;
522e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
523e5e5558eSMiklos Szeredi 	}
524e5e5558eSMiklos Szeredi 
525e5e5558eSMiklos Szeredi 	return 0;
526e5e5558eSMiklos Szeredi }
527e5e5558eSMiklos Szeredi 
52804730fefSMiklos Szeredi static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
52904730fefSMiklos Szeredi 				       struct inode *inode, loff_t pos,
53004730fefSMiklos Szeredi 				       size_t count)
531e5e5558eSMiklos Szeredi {
53204730fefSMiklos Szeredi 	return fuse_send_read_common(req, file, inode, pos, count, 1);
533e5e5558eSMiklos Szeredi }
534e5e5558eSMiklos Szeredi 
535e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
536e5e5558eSMiklos Szeredi {
53704730fefSMiklos Szeredi 	int err;
53804730fefSMiklos Szeredi 	size_t nbytes;
53904730fefSMiklos Szeredi 	struct page *page;
54004730fefSMiklos Szeredi 	struct inode *inode = file->f_dentry->d_inode;
54104730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
5427c352bdfSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
54304730fefSMiklos Szeredi 	if (!req)
54404730fefSMiklos Szeredi 		return -EINTR;
545e5e5558eSMiklos Szeredi 
54604730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
54704730fefSMiklos Szeredi 	if (!page) {
54804730fefSMiklos Szeredi 		fuse_put_request(fc, req);
549e5e5558eSMiklos Szeredi 		return -ENOMEM;
55004730fefSMiklos Szeredi 	}
55104730fefSMiklos Szeredi 	req->num_pages = 1;
55204730fefSMiklos Szeredi 	req->pages[0] = page;
55304730fefSMiklos Szeredi 	nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
55404730fefSMiklos Szeredi 	err = req->out.h.error;
55504730fefSMiklos Szeredi 	fuse_put_request(fc, req);
55604730fefSMiklos Szeredi 	if (!err)
55704730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
55804730fefSMiklos Szeredi 				    filldir);
559e5e5558eSMiklos Szeredi 
56004730fefSMiklos Szeredi 	__free_page(page);
561b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
56204730fefSMiklos Szeredi 	return err;
563e5e5558eSMiklos Szeredi }
564e5e5558eSMiklos Szeredi 
565e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
566e5e5558eSMiklos Szeredi {
567e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
568e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
569e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
570e5e5558eSMiklos Szeredi 	char *link;
571e5e5558eSMiklos Szeredi 
572e5e5558eSMiklos Szeredi 	if (!req)
5737c352bdfSMiklos Szeredi 		return ERR_PTR(-EINTR);
574e5e5558eSMiklos Szeredi 
575e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
576e5e5558eSMiklos Szeredi 	if (!link) {
577e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
578e5e5558eSMiklos Szeredi 		goto out;
579e5e5558eSMiklos Szeredi 	}
580e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
581e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
582e5e5558eSMiklos Szeredi 	req->inode = inode;
583e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
584e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
585e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
586e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
587e5e5558eSMiklos Szeredi 	request_send(fc, req);
588e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
589e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
590e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
591e5e5558eSMiklos Szeredi 	} else
592e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
593e5e5558eSMiklos Szeredi  out:
594e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
595b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
596e5e5558eSMiklos Szeredi 	return link;
597e5e5558eSMiklos Szeredi }
598e5e5558eSMiklos Szeredi 
599e5e5558eSMiklos Szeredi static void free_link(char *link)
600e5e5558eSMiklos Szeredi {
601e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
602e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
603e5e5558eSMiklos Szeredi }
604e5e5558eSMiklos Szeredi 
605e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
606e5e5558eSMiklos Szeredi {
607e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
608e5e5558eSMiklos Szeredi 	return NULL;
609e5e5558eSMiklos Szeredi }
610e5e5558eSMiklos Szeredi 
611e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
612e5e5558eSMiklos Szeredi {
613e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
614e5e5558eSMiklos Szeredi }
615e5e5558eSMiklos Szeredi 
616e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
617e5e5558eSMiklos Szeredi {
61804730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
619e5e5558eSMiklos Szeredi }
620e5e5558eSMiklos Szeredi 
621e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
622e5e5558eSMiklos Szeredi {
62304730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
624e5e5558eSMiklos Szeredi }
625e5e5558eSMiklos Szeredi 
62682547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
62782547981SMiklos Szeredi {
62882547981SMiklos Szeredi 	/* nfsd can call this with no file */
62982547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
63082547981SMiklos Szeredi }
63182547981SMiklos Szeredi 
6329e6268dbSMiklos Szeredi static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
6339e6268dbSMiklos Szeredi {
6349e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
6359e6268dbSMiklos Szeredi 	unsigned fvalid = 0;
6369e6268dbSMiklos Szeredi 
6379e6268dbSMiklos Szeredi 	memset(fattr, 0, sizeof(*fattr));
6389e6268dbSMiklos Szeredi 
6399e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
6409e6268dbSMiklos Szeredi 		fvalid |= FATTR_MODE,   fattr->mode = iattr->ia_mode;
6419e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
6429e6268dbSMiklos Szeredi 		fvalid |= FATTR_UID,    fattr->uid = iattr->ia_uid;
6439e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
6449e6268dbSMiklos Szeredi 		fvalid |= FATTR_GID,    fattr->gid = iattr->ia_gid;
6459e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
6469e6268dbSMiklos Szeredi 		fvalid |= FATTR_SIZE,   fattr->size = iattr->ia_size;
6479e6268dbSMiklos Szeredi 	/* You can only _set_ these together (they may change by themselves) */
6489e6268dbSMiklos Szeredi 	if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
6499e6268dbSMiklos Szeredi 		fvalid |= FATTR_ATIME | FATTR_MTIME;
6509e6268dbSMiklos Szeredi 		fattr->atime = iattr->ia_atime.tv_sec;
6519e6268dbSMiklos Szeredi 		fattr->mtime = iattr->ia_mtime.tv_sec;
6529e6268dbSMiklos Szeredi 	}
6539e6268dbSMiklos Szeredi 
6549e6268dbSMiklos Szeredi 	return fvalid;
6559e6268dbSMiklos Szeredi }
6569e6268dbSMiklos Szeredi 
6579e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
6589e6268dbSMiklos Szeredi {
6599e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
6609e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
6619e6268dbSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
6629e6268dbSMiklos Szeredi 	struct fuse_req *req;
6639e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
6649e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
6659e6268dbSMiklos Szeredi 	int err;
6669e6268dbSMiklos Szeredi 	int is_truncate = 0;
6679e6268dbSMiklos Szeredi 
6681e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
6691e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
6701e9a4ed9SMiklos Szeredi 		if (err)
6711e9a4ed9SMiklos Szeredi 			return err;
6721e9a4ed9SMiklos Szeredi 	}
6731e9a4ed9SMiklos Szeredi 
6749e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
6759e6268dbSMiklos Szeredi 		unsigned long limit;
6769e6268dbSMiklos Szeredi 		is_truncate = 1;
6779e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
6789e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
6799e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
6809e6268dbSMiklos Szeredi 			return -EFBIG;
6819e6268dbSMiklos Szeredi 		}
6829e6268dbSMiklos Szeredi 	}
6839e6268dbSMiklos Szeredi 
6849e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
6859e6268dbSMiklos Szeredi 	if (!req)
6867c352bdfSMiklos Szeredi 		return -EINTR;
6879e6268dbSMiklos Szeredi 
6889e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
6899e6268dbSMiklos Szeredi 	inarg.valid = iattr_to_fattr(attr, &inarg.attr);
6909e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
6919e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
6929e6268dbSMiklos Szeredi 	req->inode = inode;
6939e6268dbSMiklos Szeredi 	req->in.numargs = 1;
6949e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
6959e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
6969e6268dbSMiklos Szeredi 	req->out.numargs = 1;
6979e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
6989e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
6999e6268dbSMiklos Szeredi 	request_send(fc, req);
7009e6268dbSMiklos Szeredi 	err = req->out.h.error;
7019e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
7029e6268dbSMiklos Szeredi 	if (!err) {
7039e6268dbSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
7049e6268dbSMiklos Szeredi 			make_bad_inode(inode);
7059e6268dbSMiklos Szeredi 			err = -EIO;
7069e6268dbSMiklos Szeredi 		} else {
7079e6268dbSMiklos Szeredi 			if (is_truncate) {
7089e6268dbSMiklos Szeredi 				loff_t origsize = i_size_read(inode);
7099e6268dbSMiklos Szeredi 				i_size_write(inode, outarg.attr.size);
7109e6268dbSMiklos Szeredi 				if (origsize > outarg.attr.size)
7119e6268dbSMiklos Szeredi 					vmtruncate(inode, outarg.attr.size);
7129e6268dbSMiklos Szeredi 			}
7139e6268dbSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr);
7149e6268dbSMiklos Szeredi 			fi->i_time = time_to_jiffies(outarg.attr_valid,
7159e6268dbSMiklos Szeredi 						     outarg.attr_valid_nsec);
7169e6268dbSMiklos Szeredi 		}
7179e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
7189e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
7199e6268dbSMiklos Szeredi 
7209e6268dbSMiklos Szeredi 	return err;
7219e6268dbSMiklos Szeredi }
7229e6268dbSMiklos Szeredi 
723e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
724e5e5558eSMiklos Szeredi 			struct kstat *stat)
725e5e5558eSMiklos Szeredi {
726e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
727e5e5558eSMiklos Szeredi 	int err = fuse_revalidate(entry);
728e5e5558eSMiklos Szeredi 	if (!err)
729e5e5558eSMiklos Szeredi 		generic_fillattr(inode, stat);
730e5e5558eSMiklos Szeredi 
731e5e5558eSMiklos Szeredi 	return err;
732e5e5558eSMiklos Szeredi }
733e5e5558eSMiklos Szeredi 
734e5e5558eSMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
735e5e5558eSMiklos Szeredi 				  struct nameidata *nd)
736e5e5558eSMiklos Szeredi {
737e5e5558eSMiklos Szeredi 	struct inode *inode;
738e5e5558eSMiklos Szeredi 	int err = fuse_lookup_iget(dir, entry, &inode);
739e5e5558eSMiklos Szeredi 	if (err)
740e5e5558eSMiklos Szeredi 		return ERR_PTR(err);
741e5e5558eSMiklos Szeredi 	if (inode && S_ISDIR(inode->i_mode)) {
742e5e5558eSMiklos Szeredi 		/* Don't allow creating an alias to a directory  */
743e5e5558eSMiklos Szeredi 		struct dentry *alias = d_find_alias(inode);
744*f12ec440SMiklos Szeredi 		if (alias) {
745e5e5558eSMiklos Szeredi 			dput(alias);
746e5e5558eSMiklos Szeredi 			iput(inode);
747e5e5558eSMiklos Szeredi 			return ERR_PTR(-EIO);
748e5e5558eSMiklos Szeredi 		}
749e5e5558eSMiklos Szeredi 	}
750*f12ec440SMiklos Szeredi 	d_add(entry, inode);
751*f12ec440SMiklos Szeredi 	return NULL;
752e5e5558eSMiklos Szeredi }
753e5e5558eSMiklos Szeredi 
75492a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
75592a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
75692a8780eSMiklos Szeredi {
75792a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
75892a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
75992a8780eSMiklos Szeredi 	struct fuse_req *req;
76092a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
76192a8780eSMiklos Szeredi 	int err;
76292a8780eSMiklos Szeredi 
76392a8780eSMiklos Szeredi 	if (size > FUSE_XATTR_SIZE_MAX)
76492a8780eSMiklos Szeredi 		return -E2BIG;
76592a8780eSMiklos Szeredi 
76692a8780eSMiklos Szeredi 	if (fc->no_setxattr)
76792a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
76892a8780eSMiklos Szeredi 
76992a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
77092a8780eSMiklos Szeredi 	if (!req)
7717c352bdfSMiklos Szeredi 		return -EINTR;
77292a8780eSMiklos Szeredi 
77392a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
77492a8780eSMiklos Szeredi 	inarg.size = size;
77592a8780eSMiklos Szeredi 	inarg.flags = flags;
77692a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
77792a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
77892a8780eSMiklos Szeredi 	req->inode = inode;
77992a8780eSMiklos Szeredi 	req->in.numargs = 3;
78092a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
78192a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
78292a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
78392a8780eSMiklos Szeredi 	req->in.args[1].value = name;
78492a8780eSMiklos Szeredi 	req->in.args[2].size = size;
78592a8780eSMiklos Szeredi 	req->in.args[2].value = value;
78692a8780eSMiklos Szeredi 	request_send(fc, req);
78792a8780eSMiklos Szeredi 	err = req->out.h.error;
78892a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
78992a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
79092a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
79192a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
79292a8780eSMiklos Szeredi 	}
79392a8780eSMiklos Szeredi 	return err;
79492a8780eSMiklos Szeredi }
79592a8780eSMiklos Szeredi 
79692a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
79792a8780eSMiklos Szeredi 			     void *value, size_t size)
79892a8780eSMiklos Szeredi {
79992a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
80092a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
80192a8780eSMiklos Szeredi 	struct fuse_req *req;
80292a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
80392a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
80492a8780eSMiklos Szeredi 	ssize_t ret;
80592a8780eSMiklos Szeredi 
80692a8780eSMiklos Szeredi 	if (fc->no_getxattr)
80792a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
80892a8780eSMiklos Szeredi 
80992a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
81092a8780eSMiklos Szeredi 	if (!req)
8117c352bdfSMiklos Szeredi 		return -EINTR;
81292a8780eSMiklos Szeredi 
81392a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
81492a8780eSMiklos Szeredi 	inarg.size = size;
81592a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
81692a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
81792a8780eSMiklos Szeredi 	req->inode = inode;
81892a8780eSMiklos Szeredi 	req->in.numargs = 2;
81992a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
82092a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
82192a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
82292a8780eSMiklos Szeredi 	req->in.args[1].value = name;
82392a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
82492a8780eSMiklos Szeredi 	req->out.numargs = 1;
82592a8780eSMiklos Szeredi 	if (size) {
82692a8780eSMiklos Szeredi 		req->out.argvar = 1;
82792a8780eSMiklos Szeredi 		req->out.args[0].size = size;
82892a8780eSMiklos Szeredi 		req->out.args[0].value = value;
82992a8780eSMiklos Szeredi 	} else {
83092a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
83192a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
83292a8780eSMiklos Szeredi 	}
83392a8780eSMiklos Szeredi 	request_send(fc, req);
83492a8780eSMiklos Szeredi 	ret = req->out.h.error;
83592a8780eSMiklos Szeredi 	if (!ret)
83692a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
83792a8780eSMiklos Szeredi 	else {
83892a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
83992a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
84092a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
84192a8780eSMiklos Szeredi 		}
84292a8780eSMiklos Szeredi 	}
84392a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
84492a8780eSMiklos Szeredi 	return ret;
84592a8780eSMiklos Szeredi }
84692a8780eSMiklos Szeredi 
84792a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
84892a8780eSMiklos Szeredi {
84992a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
85092a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
85192a8780eSMiklos Szeredi 	struct fuse_req *req;
85292a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
85392a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
85492a8780eSMiklos Szeredi 	ssize_t ret;
85592a8780eSMiklos Szeredi 
85692a8780eSMiklos Szeredi 	if (fc->no_listxattr)
85792a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
85892a8780eSMiklos Szeredi 
85992a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
86092a8780eSMiklos Szeredi 	if (!req)
8617c352bdfSMiklos Szeredi 		return -EINTR;
86292a8780eSMiklos Szeredi 
86392a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
86492a8780eSMiklos Szeredi 	inarg.size = size;
86592a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
86692a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
86792a8780eSMiklos Szeredi 	req->inode = inode;
86892a8780eSMiklos Szeredi 	req->in.numargs = 1;
86992a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
87092a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
87192a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
87292a8780eSMiklos Szeredi 	req->out.numargs = 1;
87392a8780eSMiklos Szeredi 	if (size) {
87492a8780eSMiklos Szeredi 		req->out.argvar = 1;
87592a8780eSMiklos Szeredi 		req->out.args[0].size = size;
87692a8780eSMiklos Szeredi 		req->out.args[0].value = list;
87792a8780eSMiklos Szeredi 	} else {
87892a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
87992a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
88092a8780eSMiklos Szeredi 	}
88192a8780eSMiklos Szeredi 	request_send(fc, req);
88292a8780eSMiklos Szeredi 	ret = req->out.h.error;
88392a8780eSMiklos Szeredi 	if (!ret)
88492a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
88592a8780eSMiklos Szeredi 	else {
88692a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
88792a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
88892a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
88992a8780eSMiklos Szeredi 		}
89092a8780eSMiklos Szeredi 	}
89192a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
89292a8780eSMiklos Szeredi 	return ret;
89392a8780eSMiklos Szeredi }
89492a8780eSMiklos Szeredi 
89592a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
89692a8780eSMiklos Szeredi {
89792a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
89892a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
89992a8780eSMiklos Szeredi 	struct fuse_req *req;
90092a8780eSMiklos Szeredi 	int err;
90192a8780eSMiklos Szeredi 
90292a8780eSMiklos Szeredi 	if (fc->no_removexattr)
90392a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
90492a8780eSMiklos Szeredi 
90592a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
90692a8780eSMiklos Szeredi 	if (!req)
9077c352bdfSMiklos Szeredi 		return -EINTR;
90892a8780eSMiklos Szeredi 
90992a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
91092a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
91192a8780eSMiklos Szeredi 	req->inode = inode;
91292a8780eSMiklos Szeredi 	req->in.numargs = 1;
91392a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
91492a8780eSMiklos Szeredi 	req->in.args[0].value = name;
91592a8780eSMiklos Szeredi 	request_send(fc, req);
91692a8780eSMiklos Szeredi 	err = req->out.h.error;
91792a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
91892a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
91992a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
92092a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
92192a8780eSMiklos Szeredi 	}
92292a8780eSMiklos Szeredi 	return err;
92392a8780eSMiklos Szeredi }
92492a8780eSMiklos Szeredi 
925e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = {
926e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
9279e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
9289e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
9299e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
9309e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
9319e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
9329e6268dbSMiklos Szeredi 	.link		= fuse_link,
9339e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
9349e6268dbSMiklos Szeredi 	.create		= fuse_create,
9359e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
936e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
937e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
93892a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
93992a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
94092a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
94192a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
942e5e5558eSMiklos Szeredi };
943e5e5558eSMiklos Szeredi 
944e5e5558eSMiklos Szeredi static struct file_operations fuse_dir_operations = {
945b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
946e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
947e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
948e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
949e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
95082547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
951e5e5558eSMiklos Szeredi };
952e5e5558eSMiklos Szeredi 
953e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = {
9549e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
955e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
956e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
95792a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
95892a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
95992a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
96092a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
961e5e5558eSMiklos Szeredi };
962e5e5558eSMiklos Szeredi 
963e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = {
9649e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
965e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
966e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
967e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
968e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
96992a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
97092a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
97192a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
97292a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
973e5e5558eSMiklos Szeredi };
974e5e5558eSMiklos Szeredi 
975e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
976e5e5558eSMiklos Szeredi {
977e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
978e5e5558eSMiklos Szeredi }
979e5e5558eSMiklos Szeredi 
980e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
981e5e5558eSMiklos Szeredi {
982e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
983e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
984e5e5558eSMiklos Szeredi }
985e5e5558eSMiklos Szeredi 
986e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
987e5e5558eSMiklos Szeredi {
988e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
989e5e5558eSMiklos Szeredi }
990