Blame view

fs/fuse/dir.c 41.1 KB
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1
2
  /*
    FUSE: Filesystem in Userspace
1729a16c2   Miklos Szeredi   fuse: style fixes
3
    Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
4
5
6
7
8
9
10
11
12
  
    This program can be distributed under the terms of the GNU GPL.
    See the file COPYING.
  */
  
  #include "fuse_i.h"
  
  #include <linux/pagemap.h>
  #include <linux/file.h>
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
13
14
  #include <linux/sched.h>
  #include <linux/namei.h>
07e77dca8   Miklos Szeredi   fuse: separate qu...
15
  #include <linux/slab.h>
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
16

0a0898cf4   Miklos Szeredi   [PATCH] fuse: use...
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  #if BITS_PER_LONG >= 64
  static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
  {
  	entry->d_time = time;
  }
  
  static inline u64 fuse_dentry_time(struct dentry *entry)
  {
  	return entry->d_time;
  }
  #else
  /*
   * On 32 bit archs store the high 32 bits of time in d_fsdata
   */
  static void fuse_dentry_settime(struct dentry *entry, u64 time)
  {
  	entry->d_time = time;
  	entry->d_fsdata = (void *) (unsigned long) (time >> 32);
  }
  
  static u64 fuse_dentry_time(struct dentry *entry)
  {
  	return (u64) entry->d_time +
  		((u64) (unsigned long) entry->d_fsdata << 32);
  }
  #endif
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
43
44
45
46
47
48
49
50
51
  /*
   * FUSE caches dentries and attributes with separate timeout.  The
   * time in jiffies until the dentry/attributes are valid is stored in
   * dentry->d_time and fuse_inode->i_time respectively.
   */
  
  /*
   * Calculate the time in jiffies until a dentry/attributes are valid
   */
