aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p
diff options
context:
space:
mode:
Diffstat (limited to 'fs/9p')
-rw-r--r--fs/9p/fid.c157
-rw-r--r--fs/9p/v9fs.c67
-rw-r--r--fs/9p/v9fs.h11
-rw-r--r--fs/9p/vfs_inode.c20
4 files changed, 195 insertions, 60 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 15e05a15b575..b364da70ff28 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * V9FS FID Management 2 * V9FS FID Management
3 * 3 *
4 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
4 * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com> 5 * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -34,9 +35,9 @@
34#include "fid.h" 35#include "fid.h"
35 36
36/** 37/**
37 * v9fs_fid_insert - add a fid to a dentry 38 * v9fs_fid_add - add a fid to a dentry
39 * @dentry: dentry that the fid is being added to
38 * @fid: fid to add 40 * @fid: fid to add
39 * @dentry: dentry that it is being added to
40 * 41 *
41 */ 42 */
42 43
@@ -66,52 +67,144 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
66} 67}
67 68
68/** 69/**
69 * v9fs_fid_lookup - return a locked fid from a dentry 70 * v9fs_fid_find - retrieve a fid that belongs to the specified uid
70 * @dentry: dentry to look for fid in 71 * @dentry: dentry to look for fid in
71 * 72 * @uid: return fid that belongs to the specified user
72 * find a fid in the dentry, obtain its semaphore and return a reference to it. 73 * @any: if non-zero, return any fid associated with the dentry
73 * code calling lookup is responsible for releasing lock
74 *
75 * TODO: only match fids that have the same uid as current user
76 * 74 *
77 */ 75 */
78 76
79struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) 77static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
80{ 78{
81 struct v9fs_dentry *dent; 79 struct v9fs_dentry *dent;
82 struct p9_fid *fid; 80 struct p9_fid *fid, *ret;
83 81
84 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 82 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
85 dent = dentry->d_fsdata; 83 dentry->d_iname, dentry, uid, any);
86 if (dent) 84 dent = (struct v9fs_dentry *) dentry->d_fsdata;
87 fid = list_entry(dent->fidlist.next, struct p9_fid, dlist); 85 ret = NULL;
88 else 86 if (dent) {
89 fid = ERR_PTR(-EBADF); 87 spin_lock(&dent->lock);
88 list_for_each_entry(fid, &dent->fidlist, dlist) {
89 if (any || fid->uid == uid) {
90 ret = fid;
91 break;
92 }
93 }
94 spin_unlock(&dent->lock);
95 }
90 96
91 P9_DPRINTK(P9_DEBUG_VFS, " fid: %p\n", fid); 97 return ret;
92 return fid;
93} 98}
94 99
95/** 100/**
96 * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and 101 * v9fs_fid_lookup - lookup for a fid, try to walk if not found
97 * release it
98 * @dentry: dentry to look for fid in 102 * @dentry: dentry to look for fid in
99 * 103 *
100 * find a fid in the dentry and then clone to a new private fid 104 * Look for a fid in the specified dentry for the current user.
101 * 105 * If no fid is found, try to create one walking from a fid from the parent
102 * TODO: only match fids that have the same uid as current user 106 * dentry (if it has one), or the root dentry. If the user haven't accessed
103 * 107 * the fs yet, attach now and walk from the root.
104 */ 108 */
105 109
106struct p9_fid *v9fs_fid_clone(struct dentry *dentry) 110struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
107{ 111{
108 struct p9_fid *ofid, *fid; 112 int i, n, l, clone, any, access;
113 u32 uid;
114 struct p9_fid *fid;
115 struct dentry *d, *ds;
116 struct v9fs_session_info *v9ses;
117 char **wnames, *uname;
118
119 v9ses = v9fs_inode2v9ses(dentry->d_inode);
120 access = v9ses->flags & V9FS_ACCESS_MASK;
121 switch (access) {
122 case V9FS_ACCESS_SINGLE:
123 case V9FS_ACCESS_USER:
124 uid = current->fsuid;
125 any = 0;
126 break;
127
128 case V9FS_ACCESS_ANY:
129 uid = v9ses->uid;
130 any = 1;
131 break;
132
133 default:
134 uid = ~0;
135 any = 0;
136 break;
137 }
109 138
110 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 139 fid = v9fs_fid_find(dentry, uid, any);
111 ofid = v9fs_fid_lookup(dentry); 140 if (fid)
112 if (IS_ERR(ofid)) 141 return fid;
113 return ofid; 142
143 ds = dentry->d_parent;
144 fid = v9fs_fid_find(ds, uid, any);
145 if (!fid) { /* walk from the root */
146 n = 0;
147 for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
148 n++;
149
150 fid = v9fs_fid_find(ds, uid, any);
151 if (!fid) { /* the user is not attached to the fs yet */
152 if (access == V9FS_ACCESS_SINGLE)
153 return ERR_PTR(-EPERM);
154
155 if (v9fs_extended(v9ses))
156 uname = NULL;
157 else
158 uname = v9ses->uname;
159
160 fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
161 v9ses->aname);
162
163 if (IS_ERR(fid))
164 return fid;
165
166 v9fs_fid_add(ds, fid);
167 }
168 } else /* walk from the parent */
169 n = 1;
170
171 if (ds == dentry)
172 return fid;
173
174 wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
175 if (!wnames)
176 return ERR_PTR(-ENOMEM);
177
178 for (d = dentry, i = n; i >= 0; i--, d = d->d_parent)
179 wnames[i] = (char *) d->d_name.name;
180
181 clone = 1;
182 i = 0;
183 while (i < n) {
184 l = min(n - i, P9_MAXWELEM);
185 fid = p9_client_walk(fid, l, &wnames[i], clone);
186 if (!fid) {
187 kfree(wnames);
188 return fid;
189 }
190
191 i += l;
192 clone = 0;
193 }
114 194
115 fid = p9_client_walk(ofid, 0, NULL, 1); 195 kfree(wnames);
196 v9fs_fid_add(dentry, fid);
116 return fid; 197 return fid;
117} 198}
199
200struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
201{
202 struct p9_fid *fid, *ret;
203
204 fid = v9fs_fid_lookup(dentry);
205 if (IS_ERR(fid))
206 return fid;
207
208 ret = p9_client_walk(fid, 0, NULL, 1);
209 return ret;
210}
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 68f82be3bf37..89ee0bace41d 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -91,6 +91,8 @@ enum {
91 Opt_legacy, Opt_nodevmap, 91 Opt_legacy, Opt_nodevmap,
92 /* Cache options */ 92 /* Cache options */
93 Opt_cache_loose, 93 Opt_cache_loose,
94 /* Access options */
95 Opt_access,
94 /* Error token */ 96 /* Error token */
95 Opt_err 97 Opt_err
96}; 98};
@@ -108,6 +110,7 @@ static match_table_t tokens = {
108 {Opt_nodevmap, "nodevmap"}, 110 {Opt_nodevmap, "nodevmap"},
109 {Opt_cache_loose, "cache=loose"}, 111 {Opt_cache_loose, "cache=loose"},
110 {Opt_cache_loose, "loose"}, 112 {Opt_cache_loose, "loose"},
113 {Opt_access, "access=%s"},
111 {Opt_err, NULL} 114 {Opt_err, NULL}
112}; 115};
113 116
@@ -125,10 +128,10 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
125 char *p; 128 char *p;
126 int option; 129 int option;
127 int ret; 130 int ret;
131 char *s, *e;
128 132
129 /* setup defaults */ 133 /* setup defaults */
130 v9ses->maxdata = 8192; 134 v9ses->maxdata = 8192;
131 v9ses->flags = V9FS_EXTENDED;
132 v9ses->afid = ~0; 135 v9ses->afid = ~0;
133 v9ses->debug = 0; 136 v9ses->debug = 0;
134 v9ses->cache = 0; 137 v9ses->cache = 0;
@@ -172,10 +175,10 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
172 v9ses->trans = v9fs_match_trans(&args[0]); 175 v9ses->trans = v9fs_match_trans(&args[0]);
173 break; 176 break;
174 case Opt_uname: 177 case Opt_uname:
175 match_strcpy(v9ses->name, &args[0]); 178 match_strcpy(v9ses->uname, &args[0]);
176 break; 179 break;
177 case Opt_remotename: 180 case Opt_remotename:
178 match_strcpy(v9ses->remotename, &args[0]); 181 match_strcpy(v9ses->aname, &args[0]);
179 break; 182 break;
180 case Opt_legacy: 183 case Opt_legacy:
181 v9ses->flags &= ~V9FS_EXTENDED; 184 v9ses->flags &= ~V9FS_EXTENDED;
@@ -186,6 +189,22 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
186 case Opt_cache_loose: 189 case Opt_cache_loose:
187 v9ses->cache = CACHE_LOOSE; 190 v9ses->cache = CACHE_LOOSE;
188 break; 191 break;
192
193 case Opt_access:
194 s = match_strdup(&args[0]);
195 v9ses->flags &= ~V9FS_ACCESS_MASK;
196 if (strcmp(s, "user") == 0)
197 v9ses->flags |= V9FS_ACCESS_USER;
198 else if (strcmp(s, "any") == 0)
199 v9ses->flags |= V9FS_ACCESS_ANY;
200 else {
201 v9ses->flags |= V9FS_ACCESS_SINGLE;
202 v9ses->uid = simple_strtol(s, &e, 10);
203 if (*e != '\0')
204 v9ses->uid = ~0;
205 }
206 break;
207
189 default: 208 default:
190 continue; 209 continue;
191 } 210 }
@@ -207,21 +226,22 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
207 struct p9_trans *trans = NULL; 226 struct p9_trans *trans = NULL;
208 struct p9_fid *fid; 227 struct p9_fid *fid;
209 228
210 v9ses->name = __getname(); 229 v9ses->uname = __getname();
211 if (!v9ses->name) 230 if (!v9ses->uname)
212 return ERR_PTR(-ENOMEM); 231 return ERR_PTR(-ENOMEM);
213 232
214 v9ses->remotename = __getname(); 233 v9ses->aname = __getname();
215 if (!v9ses->remotename) { 234 if (!v9ses->aname) {
216 __putname(v9ses->name); 235 __putname(v9ses->uname);
217 return ERR_PTR(-ENOMEM); 236 return ERR_PTR(-ENOMEM);
218 } 237 }
219 238
220 strcpy(v9ses->name, V9FS_DEFUSER); 239 v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER;
221 strcpy(v9ses->remotename, V9FS_DEFANAME); 240 strcpy(v9ses->uname, V9FS_DEFUSER);
241 strcpy(v9ses->aname, V9FS_DEFANAME);
242 v9ses->uid = ~0;
222 v9ses->dfltuid = V9FS_DEFUID; 243 v9ses->dfltuid = V9FS_DEFUID;
223 v9ses->dfltgid = V9FS_DEFGID; 244 v9ses->dfltgid = V9FS_DEFGID;
224
225 v9ses->options = kstrdup(data, GFP_KERNEL); 245 v9ses->options = kstrdup(data, GFP_KERNEL);
226 v9fs_parse_options(v9ses); 246 v9fs_parse_options(v9ses);
227 247
@@ -255,8 +275,20 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
255 goto error; 275 goto error;
256 } 276 }
257 277
258 fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, 278 if (!v9ses->clnt->dotu)
259 v9ses->remotename); 279 v9ses->flags &= ~V9FS_EXTENDED;
280
281 /* for legacy mode, fall back to V9FS_ACCESS_ANY */
282 if (!v9fs_extended(v9ses) &&
283 ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
284
285 v9ses->flags &= ~V9FS_ACCESS_MASK;
286 v9ses->flags |= V9FS_ACCESS_ANY;
287 v9ses->uid = ~0;
288 }
289
290 fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0,
291 v9ses->aname);
260 if (IS_ERR(fid)) { 292 if (IS_ERR(fid)) {
261 retval = PTR_ERR(fid); 293 retval = PTR_ERR(fid);
262 fid = NULL; 294 fid = NULL;
@@ -264,6 +296,11 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
264 goto error; 296 goto error;
265 } 297 }
266 298
299 if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
300 fid->uid = v9ses->uid;
301 else
302 fid->uid = ~0;
303
267 return fid; 304 return fid;
268 305
269error: 306error:
@@ -284,8 +321,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
284 v9ses->clnt = NULL; 321 v9ses->clnt = NULL;
285 } 322 }
286 323
287 __putname(v9ses->name); 324 __putname(v9ses->uname);
288 __putname(v9ses->remotename); 325 __putname(v9ses->aname);
289 kfree(v9ses->options); 326 kfree(v9ses->options);
290} 327}
291 328
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 8e0999b3d0cc..db4b4193f2e2 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -36,10 +36,11 @@ struct v9fs_session_info {
36 unsigned int cache; /* cache mode */ 36 unsigned int cache; /* cache mode */
37 37
38 char *options; /* copy of mount options */ 38 char *options; /* copy of mount options */
39 char *name; /* user name to mount as */ 39 char *uname; /* user name to mount as */
40 char *remotename; /* name of remote hierarchy being mounted */ 40 char *aname; /* name of remote hierarchy being mounted */
41 unsigned int dfltuid; /* default uid/muid for legacy support */ 41 unsigned int dfltuid; /* default uid/muid for legacy support */
42 unsigned int dfltgid; /* default gid for legacy support */ 42 unsigned int dfltgid; /* default gid for legacy support */
43 u32 uid; /* if ACCESS_SINGLE, the uid that has access */
43 struct p9_trans_module *trans; /* 9p transport */ 44 struct p9_trans_module *trans; /* 9p transport */
44 struct p9_client *clnt; /* 9p client */ 45 struct p9_client *clnt; /* 9p client */
45 struct dentry *debugfs_dir; 46 struct dentry *debugfs_dir;
@@ -47,7 +48,11 @@ struct v9fs_session_info {
47 48
48/* session flags */ 49/* session flags */
49enum { 50enum {
50 V9FS_EXTENDED, 51 V9FS_EXTENDED = 0x01, /* 9P2000.u */
52 V9FS_ACCESS_MASK = 0x06, /* access mask */
53 V9FS_ACCESS_SINGLE = 0x02, /* only one user can access the files */
54 V9FS_ACCESS_USER = 0x04, /* attache per user */
55 V9FS_ACCESS_ANY = 0x06, /* use the same attach for all users */
51}; 56};
52 57
53/* possible values of ->cache */ 58/* possible values of ->cache */
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index f08a35d2973a..175b4d9bf3f8 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -364,7 +364,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
364 file_inode = file->d_inode; 364 file_inode = file->d_inode;
365 v9ses = v9fs_inode2v9ses(file_inode); 365 v9ses = v9fs_inode2v9ses(file_inode);
366 v9fid = v9fs_fid_clone(file); 366 v9fid = v9fs_fid_clone(file);
367 if(IS_ERR(v9fid)) 367 if (IS_ERR(v9fid))
368 return PTR_ERR(v9fid); 368 return PTR_ERR(v9fid);
369 369
370 return p9_client_remove(v9fid); 370 return p9_client_remove(v9fid);
@@ -398,7 +398,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
398 fid = NULL; 398 fid = NULL;
399 name = (char *) dentry->d_name.name; 399 name = (char *) dentry->d_name.name;
400 dfid = v9fs_fid_clone(dentry->d_parent); 400 dfid = v9fs_fid_clone(dentry->d_parent);
401 if(IS_ERR(dfid)) { 401 if (IS_ERR(dfid)) {
402 err = PTR_ERR(dfid); 402 err = PTR_ERR(dfid);
403 dfid = NULL; 403 dfid = NULL;
404 goto error; 404 goto error;
@@ -432,7 +432,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
432 goto error; 432 goto error;
433 } 433 }
434 434
435 if(v9ses->cache) 435 if (v9ses->cache)
436 dentry->d_op = &v9fs_cached_dentry_operations; 436 dentry->d_op = &v9fs_cached_dentry_operations;
437 else 437 else
438 dentry->d_op = &v9fs_dentry_operations; 438 dentry->d_op = &v9fs_dentry_operations;
@@ -593,7 +593,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
593 if (result < 0) 593 if (result < 0)
594 goto error; 594 goto error;
595 595
596 if((fid->qid.version)&&(v9ses->cache)) 596 if ((fid->qid.version) && (v9ses->cache))
597 dentry->d_op = &v9fs_cached_dentry_operations; 597 dentry->d_op = &v9fs_cached_dentry_operations;
598 else 598 else
599 dentry->d_op = &v9fs_dentry_operations; 599 dentry->d_op = &v9fs_dentry_operations;
@@ -658,17 +658,17 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
658 old_inode = old_dentry->d_inode; 658 old_inode = old_dentry->d_inode;
659 v9ses = v9fs_inode2v9ses(old_inode); 659 v9ses = v9fs_inode2v9ses(old_inode);
660 oldfid = v9fs_fid_lookup(old_dentry); 660 oldfid = v9fs_fid_lookup(old_dentry);
661 if(IS_ERR(oldfid)) 661 if (IS_ERR(oldfid))
662 return PTR_ERR(oldfid); 662 return PTR_ERR(oldfid);
663 663
664 olddirfid = v9fs_fid_clone(old_dentry->d_parent); 664 olddirfid = v9fs_fid_clone(old_dentry->d_parent);
665 if(IS_ERR(olddirfid)) { 665 if (IS_ERR(olddirfid)) {
666 retval = PTR_ERR(olddirfid); 666 retval = PTR_ERR(olddirfid);
667 goto done; 667 goto done;
668 } 668 }
669 669
670 newdirfid = v9fs_fid_clone(new_dentry->d_parent); 670 newdirfid = v9fs_fid_clone(new_dentry->d_parent);
671 if(IS_ERR(newdirfid)) { 671 if (IS_ERR(newdirfid)) {
672 retval = PTR_ERR(newdirfid); 672 retval = PTR_ERR(newdirfid);
673 goto clunk_olddir; 673 goto clunk_olddir;
674 } 674 }
@@ -682,7 +682,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
682 } 682 }
683 683
684 v9fs_blank_wstat(&wstat); 684 v9fs_blank_wstat(&wstat);
685 wstat.muid = v9ses->name; 685 wstat.muid = v9ses->uname;
686 wstat.name = (char *) new_dentry->d_name.name; 686 wstat.name = (char *) new_dentry->d_name.name;
687 retval = p9_client_wstat(oldfid, &wstat); 687 retval = p9_client_wstat(oldfid, &wstat);
688 688
@@ -887,7 +887,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
887 retval = -EPERM; 887 retval = -EPERM;
888 v9ses = v9fs_inode2v9ses(dentry->d_inode); 888 v9ses = v9fs_inode2v9ses(dentry->d_inode);
889 fid = v9fs_fid_lookup(dentry); 889 fid = v9fs_fid_lookup(dentry);
890 if(IS_ERR(fid)) 890 if (IS_ERR(fid))
891 return PTR_ERR(fid); 891 return PTR_ERR(fid);
892 892
893 if (!v9fs_extended(v9ses)) 893 if (!v9fs_extended(v9ses))
@@ -1070,7 +1070,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1070 old_dentry->d_name.name); 1070 old_dentry->d_name.name);
1071 1071
1072 oldfid = v9fs_fid_clone(old_dentry); 1072 oldfid = v9fs_fid_clone(old_dentry);
1073 if(IS_ERR(oldfid)) 1073 if (IS_ERR(oldfid))
1074 return PTR_ERR(oldfid); 1074 return PTR_ERR(oldfid);
1075 1075
1076 name = __getname(); 1076 name = __getname();