xref: /openbmc/linux/fs/fuse/dir.c (revision 8254798199332966e2ab647380c990193af7e854)
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);
49e5e5558eSMiklos Szeredi 		struct fuse_req *req = fuse_get_request_nonint(fc);
50e5e5558eSMiklos Szeredi 		if (!req)
51e5e5558eSMiklos Szeredi 			return 0;
52e5e5558eSMiklos Szeredi 
53e5e5558eSMiklos Szeredi 		fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
54e5e5558eSMiklos Szeredi 		request_send_nonint(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)
94e5e5558eSMiklos Szeredi 		return -ERESTARTNOINTR;
95e5e5558eSMiklos Szeredi 
96e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
97e5e5558eSMiklos Szeredi 	request_send(fc, req);
98e5e5558eSMiklos Szeredi 	err = req->out.h.error;
99e5e5558eSMiklos Szeredi 	if (!err) {
100e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
1019e6268dbSMiklos Szeredi 				  &outarg.attr);
102e5e5558eSMiklos Szeredi 		if (!inode) {
1039e6268dbSMiklos Szeredi 			fuse_send_forget(fc, req, outarg.nodeid, 1);
104e5e5558eSMiklos Szeredi 			return -ENOMEM;
105e5e5558eSMiklos Szeredi 		}
106e5e5558eSMiklos Szeredi 	}
107e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
108e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
109e5e5558eSMiklos Szeredi 		return err;
110e5e5558eSMiklos Szeredi 
111e5e5558eSMiklos Szeredi 	if (inode) {
112e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
113e5e5558eSMiklos Szeredi 		entry->d_time =	time_to_jiffies(outarg.entry_valid,
114e5e5558eSMiklos Szeredi 						outarg.entry_valid_nsec);
115e5e5558eSMiklos Szeredi 		fi->i_time = time_to_jiffies(outarg.attr_valid,
116e5e5558eSMiklos Szeredi 					     outarg.attr_valid_nsec);
117e5e5558eSMiklos Szeredi 	}
118e5e5558eSMiklos Szeredi 
119e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
120e5e5558eSMiklos Szeredi 	*inodep = inode;
121e5e5558eSMiklos Szeredi 	return 0;
122e5e5558eSMiklos Szeredi }
123e5e5558eSMiklos Szeredi 
1249e6268dbSMiklos Szeredi void fuse_invalidate_attr(struct inode *inode)
1259e6268dbSMiklos Szeredi {
1269e6268dbSMiklos Szeredi 	get_fuse_inode(inode)->i_time = jiffies - 1;
1279e6268dbSMiklos Szeredi }
1289e6268dbSMiklos Szeredi 
1299e6268dbSMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry)
1309e6268dbSMiklos Szeredi {
1319e6268dbSMiklos Szeredi 	d_invalidate(entry);
1329e6268dbSMiklos Szeredi 	entry->d_time = jiffies - 1;
1339e6268dbSMiklos Szeredi }
1349e6268dbSMiklos Szeredi 
1359e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
1369e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
1379e6268dbSMiklos Szeredi 			    int mode)
1389e6268dbSMiklos Szeredi {
1399e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
1409e6268dbSMiklos Szeredi 	struct inode *inode;
1419e6268dbSMiklos Szeredi 	struct fuse_inode *fi;
1429e6268dbSMiklos Szeredi 	int err;
1439e6268dbSMiklos Szeredi 
1449e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
1459e6268dbSMiklos Szeredi 	req->inode = dir;
1469e6268dbSMiklos Szeredi 	req->out.numargs = 1;
1479e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
1489e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
1499e6268dbSMiklos Szeredi 	request_send(fc, req);
1509e6268dbSMiklos Szeredi 	err = req->out.h.error;
1519e6268dbSMiklos Szeredi 	if (err) {
1529e6268dbSMiklos Szeredi 		fuse_put_request(fc, req);
1539e6268dbSMiklos Szeredi 		return err;
1549e6268dbSMiklos Szeredi 	}
1559e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
1569e6268dbSMiklos Szeredi 			  &outarg.attr);
1579e6268dbSMiklos Szeredi 	if (!inode) {
1589e6268dbSMiklos Szeredi 		fuse_send_forget(fc, req, outarg.nodeid, 1);
1599e6268dbSMiklos Szeredi 		return -ENOMEM;
1609e6268dbSMiklos Szeredi 	}
1619e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
1629e6268dbSMiklos Szeredi 
1639e6268dbSMiklos Szeredi 	/* Don't allow userspace to do really stupid things... */
1649e6268dbSMiklos Szeredi 	if ((inode->i_mode ^ mode) & S_IFMT) {
1659e6268dbSMiklos Szeredi 		iput(inode);
1669e6268dbSMiklos Szeredi 		return -EIO;
1679e6268dbSMiklos Szeredi 	}
1689e6268dbSMiklos Szeredi 
1699e6268dbSMiklos Szeredi 	entry->d_time = time_to_jiffies(outarg.entry_valid,
1709e6268dbSMiklos Szeredi 					outarg.entry_valid_nsec);
1719e6268dbSMiklos Szeredi 
1729e6268dbSMiklos Szeredi 	fi = get_fuse_inode(inode);
1739e6268dbSMiklos Szeredi 	fi->i_time = time_to_jiffies(outarg.attr_valid,
1749e6268dbSMiklos Szeredi 				     outarg.attr_valid_nsec);
1759e6268dbSMiklos Szeredi 
1769e6268dbSMiklos Szeredi 	d_instantiate(entry, inode);
1779e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
1789e6268dbSMiklos Szeredi 	return 0;
1799e6268dbSMiklos Szeredi }
1809e6268dbSMiklos Szeredi 
1819e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
1829e6268dbSMiklos Szeredi 		      dev_t rdev)
1839e6268dbSMiklos Szeredi {
1849e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
1859e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
1869e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
1879e6268dbSMiklos Szeredi 	if (!req)
1889e6268dbSMiklos Szeredi 		return -ERESTARTNOINTR;
1899e6268dbSMiklos Szeredi 
1909e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
1919e6268dbSMiklos Szeredi 	inarg.mode = mode;
1929e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
1939e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
1949e6268dbSMiklos Szeredi 	req->in.numargs = 2;
1959e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
1969e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
1979e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
1989e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
1999e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
2009e6268dbSMiklos Szeredi }
2019e6268dbSMiklos Szeredi 
2029e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
2039e6268dbSMiklos Szeredi 		       struct nameidata *nd)
2049e6268dbSMiklos Szeredi {
2059e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
2069e6268dbSMiklos Szeredi }
2079e6268dbSMiklos Szeredi 
2089e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
2099e6268dbSMiklos Szeredi {
2109e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
2119e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2129e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
2139e6268dbSMiklos Szeredi 	if (!req)
2149e6268dbSMiklos Szeredi 		return -ERESTARTNOINTR;
2159e6268dbSMiklos Szeredi 
2169e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
2179e6268dbSMiklos Szeredi 	inarg.mode = mode;
2189e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
2199e6268dbSMiklos Szeredi 	req->in.numargs = 2;
2209e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
2219e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
2229e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
2239e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
2249e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
2259e6268dbSMiklos Szeredi }
2269e6268dbSMiklos Szeredi 
2279e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
2289e6268dbSMiklos Szeredi 			const char *link)
2299e6268dbSMiklos Szeredi {
2309e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2319e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
2329e6268dbSMiklos Szeredi 	struct fuse_req *req;
2339e6268dbSMiklos Szeredi 
2349e6268dbSMiklos Szeredi 	if (len > FUSE_SYMLINK_MAX)
2359e6268dbSMiklos Szeredi 		return -ENAMETOOLONG;
2369e6268dbSMiklos Szeredi 
2379e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
2389e6268dbSMiklos Szeredi 	if (!req)
2399e6268dbSMiklos Szeredi 		return -ERESTARTNOINTR;
2409e6268dbSMiklos Szeredi 
2419e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SYMLINK;
2429e6268dbSMiklos Szeredi 	req->in.numargs = 2;
2439e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
2449e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
2459e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
2469e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
2479e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
2489e6268dbSMiklos Szeredi }
2499e6268dbSMiklos Szeredi 
2509e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
2519e6268dbSMiklos Szeredi {
2529e6268dbSMiklos Szeredi 	int err;
2539e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2549e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
2559e6268dbSMiklos Szeredi 	if (!req)
2569e6268dbSMiklos Szeredi 		return -ERESTARTNOINTR;
2579e6268dbSMiklos Szeredi 
2589e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
2599e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
2609e6268dbSMiklos Szeredi 	req->inode = dir;
2619e6268dbSMiklos Szeredi 	req->in.numargs = 1;
2629e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
2639e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
2649e6268dbSMiklos Szeredi 	request_send(fc, req);
2659e6268dbSMiklos Szeredi 	err = req->out.h.error;
2669e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
2679e6268dbSMiklos Szeredi 	if (!err) {
2689e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
2699e6268dbSMiklos Szeredi 
2709e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
2719e6268dbSMiklos Szeredi                    the inode does have more links this will be
2729e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
2739e6268dbSMiklos Szeredi 		inode->i_nlink = 0;
2749e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
2759e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
2769e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
2779e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
2789e6268dbSMiklos Szeredi 	return err;
2799e6268dbSMiklos Szeredi }
2809e6268dbSMiklos Szeredi 
2819e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
2829e6268dbSMiklos Szeredi {
2839e6268dbSMiklos Szeredi 	int err;
2849e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2859e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
2869e6268dbSMiklos Szeredi 	if (!req)
2879e6268dbSMiklos Szeredi 		return -ERESTARTNOINTR;
2889e6268dbSMiklos Szeredi 
2899e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
2909e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
2919e6268dbSMiklos Szeredi 	req->inode = dir;
2929e6268dbSMiklos Szeredi 	req->in.numargs = 1;
2939e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
2949e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
2959e6268dbSMiklos Szeredi 	request_send(fc, req);
2969e6268dbSMiklos Szeredi 	err = req->out.h.error;
2979e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
2989e6268dbSMiklos Szeredi 	if (!err) {
2999e6268dbSMiklos Szeredi 		entry->d_inode->i_nlink = 0;
3009e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
3019e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
3029e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
3039e6268dbSMiklos Szeredi 	return err;
3049e6268dbSMiklos Szeredi }
3059e6268dbSMiklos Szeredi 
3069e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
3079e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
3089e6268dbSMiklos Szeredi {
3099e6268dbSMiklos Szeredi 	int err;
3109e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
3119e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
3129e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3139e6268dbSMiklos Szeredi 	if (!req)
3149e6268dbSMiklos Szeredi 		return -ERESTARTNOINTR;
3159e6268dbSMiklos Szeredi 
3169e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3179e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
3189e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
3199e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
3209e6268dbSMiklos Szeredi 	req->inode = olddir;
3219e6268dbSMiklos Szeredi 	req->inode2 = newdir;
3229e6268dbSMiklos Szeredi 	req->in.numargs = 3;
3239e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3249e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3259e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
3269e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
3279e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
3289e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
3299e6268dbSMiklos Szeredi 	request_send(fc, req);
3309e6268dbSMiklos Szeredi 	err = req->out.h.error;
3319e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
3329e6268dbSMiklos Szeredi 	if (!err) {
3339e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
3349e6268dbSMiklos Szeredi 		if (olddir != newdir)
3359e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
3369e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
3379e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
3389e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
3399e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
3409e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
3419e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
3429e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
3439e6268dbSMiklos Szeredi 		if (newent->d_inode)
3449e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
3459e6268dbSMiklos Szeredi 	}
3469e6268dbSMiklos Szeredi 
3479e6268dbSMiklos Szeredi 	return err;
3489e6268dbSMiklos Szeredi }
3499e6268dbSMiklos Szeredi 
3509e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
3519e6268dbSMiklos Szeredi 		     struct dentry *newent)
3529e6268dbSMiklos Szeredi {
3539e6268dbSMiklos Szeredi 	int err;
3549e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
3559e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
3569e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
3579e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3589e6268dbSMiklos Szeredi 	if (!req)
3599e6268dbSMiklos Szeredi 		return -ERESTARTNOINTR;
3609e6268dbSMiklos Szeredi 
3619e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3629e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
3639e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
3649e6268dbSMiklos Szeredi 	req->inode2 = inode;
3659e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3669e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3679e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3689e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
3699e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
3709e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
3719e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
3729e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
3739e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
3749e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
3759e6268dbSMiklos Szeredi 	   etc.)
3769e6268dbSMiklos Szeredi 	*/
3779e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
3789e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
3799e6268dbSMiklos Szeredi 	return err;
3809e6268dbSMiklos Szeredi }
3819e6268dbSMiklos Szeredi 
382e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode)
383e5e5558eSMiklos Szeredi {
384e5e5558eSMiklos Szeredi 	int err;
385e5e5558eSMiklos Szeredi 	struct fuse_attr_out arg;
386e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
387e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
388e5e5558eSMiklos Szeredi 	if (!req)
389e5e5558eSMiklos Szeredi 		return -ERESTARTNOINTR;
390e5e5558eSMiklos Szeredi 
391e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
392e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
393e5e5558eSMiklos Szeredi 	req->inode = inode;
394e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
395e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(arg);
396e5e5558eSMiklos Szeredi 	req->out.args[0].value = &arg;
397e5e5558eSMiklos Szeredi 	request_send(fc, req);
398e5e5558eSMiklos Szeredi 	err = req->out.h.error;
399e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
400e5e5558eSMiklos Szeredi 	if (!err) {
401e5e5558eSMiklos Szeredi 		if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
402e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
403e5e5558eSMiklos Szeredi 			err = -EIO;
404e5e5558eSMiklos Szeredi 		} else {
405e5e5558eSMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
406e5e5558eSMiklos Szeredi 			fuse_change_attributes(inode, &arg.attr);
407e5e5558eSMiklos Szeredi 			fi->i_time = time_to_jiffies(arg.attr_valid,
408e5e5558eSMiklos Szeredi 						     arg.attr_valid_nsec);
409e5e5558eSMiklos Szeredi 		}
410e5e5558eSMiklos Szeredi 	}
411e5e5558eSMiklos Szeredi 	return err;
412e5e5558eSMiklos Szeredi }
413e5e5558eSMiklos Szeredi 
41487729a55SMiklos Szeredi /*
41587729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
41687729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
41787729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
41887729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
41987729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
42087729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
42187729a55SMiklos Szeredi  * DoS against the requester.
42287729a55SMiklos Szeredi  *
42387729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
42487729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
42587729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
42687729a55SMiklos Szeredi  */
42787729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
42887729a55SMiklos Szeredi {
42987729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
43087729a55SMiklos Szeredi 		return 1;
43187729a55SMiklos Szeredi 
43287729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
43387729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
43487729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
43587729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
43687729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
43787729a55SMiklos Szeredi 	    task->gid == fc->group_id)
43887729a55SMiklos Szeredi 		return 1;
43987729a55SMiklos Szeredi 
44087729a55SMiklos Szeredi 	return 0;
44187729a55SMiklos Szeredi }
44287729a55SMiklos Szeredi 
443e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry)
444e5e5558eSMiklos Szeredi {
445e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
446e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
447e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
448e5e5558eSMiklos Szeredi 
44987729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
450e5e5558eSMiklos Szeredi 		return -EACCES;
45187729a55SMiklos Szeredi 	if (get_node_id(inode) != FUSE_ROOT_ID &&
45287729a55SMiklos Szeredi 	    time_before_eq(jiffies, fi->i_time))
453e5e5558eSMiklos Szeredi 		return 0;
454e5e5558eSMiklos Szeredi 
455e5e5558eSMiklos Szeredi 	return fuse_do_getattr(inode);
456e5e5558eSMiklos Szeredi }
457e5e5558eSMiklos Szeredi 
458e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
459e5e5558eSMiklos Szeredi {
460e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
461e5e5558eSMiklos Szeredi 
46287729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
463e5e5558eSMiklos Szeredi 		return -EACCES;
4641e9a4ed9SMiklos Szeredi 	else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
4651e9a4ed9SMiklos Szeredi 		int err = generic_permission(inode, mask, NULL);
4661e9a4ed9SMiklos Szeredi 
4671e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
4681e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
4691e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
4701e9a4ed9SMiklos Szeredi 		if (err == -EACCES) {
4711e9a4ed9SMiklos Szeredi 		 	err = fuse_do_getattr(inode);
4721e9a4ed9SMiklos Szeredi 			if (!err)
4731e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
4741e9a4ed9SMiklos Szeredi 		}
4751e9a4ed9SMiklos Szeredi 
4761e9a4ed9SMiklos Szeredi 		/* FIXME: Need some mechanism to revoke permissions:
4771e9a4ed9SMiklos Szeredi 		   currently if the filesystem suddenly changes the
4781e9a4ed9SMiklos Szeredi 		   file mode, we will not be informed about it, and
4791e9a4ed9SMiklos Szeredi 		   continue to allow access to the file/directory.
4801e9a4ed9SMiklos Szeredi 
4811e9a4ed9SMiklos Szeredi 		   This is actually not so grave, since the user can
4821e9a4ed9SMiklos Szeredi 		   simply keep access to the file/directory anyway by
4831e9a4ed9SMiklos Szeredi 		   keeping it open... */
4841e9a4ed9SMiklos Szeredi 
4851e9a4ed9SMiklos Szeredi 		return err;
4861e9a4ed9SMiklos Szeredi 	} else {
487e5e5558eSMiklos Szeredi 		int mode = inode->i_mode;
488e5e5558eSMiklos Szeredi 		if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
489e5e5558eSMiklos Szeredi                     (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
490e5e5558eSMiklos Szeredi                         return -EROFS;
491e5e5558eSMiklos Szeredi 		if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
492e5e5558eSMiklos Szeredi 			return -EACCES;
493e5e5558eSMiklos Szeredi 		return 0;
494e5e5558eSMiklos Szeredi 	}
495e5e5558eSMiklos Szeredi }
496e5e5558eSMiklos Szeredi 
497e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
498e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
499e5e5558eSMiklos Szeredi {
500e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
501e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
502e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
503e5e5558eSMiklos Szeredi 		int over;
504e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
505e5e5558eSMiklos Szeredi 			return -EIO;
506e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
507e5e5558eSMiklos Szeredi 			break;
508e5e5558eSMiklos Szeredi 
509e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
510e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
511e5e5558eSMiklos Szeredi 		if (over)
512e5e5558eSMiklos Szeredi 			break;
513e5e5558eSMiklos Szeredi 
514e5e5558eSMiklos Szeredi 		buf += reclen;
515e5e5558eSMiklos Szeredi 		nbytes -= reclen;
516e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
517e5e5558eSMiklos Szeredi 	}
518e5e5558eSMiklos Szeredi 
519e5e5558eSMiklos Szeredi 	return 0;
520e5e5558eSMiklos Szeredi }
521e5e5558eSMiklos Szeredi 
52204730fefSMiklos Szeredi static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
52304730fefSMiklos Szeredi 				       struct inode *inode, loff_t pos,
52404730fefSMiklos Szeredi 				       size_t count)
525e5e5558eSMiklos Szeredi {
52604730fefSMiklos Szeredi 	return fuse_send_read_common(req, file, inode, pos, count, 1);
527e5e5558eSMiklos Szeredi }
528e5e5558eSMiklos Szeredi 
529e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
530e5e5558eSMiklos Szeredi {
53104730fefSMiklos Szeredi 	int err;
53204730fefSMiklos Szeredi 	size_t nbytes;
53304730fefSMiklos Szeredi 	struct page *page;
53404730fefSMiklos Szeredi 	struct inode *inode = file->f_dentry->d_inode;
53504730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
53604730fefSMiklos Szeredi 	struct fuse_req *req = fuse_get_request_nonint(fc);
53704730fefSMiklos Szeredi 	if (!req)
53804730fefSMiklos Szeredi 		return -EINTR;
539e5e5558eSMiklos Szeredi 
54004730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
54104730fefSMiklos Szeredi 	if (!page) {
54204730fefSMiklos Szeredi 		fuse_put_request(fc, req);
543e5e5558eSMiklos Szeredi 		return -ENOMEM;
54404730fefSMiklos Szeredi 	}
54504730fefSMiklos Szeredi 	req->num_pages = 1;
54604730fefSMiklos Szeredi 	req->pages[0] = page;
54704730fefSMiklos Szeredi 	nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
54804730fefSMiklos Szeredi 	err = req->out.h.error;
54904730fefSMiklos Szeredi 	fuse_put_request(fc, req);
55004730fefSMiklos Szeredi 	if (!err)
55104730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
55204730fefSMiklos Szeredi 				    filldir);
553e5e5558eSMiklos Szeredi 
55404730fefSMiklos Szeredi 	__free_page(page);
555b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
55604730fefSMiklos Szeredi 	return err;
557e5e5558eSMiklos Szeredi }
558e5e5558eSMiklos Szeredi 
559e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
560e5e5558eSMiklos Szeredi {
561e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
562e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
563e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
564e5e5558eSMiklos Szeredi 	char *link;
565e5e5558eSMiklos Szeredi 
566e5e5558eSMiklos Szeredi 	if (!req)
567e5e5558eSMiklos Szeredi 		return ERR_PTR(-ERESTARTNOINTR);
568e5e5558eSMiklos Szeredi 
569e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
570e5e5558eSMiklos Szeredi 	if (!link) {
571e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
572e5e5558eSMiklos Szeredi 		goto out;
573e5e5558eSMiklos Szeredi 	}
574e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
575e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
576e5e5558eSMiklos Szeredi 	req->inode = inode;
577e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
578e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
579e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
580e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
581e5e5558eSMiklos Szeredi 	request_send(fc, req);
582e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
583e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
584e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
585e5e5558eSMiklos Szeredi 	} else
586e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
587e5e5558eSMiklos Szeredi  out:
588e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
589b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
590e5e5558eSMiklos Szeredi 	return link;
591e5e5558eSMiklos Szeredi }
592e5e5558eSMiklos Szeredi 
593e5e5558eSMiklos Szeredi static void free_link(char *link)
594e5e5558eSMiklos Szeredi {
595e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
596e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
597e5e5558eSMiklos Szeredi }
598e5e5558eSMiklos Szeredi 
599e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
600e5e5558eSMiklos Szeredi {
601e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
602e5e5558eSMiklos Szeredi 	return NULL;
603e5e5558eSMiklos Szeredi }
604e5e5558eSMiklos Szeredi 
605e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
606e5e5558eSMiklos Szeredi {
607e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
608e5e5558eSMiklos Szeredi }
609e5e5558eSMiklos Szeredi 
610e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
611e5e5558eSMiklos Szeredi {
61204730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
613e5e5558eSMiklos Szeredi }
614e5e5558eSMiklos Szeredi 
615e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
616e5e5558eSMiklos Szeredi {
61704730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
618e5e5558eSMiklos Szeredi }
619e5e5558eSMiklos Szeredi 
620*82547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
621*82547981SMiklos Szeredi {
622*82547981SMiklos Szeredi 	/* nfsd can call this with no file */
623*82547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
624*82547981SMiklos Szeredi }
625*82547981SMiklos Szeredi 
6269e6268dbSMiklos Szeredi static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
6279e6268dbSMiklos Szeredi {
6289e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
6299e6268dbSMiklos Szeredi 	unsigned fvalid = 0;
6309e6268dbSMiklos Szeredi 
6319e6268dbSMiklos Szeredi 	memset(fattr, 0, sizeof(*fattr));
6329e6268dbSMiklos Szeredi 
6339e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
6349e6268dbSMiklos Szeredi 		fvalid |= FATTR_MODE,   fattr->mode = iattr->ia_mode;
6359e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
6369e6268dbSMiklos Szeredi 		fvalid |= FATTR_UID,    fattr->uid = iattr->ia_uid;
6379e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
6389e6268dbSMiklos Szeredi 		fvalid |= FATTR_GID,    fattr->gid = iattr->ia_gid;
6399e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
6409e6268dbSMiklos Szeredi 		fvalid |= FATTR_SIZE,   fattr->size = iattr->ia_size;
6419e6268dbSMiklos Szeredi 	/* You can only _set_ these together (they may change by themselves) */
6429e6268dbSMiklos Szeredi 	if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
6439e6268dbSMiklos Szeredi 		fvalid |= FATTR_ATIME | FATTR_MTIME;
6449e6268dbSMiklos Szeredi 		fattr->atime = iattr->ia_atime.tv_sec;
6459e6268dbSMiklos Szeredi 		fattr->mtime = iattr->ia_mtime.tv_sec;
6469e6268dbSMiklos Szeredi 	}
6479e6268dbSMiklos Szeredi 
6489e6268dbSMiklos Szeredi 	return fvalid;
6499e6268dbSMiklos Szeredi }
6509e6268dbSMiklos Szeredi 
6519e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
6529e6268dbSMiklos Szeredi {
6539e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
6549e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
6559e6268dbSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
6569e6268dbSMiklos Szeredi 	struct fuse_req *req;
6579e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
6589e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
6599e6268dbSMiklos Szeredi 	int err;
6609e6268dbSMiklos Szeredi 	int is_truncate = 0;
6619e6268dbSMiklos Szeredi 
6621e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
6631e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
6641e9a4ed9SMiklos Szeredi 		if (err)
6651e9a4ed9SMiklos Szeredi 			return err;
6661e9a4ed9SMiklos Szeredi 	}
6671e9a4ed9SMiklos Szeredi 
6689e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
6699e6268dbSMiklos Szeredi 		unsigned long limit;
6709e6268dbSMiklos Szeredi 		is_truncate = 1;
6719e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
6729e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
6739e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
6749e6268dbSMiklos Szeredi 			return -EFBIG;
6759e6268dbSMiklos Szeredi 		}
6769e6268dbSMiklos Szeredi 	}
6779e6268dbSMiklos Szeredi 
6789e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
6799e6268dbSMiklos Szeredi 	if (!req)
6809e6268dbSMiklos Szeredi 		return -ERESTARTNOINTR;
6819e6268dbSMiklos Szeredi 
6829e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
6839e6268dbSMiklos Szeredi 	inarg.valid = iattr_to_fattr(attr, &inarg.attr);
6849e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
6859e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
6869e6268dbSMiklos Szeredi 	req->inode = inode;
6879e6268dbSMiklos Szeredi 	req->in.numargs = 1;
6889e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
6899e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
6909e6268dbSMiklos Szeredi 	req->out.numargs = 1;
6919e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
6929e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
6939e6268dbSMiklos Szeredi 	request_send(fc, req);
6949e6268dbSMiklos Szeredi 	err = req->out.h.error;
6959e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
6969e6268dbSMiklos Szeredi 	if (!err) {
6979e6268dbSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
6989e6268dbSMiklos Szeredi 			make_bad_inode(inode);
6999e6268dbSMiklos Szeredi 			err = -EIO;
7009e6268dbSMiklos Szeredi 		} else {
7019e6268dbSMiklos Szeredi 			if (is_truncate) {
7029e6268dbSMiklos Szeredi 				loff_t origsize = i_size_read(inode);
7039e6268dbSMiklos Szeredi 				i_size_write(inode, outarg.attr.size);
7049e6268dbSMiklos Szeredi 				if (origsize > outarg.attr.size)
7059e6268dbSMiklos Szeredi 					vmtruncate(inode, outarg.attr.size);
7069e6268dbSMiklos Szeredi 			}
7079e6268dbSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr);
7089e6268dbSMiklos Szeredi 			fi->i_time = time_to_jiffies(outarg.attr_valid,
7099e6268dbSMiklos Szeredi 						     outarg.attr_valid_nsec);
7109e6268dbSMiklos Szeredi 		}
7119e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
7129e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
7139e6268dbSMiklos Szeredi 
7149e6268dbSMiklos Szeredi 	return err;
7159e6268dbSMiklos Szeredi }
7169e6268dbSMiklos Szeredi 
717e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
718e5e5558eSMiklos Szeredi 			struct kstat *stat)
719e5e5558eSMiklos Szeredi {
720e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
721e5e5558eSMiklos Szeredi 	int err = fuse_revalidate(entry);
722e5e5558eSMiklos Szeredi 	if (!err)
723e5e5558eSMiklos Szeredi 		generic_fillattr(inode, stat);
724e5e5558eSMiklos Szeredi 
725e5e5558eSMiklos Szeredi 	return err;
726e5e5558eSMiklos Szeredi }
727e5e5558eSMiklos Szeredi 
728e5e5558eSMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
729e5e5558eSMiklos Szeredi 				  struct nameidata *nd)
730e5e5558eSMiklos Szeredi {
731e5e5558eSMiklos Szeredi 	struct inode *inode;
732e5e5558eSMiklos Szeredi 	int err = fuse_lookup_iget(dir, entry, &inode);
733e5e5558eSMiklos Szeredi 	if (err)
734e5e5558eSMiklos Szeredi 		return ERR_PTR(err);
735e5e5558eSMiklos Szeredi 	if (inode && S_ISDIR(inode->i_mode)) {
736e5e5558eSMiklos Szeredi 		/* Don't allow creating an alias to a directory  */
737e5e5558eSMiklos Szeredi 		struct dentry *alias = d_find_alias(inode);
738e5e5558eSMiklos Szeredi 		if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
739e5e5558eSMiklos Szeredi 			dput(alias);
740e5e5558eSMiklos Szeredi 			iput(inode);
741e5e5558eSMiklos Szeredi 			return ERR_PTR(-EIO);
742e5e5558eSMiklos Szeredi 		}
743e5e5558eSMiklos Szeredi 	}
744e5e5558eSMiklos Szeredi 	return d_splice_alias(inode, entry);
745e5e5558eSMiklos Szeredi }
746e5e5558eSMiklos Szeredi 
74792a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
74892a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
74992a8780eSMiklos Szeredi {
75092a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
75192a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
75292a8780eSMiklos Szeredi 	struct fuse_req *req;
75392a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
75492a8780eSMiklos Szeredi 	int err;
75592a8780eSMiklos Szeredi 
75692a8780eSMiklos Szeredi 	if (size > FUSE_XATTR_SIZE_MAX)
75792a8780eSMiklos Szeredi 		return -E2BIG;
75892a8780eSMiklos Szeredi 
75992a8780eSMiklos Szeredi 	if (fc->no_setxattr)
76092a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
76192a8780eSMiklos Szeredi 
76292a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
76392a8780eSMiklos Szeredi 	if (!req)
76492a8780eSMiklos Szeredi 		return -ERESTARTNOINTR;
76592a8780eSMiklos Szeredi 
76692a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
76792a8780eSMiklos Szeredi 	inarg.size = size;
76892a8780eSMiklos Szeredi 	inarg.flags = flags;
76992a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
77092a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
77192a8780eSMiklos Szeredi 	req->inode = inode;
77292a8780eSMiklos Szeredi 	req->in.numargs = 3;
77392a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
77492a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
77592a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
77692a8780eSMiklos Szeredi 	req->in.args[1].value = name;
77792a8780eSMiklos Szeredi 	req->in.args[2].size = size;
77892a8780eSMiklos Szeredi 	req->in.args[2].value = value;
77992a8780eSMiklos Szeredi 	request_send(fc, req);
78092a8780eSMiklos Szeredi 	err = req->out.h.error;
78192a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
78292a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
78392a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
78492a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
78592a8780eSMiklos Szeredi 	}
78692a8780eSMiklos Szeredi 	return err;
78792a8780eSMiklos Szeredi }
78892a8780eSMiklos Szeredi 
78992a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
79092a8780eSMiklos Szeredi 			     void *value, size_t size)
79192a8780eSMiklos Szeredi {
79292a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
79392a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
79492a8780eSMiklos Szeredi 	struct fuse_req *req;
79592a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
79692a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
79792a8780eSMiklos Szeredi 	ssize_t ret;
79892a8780eSMiklos Szeredi 
79992a8780eSMiklos Szeredi 	if (fc->no_getxattr)
80092a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
80192a8780eSMiklos Szeredi 
80292a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
80392a8780eSMiklos Szeredi 	if (!req)
80492a8780eSMiklos Szeredi 		return -ERESTARTNOINTR;
80592a8780eSMiklos Szeredi 
80692a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
80792a8780eSMiklos Szeredi 	inarg.size = size;
80892a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
80992a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
81092a8780eSMiklos Szeredi 	req->inode = inode;
81192a8780eSMiklos Szeredi 	req->in.numargs = 2;
81292a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
81392a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
81492a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
81592a8780eSMiklos Szeredi 	req->in.args[1].value = name;
81692a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
81792a8780eSMiklos Szeredi 	req->out.numargs = 1;
81892a8780eSMiklos Szeredi 	if (size) {
81992a8780eSMiklos Szeredi 		req->out.argvar = 1;
82092a8780eSMiklos Szeredi 		req->out.args[0].size = size;
82192a8780eSMiklos Szeredi 		req->out.args[0].value = value;
82292a8780eSMiklos Szeredi 	} else {
82392a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
82492a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
82592a8780eSMiklos Szeredi 	}
82692a8780eSMiklos Szeredi 	request_send(fc, req);
82792a8780eSMiklos Szeredi 	ret = req->out.h.error;
82892a8780eSMiklos Szeredi 	if (!ret)
82992a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
83092a8780eSMiklos Szeredi 	else {
83192a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
83292a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
83392a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
83492a8780eSMiklos Szeredi 		}
83592a8780eSMiklos Szeredi 	}
83692a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
83792a8780eSMiklos Szeredi 	return ret;
83892a8780eSMiklos Szeredi }
83992a8780eSMiklos Szeredi 
84092a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
84192a8780eSMiklos Szeredi {
84292a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
84392a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
84492a8780eSMiklos Szeredi 	struct fuse_req *req;
84592a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
84692a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
84792a8780eSMiklos Szeredi 	ssize_t ret;
84892a8780eSMiklos Szeredi 
84992a8780eSMiklos Szeredi 	if (fc->no_listxattr)
85092a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
85192a8780eSMiklos Szeredi 
85292a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
85392a8780eSMiklos Szeredi 	if (!req)
85492a8780eSMiklos Szeredi 		return -ERESTARTNOINTR;
85592a8780eSMiklos Szeredi 
85692a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
85792a8780eSMiklos Szeredi 	inarg.size = size;
85892a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
85992a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
86092a8780eSMiklos Szeredi 	req->inode = inode;
86192a8780eSMiklos Szeredi 	req->in.numargs = 1;
86292a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
86392a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
86492a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
86592a8780eSMiklos Szeredi 	req->out.numargs = 1;
86692a8780eSMiklos Szeredi 	if (size) {
86792a8780eSMiklos Szeredi 		req->out.argvar = 1;
86892a8780eSMiklos Szeredi 		req->out.args[0].size = size;
86992a8780eSMiklos Szeredi 		req->out.args[0].value = list;
87092a8780eSMiklos Szeredi 	} else {
87192a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
87292a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
87392a8780eSMiklos Szeredi 	}
87492a8780eSMiklos Szeredi 	request_send(fc, req);
87592a8780eSMiklos Szeredi 	ret = req->out.h.error;
87692a8780eSMiklos Szeredi 	if (!ret)
87792a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
87892a8780eSMiklos Szeredi 	else {
87992a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
88092a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
88192a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
88292a8780eSMiklos Szeredi 		}
88392a8780eSMiklos Szeredi 	}
88492a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
88592a8780eSMiklos Szeredi 	return ret;
88692a8780eSMiklos Szeredi }
88792a8780eSMiklos Szeredi 
88892a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
88992a8780eSMiklos Szeredi {
89092a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
89192a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
89292a8780eSMiklos Szeredi 	struct fuse_req *req;
89392a8780eSMiklos Szeredi 	int err;
89492a8780eSMiklos Szeredi 
89592a8780eSMiklos Szeredi 	if (fc->no_removexattr)
89692a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
89792a8780eSMiklos Szeredi 
89892a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
89992a8780eSMiklos Szeredi 	if (!req)
90092a8780eSMiklos Szeredi 		return -ERESTARTNOINTR;
90192a8780eSMiklos Szeredi 
90292a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
90392a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
90492a8780eSMiklos Szeredi 	req->inode = inode;
90592a8780eSMiklos Szeredi 	req->in.numargs = 1;
90692a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
90792a8780eSMiklos Szeredi 	req->in.args[0].value = name;
90892a8780eSMiklos Szeredi 	request_send(fc, req);
90992a8780eSMiklos Szeredi 	err = req->out.h.error;
91092a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
91192a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
91292a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
91392a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
91492a8780eSMiklos Szeredi 	}
91592a8780eSMiklos Szeredi 	return err;
91692a8780eSMiklos Szeredi }
91792a8780eSMiklos Szeredi 
918e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = {
919e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
9209e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
9219e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
9229e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
9239e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
9249e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
9259e6268dbSMiklos Szeredi 	.link		= fuse_link,
9269e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
9279e6268dbSMiklos Szeredi 	.create		= fuse_create,
9289e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
929e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
930e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
93192a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
93292a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
93392a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
93492a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
935e5e5558eSMiklos Szeredi };
936e5e5558eSMiklos Szeredi 
937e5e5558eSMiklos Szeredi static struct file_operations fuse_dir_operations = {
938b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
939e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
940e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
941e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
942e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
943*82547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
944e5e5558eSMiklos Szeredi };
945e5e5558eSMiklos Szeredi 
946e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = {
9479e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
948e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
949e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
95092a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
95192a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
95292a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
95392a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
954e5e5558eSMiklos Szeredi };
955e5e5558eSMiklos Szeredi 
956e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = {
9579e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
958e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
959e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
960e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
961e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
96292a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
96392a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
96492a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
96592a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
966e5e5558eSMiklos Szeredi };
967e5e5558eSMiklos Szeredi 
968e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
969e5e5558eSMiklos Szeredi {
970e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
971e5e5558eSMiklos Szeredi }
972e5e5558eSMiklos Szeredi 
973e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
974e5e5558eSMiklos Szeredi {
975e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
976e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
977e5e5558eSMiklos Szeredi }
978e5e5558eSMiklos Szeredi 
979e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
980e5e5558eSMiklos Szeredi {
981e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
982e5e5558eSMiklos Szeredi }
983