0a0898cf4   Miklos Szeredi   [PATCH] fuse: use...
52
  static u64 time_to_jiffies(unsigned long sec, unsigned long nsec)
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
53
  {
685d16ddb   Miklos Szeredi   [PATCH] fuse: fix...
54
55
  	if (sec || nsec) {
  		struct timespec ts = {sec, nsec};
0a0898cf4   Miklos Szeredi   [PATCH] fuse: use...
56
  		return get_jiffies_64() + timespec_to_jiffies(&ts);
685d16ddb   Miklos Szeredi   [PATCH] fuse: fix...
57
  	} else
0a0898cf4   Miklos Szeredi   [PATCH] fuse: use...
58
  		return 0;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
59
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
60
61
62
63
  /*
   * Set dentry and possibly attribute timeouts from the lookup/mk*
   * replies
   */
1fb69e781   Miklos Szeredi   fuse: fix race be...
64
65
  static void fuse_change_entry_timeout(struct dentry *entry,
  				      struct fuse_entry_out *o)
0aa7c6990   Miklos Szeredi   [PATCH] fuse: cle...
66
  {
0a0898cf4   Miklos Szeredi   [PATCH] fuse: use...
67
68
  	fuse_dentry_settime(entry,
  		time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
1fb69e781   Miklos Szeredi   fuse: fix race be...
69
70
71
72
73
74
75
76
77
78
  }
  
  static u64 attr_timeout(struct fuse_attr_out *o)
  {
  	return time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
  }
  
  static u64 entry_attr_timeout(struct fuse_entry_out *o)
  {
  	return time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
79
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
80
81
82
83
  /*
   * Mark the attributes as stale, so that at the next call to
   * ->getattr() they will be fetched from userspace
   */
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
84
85
  void fuse_invalidate_attr(struct inode *inode)
  {
0a0898cf4   Miklos Szeredi   [PATCH] fuse: use...
86
  	get_fuse_inode(inode)->i_time = 0;
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
87
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
88
89
90
91
92
93
94
95
  /*
   * Just mark the entry as stale, so that a next attempt to look it up
   * will result in a new lookup call to userspace
   *
   * This is called when a dentry is about to become negative and the
   * timeout is unknown (unlink, rmdir, rename and in some cases
   * lookup)
   */
dbd561d23   Miklos Szeredi   fuse: add export ...
96
  void fuse_invalidate_entry_cache(struct dentry *entry)
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
97
  {
0a0898cf4   Miklos Szeredi   [PATCH] fuse: use...
98
  	fuse_dentry_settime(entry, 0);
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
99
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
100
101
102
103
  /*
   * Same as fuse_invalidate_entry_cache(), but also try to remove the
   * dentry from the hash
   */
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
104
105
106
107
  static void fuse_invalidate_entry(struct dentry *entry)
  {
  	d_invalidate(entry);
  	fuse_invalidate_entry_cache(entry);
0aa7c6990   Miklos Szeredi   [PATCH] fuse: cle...
108
  }
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
109
110
  static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_req *req,
  			     u64 nodeid, struct qstr *name,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
111
112
  			     struct fuse_entry_out *outarg)
  {
0e9663ee4   Miklos Szeredi   fuse: add blksize...
113
  	memset(outarg, 0, sizeof(struct fuse_entry_out));
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
114
  	req->in.h.opcode = FUSE_LOOKUP;
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
115
  	req->in.h.nodeid = nodeid;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
116
  	req->in.numargs = 1;
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
117
118
  	req->in.args[0].size = name->len + 1;
  	req->in.args[0].value = name->name;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
119
  	req->out.numargs = 1;
0e9663ee4   Miklos Szeredi   fuse: add blksize...
120
121
122
123
  	if (fc->minor < 9)
  		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
  	else
  		req->out.args[0].size = sizeof(struct fuse_entry_out);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
124
125
  	req->out.args[0].value = outarg;
  }
5c5c5e51b   Miklos Szeredi   fuse: update file...
126
  u64 fuse_get_attr_version(struct fuse_conn *fc)
7dca9fd39   Miklos Szeredi   fuse: cleanup: ad...
127
128
129
130
131
132
133
134
135
136
137
138
139
  {
  	u64 curr_version;
  
  	/*
  	 * The spin lock isn't actually needed on 64bit archs, but we
  	 * don't yet care too much about such optimizations.
  	 */
  	spin_lock(&fc->lock);
  	curr_version = fc->attr_version;
  	spin_unlock(&fc->lock);
  
  	return curr_version;
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
140
141
142
143
144
145
146
147
148
  /*
   * Check whether the dentry is still valid
   *
   * If the entry validity timeout has expired and the dentry is
   * positive, try to redo the lookup.  If the lookup results in a
   * different inode, then let the VFS invalidate the dentry and redo
   * the lookup once more.  If the lookup results in the same inode,
   * then refresh the attributes, timeouts and mark the dentry valid.
   */
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
149
150
  static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
  {
34286d666   Nick Piggin   fs: rcu-walk awar...
151
  	struct inode *inode;
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
152

e7c0a1678   Miklos Szeredi   fuse: make fuse_d...
153
  	inode = ACCESS_ONCE(entry->d_inode);
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
154
  	if (inode && is_bad_inode(inode))
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
155
  		return 0;
0a0898cf4   Miklos Szeredi   [PATCH] fuse: use...
156
  	else if (fuse_dentry_time(entry) < get_jiffies_64()) {
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
157
  		int err;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
158
  		struct fuse_entry_out outarg;
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
159
160
  		struct fuse_conn *fc;
  		struct fuse_req *req;
07e77dca8   Miklos Szeredi   fuse: separate qu...
161
  		struct fuse_forget_link *forget;
e956edd05   Miklos Szeredi   [PATCH] fuse: fix...
162
  		struct dentry *parent;
1fb69e781   Miklos Szeredi   fuse: fix race be...
163
  		u64 attr_version;
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
164

50322fe7d   Miklos Szeredi   [PATCH] fuse: fix...
165
  		/* For negative dentries, always do a fresh lookup */
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
166
167
  		if (!inode)
  			return 0;
d24339059   Miklos Szeredi   fuse: fix oops in...
168
  		if (nd && (nd->flags & LOOKUP_RCU))
e7c0a1678   Miklos Szeredi   fuse: make fuse_d...
169
  			return -ECHILD;
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
170
  		fc = get_fuse_conn(inode);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
171
172
  		req = fuse_get_req(fc);
  		if (IS_ERR(req))
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
173
  			return 0;
07e77dca8   Miklos Szeredi   fuse: separate qu...
174
175
  		forget = fuse_alloc_forget();
  		if (!forget) {
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
176
177
178
  			fuse_put_request(fc, req);
  			return 0;
  		}
7dca9fd39   Miklos Szeredi   fuse: cleanup: ad...
179
  		attr_version = fuse_get_attr_version(fc);
1fb69e781   Miklos Szeredi   fuse: fix race be...
180

e956edd05   Miklos Szeredi   [PATCH] fuse: fix...
181
  		parent = dget_parent(entry);
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
182
183
  		fuse_lookup_init(fc, req, get_node_id(parent->d_inode),
  				 &entry->d_name, &outarg);
b93f858ab   Tejun Heo   fuse: add fuse_ p...
184
  		fuse_request_send(fc, req);
e956edd05   Miklos Szeredi   [PATCH] fuse: fix...
185
  		dput(parent);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
186
  		err = req->out.h.error;
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
187
  		fuse_put_request(fc, req);
50322fe7d   Miklos Szeredi   [PATCH] fuse: fix...
188
189
190
  		/* Zero nodeid is same as -ENOENT */
  		if (!err && !outarg.nodeid)
  			err = -ENOENT;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
191
  		if (!err) {
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
192
  			struct fuse_inode *fi = get_fuse_inode(inode);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
193
  			if (outarg.nodeid != get_node_id(inode)) {
07e77dca8   Miklos Szeredi   fuse: separate qu...
194
  				fuse_queue_forget(fc, forget, outarg.nodeid, 1);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
195
196
  				return 0;
  			}
8da5ff23c   Miklos Szeredi   [PATCH] fuse: loc...
197
  			spin_lock(&fc->lock);
1729a16c2   Miklos Szeredi   fuse: style fixes
198
  			fi->nlookup++;
8da5ff23c   Miklos Szeredi   [PATCH] fuse: loc...
199
  			spin_unlock(&fc->lock);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
200
  		}
07e77dca8   Miklos Szeredi   fuse: separate qu...
201
  		kfree(forget);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
202
  		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
203
  			return 0;
1fb69e781   Miklos Szeredi   fuse: fix race be...
204
205
206
207
  		fuse_change_attributes(inode, &outarg.attr,
  				       entry_attr_timeout(&outarg),
  				       attr_version);
  		fuse_change_entry_timeout(entry, &outarg);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
208
209
210
  	}
  	return 1;
  }
8bfc016d2   Miklos Szeredi   [PATCH] fuse: uni...
211
  static int invalid_nodeid(u64 nodeid)
2827d0b23   Miklos Szeredi   [PATCH] fuse: che...
212
213
214
  {
  	return !nodeid || nodeid == FUSE_ROOT_ID;
  }
4269590a7   Al Viro   constify dentry_o...
215
  const struct dentry_operations fuse_dentry_operations = {
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
216
217
  	.d_revalidate	= fuse_dentry_revalidate,
  };
a5bfffac6   Timo Savola   [PATCH] fuse: val...
218
  int fuse_valid_type(int m)
39ee059af   Miklos Szeredi   [PATCH] fuse: che...
219
220
221
222
  {
  	return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
  		S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
  }
d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
223
224
225
226
  /*
   * Add a directory inode to a dentry, ensuring that no other dentry
   * refers to this inode.  Called with fc->inst_mutex.
   */
0de6256da   Miklos Szeredi   fuse: prepare loo...
227
228
  static struct dentry *fuse_d_add_directory(struct dentry *entry,
  					   struct inode *inode)
d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
229
230
  {
  	struct dentry *alias = d_find_alias(inode);
0de6256da   Miklos Szeredi   fuse: prepare loo...
231
  	if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
232
233
234
235
  		/* This tries to shrink the subtree below alias */
  		fuse_invalidate_entry(alias);
  		dput(alias);
  		if (!list_empty(&inode->i_dentry))
0de6256da   Miklos Szeredi   fuse: prepare loo...
236
237
238
  			return ERR_PTR(-EBUSY);
  	} else {
  		dput(alias);
d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
239
  	}
0de6256da   Miklos Szeredi   fuse: prepare loo...
240
  	return d_splice_alias(inode, entry);
d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
241
  }
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
242
243
  int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
  		     struct fuse_entry_out *outarg, struct inode **inode)
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
244
  {
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
245
  	struct fuse_conn *fc = get_fuse_conn_super(sb);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
246
  	struct fuse_req *req;
07e77dca8   Miklos Szeredi   fuse: separate qu...
247
  	struct fuse_forget_link *forget;
1fb69e781   Miklos Szeredi   fuse: fix race be...
248
  	u64 attr_version;
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
249
  	int err;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
250

c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
251
252
253
254
  	*inode = NULL;
  	err = -ENAMETOOLONG;
  	if (name->len > FUSE_NAME_MAX)
  		goto out;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
255

ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
256
  	req = fuse_get_req(fc);
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
257
  	err = PTR_ERR(req);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
258
  	if (IS_ERR(req))
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
259
  		goto out;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
260

07e77dca8   Miklos Szeredi   fuse: separate qu...
261
262
263
  	forget = fuse_alloc_forget();
  	err = -ENOMEM;
  	if (!forget) {
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
264
  		fuse_put_request(fc, req);
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
265
  		goto out;
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
266
  	}
7dca9fd39   Miklos Szeredi   fuse: cleanup: ad...
267
  	attr_version = fuse_get_attr_version(fc);
1fb69e781   Miklos Szeredi   fuse: fix race be...
268

c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
269
  	fuse_lookup_init(fc, req, nodeid, name, outarg);
b93f858ab   Tejun Heo   fuse: add fuse_ p...
270
  	fuse_request_send(fc, req);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
271
  	err = req->out.h.error;
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
272
  	fuse_put_request(fc, req);
50322fe7d   Miklos Szeredi   [PATCH] fuse: fix...
273
  	/* Zero nodeid is same as -ENOENT, but with valid timeout */
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  	if (err || !outarg->nodeid)
  		goto out_put_forget;
  
  	err = -EIO;
  	if (!outarg->nodeid)
  		goto out_put_forget;
  	if (!fuse_valid_type(outarg->attr.mode))
  		goto out_put_forget;
  
  	*inode = fuse_iget(sb, outarg->nodeid, outarg->generation,
  			   &outarg->attr, entry_attr_timeout(outarg),
  			   attr_version);
  	err = -ENOMEM;
  	if (!*inode) {
07e77dca8   Miklos Szeredi   fuse: separate qu...
288
  		fuse_queue_forget(fc, forget, outarg->nodeid, 1);
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
289
  		goto out;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
290
  	}
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
291
292
293
  	err = 0;
  
   out_put_forget:
07e77dca8   Miklos Szeredi   fuse: separate qu...
294
  	kfree(forget);
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
   out:
  	return err;
  }
  
  static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
  				  struct nameidata *nd)
  {
  	int err;
  	struct fuse_entry_out outarg;
  	struct inode *inode;
  	struct dentry *newent;
  	struct fuse_conn *fc = get_fuse_conn(dir);
  	bool outarg_valid = true;
  
  	err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
  			       &outarg, &inode);
  	if (err == -ENOENT) {
  		outarg_valid = false;
  		err = 0;
  	}
  	if (err)
  		goto out_err;
  
  	err = -EIO;
  	if (inode && get_node_id(inode) == FUSE_ROOT_ID)
  		goto out_iput;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
321

d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
322
323
  	if (inode && S_ISDIR(inode->i_mode)) {
  		mutex_lock(&fc->inst_mutex);
0de6256da   Miklos Szeredi   fuse: prepare loo...
324
  		newent = fuse_d_add_directory(entry, inode);
d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
325
  		mutex_unlock(&fc->inst_mutex);
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
326
327
328
329
  		err = PTR_ERR(newent);
  		if (IS_ERR(newent))
  			goto out_iput;
  	} else {
0de6256da   Miklos Szeredi   fuse: prepare loo...
330
  		newent = d_splice_alias(inode, entry);
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
331
  	}
d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
332

0de6256da   Miklos Szeredi   fuse: prepare loo...
333
  	entry = newent ? newent : entry;
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
334
  	if (outarg_valid)
1fb69e781   Miklos Szeredi   fuse: fix race be...
335
  		fuse_change_entry_timeout(entry, &outarg);
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
336
337
  	else
  		fuse_invalidate_entry_cache(entry);
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
338

0de6256da   Miklos Szeredi   fuse: prepare loo...
339
  	return newent;
c180eebe1   Miklos Szeredi   fuse: add fuse_lo...
340
341
342
343
344
  
   out_iput:
  	iput(inode);
   out_err:
  	return ERR_PTR(err);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
345
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
346
347
348
349
350
351
  /*
   * Atomic create+open operation
   *
   * If the filesystem doesn't support this, then fall back to separate
   * 'mknod' + 'open' requests.
   */
541af6a07   Al Viro   fuse: propagate u...
352
353
  static int fuse_create_open(struct inode *dir, struct dentry *entry,
  			    umode_t mode, struct nameidata *nd)
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
354
355
356
357
358
  {
  	int err;
  	struct inode *inode;
  	struct fuse_conn *fc = get_fuse_conn(dir);
  	struct fuse_req *req;
07e77dca8   Miklos Szeredi   fuse: separate qu...
359
  	struct fuse_forget_link *forget;
e0a43ddcc   Miklos Szeredi   fuse: allow umask...
360
  	struct fuse_create_in inarg;
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
361
362
  	struct fuse_open_out outopen;
  	struct fuse_entry_out outentry;
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
363
364
  	struct fuse_file *ff;
  	struct file *file;
8a5e929dd   Al Viro   don't translitera...
365
  	int flags = nd->intent.open.flags;
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
366

fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
367
  	if (fc->no_create)
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
368
  		return -ENOSYS;
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
369

1b7323965   Csaba Henk   fuse: reject O_DI...
370
371
  	if (flags & O_DIRECT)
  		return -EINVAL;
07e77dca8   Miklos Szeredi   fuse: separate qu...
372
373
374
  	forget = fuse_alloc_forget();
  	if (!forget)
  		return -ENOMEM;
51eb01e73   Miklos Szeredi   [PATCH] fuse: no ...
375

ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
376
  	req = fuse_get_req(fc);
51eb01e73   Miklos Szeredi   [PATCH] fuse: no ...
377
  	err = PTR_ERR(req);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
378
  	if (IS_ERR(req))
51eb01e73   Miklos Szeredi   [PATCH] fuse: no ...
379
  		goto out_put_forget_req;
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
380

ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
381
  	err = -ENOMEM;
acf99433d   Tejun Heo   fuse: add file ke...
382
  	ff = fuse_file_alloc(fc);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
383
384
  	if (!ff)
  		goto out_put_request;
e0a43ddcc   Miklos Szeredi   fuse: allow umask...
385
386
  	if (!fc->dont_mask)
  		mode &= ~current_umask();
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
387
388
  	flags &= ~O_NOCTTY;
  	memset(&inarg, 0, sizeof(inarg));
0e9663ee4   Miklos Szeredi   fuse: add blksize...
389
  	memset(&outentry, 0, sizeof(outentry));
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
390
391
  	inarg.flags = flags;
  	inarg.mode = mode;
e0a43ddcc   Miklos Szeredi   fuse: allow umask...
392
  	inarg.umask = current_umask();
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
393
394
  	req->in.h.opcode = FUSE_CREATE;
  	req->in.h.nodeid = get_node_id(dir);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
395
  	req->in.numargs = 2;
e0a43ddcc   Miklos Szeredi   fuse: allow umask...
396
397
  	req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) :
  						sizeof(inarg);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
398
399
400
401
  	req->in.args[0].value = &inarg;
  	req->in.args[1].size = entry->d_name.len + 1;
  	req->in.args[1].value = entry->d_name.name;
  	req->out.numargs = 2;
0e9663ee4   Miklos Szeredi   fuse: add blksize...
402
403
404
405
  	if (fc->minor < 9)
  		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
  	else
  		req->out.args[0].size = sizeof(outentry);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
406
407
408
  	req->out.args[0].value = &outentry;
  	req->out.args[1].size = sizeof(outopen);
  	req->out.args[1].value = &outopen;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
409
  	fuse_request_send(fc, req);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
410
411
412
413
414
415
416
417
  	err = req->out.h.error;
  	if (err) {
  		if (err == -ENOSYS)
  			fc->no_create = 1;
  		goto out_free_ff;
  	}
  
  	err = -EIO;
2827d0b23   Miklos Szeredi   [PATCH] fuse: che...
418
  	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
419
  		goto out_free_ff;
51eb01e73   Miklos Szeredi   [PATCH] fuse: no ...
420
  	fuse_put_request(fc, req);
c7b7143c6   Miklos Szeredi   fuse: clean up ar...
421
422
423
  	ff->fh = outopen.fh;
  	ff->nodeid = outentry.nodeid;
  	ff->open_flags = outopen.open_flags;
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
424
  	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
1fb69e781   Miklos Szeredi   fuse: fix race be...
425
  			  &outentry.attr, entry_attr_timeout(&outentry), 0);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
426
427
  	if (!inode) {
  		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
8b0797a49   Miklos Szeredi   fuse: don't use i...
428
  		fuse_sync_release(ff, flags);
07e77dca8   Miklos Szeredi   fuse: separate qu...
429
  		fuse_queue_forget(fc, forget, outentry.nodeid, 1);
51eb01e73   Miklos Szeredi   [PATCH] fuse: no ...
430
  		return -ENOMEM;
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
431
  	}
07e77dca8   Miklos Szeredi   fuse: separate qu...
432
  	kfree(forget);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
433
  	d_instantiate(entry, inode);
1fb69e781   Miklos Szeredi   fuse: fix race be...
434
  	fuse_change_entry_timeout(entry, &outentry);
0952b2a4a   Miklos Szeredi   fuse: fix attribu...
435
  	fuse_invalidate_attr(dir);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
436
437
  	file = lookup_instantiate_filp(nd, entry, generic_file_open);
  	if (IS_ERR(file)) {
8b0797a49   Miklos Szeredi   fuse: don't use i...
438
  		fuse_sync_release(ff, flags);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
439
440
  		return PTR_ERR(file);
  	}
c7b7143c6   Miklos Szeredi   fuse: clean up ar...
441
442
  	file->private_data = fuse_file_get(ff);
  	fuse_finish_open(inode, file);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
443
444
445
446
447
448
  	return 0;
  
   out_free_ff:
  	fuse_file_free(ff);
   out_put_request:
  	fuse_put_request(fc, req);
51eb01e73   Miklos Szeredi   [PATCH] fuse: no ...
449
   out_put_forget_req:
07e77dca8   Miklos Szeredi   fuse: separate qu...
450
  	kfree(forget);
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
451
452
  	return err;
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
453
454
455
  /*
   * Code shared between mknod, mkdir, symlink and link
   */
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
456
457
  static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
  			    struct inode *dir, struct dentry *entry,
541af6a07   Al Viro   fuse: propagate u...
458
  			    umode_t mode)
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
459
460
461
  {
  	struct fuse_entry_out outarg;
  	struct inode *inode;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
462
  	int err;
07e77dca8   Miklos Szeredi   fuse: separate qu...
463
  	struct fuse_forget_link *forget;
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
464

07e77dca8   Miklos Szeredi   fuse: separate qu...
465
466
  	forget = fuse_alloc_forget();
  	if (!forget) {
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
467
  		fuse_put_request(fc, req);
07e77dca8   Miklos Szeredi   fuse: separate qu...
468
  		return -ENOMEM;
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
469
  	}
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
470

0e9663ee4   Miklos Szeredi   fuse: add blksize...
471
  	memset(&outarg, 0, sizeof(outarg));
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
472
  	req->in.h.nodeid = get_node_id(dir);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
473
  	req->out.numargs = 1;
0e9663ee4   Miklos Szeredi   fuse: add blksize...
474
475
476
477
  	if (fc->minor < 9)
  		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
  	else
  		req->out.args[0].size = sizeof(outarg);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
478
  	req->out.args[0].value = &outarg;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
479
  	fuse_request_send(fc, req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
480
  	err = req->out.h.error;
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
481
482
483
  	fuse_put_request(fc, req);
  	if (err)
  		goto out_put_forget_req;
39ee059af   Miklos Szeredi   [PATCH] fuse: che...
484
485
  	err = -EIO;
  	if (invalid_nodeid(outarg.nodeid))
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
486
  		goto out_put_forget_req;
39ee059af   Miklos Szeredi   [PATCH] fuse: che...
487
488
  
  	if ((outarg.attr.mode ^ mode) & S_IFMT)
2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
489
  		goto out_put_forget_req;
39ee059af   Miklos Szeredi   [PATCH] fuse: che...
490

9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
491
  	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
1fb69e781   Miklos Szeredi   fuse: fix race be...
492
  			  &outarg.attr, entry_attr_timeout(&outarg), 0);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
493
  	if (!inode) {
07e77dca8   Miklos Szeredi   fuse: separate qu...
494
  		fuse_queue_forget(fc, forget, outarg.nodeid, 1);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
495
496
  		return -ENOMEM;
  	}
07e77dca8   Miklos Szeredi   fuse: separate qu...
497
  	kfree(forget);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
498

d2a85164a   Miklos Szeredi   [PATCH] fuse: fix...
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  	if (S_ISDIR(inode->i_mode)) {
  		struct dentry *alias;
  		mutex_lock(&fc->inst_mutex);
  		alias = d_find_alias(inode);
  		if (alias) {
  			/* New directory must have moved since mkdir */
  			mutex_unlock(&fc->inst_mutex);
  			dput(alias);
  			iput(inode);
  			return -EBUSY;
  		}
  		d_instantiate(entry, inode);
  		mutex_unlock(&fc->inst_mutex);
  	} else
  		d_instantiate(entry, inode);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
514

1fb69e781   Miklos Szeredi   fuse: fix race be...
515
  	fuse_change_entry_timeout(entry, &outarg);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
516
517
  	fuse_invalidate_attr(dir);
  	return 0;
39ee059af   Miklos Szeredi   [PATCH] fuse: che...
518

2d51013ed   Miklos Szeredi   [PATCH] fuse: fix...
519
   out_put_forget_req:
07e77dca8   Miklos Szeredi   fuse: separate qu...
520
  	kfree(forget);
39ee059af   Miklos Szeredi   [PATCH] fuse: che...
521
  	return err;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
522
  }
