diff options
Diffstat (limited to 'fs/9p/fid.c')
-rw-r--r-- | fs/9p/fid.c | 157 |
1 files changed, 125 insertions, 32 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 | ||
79 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) | 77 | static 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 | ||
106 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry) | 110 | struct 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 | |||
200 | struct 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 | } | ||