Blame view

fs/9p/fid.c 6.78 KB
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
1
2
3
  /*
   * V9FS FID Management
   *
ba17674fe   Latchesar Ionkov   9p: attach-per-user
4
   *  Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
46f6dac25   Eric Van Hensbergen   [PATCH] v9fs: sim...
5
   *  Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
6
7
   *
   *  This program is free software; you can redistribute it and/or modify
42e8c509c   Eric Van Hensbergen   [PATCH] v9fs: upd...
8
9
   *  it under the terms of the GNU General Public License version 2
   *  as published by the Free Software Foundation.
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
10
11
12
13
14
15
16
17
18
19
20
21
22
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to:
   *  Free Software Foundation
   *  51 Franklin Street, Fifth Floor
   *  Boston, MA  02111-1301  USA
   *
   */
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
23
24
25
  #include <linux/module.h>
  #include <linux/errno.h>
  #include <linux/fs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
26
  #include <linux/slab.h>
914e26379   Al Viro   [PATCH] severing ...
27
  #include <linux/sched.h>
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
28
  #include <linux/idr.h>
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
29
30
  #include <net/9p/9p.h>
  #include <net/9p/client.h>
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
31

3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
32
  #include "v9fs.h"
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
33
  #include "v9fs_vfs.h"
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
34
35
36
  #include "fid.h"
  
  /**
ba17674fe   Latchesar Ionkov   9p: attach-per-user
37
38
   * v9fs_fid_add - add a fid to a dentry
   * @dentry: dentry that the fid is being added to
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
39
   * @fid: fid to add
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
40
41
   *
   */
5e608671d   Al Viro   9p: if v9fs_fid_l...
42
  static inline void __add_fid(struct dentry *dentry, struct p9_fid *fid)
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
43
  {
5e608671d   Al Viro   9p: if v9fs_fid_l...
44
45
  	hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata);
  }
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
46

2ea03e1d6   Al Viro   9p: v9fs_fid_add(...
47
  void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
48
  {
634095dab   Al Viro   9p: don't bother ...
49
  	spin_lock(&dentry->d_lock);
5e608671d   Al Viro   9p: if v9fs_fid_l...
50
  	__add_fid(dentry, fid);
634095dab   Al Viro   9p: don't bother ...
51
  	spin_unlock(&dentry->d_lock);
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
52
53
54
  }
  
  /**
ba17674fe   Latchesar Ionkov   9p: attach-per-user
55
   * v9fs_fid_find - retrieve a fid that belongs to the specified uid
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
56
   * @dentry: dentry to look for fid in
ba17674fe   Latchesar Ionkov   9p: attach-per-user
57
58
   * @uid: return fid that belongs to the specified user
   * @any: if non-zero, return any fid associated with the dentry
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
59
60
   *
   */
b46425569   Eric W. Biederman   9p: Modify struct...
61
  static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
62
  {
ba17674fe   Latchesar Ionkov   9p: attach-per-user
63
  	struct p9_fid *fid, *ret;
4b8e99239   Al Viro   9p: switch to %p[dD]
64
65
66
  	p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p) uid %d any %d
  ",
  		 dentry, dentry, from_kuid(&init_user_ns, uid),
b46425569   Eric W. Biederman   9p: Modify struct...
67
  		 any);
ba17674fe   Latchesar Ionkov   9p: attach-per-user
68
  	ret = NULL;
aaeb7ecfb   Al Viro   v9fs: get rid of ...
69
70
71
  	/* we'll recheck under lock if there's anything to look in */
  	if (dentry->d_fsdata) {
  		struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata;
634095dab   Al Viro   9p: don't bother ...
72
  		spin_lock(&dentry->d_lock);
56a79b7b0   Linus Torvalds   Merge branch 'for...
73
  		hlist_for_each_entry(fid, h, dlist) {
b46425569   Eric W. Biederman   9p: Modify struct...
74
  			if (any || uid_eq(fid->uid, uid)) {
ba17674fe   Latchesar Ionkov   9p: attach-per-user
75
76
77
78
  				ret = fid;
  				break;
  			}
  		}
634095dab   Al Viro   9p: don't bother ...
79
  		spin_unlock(&dentry->d_lock);
ba17674fe   Latchesar Ionkov   9p: attach-per-user
80
  	}
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
81

ba17674fe   Latchesar Ionkov   9p: attach-per-user
82
  	return ret;
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
83
  }
3ed8491c8   Eric Van Hensbergen   [PATCH] v9fs: deb...
84

a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  /*
   * We need to hold v9ses->rename_sem as long as we hold references
   * to returned path array. Array element contain pointers to
   * dentry names.
   */
  static int build_path_from_dentry(struct v9fs_session_info *v9ses,
  				  struct dentry *dentry, char ***names)
  {
  	int n = 0, i;
  	char **wnames;
  	struct dentry *ds;
  
  	for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
  		n++;
  
  	wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
  	if (!wnames)
  		goto err_out;
  
  	for (ds = dentry, i = (n-1); i >= 0; i--, ds = ds->d_parent)
  		wnames[i] = (char  *)ds->d_name.name;
  
  	*names = wnames;
  	return n;
  err_out:
  	return -ENOMEM;
  }