1a67aafb5   Al Viro   switch ->mknod() ...
523
  static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
524
525
526
527
  		      dev_t rdev)
  {
  	struct fuse_mknod_in inarg;
  	struct fuse_conn *fc = get_fuse_conn(dir);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
528
529
530
  	struct fuse_req *req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
531

e0a43ddcc   Miklos Szeredi   fuse: allow umask...
532
533
  	if (!fc->dont_mask)
  		mode &= ~current_umask();
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
534
535
536
  	memset(&inarg, 0, sizeof(inarg));
  	inarg.mode = mode;
  	inarg.rdev = new_encode_dev(rdev);
e0a43ddcc   Miklos Szeredi   fuse: allow umask...
537
  	inarg.umask = current_umask();
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
538
539
  	req->in.h.opcode = FUSE_MKNOD;
  	req->in.numargs = 2;
e0a43ddcc   Miklos Szeredi   fuse: allow umask...
540
541
  	req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE :
  						sizeof(inarg);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
542
543
544
545
546
  	req->in.args[0].value = &inarg;
  	req->in.args[1].size = entry->d_name.len + 1;
  	req->in.args[1].value = entry->d_name.name;
  	return create_new_entry(fc, req, dir, entry, mode);
  }
4acdaf27e   Al Viro   switch ->create()...
547
  static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode,
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
548
549
  		       struct nameidata *nd)
  {
dd7dd556e   Al Viro   no need to check ...
550
  	if (nd) {
fd72faac9   Miklos Szeredi   [PATCH] FUSE: ato...
551
552
553
554
555
  		int err = fuse_create_open(dir, entry, mode, nd);
  		if (err != -ENOSYS)
  			return err;
  		/* Fall back on mknod */
  	}
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
556
557
  	return fuse_mknod(dir, entry, mode, 0);
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
558
  static int fuse_mkdir(struct inode *dir, struct dentry *entry, umode_t mode)
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
559
560
561
  {
  	struct fuse_mkdir_in inarg;
  	struct fuse_conn *fc = get_fuse_conn(dir);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
562
563
564
  	struct fuse_req *req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
565

e0a43ddcc   Miklos Szeredi   fuse: allow umask...
566
567
  	if (!fc->dont_mask)
  		mode &= ~current_umask();
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
568
569
  	memset(&inarg, 0, sizeof(inarg));
  	inarg.mode = mode;
e0a43ddcc   Miklos Szeredi   fuse: allow umask...
570
  	inarg.umask = current_umask();
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
  	req->in.h.opcode = FUSE_MKDIR;
  	req->in.numargs = 2;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
  	req->in.args[1].size = entry->d_name.len + 1;
  	req->in.args[1].value = entry->d_name.name;
  	return create_new_entry(fc, req, dir, entry, S_IFDIR);
  }
  
  static int fuse_symlink(struct inode *dir, struct dentry *entry,
  			const char *link)
  {
  	struct fuse_conn *fc = get_fuse_conn(dir);
  	unsigned len = strlen(link) + 1;
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
585
586
587
  	struct fuse_req *req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  
  	req->in.h.opcode = FUSE_SYMLINK;
  	req->in.numargs = 2;
  	req->in.args[0].size = entry->d_name.len + 1;
  	req->in.args[0].value = entry->d_name.name;
  	req->in.args[1].size = len;
  	req->in.args[1].value = link;
  	return create_new_entry(fc, req, dir, entry, S_IFLNK);
  }
  
  static int fuse_unlink(struct inode *dir, struct dentry *entry)
  {
  	int err;
  	struct fuse_conn *fc = get_fuse_conn(dir);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
602
603
604
  	struct fuse_req *req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
605
606
607
  
  	req->in.h.opcode = FUSE_UNLINK;
  	req->in.h.nodeid = get_node_id(dir);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
608
609
610
  	req->in.numargs = 1;
  	req->in.args[0].size = entry->d_name.len + 1;
  	req->in.args[0].value = entry->d_name.name;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
611
  	fuse_request_send(fc, req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
612
613
614
615
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
  	if (!err) {
  		struct inode *inode = entry->d_inode;
1729a16c2   Miklos Szeredi   fuse: style fixes
616
617
618
619
620
  		/*
  		 * Set nlink to zero so the inode can be cleared, if the inode
  		 * does have more links this will be discovered at the next
  		 * lookup/getattr.
  		 */
ce71ec368   Dave Hansen   [PATCH] r/o bind ...
621
  		clear_nlink(inode);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
622
623
  		fuse_invalidate_attr(inode);
  		fuse_invalidate_attr(dir);
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
624
  		fuse_invalidate_entry_cache(entry);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
625
626
627
628
629
630
631
632
633
  	} else if (err == -EINTR)
  		fuse_invalidate_entry(entry);
  	return err;
  }
  
  static int fuse_rmdir(struct inode *dir, struct dentry *entry)
  {
  	int err;
  	struct fuse_conn *fc = get_fuse_conn(dir);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
634
635
636
  	struct fuse_req *req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
637
638
639
  
  	req->in.h.opcode = FUSE_RMDIR;
  	req->in.h.nodeid = get_node_id(dir);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
640
641
642
  	req->in.numargs = 1;
  	req->in.args[0].size = entry->d_name.len + 1;
  	req->in.args[0].value = entry->d_name.name;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
643
  	fuse_request_send(fc, req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
644
645
646
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
  	if (!err) {
ce71ec368   Dave Hansen   [PATCH] r/o bind ...
647
  		clear_nlink(entry->d_inode);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
648
  		fuse_invalidate_attr(dir);
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
649
  		fuse_invalidate_entry_cache(entry);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
650
651
652
653
654
655
656
657
658
659
660
  	} else if (err == -EINTR)
  		fuse_invalidate_entry(entry);
  	return err;
  }
  
  static int fuse_rename(struct inode *olddir, struct dentry *oldent,
  		       struct inode *newdir, struct dentry *newent)
  {
  	int err;
  	struct fuse_rename_in inarg;
  	struct fuse_conn *fc = get_fuse_conn(olddir);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
661
  	struct fuse_req *req = fuse_get_req(fc);
e4eaac06b   Sage Weil   vfs: push dentry_...
662

ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
663
664
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
665
666
667
668
669
  
  	memset(&inarg, 0, sizeof(inarg));
  	inarg.newdir = get_node_id(newdir);
  	req->in.h.opcode = FUSE_RENAME;
  	req->in.h.nodeid = get_node_id(olddir);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
670
671
672
673
674
675
676
  	req->in.numargs = 3;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
  	req->in.args[1].size = oldent->d_name.len + 1;
  	req->in.args[1].value = oldent->d_name.name;
  	req->in.args[2].size = newent->d_name.len + 1;
  	req->in.args[2].value = newent->d_name.name;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
677
  	fuse_request_send(fc, req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
678
679
680
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
  	if (!err) {
08b633070   Miklos Szeredi   fuse: fix attribu...
681
682
  		/* ctime changes */
  		fuse_invalidate_attr(oldent->d_inode);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
683
684
685
  		fuse_invalidate_attr(olddir);
  		if (olddir != newdir)
  			fuse_invalidate_attr(newdir);
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
686
687
  
  		/* newent will end up negative */
5219f346b   Miklos Szeredi   fuse: invalidate ...
688
689
  		if (newent->d_inode) {
  			fuse_invalidate_attr(newent->d_inode);
8cbdf1e6f   Miklos Szeredi   [PATCH] fuse: sup...
690
  			fuse_invalidate_entry_cache(newent);
5219f346b   Miklos Szeredi   fuse: invalidate ...
691
  		}
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  	} else if (err == -EINTR) {
  		/* If request was interrupted, DEITY only knows if the
  		   rename actually took place.  If the invalidation
  		   fails (e.g. some process has CWD under the renamed
  		   directory), then there can be inconsistency between
  		   the dcache and the real filesystem.  Tough luck. */
  		fuse_invalidate_entry(oldent);
  		if (newent->d_inode)
  			fuse_invalidate_entry(newent);
  	}
  
  	return err;
  }
  
  static int fuse_link(struct dentry *entry, struct inode *newdir,
  		     struct dentry *newent)
  {
  	int err;
  	struct fuse_link_in inarg;
  	struct inode *inode = entry->d_inode;
  	struct fuse_conn *fc = get_fuse_conn(inode);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
713
714
715
  	struct fuse_req *req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
716
717
718
719
  
  	memset(&inarg, 0, sizeof(inarg));
  	inarg.oldnodeid = get_node_id(inode);
  	req->in.h.opcode = FUSE_LINK;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
  	req->in.numargs = 2;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
  	req->in.args[1].size = newent->d_name.len + 1;
  	req->in.args[1].value = newent->d_name.name;
  	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
  	/* Contrary to "normal" filesystems it can happen that link
  	   makes two "logical" inodes point to the same "physical"
  	   inode.  We invalidate the attributes of the old one, so it
  	   will reflect changes in the backing inode (link count,
  	   etc.)
  	*/
  	if (!err || err == -EINTR)
  		fuse_invalidate_attr(inode);
  	return err;
  }
1fb69e781   Miklos Szeredi   fuse: fix race be...
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
  			  struct kstat *stat)
  {
  	stat->dev = inode->i_sb->s_dev;
  	stat->ino = attr->ino;
  	stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
  	stat->nlink = attr->nlink;
  	stat->uid = attr->uid;
  	stat->gid = attr->gid;
  	stat->rdev = inode->i_rdev;
  	stat->atime.tv_sec = attr->atime;
  	stat->atime.tv_nsec = attr->atimensec;
  	stat->mtime.tv_sec = attr->mtime;
  	stat->mtime.tv_nsec = attr->mtimensec;
  	stat->ctime.tv_sec = attr->ctime;
  	stat->ctime.tv_nsec = attr->ctimensec;
  	stat->size = attr->size;
  	stat->blocks = attr->blocks;
  	stat->blksize = (1 << inode->i_blkbits);
  }
c79e322f6   Miklos Szeredi   fuse: add file ha...
756
757
  static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
  			   struct file *file)
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
758
759
  {
  	int err;
c79e322f6   Miklos Szeredi   fuse: add file ha...
760
761
  	struct fuse_getattr_in inarg;
  	struct fuse_attr_out outarg;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
762
  	struct fuse_conn *fc = get_fuse_conn(inode);
1fb69e781   Miklos Szeredi   fuse: fix race be...
763
764
765
766
  	struct fuse_req *req;
  	u64 attr_version;
  
  	req = fuse_get_req(fc);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
767
768
  	if (IS_ERR(req))
  		return PTR_ERR(req);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
769

7dca9fd39   Miklos Szeredi   fuse: cleanup: ad...
770
  	attr_version = fuse_get_attr_version(fc);
1fb69e781   Miklos Szeredi   fuse: fix race be...
771

c79e322f6   Miklos Szeredi   fuse: add file ha...
772
  	memset(&inarg, 0, sizeof(inarg));
0e9663ee4   Miklos Szeredi   fuse: add blksize...
773
  	memset(&outarg, 0, sizeof(outarg));
c79e322f6   Miklos Szeredi   fuse: add file ha...
774
775
776
777
778
779
780
  	/* Directories have separate file-handle space */
  	if (file && S_ISREG(inode->i_mode)) {
  		struct fuse_file *ff = file->private_data;
  
  		inarg.getattr_flags |= FUSE_GETATTR_FH;
  		inarg.fh = ff->fh;
  	}
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
781
782
  	req->in.h.opcode = FUSE_GETATTR;
  	req->in.h.nodeid = get_node_id(inode);
c79e322f6   Miklos Szeredi   fuse: add file ha...
783
784
785
  	req->in.numargs = 1;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
786
  	req->out.numargs = 1;
0e9663ee4   Miklos Szeredi   fuse: add blksize...
787
788
789
790
  	if (fc->minor < 9)
  		req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
  	else
  		req->out.args[0].size = sizeof(outarg);
c79e322f6   Miklos Szeredi   fuse: add file ha...
791
  	req->out.args[0].value = &outarg;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
792
  	fuse_request_send(fc, req);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
793
794
795
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
  	if (!err) {
c79e322f6   Miklos Szeredi   fuse: add file ha...
796
  		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
797
798
799
  			make_bad_inode(inode);
  			err = -EIO;
  		} else {
c79e322f6   Miklos Szeredi   fuse: add file ha...
800
801
  			fuse_change_attributes(inode, &outarg.attr,
  					       attr_timeout(&outarg),
1fb69e781   Miklos Szeredi   fuse: fix race be...
802
803
  					       attr_version);
  			if (stat)
c79e322f6   Miklos Szeredi   fuse: add file ha...
804
  				fuse_fillattr(inode, &outarg.attr, stat);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
805
806
807
808
  		}
  	}
  	return err;
  }
bcb4be809   Miklos Szeredi   fuse: fix reading...
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
  int fuse_update_attributes(struct inode *inode, struct kstat *stat,
  			   struct file *file, bool *refreshed)
  {
  	struct fuse_inode *fi = get_fuse_inode(inode);
  	int err;
  	bool r;
  
  	if (fi->i_time < get_jiffies_64()) {
  		r = true;
  		err = fuse_do_getattr(inode, stat, file);
  	} else {
  		r = false;
  		err = 0;
  		if (stat) {
  			generic_fillattr(inode, stat);
  			stat->mode = fi->orig_i_mode;
  		}
  	}
  
  	if (refreshed != NULL)
  		*refreshed = r;
  
  	return err;
  }
3b463ae0c   John Muir   fuse: invalidatio...
833
  int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
451d0f599   John Muir   FUSE: Notifying t...
834
  			     u64 child_nodeid, struct qstr *name)
3b463ae0c   John Muir   fuse: invalidatio...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
  {
  	int err = -ENOTDIR;
  	struct inode *parent;
  	struct dentry *dir;
  	struct dentry *entry;
  
  	parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid);
  	if (!parent)
  		return -ENOENT;
  
  	mutex_lock(&parent->i_mutex);
  	if (!S_ISDIR(parent->i_mode))
  		goto unlock;
  
  	err = -ENOENT;
  	dir = d_find_alias(parent);
  	if (!dir)
  		goto unlock;
  
  	entry = d_lookup(dir, name);
  	dput(dir);
  	if (!entry)
  		goto unlock;
  
  	fuse_invalidate_attr(parent);
  	fuse_invalidate_entry(entry);
451d0f599   John Muir   FUSE: Notifying t...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
  
  	if (child_nodeid != 0 && entry->d_inode) {
  		mutex_lock(&entry->d_inode->i_mutex);
  		if (get_node_id(entry->d_inode) != child_nodeid) {
  			err = -ENOENT;
  			goto badentry;
  		}
  		if (d_mountpoint(entry)) {
  			err = -EBUSY;
  			goto badentry;
  		}
  		if (S_ISDIR(entry->d_inode->i_mode)) {
  			shrink_dcache_parent(entry);
  			if (!simple_empty(entry)) {
  				err = -ENOTEMPTY;
  				goto badentry;
  			}
  			entry->d_inode->i_flags |= S_DEAD;
  		}
  		dont_mount(entry);
  		clear_nlink(entry->d_inode);
  		err = 0;
   badentry:
  		mutex_unlock(&entry->d_inode->i_mutex);
  		if (!err)
  			d_delete(entry);
  	} else {
  		err = 0;
  	}