7c9e592e1   Aneesh Kumar K.V   fs/9p: Make the w...
112
  static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
b46425569   Eric W. Biederman   9p: Modify struct...
113
  					       kuid_t uid, int any)
da977b2c7   Eric Van Hensbergen   [PATCH] 9p: fix s...
114
  {
a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
115
  	struct dentry *ds;
ba17674fe   Latchesar Ionkov   9p: attach-per-user
116
  	char **wnames, *uname;
7c9e592e1   Aneesh Kumar K.V   fs/9p: Make the w...
117
118
119
  	int i, n, l, clone, access;
  	struct v9fs_session_info *v9ses;
  	struct p9_fid *fid, *old_fid = NULL;
ba17674fe   Latchesar Ionkov   9p: attach-per-user
120

42869c8ad   Aneesh Kumar K.V   fs/9p: Add v9fs_d...
121
  	v9ses = v9fs_dentry2v9ses(dentry);
ba17674fe   Latchesar Ionkov   9p: attach-per-user
122
  	access = v9ses->flags & V9FS_ACCESS_MASK;
ba17674fe   Latchesar Ionkov   9p: attach-per-user
123
124
125
  	fid = v9fs_fid_find(dentry, uid, any);
  	if (fid)
  		return fid;
a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
126
127
128
129
130
131
  	/*
  	 * we don't have a matching fid. To do a TWALK we need
  	 * parent fid. We need to prevent rename when we want to
  	 * look at the parent.
  	 */
  	down_read(&v9ses->rename_sem);
ba17674fe   Latchesar Ionkov   9p: attach-per-user
132
133
  	ds = dentry->d_parent;
  	fid = v9fs_fid_find(ds, uid, any);
a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
134
135
136
137
138
139
  	if (fid) {
  		/* Found the parent fid do a lookup with that */
  		fid = p9_client_walk(fid, 1, (char **)&dentry->d_name.name, 1);
  		goto fid_out;
  	}
  	up_read(&v9ses->rename_sem);
ba17674fe   Latchesar Ionkov   9p: attach-per-user
140

a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
141
142
143
144
145
146
  	/* start from the root and try to do a lookup */
  	fid = v9fs_fid_find(dentry->d_sb->s_root, uid, any);
  	if (!fid) {
  		/* the user is not attached to the fs yet */
  		if (access == V9FS_ACCESS_SINGLE)
  			return ERR_PTR(-EPERM);
ba17674fe   Latchesar Ionkov   9p: attach-per-user
147

a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
148
149
150
151
  		if (v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses))
  				uname = NULL;
  		else
  			uname = v9ses->uname;
ba17674fe   Latchesar Ionkov   9p: attach-per-user
152

a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
153
154
155
156
  		fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
  				       v9ses->aname);
  		if (IS_ERR(fid))
  			return fid;
ba17674fe   Latchesar Ionkov   9p: attach-per-user
157

a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
158
159
160
161
  		v9fs_fid_add(dentry->d_sb->s_root, fid);
  	}
  	/* If we are root ourself just return that */
  	if (dentry->d_sb->s_root == dentry)
ba17674fe   Latchesar Ionkov   9p: attach-per-user
162
  		return fid;
a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
163
164
165
166
167
168
169
170
171
172
173
  	/*
  	 * Do a multipath walk with attached root.
  	 * When walking parent we need to make sure we
  	 * don't have a parallel rename happening
  	 */
  	down_read(&v9ses->rename_sem);
  	n  = build_path_from_dentry(v9ses, dentry, &wnames);
  	if (n < 0) {
  		fid = ERR_PTR(n);
  		goto err_out;
  	}
ba17674fe   Latchesar Ionkov   9p: attach-per-user
174
175
176
177
  	clone = 1;
  	i = 0;
  	while (i < n) {
  		l = min(n - i, P9_MAXWELEM);
a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
178
179
180
181
  		/*
  		 * We need to hold rename lock when doing a multipath
  		 * walk to ensure none of the patch component change
  		 */
ba17674fe   Latchesar Ionkov   9p: attach-per-user
182
  		fid = p9_client_walk(fid, l, &wnames[i], clone);
c55703d80   Eric Van Hensbergen   9p: fix bug in at...
183
  		if (IS_ERR(fid)) {
5b0fa207d   Aneesh Kumar K.V   fs/9p: Clunk the ...
184
185
186
187
188
189
190
191
  			if (old_fid) {
  				/*
  				 * If we fail, clunk fid which are mapping
  				 * to path component and not the last component
  				 * of the path.
  				 */
  				p9_client_clunk(old_fid);
  			}
ba17674fe   Latchesar Ionkov   9p: attach-per-user
192
  			kfree(wnames);
a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
193
  			goto err_out;
ba17674fe   Latchesar Ionkov   9p: attach-per-user
194
  		}
5b0fa207d   Aneesh Kumar K.V   fs/9p: Clunk the ...
195
  		old_fid = fid;
ba17674fe   Latchesar Ionkov   9p: attach-per-user
196
197
198
  		i += l;
  		clone = 0;
  	}