3b463ae0c   John Muir   fuse: invalidatio...
890
  	dput(entry);
3b463ae0c   John Muir   fuse: invalidatio...
891
892
893
894
895
896
  
   unlock:
  	mutex_unlock(&parent->i_mutex);
  	iput(parent);
  	return err;
  }
87729a551   Miklos Szeredi   [PATCH] FUSE: tig...
897
898
899
900
901
902
903
904
905
906
907
908
909
  /*
   * Calling into a user-controlled filesystem gives the filesystem
   * daemon ptrace-like capabilities over the requester process.  This
   * means, that the filesystem daemon is able to record the exact
   * filesystem operations performed, and can also control the behavior
   * of the requester process in otherwise impossible ways.  For example
   * it can delay the operation for arbitrary length of time allowing
   * DoS against the requester.
   *
   * For this reason only those processes can call into the filesystem,
   * for which the owner of the mount has ptrace privilege.  This
   * excludes processes started by other users, suid or sgid processes.
   */
e57ac6837   Miklos Szeredi   fuse: fix allowin...
910
  int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
87729a551   Miklos Szeredi   [PATCH] FUSE: tig...
911
  {
c69e8d9c0   David Howells   CRED: Use RCU to ...
912
913
  	const struct cred *cred;
  	int ret;
87729a551   Miklos Szeredi   [PATCH] FUSE: tig...
914

c69e8d9c0   David Howells   CRED: Use RCU to ...
915
  	if (fc->flags & FUSE_ALLOW_OTHER)
87729a551   Miklos Szeredi   [PATCH] FUSE: tig...
916
  		return 1;
c69e8d9c0   David Howells   CRED: Use RCU to ...
917
918
919
920
921
922
923
924
925
926
927
928
929
  	rcu_read_lock();
  	ret = 0;
  	cred = __task_cred(task);
  	if (cred->euid == fc->user_id &&
  	    cred->suid == fc->user_id &&
  	    cred->uid  == fc->user_id &&
  	    cred->egid == fc->group_id &&
  	    cred->sgid == fc->group_id &&
  	    cred->gid  == fc->group_id)
  		ret = 1;
  	rcu_read_unlock();
  
  	return ret;
87729a551   Miklos Szeredi   [PATCH] FUSE: tig...
930
  }
31d40d74b   Miklos Szeredi   [PATCH] FUSE: add...
931
932
933
934
935
936
937
938
939
  static int fuse_access(struct inode *inode, int mask)
  {
  	struct fuse_conn *fc = get_fuse_conn(inode);
  	struct fuse_req *req;
  	struct fuse_access_in inarg;
  	int err;
  
  	if (fc->no_access)
  		return 0;
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
940
941
942
  	req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
31d40d74b   Miklos Szeredi   [PATCH] FUSE: add...
943
944
  
  	memset(&inarg, 0, sizeof(inarg));
e6305c43e   Al Viro   [PATCH] sanitize ...
945
  	inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC);
31d40d74b   Miklos Szeredi   [PATCH] FUSE: add...
946
947
  	req->in.h.opcode = FUSE_ACCESS;
  	req->in.h.nodeid = get_node_id(inode);
31d40d74b   Miklos Szeredi   [PATCH] FUSE: add...
948
949
950
  	req->in.numargs = 1;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
951
  	fuse_request_send(fc, req);
31d40d74b   Miklos Szeredi   [PATCH] FUSE: add...
952
953
954
955
956
957
958
959
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
  	if (err == -ENOSYS) {
  		fc->no_access = 1;
  		err = 0;
  	}
  	return err;
  }
10556cb21   Al Viro   ->permission() sa...
960
  static int fuse_perm_getattr(struct inode *inode, int mask)
19690ddb6   Miklos Szeredi   fuse: make fuse_p...
961
  {
10556cb21   Al Viro   ->permission() sa...
962
  	if (mask & MAY_NOT_BLOCK)
19690ddb6   Miklos Szeredi   fuse: make fuse_p...
963
964
965
966
  		return -ECHILD;
  
  	return fuse_do_getattr(inode, NULL, NULL);
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
967
968
969
970
971
972
973
974
975
976
977
978
979
  /*
   * Check permission.  The two basic access models of FUSE are:
   *
   * 1) Local access checking ('default_permissions' mount option) based
   * on file mode.  This is the plain old disk filesystem permission
   * modell.
   *
   * 2) "Remote" access checking, where server is responsible for
   * checking permission in each inode operation.  An exception to this
   * is if ->permission() was invoked from sys_access() in which case an
   * access request is sent.  Execute permission is still checked
   * locally based on file mode.
   */
10556cb21   Al Viro   ->permission() sa...
980
  static int fuse_permission(struct inode *inode, int mask)
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
981
982
  {
  	struct fuse_conn *fc = get_fuse_conn(inode);
244f6385c   Miklos Szeredi   fuse: refresh sta...
983
984
  	bool refreshed = false;
  	int err = 0;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
985

87729a551   Miklos Szeredi   [PATCH] FUSE: tig...
986
  	if (!fuse_allow_task(fc, current))
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
987
  		return -EACCES;
244f6385c   Miklos Szeredi   fuse: refresh sta...
988
989
  
  	/*
e8e961574   Miklos Szeredi   fuse: clean up ex...
990
  	 * If attributes are needed, refresh them before proceeding
244f6385c   Miklos Szeredi   fuse: refresh sta...
991
  	 */
e8e961574   Miklos Szeredi   fuse: clean up ex...
992
993
  	if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) ||
  	    ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) {
19690ddb6   Miklos Szeredi   fuse: make fuse_p...
994
995
996
997
  		struct fuse_inode *fi = get_fuse_inode(inode);
  
  		if (fi->i_time < get_jiffies_64()) {
  			refreshed = true;
10556cb21   Al Viro   ->permission() sa...
998
  			err = fuse_perm_getattr(inode, mask);
19690ddb6   Miklos Szeredi   fuse: make fuse_p...
999
1000
1001
  			if (err)
  				return err;
  		}
244f6385c   Miklos Szeredi   fuse: refresh sta...
1002
1003
1004
  	}
  
  	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
2830ba7f3   Al Viro   ->permission() sa...
1005
  		err = generic_permission(inode, mask);
1e9a4ed93   Miklos Szeredi   [PATCH] FUSE - mo...
1006
1007
1008
1009
  
  		/* If permission is denied, try to refresh file
  		   attributes.  This is also needed, because the root
  		   node will at first have no permissions */
244f6385c   Miklos Szeredi   fuse: refresh sta...
1010
  		if (err == -EACCES && !refreshed) {
10556cb21   Al Viro   ->permission() sa...
1011
  			err = fuse_perm_getattr(inode, mask);
1e9a4ed93   Miklos Szeredi   [PATCH] FUSE - mo...
1012
  			if (!err)
2830ba7f3   Al Viro   ->permission() sa...
1013
  				err = generic_permission(inode, mask);
1e9a4ed93   Miklos Szeredi   [PATCH] FUSE - mo...
1014
  		}
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
1015
1016
1017
1018
  		/* Note: the opposite of the above test does not
  		   exist.  So if permissions are revoked this won't be
  		   noticed immediately, only after the attribute
  		   timeout has expired */
9cfcac810   Eric Paris   vfs: re-introduce...
1019
  	} else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
10556cb21   Al Viro   ->permission() sa...
1020
  		if (mask & MAY_NOT_BLOCK)
19690ddb6   Miklos Szeredi   fuse: make fuse_p...
1021
  			return -ECHILD;
e8e961574   Miklos Szeredi   fuse: clean up ex...
1022
1023
1024
1025
1026
  		err = fuse_access(inode, mask);
  	} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
  		if (!(inode->i_mode & S_IXUGO)) {
  			if (refreshed)
  				return -EACCES;
10556cb21   Al Viro   ->permission() sa...
1027
  			err = fuse_perm_getattr(inode, mask);
e8e961574   Miklos Szeredi   fuse: clean up ex...
1028
1029
1030
  			if (!err && !(inode->i_mode & S_IXUGO))
  				return -EACCES;
  		}
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1031
  	}
244f6385c   Miklos Szeredi   fuse: refresh sta...
1032
  	return err;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  }
  
  static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
  			 void *dstbuf, filldir_t filldir)
  {
  	while (nbytes >= FUSE_NAME_OFFSET) {
  		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
  		size_t reclen = FUSE_DIRENT_SIZE(dirent);
  		int over;
  		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
  			return -EIO;
  		if (reclen > nbytes)
  			break;
  
  		over = filldir(dstbuf, dirent->name, dirent->namelen,
  			       file->f_pos, dirent->ino, dirent->type);
  		if (over)
  			break;
  
  		buf += reclen;
  		nbytes -= reclen;
  		file->f_pos = dirent->off;
  	}
  
  	return 0;
  }
04730fef1   Miklos Szeredi   [PATCH] fuse: tra...
1059
  static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1060
  {
04730fef1   Miklos Szeredi   [PATCH] fuse: tra...
1061
1062
1063
  	int err;
  	size_t nbytes;
  	struct page *page;
7706a9d61   Josef Sipek   [PATCH] struct pa...
1064
  	struct inode *inode = file->f_path.dentry->d_inode;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1065
  	struct fuse_conn *fc = get_fuse_conn(inode);
248d86e87   Miklos Szeredi   [PATCH] fuse: fai...
1066
1067
1068
1069
  	struct fuse_req *req;
  
  	if (is_bad_inode(inode))
  		return -EIO;
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
1070
1071
1072
  	req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1073

04730fef1   Miklos Szeredi   [PATCH] fuse: tra...
1074
1075
1076
1077
1078
  	page = alloc_page(GFP_KERNEL);
  	if (!page) {
  		fuse_put_request(fc, req);
  		return -ENOMEM;
  	}
f4975c67d   Miklos Szeredi   fuse: allow kerne...
1079
  	req->out.argpages = 1;
04730fef1   Miklos Szeredi   [PATCH] fuse: tra...
1080
1081
  	req->num_pages = 1;
  	req->pages[0] = page;
2106cb189   Miklos Szeredi   fuse: don't use i...
1082
  	fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, FUSE_READDIR);
b93f858ab   Tejun Heo   fuse: add fuse_ p...
1083
  	fuse_request_send(fc, req);
361b1eb55   Miklos Szeredi   [PATCH] fuse: REA...
1084
  	nbytes = req->out.args[0].size;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1085
1086
1087
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
  	if (!err)
04730fef1   Miklos Szeredi   [PATCH] fuse: tra...
1088
1089
  		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
  				    filldir);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1090

04730fef1   Miklos Szeredi   [PATCH] fuse: tra...
1091
  	__free_page(page);
b36c31ba9   Miklos Szeredi   [PATCH] fuse: don...
1092
  	fuse_invalidate_attr(inode); /* atime changed */
04730fef1   Miklos Szeredi   [PATCH] fuse: tra...
1093
  	return err;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1094
1095
1096
1097
1098
1099
  }
  
  static char *read_link(struct dentry *dentry)
  {
  	struct inode *inode = dentry->d_inode;
  	struct fuse_conn *fc = get_fuse_conn(inode);
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
1100
  	struct fuse_req *req = fuse_get_req(fc);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1101
  	char *link;
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
1102
  	if (IS_ERR(req))
e231c2ee6   David Howells   Convert ERR_PTR(P...
1103
  		return ERR_CAST(req);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1104
1105
1106
1107
1108
1109
1110
1111
  
  	link = (char *) __get_free_page(GFP_KERNEL);
  	if (!link) {
  		link = ERR_PTR(-ENOMEM);
  		goto out;
  	}
  	req->in.h.opcode = FUSE_READLINK;
  	req->in.h.nodeid = get_node_id(inode);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1112
1113
1114
1115
  	req->out.argvar = 1;
  	req->out.numargs = 1;
  	req->out.args[0].size = PAGE_SIZE - 1;
  	req->out.args[0].value = link;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
1116
  	fuse_request_send(fc, req);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1117
1118
1119
1120
1121
1122
1123
  	if (req->out.h.error) {
  		free_page((unsigned long) link);
  		link = ERR_PTR(req->out.h.error);
  	} else
  		link[req->out.args[0].size] = '\0';
   out:
  	fuse_put_request(fc, req);
b36c31ba9   Miklos Szeredi   [PATCH] fuse: don...
1124
  	fuse_invalidate_attr(inode); /* atime changed */
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
  	return link;
  }
  
  static void free_link(char *link)
  {
  	if (!IS_ERR(link))
  		free_page((unsigned long) link);
  }
  
  static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
  {
  	nd_set_link(nd, read_link(dentry));
  	return NULL;
  }
  
  static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
  {
  	free_link(nd_get_link(nd));
  }
  
  static int fuse_dir_open(struct inode *inode, struct file *file)
  {
91fe96b40   Miklos Szeredi   fuse: create fuse...
1147
  	return fuse_open_common(inode, file, true);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1148
1149
1150
1151
  }
  
  static int fuse_dir_release(struct inode *inode, struct file *file)
  {
8b0797a49   Miklos Szeredi   fuse: don't use i...
1152
1153
1154
  	fuse_release_common(file, FUSE_RELEASEDIR);
  
  	return 0;
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1155
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
1156
1157
  static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end,
  			  int datasync)
825479819   Miklos Szeredi   [PATCH] FUSE: add...
1158
  {
02c24a821   Josef Bacik   fs: push i_mutex ...
1159
  	return fuse_fsync_common(file, start, end, datasync, 1);
825479819   Miklos Szeredi   [PATCH] FUSE: add...
1160
  }
b18da0c56   Miklos Szeredi   fuse: support ioc...
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  static long fuse_dir_ioctl(struct file *file, unsigned int cmd,
  			    unsigned long arg)
  {
  	struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host);
  
  	/* FUSE_IOCTL_DIR only supported for API version >= 7.18 */
  	if (fc->minor < 18)
  		return -ENOTTY;
  
  	return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR);
  }
  
  static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd,
  				   unsigned long arg)
  {
  	struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host);
  
  	if (fc->minor < 18)
  		return -ENOTTY;
  
  	return fuse_ioctl_common(file, cmd, arg,
  				 FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR);
  }
17637cbab   Miklos Szeredi   fuse: improve uti...
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
  static bool update_mtime(unsigned ivalid)
  {
  	/* Always update if mtime is explicitly set  */
  	if (ivalid & ATTR_MTIME_SET)
  		return true;
  
  	/* If it's an open(O_TRUNC) or an ftruncate(), don't update */
  	if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
  		return false;
  
  	/* In all other cases update */
  	return true;
  }
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1197
  static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1198