ba17674fe   Latchesar Ionkov   9p: attach-per-user
199
  	kfree(wnames);
a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
200
  fid_out:
5e608671d   Al Viro   9p: if v9fs_fid_l...
201
202
203
204
205
206
207
208
209
210
211
  	if (!IS_ERR(fid)) {
  		spin_lock(&dentry->d_lock);
  		if (d_unhashed(dentry)) {
  			spin_unlock(&dentry->d_lock);
  			p9_client_clunk(fid);
  			fid = ERR_PTR(-ENOENT);
  		} else {
  			__add_fid(dentry, fid);
  			spin_unlock(&dentry->d_lock);
  		}
  	}
a534c8d15   Aneesh Kumar K.V   fs/9p: Prevent pa...
212
213
  err_out:
  	up_read(&v9ses->rename_sem);
bd238fb43   Latchesar Ionkov   9p: Reorganizatio...
214
  	return fid;
da977b2c7   Eric Van Hensbergen   [PATCH] 9p: fix s...
215
  }
ba17674fe   Latchesar Ionkov   9p: attach-per-user
216

7c9e592e1   Aneesh Kumar K.V   fs/9p: Make the w...
217
218
219
220
221
222
223
224
225
226
227
228
  /**
   * v9fs_fid_lookup - lookup for a fid, try to walk if not found
   * @dentry: dentry to look for fid in
   *
   * Look for a fid in the specified dentry for the current user.
   * If no fid is found, try to create one walking from a fid from the parent
   * dentry (if it has one), or the root dentry. If the user haven't accessed
   * the fs yet, attach now and walk from the root.
   */
  
  struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
  {
b46425569   Eric W. Biederman   9p: Modify struct...
229
  	kuid_t uid;
7c9e592e1   Aneesh Kumar K.V   fs/9p: Make the w...
230
231
  	int  any, access;
  	struct v9fs_session_info *v9ses;
42869c8ad   Aneesh Kumar K.V   fs/9p: Add v9fs_d...
232
  	v9ses = v9fs_dentry2v9ses(dentry);
7c9e592e1   Aneesh Kumar K.V   fs/9p: Make the w...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  	access = v9ses->flags & V9FS_ACCESS_MASK;
  	switch (access) {
  	case V9FS_ACCESS_SINGLE:
  	case V9FS_ACCESS_USER:
  	case V9FS_ACCESS_CLIENT:
  		uid = current_fsuid();
  		any = 0;
  		break;
  
  	case V9FS_ACCESS_ANY:
  		uid = v9ses->uid;
  		any = 1;
  		break;
  
  	default:
b46425569   Eric W. Biederman   9p: Modify struct...
248
  		uid = INVALID_UID;
7c9e592e1   Aneesh Kumar K.V   fs/9p: Make the w...
249
250
251
252
253
  		any = 0;
  		break;
  	}
  	return v9fs_fid_lookup_with_uid(dentry, uid, any);
  }
3cf387d78   Aneesh Kumar K.V   fs/9p: Add fid to...
254
255
  struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
  {
df5d8c80f   Aneesh Kumar K.V   9p: revert tsyncf...
256
  	int err;
3cf387d78   Aneesh Kumar K.V   fs/9p: Add fid to...
257
  	struct p9_fid *fid;
7d50a29fe   Al Viro   9p: use clone_fid()
258
  	fid = clone_fid(v9fs_fid_lookup_with_uid(dentry, GLOBAL_ROOT_UID, 0));
3cf387d78   Aneesh Kumar K.V   fs/9p: Add fid to...
259
260
261
262
263
264
265
  	if (IS_ERR(fid))
  		goto error_out;
  	/*
  	 * writeback fid will only be used to write back the
  	 * dirty pages. We always request for the open fid in read-write
  	 * mode so that a partial page write which result in page
  	 * read can work.
3cf387d78   Aneesh Kumar K.V   fs/9p: Add fid to...
266
  	 */
df5d8c80f   Aneesh Kumar K.V   9p: revert tsyncf...
267
  	err = p9_client_open(fid, O_RDWR);
3cf387d78   Aneesh Kumar K.V   fs/9p: Add fid to...
268
269
270
271
272
273
274
275
  	if (err < 0) {
  		p9_client_clunk(fid);
  		fid = ERR_PTR(err);
  		goto error_out;
  	}
  error_out:
  	return fid;
  }