1199
  {
  	unsigned ivalid = iattr->ia_valid;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1200
1201
  
  	if (ivalid & ATTR_MODE)
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1202
  		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1203
  	if (ivalid & ATTR_UID)
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1204
  		arg->valid |= FATTR_UID,    arg->uid = iattr->ia_uid;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1205
  	if (ivalid & ATTR_GID)
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1206
  		arg->valid |= FATTR_GID,    arg->gid = iattr->ia_gid;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1207
  	if (ivalid & ATTR_SIZE)
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1208
  		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;
17637cbab   Miklos Szeredi   fuse: improve uti...
1209
1210
  	if (ivalid & ATTR_ATIME) {
  		arg->valid |= FATTR_ATIME;
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1211
  		arg->atime = iattr->ia_atime.tv_sec;
17637cbab   Miklos Szeredi   fuse: improve uti...
1212
1213
1214
1215
1216
1217
  		arg->atimensec = iattr->ia_atime.tv_nsec;
  		if (!(ivalid & ATTR_ATIME_SET))
  			arg->valid |= FATTR_ATIME_NOW;
  	}
  	if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) {
  		arg->valid |= FATTR_MTIME;
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1218
  		arg->mtime = iattr->ia_mtime.tv_sec;
17637cbab   Miklos Szeredi   fuse: improve uti...
1219
1220
1221
  		arg->mtimensec = iattr->ia_mtime.tv_nsec;
  		if (!(ivalid & ATTR_MTIME_SET))
  			arg->valid |= FATTR_MTIME_NOW;
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1222
  	}
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1223
  }
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
1224
  /*
3be5a52b3   Miklos Szeredi   fuse: support wri...
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
   * Prevent concurrent writepages on inode
   *
   * This is done by adding a negative bias to the inode write counter
   * and waiting for all pending writes to finish.
   */
  void fuse_set_nowrite(struct inode *inode)
  {
  	struct fuse_conn *fc = get_fuse_conn(inode);
  	struct fuse_inode *fi = get_fuse_inode(inode);
  
  	BUG_ON(!mutex_is_locked(&inode->i_mutex));
  
  	spin_lock(&fc->lock);
  	BUG_ON(fi->writectr < 0);
  	fi->writectr += FUSE_NOWRITE;
  	spin_unlock(&fc->lock);
  	wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE);
  }
  
  /*
   * Allow writepages on inode
   *
   * Remove the bias from the writecounter and send any queued
   * writepages.
   */
  static void __fuse_release_nowrite(struct inode *inode)
  {
  	struct fuse_inode *fi = get_fuse_inode(inode);
  
  	BUG_ON(fi->writectr != FUSE_NOWRITE);
  	fi->writectr = 0;
  	fuse_flush_writepages(inode);
  }
  
  void fuse_release_nowrite(struct inode *inode)
  {
  	struct fuse_conn *fc = get_fuse_conn(inode);
  
  	spin_lock(&fc->lock);
  	__fuse_release_nowrite(inode);
  	spin_unlock(&fc->lock);
  }
  
  /*
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
1269
1270
1271
1272
   * Set attributes, and at the same time refresh them.
   *
   * Truncation is slightly complicated, because the 'truncate' request
   * may fail, in which case we don't want to touch the mapping.
9ffbb9162   Miklos Szeredi   [PATCH] fuse: fix...
1273
1274
   * vmtruncate() doesn't allow for this case, so do the rlimit checking
   * and the actual truncation by hand.
6f9f11806   Miklos Szeredi   [PATCH] fuse: add...
1275
   */
49d4914fd   Miklos Szeredi   fuse: clean up op...
1276
1277
  static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
  			   struct file *file)
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1278
1279
1280
  {
  	struct inode *inode = entry->d_inode;
  	struct fuse_conn *fc = get_fuse_conn(inode);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1281
1282
1283
  	struct fuse_req *req;
  	struct fuse_setattr_in inarg;
  	struct fuse_attr_out outarg;
3be5a52b3   Miklos Szeredi   fuse: support wri...
1284
1285
  	bool is_truncate = false;
  	loff_t oldsize;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1286
  	int err;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1287

e57ac6837   Miklos Szeredi   fuse: fix allowin...
1288
1289
  	if (!fuse_allow_task(fc, current))
  		return -EACCES;
db78b877f   Christoph Hellwig   always call inode...
1290
1291
1292
1293
1294
1295
  	if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
  		attr->ia_valid |= ATTR_FORCE;
  
  	err = inode_change_ok(inode, attr);
  	if (err)
  		return err;
1e9a4ed93   Miklos Szeredi   [PATCH] FUSE - mo...
1296

8d56addd7   Miklos Szeredi   fuse: fix truncat...
1297
1298
1299
1300
1301
  	if (attr->ia_valid & ATTR_OPEN) {
  		if (fc->atomic_o_trunc)
  			return 0;
  		file = NULL;
  	}
6ff958edb   Miklos Szeredi   fuse: add atomic ...
1302

2c27c65ed   Christoph Hellwig   check ATTR_SIZE c...
1303
  	if (attr->ia_valid & ATTR_SIZE)
3be5a52b3   Miklos Szeredi   fuse: support wri...
1304
  		is_truncate = true;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1305

ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
1306
1307
1308
  	req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1309

3be5a52b3   Miklos Szeredi   fuse: support wri...
1310
1311
  	if (is_truncate)
  		fuse_set_nowrite(inode);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1312
  	memset(&inarg, 0, sizeof(inarg));
0e9663ee4   Miklos Szeredi   fuse: add blksize...
1313
  	memset(&outarg, 0, sizeof(outarg));
befc649c2   Miklos Szeredi   [PATCH] FUSE: pas...
1314
  	iattr_to_fattr(attr, &inarg);
49d4914fd   Miklos Szeredi   fuse: clean up op...
1315
1316
1317
1318
1319
  	if (file) {
  		struct fuse_file *ff = file->private_data;
  		inarg.valid |= FATTR_FH;
  		inarg.fh = ff->fh;
  	}
f33321141   Miklos Szeredi   fuse: add support...
1320
1321
1322
1323
1324
  	if (attr->ia_valid & ATTR_SIZE) {
  		/* For mandatory locking in truncate */
  		inarg.valid |= FATTR_LOCKOWNER;
  		inarg.lock_owner = fuse_lock_owner_id(fc, current->files);
  	}
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1325
1326
  	req->in.h.opcode = FUSE_SETATTR;
  	req->in.h.nodeid = get_node_id(inode);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1327
1328
1329
1330
  	req->in.numargs = 1;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
  	req->out.numargs = 1;
0e9663ee4   Miklos Szeredi   fuse: add blksize...
1331
1332
1333
1334
  	if (fc->minor < 9)
  		req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
  	else
  		req->out.args[0].size = sizeof(outarg);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1335
  	req->out.args[0].value = &outarg;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
1336
  	fuse_request_send(fc, req);
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1337
1338
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
e00d2c2d4   Miklos Szeredi   fuse: truncate on...
1339
1340
1341
  	if (err) {
  		if (err == -EINTR)
  			fuse_invalidate_attr(inode);
3be5a52b3   Miklos Szeredi   fuse: support wri...
1342
  		goto error;
e00d2c2d4   Miklos Szeredi   fuse: truncate on...
1343
  	}
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1344

e00d2c2d4   Miklos Szeredi   fuse: truncate on...
1345
1346
  	if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
  		make_bad_inode(inode);
3be5a52b3   Miklos Szeredi   fuse: support wri...
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
  		err = -EIO;
  		goto error;
  	}
  
  	spin_lock(&fc->lock);
  	fuse_change_attributes_common(inode, &outarg.attr,
  				      attr_timeout(&outarg));
  	oldsize = inode->i_size;
  	i_size_write(inode, outarg.attr.size);
  
  	if (is_truncate) {
  		/* NOTE: this may release/reacquire fc->lock */
  		__fuse_release_nowrite(inode);
  	}
  	spin_unlock(&fc->lock);
  
  	/*
  	 * Only call invalidate_inode_pages2() after removing
  	 * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.
  	 */
  	if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
c08d3b0e3   npiggin@suse.de   truncate: use new...
1368
  		truncate_pagecache(inode, oldsize, outarg.attr.size);
3be5a52b3   Miklos Szeredi   fuse: support wri...
1369
  		invalidate_inode_pages2(inode->i_mapping);
e00d2c2d4   Miklos Szeredi   fuse: truncate on...
1370
  	}
e00d2c2d4   Miklos Szeredi   fuse: truncate on...
1371
  	return 0;
3be5a52b3   Miklos Szeredi   fuse: support wri...
1372
1373
1374
1375
1376
1377
  
  error:
  	if (is_truncate)
  		fuse_release_nowrite(inode);
  
  	return err;
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1378
  }
49d4914fd   Miklos Szeredi   fuse: clean up op...
1379
1380
1381
1382
1383
1384
1385
  static int fuse_setattr(struct dentry *entry, struct iattr *attr)
  {
  	if (attr->ia_valid & ATTR_FILE)
  		return fuse_do_setattr(entry, attr, attr->ia_file);
  	else
  		return fuse_do_setattr(entry, attr, NULL);
  }
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1386
1387
1388
1389
  static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
  			struct kstat *stat)
  {
  	struct inode *inode = entry->d_inode;
244f6385c   Miklos Szeredi   fuse: refresh sta...
1390
  	struct fuse_conn *fc = get_fuse_conn(inode);
244f6385c   Miklos Szeredi   fuse: refresh sta...
1391
1392
1393
  
  	if (!fuse_allow_task(fc, current))
  		return -EACCES;
bcb4be809   Miklos Szeredi   fuse: fix reading...
1394
  	return fuse_update_attributes(inode, stat, NULL, NULL);
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1395
  }
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1396
1397
1398
1399
1400
1401
1402
1403
  static int fuse_setxattr(struct dentry *entry, const char *name,
  			 const void *value, size_t size, int flags)
  {
  	struct inode *inode = entry->d_inode;
  	struct fuse_conn *fc = get_fuse_conn(inode);
  	struct fuse_req *req;
  	struct fuse_setxattr_in inarg;
  	int err;
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1404
1405
  	if (fc->no_setxattr)
  		return -EOPNOTSUPP;
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
1406
1407
1408
  	req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1409
1410
1411
1412
1413
1414
  
  	memset(&inarg, 0, sizeof(inarg));
  	inarg.size = size;
  	inarg.flags = flags;
  	req->in.h.opcode = FUSE_SETXATTR;
  	req->in.h.nodeid = get_node_id(inode);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1415
1416
1417
1418
1419
1420
1421
  	req->in.numargs = 3;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
  	req->in.args[1].size = strlen(name) + 1;
  	req->in.args[1].value = name;
  	req->in.args[2].size = size;
  	req->in.args[2].value = value;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
1422
  	fuse_request_send(fc, req);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
  	if (err == -ENOSYS) {
  		fc->no_setxattr = 1;
  		err = -EOPNOTSUPP;
  	}
  	return err;
  }
  
  static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
  			     void *value, size_t size)
  {
  	struct inode *inode = entry->d_inode;
  	struct fuse_conn *fc = get_fuse_conn(inode);
  	struct fuse_req *req;
  	struct fuse_getxattr_in inarg;
  	struct fuse_getxattr_out outarg;
  	ssize_t ret;
  
  	if (fc->no_getxattr)
  		return -EOPNOTSUPP;
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
1444
1445
1446
  	req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1447
1448
1449
1450
1451
  
  	memset(&inarg, 0, sizeof(inarg));
  	inarg.size = size;
  	req->in.h.opcode = FUSE_GETXATTR;
  	req->in.h.nodeid = get_node_id(inode);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
  	req->in.numargs = 2;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
  	req->in.args[1].size = strlen(name) + 1;
  	req->in.args[1].value = name;
  	/* This is really two different operations rolled into one */
  	req->out.numargs = 1;
  	if (size) {
  		req->out.argvar = 1;
  		req->out.args[0].size = size;
  		req->out.args[0].value = value;
  	} else {
  		req->out.args[0].size = sizeof(outarg);
  		req->out.args[0].value = &outarg;
  	}
b93f858ab   Tejun Heo   fuse: add fuse_ p...
1467
  	fuse_request_send(fc, req);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
  	ret = req->out.h.error;
  	if (!ret)
  		ret = size ? req->out.args[0].size : outarg.size;
  	else {
  		if (ret == -ENOSYS) {
  			fc->no_getxattr = 1;
  			ret = -EOPNOTSUPP;
  		}
  	}
  	fuse_put_request(fc, req);
  	return ret;
  }
  
  static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
  {
  	struct inode *inode = entry->d_inode;
  	struct fuse_conn *fc = get_fuse_conn(inode);
  	struct fuse_req *req;
  	struct fuse_getxattr_in inarg;
  	struct fuse_getxattr_out outarg;
  	ssize_t ret;
e57ac6837   Miklos Szeredi   fuse: fix allowin...
1489
1490
  	if (!fuse_allow_task(fc, current))
  		return -EACCES;
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1491
1492
  	if (fc->no_listxattr)
  		return -EOPNOTSUPP;
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
1493
1494
1495
  	req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1496
1497
1498
1499
1500
  
  	memset(&inarg, 0, sizeof(inarg));
  	inarg.size = size;
  	req->in.h.opcode = FUSE_LISTXATTR;
  	req->in.h.nodeid = get_node_id(inode);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
  	req->in.numargs = 1;
  	req->in.args[0].size = sizeof(inarg);
  	req->in.args[0].value = &inarg;
  	/* This is really two different operations rolled into one */
  	req->out.numargs = 1;
  	if (size) {
  		req->out.argvar = 1;
  		req->out.args[0].size = size;
  		req->out.args[0].value = list;
  	} else {
  		req->out.args[0].size = sizeof(outarg);
  		req->out.args[0].value = &outarg;
  	}
b93f858ab   Tejun Heo   fuse: add fuse_ p...
1514
  	fuse_request_send(fc, req);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
  	ret = req->out.h.error;
  	if (!ret)
  		ret = size ? req->out.args[0].size : outarg.size;
  	else {
  		if (ret == -ENOSYS) {
  			fc->no_listxattr = 1;
  			ret = -EOPNOTSUPP;
  		}
  	}
  	fuse_put_request(fc, req);
  	return ret;
  }
  
  static int fuse_removexattr(struct dentry *entry, const char *name)
  {
  	struct inode *inode = entry->d_inode;
  	struct fuse_conn *fc = get_fuse_conn(inode);
  	struct fuse_req *req;
  	int err;
  
  	if (fc->no_removexattr)
  		return -EOPNOTSUPP;
ce1d5a491   Miklos Szeredi   [PATCH] fuse: cle...
1537
1538
1539
  	req = fuse_get_req(fc);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1540
1541
1542
  
  	req->in.h.opcode = FUSE_REMOVEXATTR;
  	req->in.h.nodeid = get_node_id(inode);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1543
1544
1545
  	req->in.numargs = 1;
  	req->in.args[0].size = strlen(name) + 1;
  	req->in.args[0].value = name;
b93f858ab   Tejun Heo   fuse: add fuse_ p...
1546
  	fuse_request_send(fc, req);
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1547
1548
1549
1550
1551
1552
1553
1554
  	err = req->out.h.error;
  	fuse_put_request(fc, req);
  	if (err == -ENOSYS) {
  		fc->no_removexattr = 1;
  		err = -EOPNOTSUPP;
  	}
  	return err;
  }
754661f14   Arjan van de Ven   [PATCH] mark stru...
1555
  static const struct inode_operations fuse_dir_inode_operations = {
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1556
  	.lookup		= fuse_lookup,
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1557
1558
1559
1560
1561
1562
1563
1564
1565
  	.mkdir		= fuse_mkdir,
  	.symlink	= fuse_symlink,
  	.unlink		= fuse_unlink,
  	.rmdir		= fuse_rmdir,
  	.rename		= fuse_rename,
  	.link		= fuse_link,
  	.setattr	= fuse_setattr,
  	.create		= fuse_create,
  	.mknod		= fuse_mknod,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1566
1567
  	.permission	= fuse_permission,
  	.getattr	= fuse_getattr,
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1568
1569
1570
1571
  	.setxattr	= fuse_setxattr,
  	.getxattr	= fuse_getxattr,
  	.listxattr	= fuse_listxattr,
  	.removexattr	= fuse_removexattr,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1572
  };
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
1573
  static const struct file_operations fuse_dir_operations = {
b6aeadeda   Miklos Szeredi   [PATCH] FUSE - fi...
1574
  	.llseek		= generic_file_llseek,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1575
1576
1577
1578
  	.read		= generic_read_dir,
  	.readdir	= fuse_readdir,
  	.open		= fuse_dir_open,
  	.release	= fuse_dir_release,
825479819   Miklos Szeredi   [PATCH] FUSE: add...
1579
  	.fsync		= fuse_dir_fsync,
b18da0c56   Miklos Szeredi   fuse: support ioc...
1580
1581
  	.unlocked_ioctl	= fuse_dir_ioctl,
  	.compat_ioctl	= fuse_dir_compat_ioctl,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1582
  };
754661f14   Arjan van de Ven   [PATCH] mark stru...
1583
  static const struct inode_operations fuse_common_inode_operations = {
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1584
  	.setattr	= fuse_setattr,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1585
1586
  	.permission	= fuse_permission,
  	.getattr	= fuse_getattr,
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1587
1588
1589
1590
  	.setxattr	= fuse_setxattr,
  	.getxattr	= fuse_getxattr,
  	.listxattr	= fuse_listxattr,
  	.removexattr	= fuse_removexattr,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1591
  };
754661f14   Arjan van de Ven   [PATCH] mark stru...
1592
  static const struct inode_operations fuse_symlink_inode_operations = {
9e6268db4   Miklos Szeredi   [PATCH] FUSE - re...
1593
  	.setattr	= fuse_setattr,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1594
1595
1596
1597
  	.follow_link	= fuse_follow_link,
  	.put_link	= fuse_put_link,
  	.readlink	= generic_readlink,
  	.getattr	= fuse_getattr,
92a8780e1   Miklos Szeredi   [PATCH] FUSE - ex...
1598
1599
1600
1601
  	.setxattr	= fuse_setxattr,
  	.getxattr	= fuse_getxattr,
  	.listxattr	= fuse_listxattr,
  	.removexattr	= fuse_removexattr,
e5e5558e9   Miklos Szeredi   [PATCH] FUSE - re...
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
  };
  
  void fuse_init_common(struct inode *inode)
  {
  	inode->i_op = &fuse_common_inode_operations;
  }
  
  void fuse_init_dir(struct inode *inode)
  {
  	inode->i_op = &fuse_dir_inode_operations;
  	inode->i_fop = &fuse_dir_operations;
  }
  
  void fuse_init_symlink(struct inode *inode)
  {
  	inode->i_op = &fuse_symlink_inode_operations;
  }