Commit 1421e98662f1cab802e0fa39d16b8dc6b874a4eb
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: fs/9p: Don't use dotl version of mknod for dotu inode operations fs/9p: Use the correct dentry operations 9p: Check for NULL fid in v9fs_dir_release() fs/9p: Fix error handling in v9fs_get_sb fs/9p, net/9p: memory leak fixes
Showing 4 changed files Inline Diff
fs/9p/vfs_dir.c
1 | /* | 1 | /* |
2 | * linux/fs/9p/vfs_dir.c | 2 | * linux/fs/9p/vfs_dir.c |
3 | * | 3 | * |
4 | * This file contains vfs directory ops for the 9P2000 protocol. | 4 | * This file contains vfs directory ops for the 9P2000 protocol. |
5 | * | 5 | * |
6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | 6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | 7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 | 10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | 11 | * as published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to: | 19 | * along with this program; if not, write to: |
20 | * Free Software Foundation | 20 | * Free Software Foundation |
21 | * 51 Franklin Street, Fifth Floor | 21 | * 51 Franklin Street, Fifth Floor |
22 | * Boston, MA 02111-1301 USA | 22 | * Boston, MA 02111-1301 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/file.h> | 29 | #include <linux/file.h> |
30 | #include <linux/stat.h> | 30 | #include <linux/stat.h> |
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
33 | #include <linux/inet.h> | 33 | #include <linux/inet.h> |
34 | #include <linux/idr.h> | 34 | #include <linux/idr.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <net/9p/9p.h> | 36 | #include <net/9p/9p.h> |
37 | #include <net/9p/client.h> | 37 | #include <net/9p/client.h> |
38 | 38 | ||
39 | #include "v9fs.h" | 39 | #include "v9fs.h" |
40 | #include "v9fs_vfs.h" | 40 | #include "v9fs_vfs.h" |
41 | #include "fid.h" | 41 | #include "fid.h" |
42 | 42 | ||
43 | /** | 43 | /** |
44 | * struct p9_rdir - readdir accounting | 44 | * struct p9_rdir - readdir accounting |
45 | * @mutex: mutex protecting readdir | 45 | * @mutex: mutex protecting readdir |
46 | * @head: start offset of current dirread buffer | 46 | * @head: start offset of current dirread buffer |
47 | * @tail: end offset of current dirread buffer | 47 | * @tail: end offset of current dirread buffer |
48 | * @buf: dirread buffer | 48 | * @buf: dirread buffer |
49 | * | 49 | * |
50 | * private structure for keeping track of readdir | 50 | * private structure for keeping track of readdir |
51 | * allocated on demand | 51 | * allocated on demand |
52 | */ | 52 | */ |
53 | 53 | ||
54 | struct p9_rdir { | 54 | struct p9_rdir { |
55 | struct mutex mutex; | 55 | struct mutex mutex; |
56 | int head; | 56 | int head; |
57 | int tail; | 57 | int tail; |
58 | uint8_t *buf; | 58 | uint8_t *buf; |
59 | }; | 59 | }; |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * dt_type - return file type | 62 | * dt_type - return file type |
63 | * @mistat: mistat structure | 63 | * @mistat: mistat structure |
64 | * | 64 | * |
65 | */ | 65 | */ |
66 | 66 | ||
67 | static inline int dt_type(struct p9_wstat *mistat) | 67 | static inline int dt_type(struct p9_wstat *mistat) |
68 | { | 68 | { |
69 | unsigned long perm = mistat->mode; | 69 | unsigned long perm = mistat->mode; |
70 | int rettype = DT_REG; | 70 | int rettype = DT_REG; |
71 | 71 | ||
72 | if (perm & P9_DMDIR) | 72 | if (perm & P9_DMDIR) |
73 | rettype = DT_DIR; | 73 | rettype = DT_DIR; |
74 | if (perm & P9_DMSYMLINK) | 74 | if (perm & P9_DMSYMLINK) |
75 | rettype = DT_LNK; | 75 | rettype = DT_LNK; |
76 | 76 | ||
77 | return rettype; | 77 | return rettype; |
78 | } | 78 | } |
79 | 79 | ||
80 | static void p9stat_init(struct p9_wstat *stbuf) | 80 | static void p9stat_init(struct p9_wstat *stbuf) |
81 | { | 81 | { |
82 | stbuf->name = NULL; | 82 | stbuf->name = NULL; |
83 | stbuf->uid = NULL; | 83 | stbuf->uid = NULL; |
84 | stbuf->gid = NULL; | 84 | stbuf->gid = NULL; |
85 | stbuf->muid = NULL; | 85 | stbuf->muid = NULL; |
86 | stbuf->extension = NULL; | 86 | stbuf->extension = NULL; |
87 | } | 87 | } |
88 | 88 | ||
89 | /** | 89 | /** |
90 | * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir | 90 | * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir |
91 | * @filp: opened file structure | 91 | * @filp: opened file structure |
92 | * @buflen: Length in bytes of buffer to allocate | 92 | * @buflen: Length in bytes of buffer to allocate |
93 | * | 93 | * |
94 | */ | 94 | */ |
95 | 95 | ||
96 | static int v9fs_alloc_rdir_buf(struct file *filp, int buflen) | 96 | static int v9fs_alloc_rdir_buf(struct file *filp, int buflen) |
97 | { | 97 | { |
98 | struct p9_rdir *rdir; | 98 | struct p9_rdir *rdir; |
99 | struct p9_fid *fid; | 99 | struct p9_fid *fid; |
100 | int err = 0; | 100 | int err = 0; |
101 | 101 | ||
102 | fid = filp->private_data; | 102 | fid = filp->private_data; |
103 | if (!fid->rdir) { | 103 | if (!fid->rdir) { |
104 | rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL); | 104 | rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL); |
105 | 105 | ||
106 | if (rdir == NULL) { | 106 | if (rdir == NULL) { |
107 | err = -ENOMEM; | 107 | err = -ENOMEM; |
108 | goto exit; | 108 | goto exit; |
109 | } | 109 | } |
110 | spin_lock(&filp->f_dentry->d_lock); | 110 | spin_lock(&filp->f_dentry->d_lock); |
111 | if (!fid->rdir) { | 111 | if (!fid->rdir) { |
112 | rdir->buf = (uint8_t *)rdir + sizeof(struct p9_rdir); | 112 | rdir->buf = (uint8_t *)rdir + sizeof(struct p9_rdir); |
113 | mutex_init(&rdir->mutex); | 113 | mutex_init(&rdir->mutex); |
114 | rdir->head = rdir->tail = 0; | 114 | rdir->head = rdir->tail = 0; |
115 | fid->rdir = (void *) rdir; | 115 | fid->rdir = (void *) rdir; |
116 | rdir = NULL; | 116 | rdir = NULL; |
117 | } | 117 | } |
118 | spin_unlock(&filp->f_dentry->d_lock); | 118 | spin_unlock(&filp->f_dentry->d_lock); |
119 | kfree(rdir); | 119 | kfree(rdir); |
120 | } | 120 | } |
121 | exit: | 121 | exit: |
122 | return err; | 122 | return err; |
123 | } | 123 | } |
124 | 124 | ||
125 | /** | 125 | /** |
126 | * v9fs_dir_readdir - read a directory | 126 | * v9fs_dir_readdir - read a directory |
127 | * @filp: opened file structure | 127 | * @filp: opened file structure |
128 | * @dirent: directory structure ??? | 128 | * @dirent: directory structure ??? |
129 | * @filldir: function to populate directory structure ??? | 129 | * @filldir: function to populate directory structure ??? |
130 | * | 130 | * |
131 | */ | 131 | */ |
132 | 132 | ||
133 | static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) | 133 | static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) |
134 | { | 134 | { |
135 | int over; | 135 | int over; |
136 | struct p9_wstat st; | 136 | struct p9_wstat st; |
137 | int err = 0; | 137 | int err = 0; |
138 | struct p9_fid *fid; | 138 | struct p9_fid *fid; |
139 | int buflen; | 139 | int buflen; |
140 | int reclen = 0; | 140 | int reclen = 0; |
141 | struct p9_rdir *rdir; | 141 | struct p9_rdir *rdir; |
142 | 142 | ||
143 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); | 143 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); |
144 | fid = filp->private_data; | 144 | fid = filp->private_data; |
145 | 145 | ||
146 | buflen = fid->clnt->msize - P9_IOHDRSZ; | 146 | buflen = fid->clnt->msize - P9_IOHDRSZ; |
147 | 147 | ||
148 | err = v9fs_alloc_rdir_buf(filp, buflen); | 148 | err = v9fs_alloc_rdir_buf(filp, buflen); |
149 | if (err) | 149 | if (err) |
150 | goto exit; | 150 | goto exit; |
151 | rdir = (struct p9_rdir *) fid->rdir; | 151 | rdir = (struct p9_rdir *) fid->rdir; |
152 | 152 | ||
153 | err = mutex_lock_interruptible(&rdir->mutex); | 153 | err = mutex_lock_interruptible(&rdir->mutex); |
154 | if (err) | 154 | if (err) |
155 | return err; | 155 | return err; |
156 | while (err == 0) { | 156 | while (err == 0) { |
157 | if (rdir->tail == rdir->head) { | 157 | if (rdir->tail == rdir->head) { |
158 | err = v9fs_file_readn(filp, rdir->buf, NULL, | 158 | err = v9fs_file_readn(filp, rdir->buf, NULL, |
159 | buflen, filp->f_pos); | 159 | buflen, filp->f_pos); |
160 | if (err <= 0) | 160 | if (err <= 0) |
161 | goto unlock_and_exit; | 161 | goto unlock_and_exit; |
162 | 162 | ||
163 | rdir->head = 0; | 163 | rdir->head = 0; |
164 | rdir->tail = err; | 164 | rdir->tail = err; |
165 | } | 165 | } |
166 | while (rdir->head < rdir->tail) { | 166 | while (rdir->head < rdir->tail) { |
167 | p9stat_init(&st); | 167 | p9stat_init(&st); |
168 | err = p9stat_read(rdir->buf + rdir->head, | 168 | err = p9stat_read(rdir->buf + rdir->head, |
169 | rdir->tail - rdir->head, &st, | 169 | rdir->tail - rdir->head, &st, |
170 | fid->clnt->proto_version); | 170 | fid->clnt->proto_version); |
171 | if (err) { | 171 | if (err) { |
172 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); | 172 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); |
173 | err = -EIO; | 173 | err = -EIO; |
174 | p9stat_free(&st); | 174 | p9stat_free(&st); |
175 | goto unlock_and_exit; | 175 | goto unlock_and_exit; |
176 | } | 176 | } |
177 | reclen = st.size+2; | 177 | reclen = st.size+2; |
178 | 178 | ||
179 | over = filldir(dirent, st.name, strlen(st.name), | 179 | over = filldir(dirent, st.name, strlen(st.name), |
180 | filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st)); | 180 | filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st)); |
181 | 181 | ||
182 | p9stat_free(&st); | 182 | p9stat_free(&st); |
183 | 183 | ||
184 | if (over) { | 184 | if (over) { |
185 | err = 0; | 185 | err = 0; |
186 | goto unlock_and_exit; | 186 | goto unlock_and_exit; |
187 | } | 187 | } |
188 | rdir->head += reclen; | 188 | rdir->head += reclen; |
189 | filp->f_pos += reclen; | 189 | filp->f_pos += reclen; |
190 | } | 190 | } |
191 | } | 191 | } |
192 | 192 | ||
193 | unlock_and_exit: | 193 | unlock_and_exit: |
194 | mutex_unlock(&rdir->mutex); | 194 | mutex_unlock(&rdir->mutex); |
195 | exit: | 195 | exit: |
196 | return err; | 196 | return err; |
197 | } | 197 | } |
198 | 198 | ||
199 | /** | 199 | /** |
200 | * v9fs_dir_readdir_dotl - read a directory | 200 | * v9fs_dir_readdir_dotl - read a directory |
201 | * @filp: opened file structure | 201 | * @filp: opened file structure |
202 | * @dirent: buffer to fill dirent structures | 202 | * @dirent: buffer to fill dirent structures |
203 | * @filldir: function to populate dirent structures | 203 | * @filldir: function to populate dirent structures |
204 | * | 204 | * |
205 | */ | 205 | */ |
206 | static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent, | 206 | static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent, |
207 | filldir_t filldir) | 207 | filldir_t filldir) |
208 | { | 208 | { |
209 | int over; | 209 | int over; |
210 | int err = 0; | 210 | int err = 0; |
211 | struct p9_fid *fid; | 211 | struct p9_fid *fid; |
212 | int buflen; | 212 | int buflen; |
213 | struct p9_rdir *rdir; | 213 | struct p9_rdir *rdir; |
214 | struct p9_dirent curdirent; | 214 | struct p9_dirent curdirent; |
215 | u64 oldoffset = 0; | 215 | u64 oldoffset = 0; |
216 | 216 | ||
217 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); | 217 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); |
218 | fid = filp->private_data; | 218 | fid = filp->private_data; |
219 | 219 | ||
220 | buflen = fid->clnt->msize - P9_READDIRHDRSZ; | 220 | buflen = fid->clnt->msize - P9_READDIRHDRSZ; |
221 | 221 | ||
222 | err = v9fs_alloc_rdir_buf(filp, buflen); | 222 | err = v9fs_alloc_rdir_buf(filp, buflen); |
223 | if (err) | 223 | if (err) |
224 | goto exit; | 224 | goto exit; |
225 | rdir = (struct p9_rdir *) fid->rdir; | 225 | rdir = (struct p9_rdir *) fid->rdir; |
226 | 226 | ||
227 | err = mutex_lock_interruptible(&rdir->mutex); | 227 | err = mutex_lock_interruptible(&rdir->mutex); |
228 | if (err) | 228 | if (err) |
229 | return err; | 229 | return err; |
230 | 230 | ||
231 | while (err == 0) { | 231 | while (err == 0) { |
232 | if (rdir->tail == rdir->head) { | 232 | if (rdir->tail == rdir->head) { |
233 | err = p9_client_readdir(fid, rdir->buf, buflen, | 233 | err = p9_client_readdir(fid, rdir->buf, buflen, |
234 | filp->f_pos); | 234 | filp->f_pos); |
235 | if (err <= 0) | 235 | if (err <= 0) |
236 | goto unlock_and_exit; | 236 | goto unlock_and_exit; |
237 | 237 | ||
238 | rdir->head = 0; | 238 | rdir->head = 0; |
239 | rdir->tail = err; | 239 | rdir->tail = err; |
240 | } | 240 | } |
241 | 241 | ||
242 | while (rdir->head < rdir->tail) { | 242 | while (rdir->head < rdir->tail) { |
243 | 243 | ||
244 | err = p9dirent_read(rdir->buf + rdir->head, | 244 | err = p9dirent_read(rdir->buf + rdir->head, |
245 | buflen - rdir->head, &curdirent, | 245 | buflen - rdir->head, &curdirent, |
246 | fid->clnt->proto_version); | 246 | fid->clnt->proto_version); |
247 | if (err < 0) { | 247 | if (err < 0) { |
248 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); | 248 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); |
249 | err = -EIO; | 249 | err = -EIO; |
250 | goto unlock_and_exit; | 250 | goto unlock_and_exit; |
251 | } | 251 | } |
252 | 252 | ||
253 | /* d_off in dirent structure tracks the offset into | 253 | /* d_off in dirent structure tracks the offset into |
254 | * the next dirent in the dir. However, filldir() | 254 | * the next dirent in the dir. However, filldir() |
255 | * expects offset into the current dirent. Hence | 255 | * expects offset into the current dirent. Hence |
256 | * while calling filldir send the offset from the | 256 | * while calling filldir send the offset from the |
257 | * previous dirent structure. | 257 | * previous dirent structure. |
258 | */ | 258 | */ |
259 | over = filldir(dirent, curdirent.d_name, | 259 | over = filldir(dirent, curdirent.d_name, |
260 | strlen(curdirent.d_name), | 260 | strlen(curdirent.d_name), |
261 | oldoffset, v9fs_qid2ino(&curdirent.qid), | 261 | oldoffset, v9fs_qid2ino(&curdirent.qid), |
262 | curdirent.d_type); | 262 | curdirent.d_type); |
263 | oldoffset = curdirent.d_off; | 263 | oldoffset = curdirent.d_off; |
264 | 264 | ||
265 | if (over) { | 265 | if (over) { |
266 | err = 0; | 266 | err = 0; |
267 | goto unlock_and_exit; | 267 | goto unlock_and_exit; |
268 | } | 268 | } |
269 | 269 | ||
270 | filp->f_pos = curdirent.d_off; | 270 | filp->f_pos = curdirent.d_off; |
271 | rdir->head += err; | 271 | rdir->head += err; |
272 | } | 272 | } |
273 | } | 273 | } |
274 | 274 | ||
275 | unlock_and_exit: | 275 | unlock_and_exit: |
276 | mutex_unlock(&rdir->mutex); | 276 | mutex_unlock(&rdir->mutex); |
277 | exit: | 277 | exit: |
278 | return err; | 278 | return err; |
279 | } | 279 | } |
280 | 280 | ||
281 | 281 | ||
282 | /** | 282 | /** |
283 | * v9fs_dir_release - close a directory | 283 | * v9fs_dir_release - close a directory |
284 | * @inode: inode of the directory | 284 | * @inode: inode of the directory |
285 | * @filp: file pointer to a directory | 285 | * @filp: file pointer to a directory |
286 | * | 286 | * |
287 | */ | 287 | */ |
288 | 288 | ||
289 | int v9fs_dir_release(struct inode *inode, struct file *filp) | 289 | int v9fs_dir_release(struct inode *inode, struct file *filp) |
290 | { | 290 | { |
291 | struct p9_fid *fid; | 291 | struct p9_fid *fid; |
292 | 292 | ||
293 | fid = filp->private_data; | 293 | fid = filp->private_data; |
294 | P9_DPRINTK(P9_DEBUG_VFS, | 294 | P9_DPRINTK(P9_DEBUG_VFS, |
295 | "inode: %p filp: %p fid: %d\n", inode, filp, fid->fid); | 295 | "v9fs_dir_release: inode: %p filp: %p fid: %d\n", |
296 | inode, filp, fid ? fid->fid : -1); | ||
296 | filemap_write_and_wait(inode->i_mapping); | 297 | filemap_write_and_wait(inode->i_mapping); |
297 | p9_client_clunk(fid); | 298 | if (fid) |
299 | p9_client_clunk(fid); | ||
298 | return 0; | 300 | return 0; |
299 | } | 301 | } |
300 | 302 | ||
301 | const struct file_operations v9fs_dir_operations = { | 303 | const struct file_operations v9fs_dir_operations = { |
302 | .read = generic_read_dir, | 304 | .read = generic_read_dir, |
303 | .llseek = generic_file_llseek, | 305 | .llseek = generic_file_llseek, |
304 | .readdir = v9fs_dir_readdir, | 306 | .readdir = v9fs_dir_readdir, |
305 | .open = v9fs_file_open, | 307 | .open = v9fs_file_open, |
306 | .release = v9fs_dir_release, | 308 | .release = v9fs_dir_release, |
307 | }; | 309 | }; |
308 | 310 | ||
309 | const struct file_operations v9fs_dir_operations_dotl = { | 311 | const struct file_operations v9fs_dir_operations_dotl = { |
310 | .read = generic_read_dir, | 312 | .read = generic_read_dir, |
311 | .llseek = generic_file_llseek, | 313 | .llseek = generic_file_llseek, |
312 | .readdir = v9fs_dir_readdir_dotl, | 314 | .readdir = v9fs_dir_readdir_dotl, |
313 | .open = v9fs_file_open, | 315 | .open = v9fs_file_open, |
314 | .release = v9fs_dir_release, | 316 | .release = v9fs_dir_release, |
315 | }; | 317 | }; |
316 | 318 |
fs/9p/vfs_inode.c
1 | /* | 1 | /* |
2 | * linux/fs/9p/vfs_inode.c | 2 | * linux/fs/9p/vfs_inode.c |
3 | * | 3 | * |
4 | * This file contains vfs inode ops for the 9P2000 protocol. | 4 | * This file contains vfs inode ops for the 9P2000 protocol. |
5 | * | 5 | * |
6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | 6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | 7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 | 10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | 11 | * as published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to: | 19 | * along with this program; if not, write to: |
20 | * Free Software Foundation | 20 | * Free Software Foundation |
21 | * 51 Franklin Street, Fifth Floor | 21 | * 51 Franklin Street, Fifth Floor |
22 | * Boston, MA 02111-1301 USA | 22 | * Boston, MA 02111-1301 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/file.h> | 29 | #include <linux/file.h> |
30 | #include <linux/pagemap.h> | 30 | #include <linux/pagemap.h> |
31 | #include <linux/stat.h> | 31 | #include <linux/stat.h> |
32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
33 | #include <linux/inet.h> | 33 | #include <linux/inet.h> |
34 | #include <linux/namei.h> | 34 | #include <linux/namei.h> |
35 | #include <linux/idr.h> | 35 | #include <linux/idr.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/xattr.h> | 38 | #include <linux/xattr.h> |
39 | #include <net/9p/9p.h> | 39 | #include <net/9p/9p.h> |
40 | #include <net/9p/client.h> | 40 | #include <net/9p/client.h> |
41 | 41 | ||
42 | #include "v9fs.h" | 42 | #include "v9fs.h" |
43 | #include "v9fs_vfs.h" | 43 | #include "v9fs_vfs.h" |
44 | #include "fid.h" | 44 | #include "fid.h" |
45 | #include "cache.h" | 45 | #include "cache.h" |
46 | #include "xattr.h" | 46 | #include "xattr.h" |
47 | 47 | ||
48 | static const struct inode_operations v9fs_dir_inode_operations; | 48 | static const struct inode_operations v9fs_dir_inode_operations; |
49 | static const struct inode_operations v9fs_dir_inode_operations_dotu; | 49 | static const struct inode_operations v9fs_dir_inode_operations_dotu; |
50 | static const struct inode_operations v9fs_dir_inode_operations_dotl; | 50 | static const struct inode_operations v9fs_dir_inode_operations_dotl; |
51 | static const struct inode_operations v9fs_file_inode_operations; | 51 | static const struct inode_operations v9fs_file_inode_operations; |
52 | static const struct inode_operations v9fs_file_inode_operations_dotl; | 52 | static const struct inode_operations v9fs_file_inode_operations_dotl; |
53 | static const struct inode_operations v9fs_symlink_inode_operations; | 53 | static const struct inode_operations v9fs_symlink_inode_operations; |
54 | static const struct inode_operations v9fs_symlink_inode_operations_dotl; | 54 | static const struct inode_operations v9fs_symlink_inode_operations_dotl; |
55 | 55 | ||
56 | /** | 56 | /** |
57 | * unixmode2p9mode - convert unix mode bits to plan 9 | 57 | * unixmode2p9mode - convert unix mode bits to plan 9 |
58 | * @v9ses: v9fs session information | 58 | * @v9ses: v9fs session information |
59 | * @mode: mode to convert | 59 | * @mode: mode to convert |
60 | * | 60 | * |
61 | */ | 61 | */ |
62 | 62 | ||
63 | static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) | 63 | static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) |
64 | { | 64 | { |
65 | int res; | 65 | int res; |
66 | res = mode & 0777; | 66 | res = mode & 0777; |
67 | if (S_ISDIR(mode)) | 67 | if (S_ISDIR(mode)) |
68 | res |= P9_DMDIR; | 68 | res |= P9_DMDIR; |
69 | if (v9fs_proto_dotu(v9ses)) { | 69 | if (v9fs_proto_dotu(v9ses)) { |
70 | if (S_ISLNK(mode)) | 70 | if (S_ISLNK(mode)) |
71 | res |= P9_DMSYMLINK; | 71 | res |= P9_DMSYMLINK; |
72 | if (v9ses->nodev == 0) { | 72 | if (v9ses->nodev == 0) { |
73 | if (S_ISSOCK(mode)) | 73 | if (S_ISSOCK(mode)) |
74 | res |= P9_DMSOCKET; | 74 | res |= P9_DMSOCKET; |
75 | if (S_ISFIFO(mode)) | 75 | if (S_ISFIFO(mode)) |
76 | res |= P9_DMNAMEDPIPE; | 76 | res |= P9_DMNAMEDPIPE; |
77 | if (S_ISBLK(mode)) | 77 | if (S_ISBLK(mode)) |
78 | res |= P9_DMDEVICE; | 78 | res |= P9_DMDEVICE; |
79 | if (S_ISCHR(mode)) | 79 | if (S_ISCHR(mode)) |
80 | res |= P9_DMDEVICE; | 80 | res |= P9_DMDEVICE; |
81 | } | 81 | } |
82 | 82 | ||
83 | if ((mode & S_ISUID) == S_ISUID) | 83 | if ((mode & S_ISUID) == S_ISUID) |
84 | res |= P9_DMSETUID; | 84 | res |= P9_DMSETUID; |
85 | if ((mode & S_ISGID) == S_ISGID) | 85 | if ((mode & S_ISGID) == S_ISGID) |
86 | res |= P9_DMSETGID; | 86 | res |= P9_DMSETGID; |
87 | if ((mode & S_ISVTX) == S_ISVTX) | 87 | if ((mode & S_ISVTX) == S_ISVTX) |
88 | res |= P9_DMSETVTX; | 88 | res |= P9_DMSETVTX; |
89 | if ((mode & P9_DMLINK)) | 89 | if ((mode & P9_DMLINK)) |
90 | res |= P9_DMLINK; | 90 | res |= P9_DMLINK; |
91 | } | 91 | } |
92 | 92 | ||
93 | return res; | 93 | return res; |
94 | } | 94 | } |
95 | 95 | ||
96 | /** | 96 | /** |
97 | * p9mode2unixmode- convert plan9 mode bits to unix mode bits | 97 | * p9mode2unixmode- convert plan9 mode bits to unix mode bits |
98 | * @v9ses: v9fs session information | 98 | * @v9ses: v9fs session information |
99 | * @mode: mode to convert | 99 | * @mode: mode to convert |
100 | * | 100 | * |
101 | */ | 101 | */ |
102 | 102 | ||
103 | static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) | 103 | static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) |
104 | { | 104 | { |
105 | int res; | 105 | int res; |
106 | 106 | ||
107 | res = mode & 0777; | 107 | res = mode & 0777; |
108 | 108 | ||
109 | if ((mode & P9_DMDIR) == P9_DMDIR) | 109 | if ((mode & P9_DMDIR) == P9_DMDIR) |
110 | res |= S_IFDIR; | 110 | res |= S_IFDIR; |
111 | else if ((mode & P9_DMSYMLINK) && (v9fs_proto_dotu(v9ses))) | 111 | else if ((mode & P9_DMSYMLINK) && (v9fs_proto_dotu(v9ses))) |
112 | res |= S_IFLNK; | 112 | res |= S_IFLNK; |
113 | else if ((mode & P9_DMSOCKET) && (v9fs_proto_dotu(v9ses)) | 113 | else if ((mode & P9_DMSOCKET) && (v9fs_proto_dotu(v9ses)) |
114 | && (v9ses->nodev == 0)) | 114 | && (v9ses->nodev == 0)) |
115 | res |= S_IFSOCK; | 115 | res |= S_IFSOCK; |
116 | else if ((mode & P9_DMNAMEDPIPE) && (v9fs_proto_dotu(v9ses)) | 116 | else if ((mode & P9_DMNAMEDPIPE) && (v9fs_proto_dotu(v9ses)) |
117 | && (v9ses->nodev == 0)) | 117 | && (v9ses->nodev == 0)) |
118 | res |= S_IFIFO; | 118 | res |= S_IFIFO; |
119 | else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses)) | 119 | else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses)) |
120 | && (v9ses->nodev == 0)) | 120 | && (v9ses->nodev == 0)) |
121 | res |= S_IFBLK; | 121 | res |= S_IFBLK; |
122 | else | 122 | else |
123 | res |= S_IFREG; | 123 | res |= S_IFREG; |
124 | 124 | ||
125 | if (v9fs_proto_dotu(v9ses)) { | 125 | if (v9fs_proto_dotu(v9ses)) { |
126 | if ((mode & P9_DMSETUID) == P9_DMSETUID) | 126 | if ((mode & P9_DMSETUID) == P9_DMSETUID) |
127 | res |= S_ISUID; | 127 | res |= S_ISUID; |
128 | 128 | ||
129 | if ((mode & P9_DMSETGID) == P9_DMSETGID) | 129 | if ((mode & P9_DMSETGID) == P9_DMSETGID) |
130 | res |= S_ISGID; | 130 | res |= S_ISGID; |
131 | 131 | ||
132 | if ((mode & P9_DMSETVTX) == P9_DMSETVTX) | 132 | if ((mode & P9_DMSETVTX) == P9_DMSETVTX) |
133 | res |= S_ISVTX; | 133 | res |= S_ISVTX; |
134 | } | 134 | } |
135 | 135 | ||
136 | return res; | 136 | return res; |
137 | } | 137 | } |
138 | 138 | ||
139 | /** | 139 | /** |
140 | * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits | 140 | * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits |
141 | * @uflags: flags to convert | 141 | * @uflags: flags to convert |
142 | * @extended: if .u extensions are active | 142 | * @extended: if .u extensions are active |
143 | */ | 143 | */ |
144 | 144 | ||
145 | int v9fs_uflags2omode(int uflags, int extended) | 145 | int v9fs_uflags2omode(int uflags, int extended) |
146 | { | 146 | { |
147 | int ret; | 147 | int ret; |
148 | 148 | ||
149 | ret = 0; | 149 | ret = 0; |
150 | switch (uflags&3) { | 150 | switch (uflags&3) { |
151 | default: | 151 | default: |
152 | case O_RDONLY: | 152 | case O_RDONLY: |
153 | ret = P9_OREAD; | 153 | ret = P9_OREAD; |
154 | break; | 154 | break; |
155 | 155 | ||
156 | case O_WRONLY: | 156 | case O_WRONLY: |
157 | ret = P9_OWRITE; | 157 | ret = P9_OWRITE; |
158 | break; | 158 | break; |
159 | 159 | ||
160 | case O_RDWR: | 160 | case O_RDWR: |
161 | ret = P9_ORDWR; | 161 | ret = P9_ORDWR; |
162 | break; | 162 | break; |
163 | } | 163 | } |
164 | 164 | ||
165 | if (uflags & O_TRUNC) | 165 | if (uflags & O_TRUNC) |
166 | ret |= P9_OTRUNC; | 166 | ret |= P9_OTRUNC; |
167 | 167 | ||
168 | if (extended) { | 168 | if (extended) { |
169 | if (uflags & O_EXCL) | 169 | if (uflags & O_EXCL) |
170 | ret |= P9_OEXCL; | 170 | ret |= P9_OEXCL; |
171 | 171 | ||
172 | if (uflags & O_APPEND) | 172 | if (uflags & O_APPEND) |
173 | ret |= P9_OAPPEND; | 173 | ret |= P9_OAPPEND; |
174 | } | 174 | } |
175 | 175 | ||
176 | return ret; | 176 | return ret; |
177 | } | 177 | } |
178 | 178 | ||
179 | /** | 179 | /** |
180 | * v9fs_blank_wstat - helper function to setup a 9P stat structure | 180 | * v9fs_blank_wstat - helper function to setup a 9P stat structure |
181 | * @wstat: structure to initialize | 181 | * @wstat: structure to initialize |
182 | * | 182 | * |
183 | */ | 183 | */ |
184 | 184 | ||
185 | void | 185 | void |
186 | v9fs_blank_wstat(struct p9_wstat *wstat) | 186 | v9fs_blank_wstat(struct p9_wstat *wstat) |
187 | { | 187 | { |
188 | wstat->type = ~0; | 188 | wstat->type = ~0; |
189 | wstat->dev = ~0; | 189 | wstat->dev = ~0; |
190 | wstat->qid.type = ~0; | 190 | wstat->qid.type = ~0; |
191 | wstat->qid.version = ~0; | 191 | wstat->qid.version = ~0; |
192 | *((long long *)&wstat->qid.path) = ~0; | 192 | *((long long *)&wstat->qid.path) = ~0; |
193 | wstat->mode = ~0; | 193 | wstat->mode = ~0; |
194 | wstat->atime = ~0; | 194 | wstat->atime = ~0; |
195 | wstat->mtime = ~0; | 195 | wstat->mtime = ~0; |
196 | wstat->length = ~0; | 196 | wstat->length = ~0; |
197 | wstat->name = NULL; | 197 | wstat->name = NULL; |
198 | wstat->uid = NULL; | 198 | wstat->uid = NULL; |
199 | wstat->gid = NULL; | 199 | wstat->gid = NULL; |
200 | wstat->muid = NULL; | 200 | wstat->muid = NULL; |
201 | wstat->n_uid = ~0; | 201 | wstat->n_uid = ~0; |
202 | wstat->n_gid = ~0; | 202 | wstat->n_gid = ~0; |
203 | wstat->n_muid = ~0; | 203 | wstat->n_muid = ~0; |
204 | wstat->extension = NULL; | 204 | wstat->extension = NULL; |
205 | } | 205 | } |
206 | 206 | ||
207 | #ifdef CONFIG_9P_FSCACHE | 207 | #ifdef CONFIG_9P_FSCACHE |
208 | /** | 208 | /** |
209 | * v9fs_alloc_inode - helper function to allocate an inode | 209 | * v9fs_alloc_inode - helper function to allocate an inode |
210 | * This callback is executed before setting up the inode so that we | 210 | * This callback is executed before setting up the inode so that we |
211 | * can associate a vcookie with each inode. | 211 | * can associate a vcookie with each inode. |
212 | * | 212 | * |
213 | */ | 213 | */ |
214 | 214 | ||
215 | struct inode *v9fs_alloc_inode(struct super_block *sb) | 215 | struct inode *v9fs_alloc_inode(struct super_block *sb) |
216 | { | 216 | { |
217 | struct v9fs_cookie *vcookie; | 217 | struct v9fs_cookie *vcookie; |
218 | vcookie = (struct v9fs_cookie *)kmem_cache_alloc(vcookie_cache, | 218 | vcookie = (struct v9fs_cookie *)kmem_cache_alloc(vcookie_cache, |
219 | GFP_KERNEL); | 219 | GFP_KERNEL); |
220 | if (!vcookie) | 220 | if (!vcookie) |
221 | return NULL; | 221 | return NULL; |
222 | 222 | ||
223 | vcookie->fscache = NULL; | 223 | vcookie->fscache = NULL; |
224 | vcookie->qid = NULL; | 224 | vcookie->qid = NULL; |
225 | spin_lock_init(&vcookie->lock); | 225 | spin_lock_init(&vcookie->lock); |
226 | return &vcookie->inode; | 226 | return &vcookie->inode; |
227 | } | 227 | } |
228 | 228 | ||
229 | /** | 229 | /** |
230 | * v9fs_destroy_inode - destroy an inode | 230 | * v9fs_destroy_inode - destroy an inode |
231 | * | 231 | * |
232 | */ | 232 | */ |
233 | 233 | ||
234 | void v9fs_destroy_inode(struct inode *inode) | 234 | void v9fs_destroy_inode(struct inode *inode) |
235 | { | 235 | { |
236 | kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode)); | 236 | kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode)); |
237 | } | 237 | } |
238 | #endif | 238 | #endif |
239 | 239 | ||
240 | /** | 240 | /** |
241 | * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a | 241 | * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a |
242 | * new file system object. This checks the S_ISGID to determine the owning | 242 | * new file system object. This checks the S_ISGID to determine the owning |
243 | * group of the new file system object. | 243 | * group of the new file system object. |
244 | */ | 244 | */ |
245 | 245 | ||
246 | static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode) | 246 | static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode) |
247 | { | 247 | { |
248 | BUG_ON(dir_inode == NULL); | 248 | BUG_ON(dir_inode == NULL); |
249 | 249 | ||
250 | if (dir_inode->i_mode & S_ISGID) { | 250 | if (dir_inode->i_mode & S_ISGID) { |
251 | /* set_gid bit is set.*/ | 251 | /* set_gid bit is set.*/ |
252 | return dir_inode->i_gid; | 252 | return dir_inode->i_gid; |
253 | } | 253 | } |
254 | return current_fsgid(); | 254 | return current_fsgid(); |
255 | } | 255 | } |
256 | 256 | ||
257 | /** | 257 | /** |
258 | * v9fs_dentry_from_dir_inode - helper function to get the dentry from | 258 | * v9fs_dentry_from_dir_inode - helper function to get the dentry from |
259 | * dir inode. | 259 | * dir inode. |
260 | * | 260 | * |
261 | */ | 261 | */ |
262 | 262 | ||
263 | static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode) | 263 | static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode) |
264 | { | 264 | { |
265 | struct dentry *dentry; | 265 | struct dentry *dentry; |
266 | 266 | ||
267 | spin_lock(&dcache_lock); | 267 | spin_lock(&dcache_lock); |
268 | /* Directory should have only one entry. */ | 268 | /* Directory should have only one entry. */ |
269 | BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry)); | 269 | BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry)); |
270 | dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); | 270 | dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); |
271 | spin_unlock(&dcache_lock); | 271 | spin_unlock(&dcache_lock); |
272 | return dentry; | 272 | return dentry; |
273 | } | 273 | } |
274 | 274 | ||
275 | /** | 275 | /** |
276 | * v9fs_get_inode - helper function to setup an inode | 276 | * v9fs_get_inode - helper function to setup an inode |
277 | * @sb: superblock | 277 | * @sb: superblock |
278 | * @mode: mode to setup inode with | 278 | * @mode: mode to setup inode with |
279 | * | 279 | * |
280 | */ | 280 | */ |
281 | 281 | ||
282 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) | 282 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) |
283 | { | 283 | { |
284 | int err; | 284 | int err; |
285 | struct inode *inode; | 285 | struct inode *inode; |
286 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 286 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
287 | 287 | ||
288 | P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); | 288 | P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); |
289 | 289 | ||
290 | inode = new_inode(sb); | 290 | inode = new_inode(sb); |
291 | if (!inode) { | 291 | if (!inode) { |
292 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); | 292 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); |
293 | return ERR_PTR(-ENOMEM); | 293 | return ERR_PTR(-ENOMEM); |
294 | } | 294 | } |
295 | 295 | ||
296 | inode_init_owner(inode, NULL, mode); | 296 | inode_init_owner(inode, NULL, mode); |
297 | inode->i_blocks = 0; | 297 | inode->i_blocks = 0; |
298 | inode->i_rdev = 0; | 298 | inode->i_rdev = 0; |
299 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 299 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
300 | inode->i_mapping->a_ops = &v9fs_addr_operations; | 300 | inode->i_mapping->a_ops = &v9fs_addr_operations; |
301 | 301 | ||
302 | switch (mode & S_IFMT) { | 302 | switch (mode & S_IFMT) { |
303 | case S_IFIFO: | 303 | case S_IFIFO: |
304 | case S_IFBLK: | 304 | case S_IFBLK: |
305 | case S_IFCHR: | 305 | case S_IFCHR: |
306 | case S_IFSOCK: | 306 | case S_IFSOCK: |
307 | if (v9fs_proto_dotl(v9ses)) { | 307 | if (v9fs_proto_dotl(v9ses)) { |
308 | inode->i_op = &v9fs_file_inode_operations_dotl; | 308 | inode->i_op = &v9fs_file_inode_operations_dotl; |
309 | inode->i_fop = &v9fs_file_operations_dotl; | 309 | inode->i_fop = &v9fs_file_operations_dotl; |
310 | } else if (v9fs_proto_dotu(v9ses)) { | 310 | } else if (v9fs_proto_dotu(v9ses)) { |
311 | inode->i_op = &v9fs_file_inode_operations; | 311 | inode->i_op = &v9fs_file_inode_operations; |
312 | inode->i_fop = &v9fs_file_operations; | 312 | inode->i_fop = &v9fs_file_operations; |
313 | } else { | 313 | } else { |
314 | P9_DPRINTK(P9_DEBUG_ERROR, | 314 | P9_DPRINTK(P9_DEBUG_ERROR, |
315 | "special files without extended mode\n"); | 315 | "special files without extended mode\n"); |
316 | err = -EINVAL; | 316 | err = -EINVAL; |
317 | goto error; | 317 | goto error; |
318 | } | 318 | } |
319 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | 319 | init_special_inode(inode, inode->i_mode, inode->i_rdev); |
320 | break; | 320 | break; |
321 | case S_IFREG: | 321 | case S_IFREG: |
322 | if (v9fs_proto_dotl(v9ses)) { | 322 | if (v9fs_proto_dotl(v9ses)) { |
323 | inode->i_op = &v9fs_file_inode_operations_dotl; | 323 | inode->i_op = &v9fs_file_inode_operations_dotl; |
324 | inode->i_fop = &v9fs_file_operations_dotl; | 324 | inode->i_fop = &v9fs_file_operations_dotl; |
325 | } else { | 325 | } else { |
326 | inode->i_op = &v9fs_file_inode_operations; | 326 | inode->i_op = &v9fs_file_inode_operations; |
327 | inode->i_fop = &v9fs_file_operations; | 327 | inode->i_fop = &v9fs_file_operations; |
328 | } | 328 | } |
329 | 329 | ||
330 | break; | 330 | break; |
331 | 331 | ||
332 | case S_IFLNK: | 332 | case S_IFLNK: |
333 | if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) { | 333 | if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) { |
334 | P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with " | 334 | P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with " |
335 | "legacy protocol.\n"); | 335 | "legacy protocol.\n"); |
336 | err = -EINVAL; | 336 | err = -EINVAL; |
337 | goto error; | 337 | goto error; |
338 | } | 338 | } |
339 | 339 | ||
340 | if (v9fs_proto_dotl(v9ses)) | 340 | if (v9fs_proto_dotl(v9ses)) |
341 | inode->i_op = &v9fs_symlink_inode_operations_dotl; | 341 | inode->i_op = &v9fs_symlink_inode_operations_dotl; |
342 | else | 342 | else |
343 | inode->i_op = &v9fs_symlink_inode_operations; | 343 | inode->i_op = &v9fs_symlink_inode_operations; |
344 | 344 | ||
345 | break; | 345 | break; |
346 | case S_IFDIR: | 346 | case S_IFDIR: |
347 | inc_nlink(inode); | 347 | inc_nlink(inode); |
348 | if (v9fs_proto_dotl(v9ses)) | 348 | if (v9fs_proto_dotl(v9ses)) |
349 | inode->i_op = &v9fs_dir_inode_operations_dotl; | 349 | inode->i_op = &v9fs_dir_inode_operations_dotl; |
350 | else if (v9fs_proto_dotu(v9ses)) | 350 | else if (v9fs_proto_dotu(v9ses)) |
351 | inode->i_op = &v9fs_dir_inode_operations_dotu; | 351 | inode->i_op = &v9fs_dir_inode_operations_dotu; |
352 | else | 352 | else |
353 | inode->i_op = &v9fs_dir_inode_operations; | 353 | inode->i_op = &v9fs_dir_inode_operations; |
354 | 354 | ||
355 | if (v9fs_proto_dotl(v9ses)) | 355 | if (v9fs_proto_dotl(v9ses)) |
356 | inode->i_fop = &v9fs_dir_operations_dotl; | 356 | inode->i_fop = &v9fs_dir_operations_dotl; |
357 | else | 357 | else |
358 | inode->i_fop = &v9fs_dir_operations; | 358 | inode->i_fop = &v9fs_dir_operations; |
359 | 359 | ||
360 | break; | 360 | break; |
361 | default: | 361 | default: |
362 | P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", | 362 | P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", |
363 | mode, mode & S_IFMT); | 363 | mode, mode & S_IFMT); |
364 | err = -EINVAL; | 364 | err = -EINVAL; |
365 | goto error; | 365 | goto error; |
366 | } | 366 | } |
367 | 367 | ||
368 | return inode; | 368 | return inode; |
369 | 369 | ||
370 | error: | 370 | error: |
371 | iput(inode); | 371 | iput(inode); |
372 | return ERR_PTR(err); | 372 | return ERR_PTR(err); |
373 | } | 373 | } |
374 | 374 | ||
375 | /* | 375 | /* |
376 | static struct v9fs_fid* | 376 | static struct v9fs_fid* |
377 | v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) | 377 | v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) |
378 | { | 378 | { |
379 | int err; | 379 | int err; |
380 | int nfid; | 380 | int nfid; |
381 | struct v9fs_fid *ret; | 381 | struct v9fs_fid *ret; |
382 | struct v9fs_fcall *fcall; | 382 | struct v9fs_fcall *fcall; |
383 | 383 | ||
384 | nfid = v9fs_get_idpool(&v9ses->fidpool); | 384 | nfid = v9fs_get_idpool(&v9ses->fidpool); |
385 | if (nfid < 0) { | 385 | if (nfid < 0) { |
386 | eprintk(KERN_WARNING, "no free fids available\n"); | 386 | eprintk(KERN_WARNING, "no free fids available\n"); |
387 | return ERR_PTR(-ENOSPC); | 387 | return ERR_PTR(-ENOSPC); |
388 | } | 388 | } |
389 | 389 | ||
390 | err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, | 390 | err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, |
391 | &fcall); | 391 | &fcall); |
392 | 392 | ||
393 | if (err < 0) { | 393 | if (err < 0) { |
394 | if (fcall && fcall->id == RWALK) | 394 | if (fcall && fcall->id == RWALK) |
395 | goto clunk_fid; | 395 | goto clunk_fid; |
396 | 396 | ||
397 | PRINT_FCALL_ERROR("walk error", fcall); | 397 | PRINT_FCALL_ERROR("walk error", fcall); |
398 | v9fs_put_idpool(nfid, &v9ses->fidpool); | 398 | v9fs_put_idpool(nfid, &v9ses->fidpool); |
399 | goto error; | 399 | goto error; |
400 | } | 400 | } |
401 | 401 | ||
402 | kfree(fcall); | 402 | kfree(fcall); |
403 | fcall = NULL; | 403 | fcall = NULL; |
404 | ret = v9fs_fid_create(v9ses, nfid); | 404 | ret = v9fs_fid_create(v9ses, nfid); |
405 | if (!ret) { | 405 | if (!ret) { |
406 | err = -ENOMEM; | 406 | err = -ENOMEM; |
407 | goto clunk_fid; | 407 | goto clunk_fid; |
408 | } | 408 | } |
409 | 409 | ||
410 | err = v9fs_fid_insert(ret, dentry); | 410 | err = v9fs_fid_insert(ret, dentry); |
411 | if (err < 0) { | 411 | if (err < 0) { |
412 | v9fs_fid_destroy(ret); | 412 | v9fs_fid_destroy(ret); |
413 | goto clunk_fid; | 413 | goto clunk_fid; |
414 | } | 414 | } |
415 | 415 | ||
416 | return ret; | 416 | return ret; |
417 | 417 | ||
418 | clunk_fid: | 418 | clunk_fid: |
419 | v9fs_t_clunk(v9ses, nfid); | 419 | v9fs_t_clunk(v9ses, nfid); |
420 | 420 | ||
421 | error: | 421 | error: |
422 | kfree(fcall); | 422 | kfree(fcall); |
423 | return ERR_PTR(err); | 423 | return ERR_PTR(err); |
424 | } | 424 | } |
425 | */ | 425 | */ |
426 | 426 | ||
427 | 427 | ||
428 | /** | 428 | /** |
429 | * v9fs_clear_inode - release an inode | 429 | * v9fs_clear_inode - release an inode |
430 | * @inode: inode to release | 430 | * @inode: inode to release |
431 | * | 431 | * |
432 | */ | 432 | */ |
433 | void v9fs_evict_inode(struct inode *inode) | 433 | void v9fs_evict_inode(struct inode *inode) |
434 | { | 434 | { |
435 | truncate_inode_pages(inode->i_mapping, 0); | 435 | truncate_inode_pages(inode->i_mapping, 0); |
436 | end_writeback(inode); | 436 | end_writeback(inode); |
437 | filemap_fdatawrite(inode->i_mapping); | 437 | filemap_fdatawrite(inode->i_mapping); |
438 | 438 | ||
439 | #ifdef CONFIG_9P_FSCACHE | 439 | #ifdef CONFIG_9P_FSCACHE |
440 | v9fs_cache_inode_put_cookie(inode); | 440 | v9fs_cache_inode_put_cookie(inode); |
441 | #endif | 441 | #endif |
442 | } | 442 | } |
443 | 443 | ||
444 | static struct inode * | 444 | static struct inode * |
445 | v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid, | 445 | v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid, |
446 | struct super_block *sb) | 446 | struct super_block *sb) |
447 | { | 447 | { |
448 | int err, umode; | 448 | int err, umode; |
449 | struct inode *ret = NULL; | 449 | struct inode *ret = NULL; |
450 | struct p9_wstat *st; | 450 | struct p9_wstat *st; |
451 | 451 | ||
452 | st = p9_client_stat(fid); | 452 | st = p9_client_stat(fid); |
453 | if (IS_ERR(st)) | 453 | if (IS_ERR(st)) |
454 | return ERR_CAST(st); | 454 | return ERR_CAST(st); |
455 | 455 | ||
456 | umode = p9mode2unixmode(v9ses, st->mode); | 456 | umode = p9mode2unixmode(v9ses, st->mode); |
457 | ret = v9fs_get_inode(sb, umode); | 457 | ret = v9fs_get_inode(sb, umode); |
458 | if (IS_ERR(ret)) { | 458 | if (IS_ERR(ret)) { |
459 | err = PTR_ERR(ret); | 459 | err = PTR_ERR(ret); |
460 | goto error; | 460 | goto error; |
461 | } | 461 | } |
462 | 462 | ||
463 | v9fs_stat2inode(st, ret, sb); | 463 | v9fs_stat2inode(st, ret, sb); |
464 | ret->i_ino = v9fs_qid2ino(&st->qid); | 464 | ret->i_ino = v9fs_qid2ino(&st->qid); |
465 | 465 | ||
466 | #ifdef CONFIG_9P_FSCACHE | 466 | #ifdef CONFIG_9P_FSCACHE |
467 | v9fs_vcookie_set_qid(ret, &st->qid); | 467 | v9fs_vcookie_set_qid(ret, &st->qid); |
468 | v9fs_cache_inode_get_cookie(ret); | 468 | v9fs_cache_inode_get_cookie(ret); |
469 | #endif | 469 | #endif |
470 | p9stat_free(st); | 470 | p9stat_free(st); |
471 | kfree(st); | 471 | kfree(st); |
472 | return ret; | 472 | return ret; |
473 | error: | 473 | error: |
474 | p9stat_free(st); | 474 | p9stat_free(st); |
475 | kfree(st); | 475 | kfree(st); |
476 | return ERR_PTR(err); | 476 | return ERR_PTR(err); |
477 | } | 477 | } |
478 | 478 | ||
479 | static struct inode * | 479 | static struct inode * |
480 | v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, | 480 | v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, |
481 | struct super_block *sb) | 481 | struct super_block *sb) |
482 | { | 482 | { |
483 | struct inode *ret = NULL; | 483 | struct inode *ret = NULL; |
484 | int err; | 484 | int err; |
485 | struct p9_stat_dotl *st; | 485 | struct p9_stat_dotl *st; |
486 | 486 | ||
487 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); | 487 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); |
488 | if (IS_ERR(st)) | 488 | if (IS_ERR(st)) |
489 | return ERR_CAST(st); | 489 | return ERR_CAST(st); |
490 | 490 | ||
491 | ret = v9fs_get_inode(sb, st->st_mode); | 491 | ret = v9fs_get_inode(sb, st->st_mode); |
492 | if (IS_ERR(ret)) { | 492 | if (IS_ERR(ret)) { |
493 | err = PTR_ERR(ret); | 493 | err = PTR_ERR(ret); |
494 | goto error; | 494 | goto error; |
495 | } | 495 | } |
496 | 496 | ||
497 | v9fs_stat2inode_dotl(st, ret); | 497 | v9fs_stat2inode_dotl(st, ret); |
498 | ret->i_ino = v9fs_qid2ino(&st->qid); | 498 | ret->i_ino = v9fs_qid2ino(&st->qid); |
499 | #ifdef CONFIG_9P_FSCACHE | 499 | #ifdef CONFIG_9P_FSCACHE |
500 | v9fs_vcookie_set_qid(ret, &st->qid); | 500 | v9fs_vcookie_set_qid(ret, &st->qid); |
501 | v9fs_cache_inode_get_cookie(ret); | 501 | v9fs_cache_inode_get_cookie(ret); |
502 | #endif | 502 | #endif |
503 | kfree(st); | 503 | kfree(st); |
504 | return ret; | 504 | return ret; |
505 | error: | 505 | error: |
506 | kfree(st); | 506 | kfree(st); |
507 | return ERR_PTR(err); | 507 | return ERR_PTR(err); |
508 | } | 508 | } |
509 | 509 | ||
510 | /** | 510 | /** |
511 | * v9fs_inode_from_fid - Helper routine to populate an inode by | 511 | * v9fs_inode_from_fid - Helper routine to populate an inode by |
512 | * issuing a attribute request | 512 | * issuing a attribute request |
513 | * @v9ses: session information | 513 | * @v9ses: session information |
514 | * @fid: fid to issue attribute request for | 514 | * @fid: fid to issue attribute request for |
515 | * @sb: superblock on which to create inode | 515 | * @sb: superblock on which to create inode |
516 | * | 516 | * |
517 | */ | 517 | */ |
518 | static inline struct inode * | 518 | static inline struct inode * |
519 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, | 519 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, |
520 | struct super_block *sb) | 520 | struct super_block *sb) |
521 | { | 521 | { |
522 | if (v9fs_proto_dotl(v9ses)) | 522 | if (v9fs_proto_dotl(v9ses)) |
523 | return v9fs_inode_dotl(v9ses, fid, sb); | 523 | return v9fs_inode_dotl(v9ses, fid, sb); |
524 | else | 524 | else |
525 | return v9fs_inode(v9ses, fid, sb); | 525 | return v9fs_inode(v9ses, fid, sb); |
526 | } | 526 | } |
527 | 527 | ||
528 | /** | 528 | /** |
529 | * v9fs_remove - helper function to remove files and directories | 529 | * v9fs_remove - helper function to remove files and directories |
530 | * @dir: directory inode that is being deleted | 530 | * @dir: directory inode that is being deleted |
531 | * @file: dentry that is being deleted | 531 | * @file: dentry that is being deleted |
532 | * @rmdir: removing a directory | 532 | * @rmdir: removing a directory |
533 | * | 533 | * |
534 | */ | 534 | */ |
535 | 535 | ||
536 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | 536 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) |
537 | { | 537 | { |
538 | int retval; | 538 | int retval; |
539 | struct inode *file_inode; | 539 | struct inode *file_inode; |
540 | struct p9_fid *v9fid; | 540 | struct p9_fid *v9fid; |
541 | 541 | ||
542 | P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, | 542 | P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, |
543 | rmdir); | 543 | rmdir); |
544 | 544 | ||
545 | file_inode = file->d_inode; | 545 | file_inode = file->d_inode; |
546 | v9fid = v9fs_fid_clone(file); | 546 | v9fid = v9fs_fid_clone(file); |
547 | if (IS_ERR(v9fid)) | 547 | if (IS_ERR(v9fid)) |
548 | return PTR_ERR(v9fid); | 548 | return PTR_ERR(v9fid); |
549 | 549 | ||
550 | retval = p9_client_remove(v9fid); | 550 | retval = p9_client_remove(v9fid); |
551 | if (!retval) | 551 | if (!retval) |
552 | drop_nlink(file_inode); | 552 | drop_nlink(file_inode); |
553 | return retval; | 553 | return retval; |
554 | } | 554 | } |
555 | 555 | ||
556 | static int | 556 | static int |
557 | v9fs_open_created(struct inode *inode, struct file *file) | 557 | v9fs_open_created(struct inode *inode, struct file *file) |
558 | { | 558 | { |
559 | return 0; | 559 | return 0; |
560 | } | 560 | } |
561 | 561 | ||
562 | 562 | ||
563 | /** | 563 | /** |
564 | * v9fs_create - Create a file | 564 | * v9fs_create - Create a file |
565 | * @v9ses: session information | 565 | * @v9ses: session information |
566 | * @dir: directory that dentry is being created in | 566 | * @dir: directory that dentry is being created in |
567 | * @dentry: dentry that is being created | 567 | * @dentry: dentry that is being created |
568 | * @extension: 9p2000.u extension string to support devices, etc. | 568 | * @extension: 9p2000.u extension string to support devices, etc. |
569 | * @perm: create permissions | 569 | * @perm: create permissions |
570 | * @mode: open mode | 570 | * @mode: open mode |
571 | * | 571 | * |
572 | */ | 572 | */ |
573 | static struct p9_fid * | 573 | static struct p9_fid * |
574 | v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, | 574 | v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, |
575 | struct dentry *dentry, char *extension, u32 perm, u8 mode) | 575 | struct dentry *dentry, char *extension, u32 perm, u8 mode) |
576 | { | 576 | { |
577 | int err; | 577 | int err; |
578 | char *name; | 578 | char *name; |
579 | struct p9_fid *dfid, *ofid, *fid; | 579 | struct p9_fid *dfid, *ofid, *fid; |
580 | struct inode *inode; | 580 | struct inode *inode; |
581 | 581 | ||
582 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); | 582 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); |
583 | 583 | ||
584 | err = 0; | 584 | err = 0; |
585 | ofid = NULL; | 585 | ofid = NULL; |
586 | fid = NULL; | 586 | fid = NULL; |
587 | name = (char *) dentry->d_name.name; | 587 | name = (char *) dentry->d_name.name; |
588 | dfid = v9fs_fid_lookup(dentry->d_parent); | 588 | dfid = v9fs_fid_lookup(dentry->d_parent); |
589 | if (IS_ERR(dfid)) { | 589 | if (IS_ERR(dfid)) { |
590 | err = PTR_ERR(dfid); | 590 | err = PTR_ERR(dfid); |
591 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 591 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); |
592 | return ERR_PTR(err); | 592 | return ERR_PTR(err); |
593 | } | 593 | } |
594 | 594 | ||
595 | /* clone a fid to use for creation */ | 595 | /* clone a fid to use for creation */ |
596 | ofid = p9_client_walk(dfid, 0, NULL, 1); | 596 | ofid = p9_client_walk(dfid, 0, NULL, 1); |
597 | if (IS_ERR(ofid)) { | 597 | if (IS_ERR(ofid)) { |
598 | err = PTR_ERR(ofid); | 598 | err = PTR_ERR(ofid); |
599 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | 599 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); |
600 | return ERR_PTR(err); | 600 | return ERR_PTR(err); |
601 | } | 601 | } |
602 | 602 | ||
603 | err = p9_client_fcreate(ofid, name, perm, mode, extension); | 603 | err = p9_client_fcreate(ofid, name, perm, mode, extension); |
604 | if (err < 0) { | 604 | if (err < 0) { |
605 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err); | 605 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err); |
606 | goto error; | 606 | goto error; |
607 | } | 607 | } |
608 | 608 | ||
609 | /* now walk from the parent so we can get unopened fid */ | 609 | /* now walk from the parent so we can get unopened fid */ |
610 | fid = p9_client_walk(dfid, 1, &name, 1); | 610 | fid = p9_client_walk(dfid, 1, &name, 1); |
611 | if (IS_ERR(fid)) { | 611 | if (IS_ERR(fid)) { |
612 | err = PTR_ERR(fid); | 612 | err = PTR_ERR(fid); |
613 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | 613 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); |
614 | fid = NULL; | 614 | fid = NULL; |
615 | goto error; | 615 | goto error; |
616 | } | 616 | } |
617 | 617 | ||
618 | /* instantiate inode and assign the unopened fid to the dentry */ | 618 | /* instantiate inode and assign the unopened fid to the dentry */ |
619 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 619 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); |
620 | if (IS_ERR(inode)) { | 620 | if (IS_ERR(inode)) { |
621 | err = PTR_ERR(inode); | 621 | err = PTR_ERR(inode); |
622 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); | 622 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); |
623 | goto error; | 623 | goto error; |
624 | } | 624 | } |
625 | 625 | ||
626 | if (v9ses->cache) | 626 | if (v9ses->cache) |
627 | dentry->d_op = &v9fs_cached_dentry_operations; | 627 | dentry->d_op = &v9fs_cached_dentry_operations; |
628 | else | 628 | else |
629 | dentry->d_op = &v9fs_dentry_operations; | 629 | dentry->d_op = &v9fs_dentry_operations; |
630 | 630 | ||
631 | d_instantiate(dentry, inode); | 631 | d_instantiate(dentry, inode); |
632 | err = v9fs_fid_add(dentry, fid); | 632 | err = v9fs_fid_add(dentry, fid); |
633 | if (err < 0) | 633 | if (err < 0) |
634 | goto error; | 634 | goto error; |
635 | 635 | ||
636 | return ofid; | 636 | return ofid; |
637 | 637 | ||
638 | error: | 638 | error: |
639 | if (ofid) | 639 | if (ofid) |
640 | p9_client_clunk(ofid); | 640 | p9_client_clunk(ofid); |
641 | 641 | ||
642 | if (fid) | 642 | if (fid) |
643 | p9_client_clunk(fid); | 643 | p9_client_clunk(fid); |
644 | 644 | ||
645 | return ERR_PTR(err); | 645 | return ERR_PTR(err); |
646 | } | 646 | } |
647 | 647 | ||
648 | /** | 648 | /** |
649 | * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol. | 649 | * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol. |
650 | * @dir: directory inode that is being created | 650 | * @dir: directory inode that is being created |
651 | * @dentry: dentry that is being deleted | 651 | * @dentry: dentry that is being deleted |
652 | * @mode: create permissions | 652 | * @mode: create permissions |
653 | * @nd: path information | 653 | * @nd: path information |
654 | * | 654 | * |
655 | */ | 655 | */ |
656 | 656 | ||
657 | static int | 657 | static int |
658 | v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, | 658 | v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, |
659 | struct nameidata *nd) | 659 | struct nameidata *nd) |
660 | { | 660 | { |
661 | int err = 0; | 661 | int err = 0; |
662 | char *name = NULL; | 662 | char *name = NULL; |
663 | gid_t gid; | 663 | gid_t gid; |
664 | int flags; | 664 | int flags; |
665 | struct v9fs_session_info *v9ses; | 665 | struct v9fs_session_info *v9ses; |
666 | struct p9_fid *fid = NULL; | 666 | struct p9_fid *fid = NULL; |
667 | struct p9_fid *dfid, *ofid; | 667 | struct p9_fid *dfid, *ofid; |
668 | struct file *filp; | 668 | struct file *filp; |
669 | struct p9_qid qid; | 669 | struct p9_qid qid; |
670 | struct inode *inode; | 670 | struct inode *inode; |
671 | 671 | ||
672 | v9ses = v9fs_inode2v9ses(dir); | 672 | v9ses = v9fs_inode2v9ses(dir); |
673 | if (nd && nd->flags & LOOKUP_OPEN) | 673 | if (nd && nd->flags & LOOKUP_OPEN) |
674 | flags = nd->intent.open.flags - 1; | 674 | flags = nd->intent.open.flags - 1; |
675 | else | 675 | else |
676 | flags = O_RDWR; | 676 | flags = O_RDWR; |
677 | 677 | ||
678 | name = (char *) dentry->d_name.name; | 678 | name = (char *) dentry->d_name.name; |
679 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x " | 679 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x " |
680 | "mode:0x%x\n", name, flags, mode); | 680 | "mode:0x%x\n", name, flags, mode); |
681 | 681 | ||
682 | dfid = v9fs_fid_lookup(dentry->d_parent); | 682 | dfid = v9fs_fid_lookup(dentry->d_parent); |
683 | if (IS_ERR(dfid)) { | 683 | if (IS_ERR(dfid)) { |
684 | err = PTR_ERR(dfid); | 684 | err = PTR_ERR(dfid); |
685 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 685 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); |
686 | return err; | 686 | return err; |
687 | } | 687 | } |
688 | 688 | ||
689 | /* clone a fid to use for creation */ | 689 | /* clone a fid to use for creation */ |
690 | ofid = p9_client_walk(dfid, 0, NULL, 1); | 690 | ofid = p9_client_walk(dfid, 0, NULL, 1); |
691 | if (IS_ERR(ofid)) { | 691 | if (IS_ERR(ofid)) { |
692 | err = PTR_ERR(ofid); | 692 | err = PTR_ERR(ofid); |
693 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | 693 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); |
694 | return err; | 694 | return err; |
695 | } | 695 | } |
696 | 696 | ||
697 | gid = v9fs_get_fsgid_for_create(dir); | 697 | gid = v9fs_get_fsgid_for_create(dir); |
698 | err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); | 698 | err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); |
699 | if (err < 0) { | 699 | if (err < 0) { |
700 | P9_DPRINTK(P9_DEBUG_VFS, | 700 | P9_DPRINTK(P9_DEBUG_VFS, |
701 | "p9_client_open_dotl failed in creat %d\n", | 701 | "p9_client_open_dotl failed in creat %d\n", |
702 | err); | 702 | err); |
703 | goto error; | 703 | goto error; |
704 | } | 704 | } |
705 | 705 | ||
706 | /* No need to populate the inode if we are not opening the file AND | 706 | /* No need to populate the inode if we are not opening the file AND |
707 | * not in cached mode. | 707 | * not in cached mode. |
708 | */ | 708 | */ |
709 | if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) { | 709 | if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) { |
710 | /* Not in cached mode. No need to populate inode with stat */ | 710 | /* Not in cached mode. No need to populate inode with stat */ |
711 | dentry->d_op = &v9fs_dentry_operations; | 711 | dentry->d_op = &v9fs_dentry_operations; |
712 | p9_client_clunk(ofid); | 712 | p9_client_clunk(ofid); |
713 | d_instantiate(dentry, NULL); | 713 | d_instantiate(dentry, NULL); |
714 | return 0; | 714 | return 0; |
715 | } | 715 | } |
716 | 716 | ||
717 | /* Now walk from the parent so we can get an unopened fid. */ | 717 | /* Now walk from the parent so we can get an unopened fid. */ |
718 | fid = p9_client_walk(dfid, 1, &name, 1); | 718 | fid = p9_client_walk(dfid, 1, &name, 1); |
719 | if (IS_ERR(fid)) { | 719 | if (IS_ERR(fid)) { |
720 | err = PTR_ERR(fid); | 720 | err = PTR_ERR(fid); |
721 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | 721 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); |
722 | fid = NULL; | 722 | fid = NULL; |
723 | goto error; | 723 | goto error; |
724 | } | 724 | } |
725 | 725 | ||
726 | /* instantiate inode and assign the unopened fid to dentry */ | 726 | /* instantiate inode and assign the unopened fid to dentry */ |
727 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 727 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); |
728 | if (IS_ERR(inode)) { | 728 | if (IS_ERR(inode)) { |
729 | err = PTR_ERR(inode); | 729 | err = PTR_ERR(inode); |
730 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); | 730 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); |
731 | goto error; | 731 | goto error; |
732 | } | 732 | } |
733 | dentry->d_op = &v9fs_cached_dentry_operations; | 733 | if (v9ses->cache) |
734 | dentry->d_op = &v9fs_cached_dentry_operations; | ||
735 | else | ||
736 | dentry->d_op = &v9fs_dentry_operations; | ||
734 | d_instantiate(dentry, inode); | 737 | d_instantiate(dentry, inode); |
735 | err = v9fs_fid_add(dentry, fid); | 738 | err = v9fs_fid_add(dentry, fid); |
736 | if (err < 0) | 739 | if (err < 0) |
737 | goto error; | 740 | goto error; |
738 | 741 | ||
739 | /* if we are opening a file, assign the open fid to the file */ | 742 | /* if we are opening a file, assign the open fid to the file */ |
740 | if (nd && nd->flags & LOOKUP_OPEN) { | 743 | if (nd && nd->flags & LOOKUP_OPEN) { |
741 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); | 744 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); |
742 | if (IS_ERR(filp)) { | 745 | if (IS_ERR(filp)) { |
743 | p9_client_clunk(ofid); | 746 | p9_client_clunk(ofid); |
744 | return PTR_ERR(filp); | 747 | return PTR_ERR(filp); |
745 | } | 748 | } |
746 | filp->private_data = ofid; | 749 | filp->private_data = ofid; |
747 | } else | 750 | } else |
748 | p9_client_clunk(ofid); | 751 | p9_client_clunk(ofid); |
749 | 752 | ||
750 | return 0; | 753 | return 0; |
751 | 754 | ||
752 | error: | 755 | error: |
753 | if (ofid) | 756 | if (ofid) |
754 | p9_client_clunk(ofid); | 757 | p9_client_clunk(ofid); |
755 | if (fid) | 758 | if (fid) |
756 | p9_client_clunk(fid); | 759 | p9_client_clunk(fid); |
757 | return err; | 760 | return err; |
758 | } | 761 | } |
759 | 762 | ||
760 | /** | 763 | /** |
761 | * v9fs_vfs_create - VFS hook to create files | 764 | * v9fs_vfs_create - VFS hook to create files |
762 | * @dir: directory inode that is being created | 765 | * @dir: directory inode that is being created |
763 | * @dentry: dentry that is being deleted | 766 | * @dentry: dentry that is being deleted |
764 | * @mode: create permissions | 767 | * @mode: create permissions |
765 | * @nd: path information | 768 | * @nd: path information |
766 | * | 769 | * |
767 | */ | 770 | */ |
768 | 771 | ||
769 | static int | 772 | static int |
770 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | 773 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, |
771 | struct nameidata *nd) | 774 | struct nameidata *nd) |
772 | { | 775 | { |
773 | int err; | 776 | int err; |
774 | u32 perm; | 777 | u32 perm; |
775 | int flags; | 778 | int flags; |
776 | struct v9fs_session_info *v9ses; | 779 | struct v9fs_session_info *v9ses; |
777 | struct p9_fid *fid; | 780 | struct p9_fid *fid; |
778 | struct file *filp; | 781 | struct file *filp; |
779 | 782 | ||
780 | err = 0; | 783 | err = 0; |
781 | fid = NULL; | 784 | fid = NULL; |
782 | v9ses = v9fs_inode2v9ses(dir); | 785 | v9ses = v9fs_inode2v9ses(dir); |
783 | perm = unixmode2p9mode(v9ses, mode); | 786 | perm = unixmode2p9mode(v9ses, mode); |
784 | if (nd && nd->flags & LOOKUP_OPEN) | 787 | if (nd && nd->flags & LOOKUP_OPEN) |
785 | flags = nd->intent.open.flags - 1; | 788 | flags = nd->intent.open.flags - 1; |
786 | else | 789 | else |
787 | flags = O_RDWR; | 790 | flags = O_RDWR; |
788 | 791 | ||
789 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, | 792 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, |
790 | v9fs_uflags2omode(flags, | 793 | v9fs_uflags2omode(flags, |
791 | v9fs_proto_dotu(v9ses))); | 794 | v9fs_proto_dotu(v9ses))); |
792 | if (IS_ERR(fid)) { | 795 | if (IS_ERR(fid)) { |
793 | err = PTR_ERR(fid); | 796 | err = PTR_ERR(fid); |
794 | fid = NULL; | 797 | fid = NULL; |
795 | goto error; | 798 | goto error; |
796 | } | 799 | } |
797 | 800 | ||
798 | /* if we are opening a file, assign the open fid to the file */ | 801 | /* if we are opening a file, assign the open fid to the file */ |
799 | if (nd && nd->flags & LOOKUP_OPEN) { | 802 | if (nd && nd->flags & LOOKUP_OPEN) { |
800 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); | 803 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); |
801 | if (IS_ERR(filp)) { | 804 | if (IS_ERR(filp)) { |
802 | err = PTR_ERR(filp); | 805 | err = PTR_ERR(filp); |
803 | goto error; | 806 | goto error; |
804 | } | 807 | } |
805 | 808 | ||
806 | filp->private_data = fid; | 809 | filp->private_data = fid; |
807 | } else | 810 | } else |
808 | p9_client_clunk(fid); | 811 | p9_client_clunk(fid); |
809 | 812 | ||
810 | return 0; | 813 | return 0; |
811 | 814 | ||
812 | error: | 815 | error: |
813 | if (fid) | 816 | if (fid) |
814 | p9_client_clunk(fid); | 817 | p9_client_clunk(fid); |
815 | 818 | ||
816 | return err; | 819 | return err; |
817 | } | 820 | } |
818 | 821 | ||
819 | /** | 822 | /** |
820 | * v9fs_vfs_mkdir - VFS mkdir hook to create a directory | 823 | * v9fs_vfs_mkdir - VFS mkdir hook to create a directory |
821 | * @dir: inode that is being unlinked | 824 | * @dir: inode that is being unlinked |
822 | * @dentry: dentry that is being unlinked | 825 | * @dentry: dentry that is being unlinked |
823 | * @mode: mode for new directory | 826 | * @mode: mode for new directory |
824 | * | 827 | * |
825 | */ | 828 | */ |
826 | 829 | ||
827 | static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 830 | static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
828 | { | 831 | { |
829 | int err; | 832 | int err; |
830 | u32 perm; | 833 | u32 perm; |
831 | struct v9fs_session_info *v9ses; | 834 | struct v9fs_session_info *v9ses; |
832 | struct p9_fid *fid; | 835 | struct p9_fid *fid; |
833 | 836 | ||
834 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); | 837 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); |
835 | err = 0; | 838 | err = 0; |
836 | v9ses = v9fs_inode2v9ses(dir); | 839 | v9ses = v9fs_inode2v9ses(dir); |
837 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); | 840 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); |
838 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD); | 841 | fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD); |
839 | if (IS_ERR(fid)) { | 842 | if (IS_ERR(fid)) { |
840 | err = PTR_ERR(fid); | 843 | err = PTR_ERR(fid); |
841 | fid = NULL; | 844 | fid = NULL; |
842 | } | 845 | } |
843 | 846 | ||
844 | if (fid) | 847 | if (fid) |
845 | p9_client_clunk(fid); | 848 | p9_client_clunk(fid); |
846 | 849 | ||
847 | return err; | 850 | return err; |
848 | } | 851 | } |
849 | 852 | ||
850 | 853 | ||
851 | /** | 854 | /** |
852 | * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory | 855 | * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory |
853 | * @dir: inode that is being unlinked | 856 | * @dir: inode that is being unlinked |
854 | * @dentry: dentry that is being unlinked | 857 | * @dentry: dentry that is being unlinked |
855 | * @mode: mode for new directory | 858 | * @mode: mode for new directory |
856 | * | 859 | * |
857 | */ | 860 | */ |
858 | 861 | ||
859 | static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry, | 862 | static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry, |
860 | int mode) | 863 | int mode) |
861 | { | 864 | { |
862 | int err; | 865 | int err; |
863 | struct v9fs_session_info *v9ses; | 866 | struct v9fs_session_info *v9ses; |
864 | struct p9_fid *fid = NULL, *dfid = NULL; | 867 | struct p9_fid *fid = NULL, *dfid = NULL; |
865 | gid_t gid; | 868 | gid_t gid; |
866 | char *name; | 869 | char *name; |
867 | struct inode *inode; | 870 | struct inode *inode; |
868 | struct p9_qid qid; | 871 | struct p9_qid qid; |
869 | struct dentry *dir_dentry; | 872 | struct dentry *dir_dentry; |
870 | 873 | ||
871 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); | 874 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); |
872 | err = 0; | 875 | err = 0; |
873 | v9ses = v9fs_inode2v9ses(dir); | 876 | v9ses = v9fs_inode2v9ses(dir); |
874 | 877 | ||
875 | mode |= S_IFDIR; | 878 | mode |= S_IFDIR; |
876 | dir_dentry = v9fs_dentry_from_dir_inode(dir); | 879 | dir_dentry = v9fs_dentry_from_dir_inode(dir); |
877 | dfid = v9fs_fid_lookup(dir_dentry); | 880 | dfid = v9fs_fid_lookup(dir_dentry); |
878 | if (IS_ERR(dfid)) { | 881 | if (IS_ERR(dfid)) { |
879 | err = PTR_ERR(dfid); | 882 | err = PTR_ERR(dfid); |
880 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 883 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); |
881 | dfid = NULL; | 884 | dfid = NULL; |
882 | goto error; | 885 | goto error; |
883 | } | 886 | } |
884 | 887 | ||
885 | gid = v9fs_get_fsgid_for_create(dir); | 888 | gid = v9fs_get_fsgid_for_create(dir); |
886 | if (gid < 0) { | 889 | if (gid < 0) { |
887 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n"); | 890 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n"); |
888 | goto error; | 891 | goto error; |
889 | } | 892 | } |
890 | 893 | ||
891 | name = (char *) dentry->d_name.name; | 894 | name = (char *) dentry->d_name.name; |
892 | err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid); | 895 | err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid); |
893 | if (err < 0) | 896 | if (err < 0) |
894 | goto error; | 897 | goto error; |
895 | 898 | ||
896 | /* instantiate inode and assign the unopened fid to the dentry */ | 899 | /* instantiate inode and assign the unopened fid to the dentry */ |
897 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { | 900 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { |
898 | fid = p9_client_walk(dfid, 1, &name, 1); | 901 | fid = p9_client_walk(dfid, 1, &name, 1); |
899 | if (IS_ERR(fid)) { | 902 | if (IS_ERR(fid)) { |
900 | err = PTR_ERR(fid); | 903 | err = PTR_ERR(fid); |
901 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", | 904 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", |
902 | err); | 905 | err); |
903 | fid = NULL; | 906 | fid = NULL; |
904 | goto error; | 907 | goto error; |
905 | } | 908 | } |
906 | 909 | ||
907 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 910 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); |
908 | if (IS_ERR(inode)) { | 911 | if (IS_ERR(inode)) { |
909 | err = PTR_ERR(inode); | 912 | err = PTR_ERR(inode); |
910 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", | 913 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", |
911 | err); | 914 | err); |
912 | goto error; | 915 | goto error; |
913 | } | 916 | } |
914 | dentry->d_op = &v9fs_cached_dentry_operations; | 917 | dentry->d_op = &v9fs_cached_dentry_operations; |
915 | d_instantiate(dentry, inode); | 918 | d_instantiate(dentry, inode); |
916 | err = v9fs_fid_add(dentry, fid); | 919 | err = v9fs_fid_add(dentry, fid); |
917 | if (err < 0) | 920 | if (err < 0) |
918 | goto error; | 921 | goto error; |
919 | fid = NULL; | 922 | fid = NULL; |
920 | } | 923 | } |
921 | error: | 924 | error: |
922 | if (fid) | 925 | if (fid) |
923 | p9_client_clunk(fid); | 926 | p9_client_clunk(fid); |
924 | return err; | 927 | return err; |
925 | } | 928 | } |
926 | 929 | ||
927 | /** | 930 | /** |
928 | * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode | 931 | * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode |
929 | * @dir: inode that is being walked from | 932 | * @dir: inode that is being walked from |
930 | * @dentry: dentry that is being walked to? | 933 | * @dentry: dentry that is being walked to? |
931 | * @nameidata: path data | 934 | * @nameidata: path data |
932 | * | 935 | * |
933 | */ | 936 | */ |
934 | 937 | ||
935 | static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | 938 | static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, |
936 | struct nameidata *nameidata) | 939 | struct nameidata *nameidata) |
937 | { | 940 | { |
938 | struct super_block *sb; | 941 | struct super_block *sb; |
939 | struct v9fs_session_info *v9ses; | 942 | struct v9fs_session_info *v9ses; |
940 | struct p9_fid *dfid, *fid; | 943 | struct p9_fid *dfid, *fid; |
941 | struct inode *inode; | 944 | struct inode *inode; |
942 | char *name; | 945 | char *name; |
943 | int result = 0; | 946 | int result = 0; |
944 | 947 | ||
945 | P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", | 948 | P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", |
946 | dir, dentry->d_name.name, dentry, nameidata); | 949 | dir, dentry->d_name.name, dentry, nameidata); |
947 | 950 | ||
948 | if (dentry->d_name.len > NAME_MAX) | 951 | if (dentry->d_name.len > NAME_MAX) |
949 | return ERR_PTR(-ENAMETOOLONG); | 952 | return ERR_PTR(-ENAMETOOLONG); |
950 | 953 | ||
951 | sb = dir->i_sb; | 954 | sb = dir->i_sb; |
952 | v9ses = v9fs_inode2v9ses(dir); | 955 | v9ses = v9fs_inode2v9ses(dir); |
953 | /* We can walk d_parent because we hold the dir->i_mutex */ | 956 | /* We can walk d_parent because we hold the dir->i_mutex */ |
954 | dfid = v9fs_fid_lookup(dentry->d_parent); | 957 | dfid = v9fs_fid_lookup(dentry->d_parent); |
955 | if (IS_ERR(dfid)) | 958 | if (IS_ERR(dfid)) |
956 | return ERR_CAST(dfid); | 959 | return ERR_CAST(dfid); |
957 | 960 | ||
958 | name = (char *) dentry->d_name.name; | 961 | name = (char *) dentry->d_name.name; |
959 | fid = p9_client_walk(dfid, 1, &name, 1); | 962 | fid = p9_client_walk(dfid, 1, &name, 1); |
960 | if (IS_ERR(fid)) { | 963 | if (IS_ERR(fid)) { |
961 | result = PTR_ERR(fid); | 964 | result = PTR_ERR(fid); |
962 | if (result == -ENOENT) { | 965 | if (result == -ENOENT) { |
963 | inode = NULL; | 966 | inode = NULL; |
964 | goto inst_out; | 967 | goto inst_out; |
965 | } | 968 | } |
966 | 969 | ||
967 | return ERR_PTR(result); | 970 | return ERR_PTR(result); |
968 | } | 971 | } |
969 | 972 | ||
970 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 973 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); |
971 | if (IS_ERR(inode)) { | 974 | if (IS_ERR(inode)) { |
972 | result = PTR_ERR(inode); | 975 | result = PTR_ERR(inode); |
973 | inode = NULL; | 976 | inode = NULL; |
974 | goto error; | 977 | goto error; |
975 | } | 978 | } |
976 | 979 | ||
977 | result = v9fs_fid_add(dentry, fid); | 980 | result = v9fs_fid_add(dentry, fid); |
978 | if (result < 0) | 981 | if (result < 0) |
979 | goto error; | 982 | goto error; |
980 | 983 | ||
981 | inst_out: | 984 | inst_out: |
982 | if (v9ses->cache) | 985 | if (v9ses->cache) |
983 | dentry->d_op = &v9fs_cached_dentry_operations; | 986 | dentry->d_op = &v9fs_cached_dentry_operations; |
984 | else | 987 | else |
985 | dentry->d_op = &v9fs_dentry_operations; | 988 | dentry->d_op = &v9fs_dentry_operations; |
986 | 989 | ||
987 | d_add(dentry, inode); | 990 | d_add(dentry, inode); |
988 | return NULL; | 991 | return NULL; |
989 | 992 | ||
990 | error: | 993 | error: |
991 | p9_client_clunk(fid); | 994 | p9_client_clunk(fid); |
992 | 995 | ||
993 | return ERR_PTR(result); | 996 | return ERR_PTR(result); |
994 | } | 997 | } |
995 | 998 | ||
996 | /** | 999 | /** |
997 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode | 1000 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode |
998 | * @i: inode that is being unlinked | 1001 | * @i: inode that is being unlinked |
999 | * @d: dentry that is being unlinked | 1002 | * @d: dentry that is being unlinked |
1000 | * | 1003 | * |
1001 | */ | 1004 | */ |
1002 | 1005 | ||
1003 | static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) | 1006 | static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) |
1004 | { | 1007 | { |
1005 | return v9fs_remove(i, d, 0); | 1008 | return v9fs_remove(i, d, 0); |
1006 | } | 1009 | } |
1007 | 1010 | ||
1008 | /** | 1011 | /** |
1009 | * v9fs_vfs_rmdir - VFS unlink hook to delete a directory | 1012 | * v9fs_vfs_rmdir - VFS unlink hook to delete a directory |
1010 | * @i: inode that is being unlinked | 1013 | * @i: inode that is being unlinked |
1011 | * @d: dentry that is being unlinked | 1014 | * @d: dentry that is being unlinked |
1012 | * | 1015 | * |
1013 | */ | 1016 | */ |
1014 | 1017 | ||
1015 | static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) | 1018 | static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) |
1016 | { | 1019 | { |
1017 | return v9fs_remove(i, d, 1); | 1020 | return v9fs_remove(i, d, 1); |
1018 | } | 1021 | } |
1019 | 1022 | ||
1020 | /** | 1023 | /** |
1021 | * v9fs_vfs_rename - VFS hook to rename an inode | 1024 | * v9fs_vfs_rename - VFS hook to rename an inode |
1022 | * @old_dir: old dir inode | 1025 | * @old_dir: old dir inode |
1023 | * @old_dentry: old dentry | 1026 | * @old_dentry: old dentry |
1024 | * @new_dir: new dir inode | 1027 | * @new_dir: new dir inode |
1025 | * @new_dentry: new dentry | 1028 | * @new_dentry: new dentry |
1026 | * | 1029 | * |
1027 | */ | 1030 | */ |
1028 | 1031 | ||
1029 | static int | 1032 | static int |
1030 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 1033 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
1031 | struct inode *new_dir, struct dentry *new_dentry) | 1034 | struct inode *new_dir, struct dentry *new_dentry) |
1032 | { | 1035 | { |
1033 | struct inode *old_inode; | 1036 | struct inode *old_inode; |
1034 | struct v9fs_session_info *v9ses; | 1037 | struct v9fs_session_info *v9ses; |
1035 | struct p9_fid *oldfid; | 1038 | struct p9_fid *oldfid; |
1036 | struct p9_fid *olddirfid; | 1039 | struct p9_fid *olddirfid; |
1037 | struct p9_fid *newdirfid; | 1040 | struct p9_fid *newdirfid; |
1038 | struct p9_wstat wstat; | 1041 | struct p9_wstat wstat; |
1039 | int retval; | 1042 | int retval; |
1040 | 1043 | ||
1041 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); | 1044 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); |
1042 | retval = 0; | 1045 | retval = 0; |
1043 | old_inode = old_dentry->d_inode; | 1046 | old_inode = old_dentry->d_inode; |
1044 | v9ses = v9fs_inode2v9ses(old_inode); | 1047 | v9ses = v9fs_inode2v9ses(old_inode); |
1045 | oldfid = v9fs_fid_lookup(old_dentry); | 1048 | oldfid = v9fs_fid_lookup(old_dentry); |
1046 | if (IS_ERR(oldfid)) | 1049 | if (IS_ERR(oldfid)) |
1047 | return PTR_ERR(oldfid); | 1050 | return PTR_ERR(oldfid); |
1048 | 1051 | ||
1049 | olddirfid = v9fs_fid_clone(old_dentry->d_parent); | 1052 | olddirfid = v9fs_fid_clone(old_dentry->d_parent); |
1050 | if (IS_ERR(olddirfid)) { | 1053 | if (IS_ERR(olddirfid)) { |
1051 | retval = PTR_ERR(olddirfid); | 1054 | retval = PTR_ERR(olddirfid); |
1052 | goto done; | 1055 | goto done; |
1053 | } | 1056 | } |
1054 | 1057 | ||
1055 | newdirfid = v9fs_fid_clone(new_dentry->d_parent); | 1058 | newdirfid = v9fs_fid_clone(new_dentry->d_parent); |
1056 | if (IS_ERR(newdirfid)) { | 1059 | if (IS_ERR(newdirfid)) { |
1057 | retval = PTR_ERR(newdirfid); | 1060 | retval = PTR_ERR(newdirfid); |
1058 | goto clunk_olddir; | 1061 | goto clunk_olddir; |
1059 | } | 1062 | } |
1060 | 1063 | ||
1061 | down_write(&v9ses->rename_sem); | 1064 | down_write(&v9ses->rename_sem); |
1062 | if (v9fs_proto_dotl(v9ses)) { | 1065 | if (v9fs_proto_dotl(v9ses)) { |
1063 | retval = p9_client_rename(oldfid, newdirfid, | 1066 | retval = p9_client_rename(oldfid, newdirfid, |
1064 | (char *) new_dentry->d_name.name); | 1067 | (char *) new_dentry->d_name.name); |
1065 | if (retval != -ENOSYS) | 1068 | if (retval != -ENOSYS) |
1066 | goto clunk_newdir; | 1069 | goto clunk_newdir; |
1067 | } | 1070 | } |
1068 | if (old_dentry->d_parent != new_dentry->d_parent) { | 1071 | if (old_dentry->d_parent != new_dentry->d_parent) { |
1069 | /* | 1072 | /* |
1070 | * 9P .u can only handle file rename in the same directory | 1073 | * 9P .u can only handle file rename in the same directory |
1071 | */ | 1074 | */ |
1072 | 1075 | ||
1073 | P9_DPRINTK(P9_DEBUG_ERROR, | 1076 | P9_DPRINTK(P9_DEBUG_ERROR, |
1074 | "old dir and new dir are different\n"); | 1077 | "old dir and new dir are different\n"); |
1075 | retval = -EXDEV; | 1078 | retval = -EXDEV; |
1076 | goto clunk_newdir; | 1079 | goto clunk_newdir; |
1077 | } | 1080 | } |
1078 | v9fs_blank_wstat(&wstat); | 1081 | v9fs_blank_wstat(&wstat); |
1079 | wstat.muid = v9ses->uname; | 1082 | wstat.muid = v9ses->uname; |
1080 | wstat.name = (char *) new_dentry->d_name.name; | 1083 | wstat.name = (char *) new_dentry->d_name.name; |
1081 | retval = p9_client_wstat(oldfid, &wstat); | 1084 | retval = p9_client_wstat(oldfid, &wstat); |
1082 | 1085 | ||
1083 | clunk_newdir: | 1086 | clunk_newdir: |
1084 | if (!retval) | 1087 | if (!retval) |
1085 | /* successful rename */ | 1088 | /* successful rename */ |
1086 | d_move(old_dentry, new_dentry); | 1089 | d_move(old_dentry, new_dentry); |
1087 | up_write(&v9ses->rename_sem); | 1090 | up_write(&v9ses->rename_sem); |
1088 | p9_client_clunk(newdirfid); | 1091 | p9_client_clunk(newdirfid); |
1089 | 1092 | ||
1090 | clunk_olddir: | 1093 | clunk_olddir: |
1091 | p9_client_clunk(olddirfid); | 1094 | p9_client_clunk(olddirfid); |
1092 | 1095 | ||
1093 | done: | 1096 | done: |
1094 | return retval; | 1097 | return retval; |
1095 | } | 1098 | } |
1096 | 1099 | ||
1097 | /** | 1100 | /** |
1098 | * v9fs_vfs_getattr - retrieve file metadata | 1101 | * v9fs_vfs_getattr - retrieve file metadata |
1099 | * @mnt: mount information | 1102 | * @mnt: mount information |
1100 | * @dentry: file to get attributes on | 1103 | * @dentry: file to get attributes on |
1101 | * @stat: metadata structure to populate | 1104 | * @stat: metadata structure to populate |
1102 | * | 1105 | * |
1103 | */ | 1106 | */ |
1104 | 1107 | ||
1105 | static int | 1108 | static int |
1106 | v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | 1109 | v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, |
1107 | struct kstat *stat) | 1110 | struct kstat *stat) |
1108 | { | 1111 | { |
1109 | int err; | 1112 | int err; |
1110 | struct v9fs_session_info *v9ses; | 1113 | struct v9fs_session_info *v9ses; |
1111 | struct p9_fid *fid; | 1114 | struct p9_fid *fid; |
1112 | struct p9_wstat *st; | 1115 | struct p9_wstat *st; |
1113 | 1116 | ||
1114 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); | 1117 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); |
1115 | err = -EPERM; | 1118 | err = -EPERM; |
1116 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 1119 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
1117 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) | 1120 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) |
1118 | return simple_getattr(mnt, dentry, stat); | 1121 | return simple_getattr(mnt, dentry, stat); |
1119 | 1122 | ||
1120 | fid = v9fs_fid_lookup(dentry); | 1123 | fid = v9fs_fid_lookup(dentry); |
1121 | if (IS_ERR(fid)) | 1124 | if (IS_ERR(fid)) |
1122 | return PTR_ERR(fid); | 1125 | return PTR_ERR(fid); |
1123 | 1126 | ||
1124 | st = p9_client_stat(fid); | 1127 | st = p9_client_stat(fid); |
1125 | if (IS_ERR(st)) | 1128 | if (IS_ERR(st)) |
1126 | return PTR_ERR(st); | 1129 | return PTR_ERR(st); |
1127 | 1130 | ||
1128 | v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); | 1131 | v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); |
1129 | generic_fillattr(dentry->d_inode, stat); | 1132 | generic_fillattr(dentry->d_inode, stat); |
1130 | 1133 | ||
1134 | p9stat_free(st); | ||
1131 | kfree(st); | 1135 | kfree(st); |
1132 | return 0; | 1136 | return 0; |
1133 | } | 1137 | } |
1134 | 1138 | ||
1135 | static int | 1139 | static int |
1136 | v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry, | 1140 | v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry, |
1137 | struct kstat *stat) | 1141 | struct kstat *stat) |
1138 | { | 1142 | { |
1139 | int err; | 1143 | int err; |
1140 | struct v9fs_session_info *v9ses; | 1144 | struct v9fs_session_info *v9ses; |
1141 | struct p9_fid *fid; | 1145 | struct p9_fid *fid; |
1142 | struct p9_stat_dotl *st; | 1146 | struct p9_stat_dotl *st; |
1143 | 1147 | ||
1144 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); | 1148 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); |
1145 | err = -EPERM; | 1149 | err = -EPERM; |
1146 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 1150 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
1147 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) | 1151 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) |
1148 | return simple_getattr(mnt, dentry, stat); | 1152 | return simple_getattr(mnt, dentry, stat); |
1149 | 1153 | ||
1150 | fid = v9fs_fid_lookup(dentry); | 1154 | fid = v9fs_fid_lookup(dentry); |
1151 | if (IS_ERR(fid)) | 1155 | if (IS_ERR(fid)) |
1152 | return PTR_ERR(fid); | 1156 | return PTR_ERR(fid); |
1153 | 1157 | ||
1154 | /* Ask for all the fields in stat structure. Server will return | 1158 | /* Ask for all the fields in stat structure. Server will return |
1155 | * whatever it supports | 1159 | * whatever it supports |
1156 | */ | 1160 | */ |
1157 | 1161 | ||
1158 | st = p9_client_getattr_dotl(fid, P9_STATS_ALL); | 1162 | st = p9_client_getattr_dotl(fid, P9_STATS_ALL); |
1159 | if (IS_ERR(st)) | 1163 | if (IS_ERR(st)) |
1160 | return PTR_ERR(st); | 1164 | return PTR_ERR(st); |
1161 | 1165 | ||
1162 | v9fs_stat2inode_dotl(st, dentry->d_inode); | 1166 | v9fs_stat2inode_dotl(st, dentry->d_inode); |
1163 | generic_fillattr(dentry->d_inode, stat); | 1167 | generic_fillattr(dentry->d_inode, stat); |
1164 | /* Change block size to what the server returned */ | 1168 | /* Change block size to what the server returned */ |
1165 | stat->blksize = st->st_blksize; | 1169 | stat->blksize = st->st_blksize; |
1166 | 1170 | ||
1167 | kfree(st); | 1171 | kfree(st); |
1168 | return 0; | 1172 | return 0; |
1169 | } | 1173 | } |
1170 | 1174 | ||
1171 | /** | 1175 | /** |
1172 | * v9fs_vfs_setattr - set file metadata | 1176 | * v9fs_vfs_setattr - set file metadata |
1173 | * @dentry: file whose metadata to set | 1177 | * @dentry: file whose metadata to set |
1174 | * @iattr: metadata assignment structure | 1178 | * @iattr: metadata assignment structure |
1175 | * | 1179 | * |
1176 | */ | 1180 | */ |
1177 | 1181 | ||
1178 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | 1182 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) |
1179 | { | 1183 | { |
1180 | int retval; | 1184 | int retval; |
1181 | struct v9fs_session_info *v9ses; | 1185 | struct v9fs_session_info *v9ses; |
1182 | struct p9_fid *fid; | 1186 | struct p9_fid *fid; |
1183 | struct p9_wstat wstat; | 1187 | struct p9_wstat wstat; |
1184 | 1188 | ||
1185 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); | 1189 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); |
1186 | retval = -EPERM; | 1190 | retval = -EPERM; |
1187 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 1191 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
1188 | fid = v9fs_fid_lookup(dentry); | 1192 | fid = v9fs_fid_lookup(dentry); |
1189 | if(IS_ERR(fid)) | 1193 | if(IS_ERR(fid)) |
1190 | return PTR_ERR(fid); | 1194 | return PTR_ERR(fid); |
1191 | 1195 | ||
1192 | v9fs_blank_wstat(&wstat); | 1196 | v9fs_blank_wstat(&wstat); |
1193 | if (iattr->ia_valid & ATTR_MODE) | 1197 | if (iattr->ia_valid & ATTR_MODE) |
1194 | wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); | 1198 | wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); |
1195 | 1199 | ||
1196 | if (iattr->ia_valid & ATTR_MTIME) | 1200 | if (iattr->ia_valid & ATTR_MTIME) |
1197 | wstat.mtime = iattr->ia_mtime.tv_sec; | 1201 | wstat.mtime = iattr->ia_mtime.tv_sec; |
1198 | 1202 | ||
1199 | if (iattr->ia_valid & ATTR_ATIME) | 1203 | if (iattr->ia_valid & ATTR_ATIME) |
1200 | wstat.atime = iattr->ia_atime.tv_sec; | 1204 | wstat.atime = iattr->ia_atime.tv_sec; |
1201 | 1205 | ||
1202 | if (iattr->ia_valid & ATTR_SIZE) | 1206 | if (iattr->ia_valid & ATTR_SIZE) |
1203 | wstat.length = iattr->ia_size; | 1207 | wstat.length = iattr->ia_size; |
1204 | 1208 | ||
1205 | if (v9fs_proto_dotu(v9ses)) { | 1209 | if (v9fs_proto_dotu(v9ses)) { |
1206 | if (iattr->ia_valid & ATTR_UID) | 1210 | if (iattr->ia_valid & ATTR_UID) |
1207 | wstat.n_uid = iattr->ia_uid; | 1211 | wstat.n_uid = iattr->ia_uid; |
1208 | 1212 | ||
1209 | if (iattr->ia_valid & ATTR_GID) | 1213 | if (iattr->ia_valid & ATTR_GID) |
1210 | wstat.n_gid = iattr->ia_gid; | 1214 | wstat.n_gid = iattr->ia_gid; |
1211 | } | 1215 | } |
1212 | 1216 | ||
1213 | retval = p9_client_wstat(fid, &wstat); | 1217 | retval = p9_client_wstat(fid, &wstat); |
1214 | if (retval < 0) | 1218 | if (retval < 0) |
1215 | return retval; | 1219 | return retval; |
1216 | 1220 | ||
1217 | if ((iattr->ia_valid & ATTR_SIZE) && | 1221 | if ((iattr->ia_valid & ATTR_SIZE) && |
1218 | iattr->ia_size != i_size_read(dentry->d_inode)) { | 1222 | iattr->ia_size != i_size_read(dentry->d_inode)) { |
1219 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); | 1223 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); |
1220 | if (retval) | 1224 | if (retval) |
1221 | return retval; | 1225 | return retval; |
1222 | } | 1226 | } |
1223 | 1227 | ||
1224 | setattr_copy(dentry->d_inode, iattr); | 1228 | setattr_copy(dentry->d_inode, iattr); |
1225 | mark_inode_dirty(dentry->d_inode); | 1229 | mark_inode_dirty(dentry->d_inode); |
1226 | return 0; | 1230 | return 0; |
1227 | } | 1231 | } |
1228 | 1232 | ||
1229 | /** | 1233 | /** |
1230 | * v9fs_vfs_setattr_dotl - set file metadata | 1234 | * v9fs_vfs_setattr_dotl - set file metadata |
1231 | * @dentry: file whose metadata to set | 1235 | * @dentry: file whose metadata to set |
1232 | * @iattr: metadata assignment structure | 1236 | * @iattr: metadata assignment structure |
1233 | * | 1237 | * |
1234 | */ | 1238 | */ |
1235 | 1239 | ||
1236 | static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) | 1240 | static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) |
1237 | { | 1241 | { |
1238 | int retval; | 1242 | int retval; |
1239 | struct v9fs_session_info *v9ses; | 1243 | struct v9fs_session_info *v9ses; |
1240 | struct p9_fid *fid; | 1244 | struct p9_fid *fid; |
1241 | struct p9_iattr_dotl p9attr; | 1245 | struct p9_iattr_dotl p9attr; |
1242 | 1246 | ||
1243 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); | 1247 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); |
1244 | 1248 | ||
1245 | retval = inode_change_ok(dentry->d_inode, iattr); | 1249 | retval = inode_change_ok(dentry->d_inode, iattr); |
1246 | if (retval) | 1250 | if (retval) |
1247 | return retval; | 1251 | return retval; |
1248 | 1252 | ||
1249 | p9attr.valid = iattr->ia_valid; | 1253 | p9attr.valid = iattr->ia_valid; |
1250 | p9attr.mode = iattr->ia_mode; | 1254 | p9attr.mode = iattr->ia_mode; |
1251 | p9attr.uid = iattr->ia_uid; | 1255 | p9attr.uid = iattr->ia_uid; |
1252 | p9attr.gid = iattr->ia_gid; | 1256 | p9attr.gid = iattr->ia_gid; |
1253 | p9attr.size = iattr->ia_size; | 1257 | p9attr.size = iattr->ia_size; |
1254 | p9attr.atime_sec = iattr->ia_atime.tv_sec; | 1258 | p9attr.atime_sec = iattr->ia_atime.tv_sec; |
1255 | p9attr.atime_nsec = iattr->ia_atime.tv_nsec; | 1259 | p9attr.atime_nsec = iattr->ia_atime.tv_nsec; |
1256 | p9attr.mtime_sec = iattr->ia_mtime.tv_sec; | 1260 | p9attr.mtime_sec = iattr->ia_mtime.tv_sec; |
1257 | p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; | 1261 | p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; |
1258 | 1262 | ||
1259 | retval = -EPERM; | 1263 | retval = -EPERM; |
1260 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 1264 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
1261 | fid = v9fs_fid_lookup(dentry); | 1265 | fid = v9fs_fid_lookup(dentry); |
1262 | if (IS_ERR(fid)) | 1266 | if (IS_ERR(fid)) |
1263 | return PTR_ERR(fid); | 1267 | return PTR_ERR(fid); |
1264 | 1268 | ||
1265 | retval = p9_client_setattr(fid, &p9attr); | 1269 | retval = p9_client_setattr(fid, &p9attr); |
1266 | if (retval < 0) | 1270 | if (retval < 0) |
1267 | return retval; | 1271 | return retval; |
1268 | 1272 | ||
1269 | if ((iattr->ia_valid & ATTR_SIZE) && | 1273 | if ((iattr->ia_valid & ATTR_SIZE) && |
1270 | iattr->ia_size != i_size_read(dentry->d_inode)) { | 1274 | iattr->ia_size != i_size_read(dentry->d_inode)) { |
1271 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); | 1275 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); |
1272 | if (retval) | 1276 | if (retval) |
1273 | return retval; | 1277 | return retval; |
1274 | } | 1278 | } |
1275 | 1279 | ||
1276 | setattr_copy(dentry->d_inode, iattr); | 1280 | setattr_copy(dentry->d_inode, iattr); |
1277 | mark_inode_dirty(dentry->d_inode); | 1281 | mark_inode_dirty(dentry->d_inode); |
1278 | return 0; | 1282 | return 0; |
1279 | } | 1283 | } |
1280 | 1284 | ||
1281 | /** | 1285 | /** |
1282 | * v9fs_stat2inode - populate an inode structure with mistat info | 1286 | * v9fs_stat2inode - populate an inode structure with mistat info |
1283 | * @stat: Plan 9 metadata (mistat) structure | 1287 | * @stat: Plan 9 metadata (mistat) structure |
1284 | * @inode: inode to populate | 1288 | * @inode: inode to populate |
1285 | * @sb: superblock of filesystem | 1289 | * @sb: superblock of filesystem |
1286 | * | 1290 | * |
1287 | */ | 1291 | */ |
1288 | 1292 | ||
1289 | void | 1293 | void |
1290 | v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, | 1294 | v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, |
1291 | struct super_block *sb) | 1295 | struct super_block *sb) |
1292 | { | 1296 | { |
1293 | char ext[32]; | 1297 | char ext[32]; |
1294 | char tag_name[14]; | 1298 | char tag_name[14]; |
1295 | unsigned int i_nlink; | 1299 | unsigned int i_nlink; |
1296 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 1300 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
1297 | 1301 | ||
1298 | inode->i_nlink = 1; | 1302 | inode->i_nlink = 1; |
1299 | 1303 | ||
1300 | inode->i_atime.tv_sec = stat->atime; | 1304 | inode->i_atime.tv_sec = stat->atime; |
1301 | inode->i_mtime.tv_sec = stat->mtime; | 1305 | inode->i_mtime.tv_sec = stat->mtime; |
1302 | inode->i_ctime.tv_sec = stat->mtime; | 1306 | inode->i_ctime.tv_sec = stat->mtime; |
1303 | 1307 | ||
1304 | inode->i_uid = v9ses->dfltuid; | 1308 | inode->i_uid = v9ses->dfltuid; |
1305 | inode->i_gid = v9ses->dfltgid; | 1309 | inode->i_gid = v9ses->dfltgid; |
1306 | 1310 | ||
1307 | if (v9fs_proto_dotu(v9ses)) { | 1311 | if (v9fs_proto_dotu(v9ses)) { |
1308 | inode->i_uid = stat->n_uid; | 1312 | inode->i_uid = stat->n_uid; |
1309 | inode->i_gid = stat->n_gid; | 1313 | inode->i_gid = stat->n_gid; |
1310 | } | 1314 | } |
1311 | if ((S_ISREG(inode->i_mode)) || (S_ISDIR(inode->i_mode))) { | 1315 | if ((S_ISREG(inode->i_mode)) || (S_ISDIR(inode->i_mode))) { |
1312 | if (v9fs_proto_dotu(v9ses) && (stat->extension[0] != '\0')) { | 1316 | if (v9fs_proto_dotu(v9ses) && (stat->extension[0] != '\0')) { |
1313 | /* | 1317 | /* |
1314 | * Hadlink support got added later to | 1318 | * Hadlink support got added later to |
1315 | * to the .u extension. So there can be | 1319 | * to the .u extension. So there can be |
1316 | * server out there that doesn't support | 1320 | * server out there that doesn't support |
1317 | * this even with .u extension. So check | 1321 | * this even with .u extension. So check |
1318 | * for non NULL stat->extension | 1322 | * for non NULL stat->extension |
1319 | */ | 1323 | */ |
1320 | strncpy(ext, stat->extension, sizeof(ext)); | 1324 | strncpy(ext, stat->extension, sizeof(ext)); |
1321 | /* HARDLINKCOUNT %u */ | 1325 | /* HARDLINKCOUNT %u */ |
1322 | sscanf(ext, "%13s %u", tag_name, &i_nlink); | 1326 | sscanf(ext, "%13s %u", tag_name, &i_nlink); |
1323 | if (!strncmp(tag_name, "HARDLINKCOUNT", 13)) | 1327 | if (!strncmp(tag_name, "HARDLINKCOUNT", 13)) |
1324 | inode->i_nlink = i_nlink; | 1328 | inode->i_nlink = i_nlink; |
1325 | } | 1329 | } |
1326 | } | 1330 | } |
1327 | inode->i_mode = p9mode2unixmode(v9ses, stat->mode); | 1331 | inode->i_mode = p9mode2unixmode(v9ses, stat->mode); |
1328 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { | 1332 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { |
1329 | char type = 0; | 1333 | char type = 0; |
1330 | int major = -1; | 1334 | int major = -1; |
1331 | int minor = -1; | 1335 | int minor = -1; |
1332 | 1336 | ||
1333 | strncpy(ext, stat->extension, sizeof(ext)); | 1337 | strncpy(ext, stat->extension, sizeof(ext)); |
1334 | sscanf(ext, "%c %u %u", &type, &major, &minor); | 1338 | sscanf(ext, "%c %u %u", &type, &major, &minor); |
1335 | switch (type) { | 1339 | switch (type) { |
1336 | case 'c': | 1340 | case 'c': |
1337 | inode->i_mode &= ~S_IFBLK; | 1341 | inode->i_mode &= ~S_IFBLK; |
1338 | inode->i_mode |= S_IFCHR; | 1342 | inode->i_mode |= S_IFCHR; |
1339 | break; | 1343 | break; |
1340 | case 'b': | 1344 | case 'b': |
1341 | break; | 1345 | break; |
1342 | default: | 1346 | default: |
1343 | P9_DPRINTK(P9_DEBUG_ERROR, | 1347 | P9_DPRINTK(P9_DEBUG_ERROR, |
1344 | "Unknown special type %c %s\n", type, | 1348 | "Unknown special type %c %s\n", type, |
1345 | stat->extension); | 1349 | stat->extension); |
1346 | }; | 1350 | }; |
1347 | inode->i_rdev = MKDEV(major, minor); | 1351 | inode->i_rdev = MKDEV(major, minor); |
1348 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | 1352 | init_special_inode(inode, inode->i_mode, inode->i_rdev); |
1349 | } else | 1353 | } else |
1350 | inode->i_rdev = 0; | 1354 | inode->i_rdev = 0; |
1351 | 1355 | ||
1352 | i_size_write(inode, stat->length); | 1356 | i_size_write(inode, stat->length); |
1353 | 1357 | ||
1354 | /* not real number of blocks, but 512 byte ones ... */ | 1358 | /* not real number of blocks, but 512 byte ones ... */ |
1355 | inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; | 1359 | inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; |
1356 | } | 1360 | } |
1357 | 1361 | ||
1358 | /** | 1362 | /** |
1359 | * v9fs_stat2inode_dotl - populate an inode structure with stat info | 1363 | * v9fs_stat2inode_dotl - populate an inode structure with stat info |
1360 | * @stat: stat structure | 1364 | * @stat: stat structure |
1361 | * @inode: inode to populate | 1365 | * @inode: inode to populate |
1362 | * @sb: superblock of filesystem | 1366 | * @sb: superblock of filesystem |
1363 | * | 1367 | * |
1364 | */ | 1368 | */ |
1365 | 1369 | ||
1366 | void | 1370 | void |
1367 | v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) | 1371 | v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) |
1368 | { | 1372 | { |
1369 | 1373 | ||
1370 | if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { | 1374 | if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { |
1371 | inode->i_atime.tv_sec = stat->st_atime_sec; | 1375 | inode->i_atime.tv_sec = stat->st_atime_sec; |
1372 | inode->i_atime.tv_nsec = stat->st_atime_nsec; | 1376 | inode->i_atime.tv_nsec = stat->st_atime_nsec; |
1373 | inode->i_mtime.tv_sec = stat->st_mtime_sec; | 1377 | inode->i_mtime.tv_sec = stat->st_mtime_sec; |
1374 | inode->i_mtime.tv_nsec = stat->st_mtime_nsec; | 1378 | inode->i_mtime.tv_nsec = stat->st_mtime_nsec; |
1375 | inode->i_ctime.tv_sec = stat->st_ctime_sec; | 1379 | inode->i_ctime.tv_sec = stat->st_ctime_sec; |
1376 | inode->i_ctime.tv_nsec = stat->st_ctime_nsec; | 1380 | inode->i_ctime.tv_nsec = stat->st_ctime_nsec; |
1377 | inode->i_uid = stat->st_uid; | 1381 | inode->i_uid = stat->st_uid; |
1378 | inode->i_gid = stat->st_gid; | 1382 | inode->i_gid = stat->st_gid; |
1379 | inode->i_nlink = stat->st_nlink; | 1383 | inode->i_nlink = stat->st_nlink; |
1380 | inode->i_mode = stat->st_mode; | 1384 | inode->i_mode = stat->st_mode; |
1381 | inode->i_rdev = new_decode_dev(stat->st_rdev); | 1385 | inode->i_rdev = new_decode_dev(stat->st_rdev); |
1382 | 1386 | ||
1383 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) | 1387 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) |
1384 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | 1388 | init_special_inode(inode, inode->i_mode, inode->i_rdev); |
1385 | 1389 | ||
1386 | i_size_write(inode, stat->st_size); | 1390 | i_size_write(inode, stat->st_size); |
1387 | inode->i_blocks = stat->st_blocks; | 1391 | inode->i_blocks = stat->st_blocks; |
1388 | } else { | 1392 | } else { |
1389 | if (stat->st_result_mask & P9_STATS_ATIME) { | 1393 | if (stat->st_result_mask & P9_STATS_ATIME) { |
1390 | inode->i_atime.tv_sec = stat->st_atime_sec; | 1394 | inode->i_atime.tv_sec = stat->st_atime_sec; |
1391 | inode->i_atime.tv_nsec = stat->st_atime_nsec; | 1395 | inode->i_atime.tv_nsec = stat->st_atime_nsec; |
1392 | } | 1396 | } |
1393 | if (stat->st_result_mask & P9_STATS_MTIME) { | 1397 | if (stat->st_result_mask & P9_STATS_MTIME) { |
1394 | inode->i_mtime.tv_sec = stat->st_mtime_sec; | 1398 | inode->i_mtime.tv_sec = stat->st_mtime_sec; |
1395 | inode->i_mtime.tv_nsec = stat->st_mtime_nsec; | 1399 | inode->i_mtime.tv_nsec = stat->st_mtime_nsec; |
1396 | } | 1400 | } |
1397 | if (stat->st_result_mask & P9_STATS_CTIME) { | 1401 | if (stat->st_result_mask & P9_STATS_CTIME) { |
1398 | inode->i_ctime.tv_sec = stat->st_ctime_sec; | 1402 | inode->i_ctime.tv_sec = stat->st_ctime_sec; |
1399 | inode->i_ctime.tv_nsec = stat->st_ctime_nsec; | 1403 | inode->i_ctime.tv_nsec = stat->st_ctime_nsec; |
1400 | } | 1404 | } |
1401 | if (stat->st_result_mask & P9_STATS_UID) | 1405 | if (stat->st_result_mask & P9_STATS_UID) |
1402 | inode->i_uid = stat->st_uid; | 1406 | inode->i_uid = stat->st_uid; |
1403 | if (stat->st_result_mask & P9_STATS_GID) | 1407 | if (stat->st_result_mask & P9_STATS_GID) |
1404 | inode->i_gid = stat->st_gid; | 1408 | inode->i_gid = stat->st_gid; |
1405 | if (stat->st_result_mask & P9_STATS_NLINK) | 1409 | if (stat->st_result_mask & P9_STATS_NLINK) |
1406 | inode->i_nlink = stat->st_nlink; | 1410 | inode->i_nlink = stat->st_nlink; |
1407 | if (stat->st_result_mask & P9_STATS_MODE) { | 1411 | if (stat->st_result_mask & P9_STATS_MODE) { |
1408 | inode->i_mode = stat->st_mode; | 1412 | inode->i_mode = stat->st_mode; |
1409 | if ((S_ISBLK(inode->i_mode)) || | 1413 | if ((S_ISBLK(inode->i_mode)) || |
1410 | (S_ISCHR(inode->i_mode))) | 1414 | (S_ISCHR(inode->i_mode))) |
1411 | init_special_inode(inode, inode->i_mode, | 1415 | init_special_inode(inode, inode->i_mode, |
1412 | inode->i_rdev); | 1416 | inode->i_rdev); |
1413 | } | 1417 | } |
1414 | if (stat->st_result_mask & P9_STATS_RDEV) | 1418 | if (stat->st_result_mask & P9_STATS_RDEV) |
1415 | inode->i_rdev = new_decode_dev(stat->st_rdev); | 1419 | inode->i_rdev = new_decode_dev(stat->st_rdev); |
1416 | if (stat->st_result_mask & P9_STATS_SIZE) | 1420 | if (stat->st_result_mask & P9_STATS_SIZE) |
1417 | i_size_write(inode, stat->st_size); | 1421 | i_size_write(inode, stat->st_size); |
1418 | if (stat->st_result_mask & P9_STATS_BLOCKS) | 1422 | if (stat->st_result_mask & P9_STATS_BLOCKS) |
1419 | inode->i_blocks = stat->st_blocks; | 1423 | inode->i_blocks = stat->st_blocks; |
1420 | } | 1424 | } |
1421 | if (stat->st_result_mask & P9_STATS_GEN) | 1425 | if (stat->st_result_mask & P9_STATS_GEN) |
1422 | inode->i_generation = stat->st_gen; | 1426 | inode->i_generation = stat->st_gen; |
1423 | 1427 | ||
1424 | /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION | 1428 | /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION |
1425 | * because the inode structure does not have fields for them. | 1429 | * because the inode structure does not have fields for them. |
1426 | */ | 1430 | */ |
1427 | } | 1431 | } |
1428 | 1432 | ||
1429 | /** | 1433 | /** |
1430 | * v9fs_qid2ino - convert qid into inode number | 1434 | * v9fs_qid2ino - convert qid into inode number |
1431 | * @qid: qid to hash | 1435 | * @qid: qid to hash |
1432 | * | 1436 | * |
1433 | * BUG: potential for inode number collisions? | 1437 | * BUG: potential for inode number collisions? |
1434 | */ | 1438 | */ |
1435 | 1439 | ||
1436 | ino_t v9fs_qid2ino(struct p9_qid *qid) | 1440 | ino_t v9fs_qid2ino(struct p9_qid *qid) |
1437 | { | 1441 | { |
1438 | u64 path = qid->path + 2; | 1442 | u64 path = qid->path + 2; |
1439 | ino_t i = 0; | 1443 | ino_t i = 0; |
1440 | 1444 | ||
1441 | if (sizeof(ino_t) == sizeof(path)) | 1445 | if (sizeof(ino_t) == sizeof(path)) |
1442 | memcpy(&i, &path, sizeof(ino_t)); | 1446 | memcpy(&i, &path, sizeof(ino_t)); |
1443 | else | 1447 | else |
1444 | i = (ino_t) (path ^ (path >> 32)); | 1448 | i = (ino_t) (path ^ (path >> 32)); |
1445 | 1449 | ||
1446 | return i; | 1450 | return i; |
1447 | } | 1451 | } |
1448 | 1452 | ||
1449 | /** | 1453 | /** |
1450 | * v9fs_readlink - read a symlink's location (internal version) | 1454 | * v9fs_readlink - read a symlink's location (internal version) |
1451 | * @dentry: dentry for symlink | 1455 | * @dentry: dentry for symlink |
1452 | * @buffer: buffer to load symlink location into | 1456 | * @buffer: buffer to load symlink location into |
1453 | * @buflen: length of buffer | 1457 | * @buflen: length of buffer |
1454 | * | 1458 | * |
1455 | */ | 1459 | */ |
1456 | 1460 | ||
1457 | static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | 1461 | static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) |
1458 | { | 1462 | { |
1459 | int retval; | 1463 | int retval; |
1460 | 1464 | ||
1461 | struct v9fs_session_info *v9ses; | 1465 | struct v9fs_session_info *v9ses; |
1462 | struct p9_fid *fid; | 1466 | struct p9_fid *fid; |
1463 | struct p9_wstat *st; | 1467 | struct p9_wstat *st; |
1464 | 1468 | ||
1465 | P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); | 1469 | P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); |
1466 | retval = -EPERM; | 1470 | retval = -EPERM; |
1467 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 1471 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
1468 | fid = v9fs_fid_lookup(dentry); | 1472 | fid = v9fs_fid_lookup(dentry); |
1469 | if (IS_ERR(fid)) | 1473 | if (IS_ERR(fid)) |
1470 | return PTR_ERR(fid); | 1474 | return PTR_ERR(fid); |
1471 | 1475 | ||
1472 | if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) | 1476 | if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) |
1473 | return -EBADF; | 1477 | return -EBADF; |
1474 | 1478 | ||
1475 | st = p9_client_stat(fid); | 1479 | st = p9_client_stat(fid); |
1476 | if (IS_ERR(st)) | 1480 | if (IS_ERR(st)) |
1477 | return PTR_ERR(st); | 1481 | return PTR_ERR(st); |
1478 | 1482 | ||
1479 | if (!(st->mode & P9_DMSYMLINK)) { | 1483 | if (!(st->mode & P9_DMSYMLINK)) { |
1480 | retval = -EINVAL; | 1484 | retval = -EINVAL; |
1481 | goto done; | 1485 | goto done; |
1482 | } | 1486 | } |
1483 | 1487 | ||
1484 | /* copy extension buffer into buffer */ | 1488 | /* copy extension buffer into buffer */ |
1485 | strncpy(buffer, st->extension, buflen); | 1489 | strncpy(buffer, st->extension, buflen); |
1486 | 1490 | ||
1487 | P9_DPRINTK(P9_DEBUG_VFS, | 1491 | P9_DPRINTK(P9_DEBUG_VFS, |
1488 | "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer); | 1492 | "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer); |
1489 | 1493 | ||
1490 | retval = strnlen(buffer, buflen); | 1494 | retval = strnlen(buffer, buflen); |
1491 | done: | 1495 | done: |
1496 | p9stat_free(st); | ||
1492 | kfree(st); | 1497 | kfree(st); |
1493 | return retval; | 1498 | return retval; |
1494 | } | 1499 | } |
1495 | 1500 | ||
1496 | /** | 1501 | /** |
1497 | * v9fs_vfs_follow_link - follow a symlink path | 1502 | * v9fs_vfs_follow_link - follow a symlink path |
1498 | * @dentry: dentry for symlink | 1503 | * @dentry: dentry for symlink |
1499 | * @nd: nameidata | 1504 | * @nd: nameidata |
1500 | * | 1505 | * |
1501 | */ | 1506 | */ |
1502 | 1507 | ||
1503 | static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) | 1508 | static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) |
1504 | { | 1509 | { |
1505 | int len = 0; | 1510 | int len = 0; |
1506 | char *link = __getname(); | 1511 | char *link = __getname(); |
1507 | 1512 | ||
1508 | P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name); | 1513 | P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name); |
1509 | 1514 | ||
1510 | if (!link) | 1515 | if (!link) |
1511 | link = ERR_PTR(-ENOMEM); | 1516 | link = ERR_PTR(-ENOMEM); |
1512 | else { | 1517 | else { |
1513 | len = v9fs_readlink(dentry, link, PATH_MAX); | 1518 | len = v9fs_readlink(dentry, link, PATH_MAX); |
1514 | 1519 | ||
1515 | if (len < 0) { | 1520 | if (len < 0) { |
1516 | __putname(link); | 1521 | __putname(link); |
1517 | link = ERR_PTR(len); | 1522 | link = ERR_PTR(len); |
1518 | } else | 1523 | } else |
1519 | link[min(len, PATH_MAX-1)] = 0; | 1524 | link[min(len, PATH_MAX-1)] = 0; |
1520 | } | 1525 | } |
1521 | nd_set_link(nd, link); | 1526 | nd_set_link(nd, link); |
1522 | 1527 | ||
1523 | return NULL; | 1528 | return NULL; |
1524 | } | 1529 | } |
1525 | 1530 | ||
1526 | /** | 1531 | /** |
1527 | * v9fs_vfs_put_link - release a symlink path | 1532 | * v9fs_vfs_put_link - release a symlink path |
1528 | * @dentry: dentry for symlink | 1533 | * @dentry: dentry for symlink |
1529 | * @nd: nameidata | 1534 | * @nd: nameidata |
1530 | * @p: unused | 1535 | * @p: unused |
1531 | * | 1536 | * |
1532 | */ | 1537 | */ |
1533 | 1538 | ||
1534 | static void | 1539 | static void |
1535 | v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) | 1540 | v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) |
1536 | { | 1541 | { |
1537 | char *s = nd_get_link(nd); | 1542 | char *s = nd_get_link(nd); |
1538 | 1543 | ||
1539 | P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, | 1544 | P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, |
1540 | IS_ERR(s) ? "<error>" : s); | 1545 | IS_ERR(s) ? "<error>" : s); |
1541 | if (!IS_ERR(s)) | 1546 | if (!IS_ERR(s)) |
1542 | __putname(s); | 1547 | __putname(s); |
1543 | } | 1548 | } |
1544 | 1549 | ||
1545 | /** | 1550 | /** |
1546 | * v9fs_vfs_mkspecial - create a special file | 1551 | * v9fs_vfs_mkspecial - create a special file |
1547 | * @dir: inode to create special file in | 1552 | * @dir: inode to create special file in |
1548 | * @dentry: dentry to create | 1553 | * @dentry: dentry to create |
1549 | * @mode: mode to create special file | 1554 | * @mode: mode to create special file |
1550 | * @extension: 9p2000.u format extension string representing special file | 1555 | * @extension: 9p2000.u format extension string representing special file |
1551 | * | 1556 | * |
1552 | */ | 1557 | */ |
1553 | 1558 | ||
1554 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | 1559 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, |
1555 | int mode, const char *extension) | 1560 | int mode, const char *extension) |
1556 | { | 1561 | { |
1557 | u32 perm; | 1562 | u32 perm; |
1558 | struct v9fs_session_info *v9ses; | 1563 | struct v9fs_session_info *v9ses; |
1559 | struct p9_fid *fid; | 1564 | struct p9_fid *fid; |
1560 | 1565 | ||
1561 | v9ses = v9fs_inode2v9ses(dir); | 1566 | v9ses = v9fs_inode2v9ses(dir); |
1562 | if (!v9fs_proto_dotu(v9ses)) { | 1567 | if (!v9fs_proto_dotu(v9ses)) { |
1563 | P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); | 1568 | P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); |
1564 | return -EPERM; | 1569 | return -EPERM; |
1565 | } | 1570 | } |
1566 | 1571 | ||
1567 | perm = unixmode2p9mode(v9ses, mode); | 1572 | perm = unixmode2p9mode(v9ses, mode); |
1568 | fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm, | 1573 | fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm, |
1569 | P9_OREAD); | 1574 | P9_OREAD); |
1570 | if (IS_ERR(fid)) | 1575 | if (IS_ERR(fid)) |
1571 | return PTR_ERR(fid); | 1576 | return PTR_ERR(fid); |
1572 | 1577 | ||
1573 | p9_client_clunk(fid); | 1578 | p9_client_clunk(fid); |
1574 | return 0; | 1579 | return 0; |
1575 | } | 1580 | } |
1576 | 1581 | ||
1577 | /** | 1582 | /** |
1578 | * v9fs_vfs_symlink_dotl - helper function to create symlinks | 1583 | * v9fs_vfs_symlink_dotl - helper function to create symlinks |
1579 | * @dir: directory inode containing symlink | 1584 | * @dir: directory inode containing symlink |
1580 | * @dentry: dentry for symlink | 1585 | * @dentry: dentry for symlink |
1581 | * @symname: symlink data | 1586 | * @symname: symlink data |
1582 | * | 1587 | * |
1583 | * See Also: 9P2000.L RFC for more information | 1588 | * See Also: 9P2000.L RFC for more information |
1584 | * | 1589 | * |
1585 | */ | 1590 | */ |
1586 | 1591 | ||
1587 | static int | 1592 | static int |
1588 | v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | 1593 | v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, |
1589 | const char *symname) | 1594 | const char *symname) |
1590 | { | 1595 | { |
1591 | struct v9fs_session_info *v9ses; | 1596 | struct v9fs_session_info *v9ses; |
1592 | struct p9_fid *dfid; | 1597 | struct p9_fid *dfid; |
1593 | struct p9_fid *fid = NULL; | 1598 | struct p9_fid *fid = NULL; |
1594 | struct inode *inode; | 1599 | struct inode *inode; |
1595 | struct p9_qid qid; | 1600 | struct p9_qid qid; |
1596 | char *name; | 1601 | char *name; |
1597 | int err; | 1602 | int err; |
1598 | gid_t gid; | 1603 | gid_t gid; |
1599 | 1604 | ||
1600 | name = (char *) dentry->d_name.name; | 1605 | name = (char *) dentry->d_name.name; |
1601 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n", | 1606 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n", |
1602 | dir->i_ino, name, symname); | 1607 | dir->i_ino, name, symname); |
1603 | v9ses = v9fs_inode2v9ses(dir); | 1608 | v9ses = v9fs_inode2v9ses(dir); |
1604 | 1609 | ||
1605 | dfid = v9fs_fid_lookup(dentry->d_parent); | 1610 | dfid = v9fs_fid_lookup(dentry->d_parent); |
1606 | if (IS_ERR(dfid)) { | 1611 | if (IS_ERR(dfid)) { |
1607 | err = PTR_ERR(dfid); | 1612 | err = PTR_ERR(dfid); |
1608 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 1613 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); |
1609 | return err; | 1614 | return err; |
1610 | } | 1615 | } |
1611 | 1616 | ||
1612 | gid = v9fs_get_fsgid_for_create(dir); | 1617 | gid = v9fs_get_fsgid_for_create(dir); |
1613 | 1618 | ||
1614 | if (gid < 0) { | 1619 | if (gid < 0) { |
1615 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid); | 1620 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid); |
1616 | goto error; | 1621 | goto error; |
1617 | } | 1622 | } |
1618 | 1623 | ||
1619 | /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ | 1624 | /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ |
1620 | err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid); | 1625 | err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid); |
1621 | 1626 | ||
1622 | if (err < 0) { | 1627 | if (err < 0) { |
1623 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err); | 1628 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err); |
1624 | goto error; | 1629 | goto error; |
1625 | } | 1630 | } |
1626 | 1631 | ||
1627 | if (v9ses->cache) { | 1632 | if (v9ses->cache) { |
1628 | /* Now walk from the parent so we can get an unopened fid. */ | 1633 | /* Now walk from the parent so we can get an unopened fid. */ |
1629 | fid = p9_client_walk(dfid, 1, &name, 1); | 1634 | fid = p9_client_walk(dfid, 1, &name, 1); |
1630 | if (IS_ERR(fid)) { | 1635 | if (IS_ERR(fid)) { |
1631 | err = PTR_ERR(fid); | 1636 | err = PTR_ERR(fid); |
1632 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", | 1637 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", |
1633 | err); | 1638 | err); |
1634 | fid = NULL; | 1639 | fid = NULL; |
1635 | goto error; | 1640 | goto error; |
1636 | } | 1641 | } |
1637 | 1642 | ||
1638 | /* instantiate inode and assign the unopened fid to dentry */ | 1643 | /* instantiate inode and assign the unopened fid to dentry */ |
1639 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 1644 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); |
1640 | if (IS_ERR(inode)) { | 1645 | if (IS_ERR(inode)) { |
1641 | err = PTR_ERR(inode); | 1646 | err = PTR_ERR(inode); |
1642 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", | 1647 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", |
1643 | err); | 1648 | err); |
1644 | goto error; | 1649 | goto error; |
1645 | } | 1650 | } |
1646 | dentry->d_op = &v9fs_cached_dentry_operations; | 1651 | dentry->d_op = &v9fs_cached_dentry_operations; |
1647 | d_instantiate(dentry, inode); | 1652 | d_instantiate(dentry, inode); |
1648 | err = v9fs_fid_add(dentry, fid); | 1653 | err = v9fs_fid_add(dentry, fid); |
1649 | if (err < 0) | 1654 | if (err < 0) |
1650 | goto error; | 1655 | goto error; |
1651 | fid = NULL; | 1656 | fid = NULL; |
1652 | } else { | 1657 | } else { |
1653 | /* Not in cached mode. No need to populate inode with stat */ | 1658 | /* Not in cached mode. No need to populate inode with stat */ |
1654 | inode = v9fs_get_inode(dir->i_sb, S_IFLNK); | 1659 | inode = v9fs_get_inode(dir->i_sb, S_IFLNK); |
1655 | if (IS_ERR(inode)) { | 1660 | if (IS_ERR(inode)) { |
1656 | err = PTR_ERR(inode); | 1661 | err = PTR_ERR(inode); |
1657 | goto error; | 1662 | goto error; |
1658 | } | 1663 | } |
1659 | dentry->d_op = &v9fs_dentry_operations; | 1664 | dentry->d_op = &v9fs_dentry_operations; |
1660 | d_instantiate(dentry, inode); | 1665 | d_instantiate(dentry, inode); |
1661 | } | 1666 | } |
1662 | 1667 | ||
1663 | error: | 1668 | error: |
1664 | if (fid) | 1669 | if (fid) |
1665 | p9_client_clunk(fid); | 1670 | p9_client_clunk(fid); |
1666 | 1671 | ||
1667 | return err; | 1672 | return err; |
1668 | } | 1673 | } |
1669 | 1674 | ||
1670 | /** | 1675 | /** |
1671 | * v9fs_vfs_symlink - helper function to create symlinks | 1676 | * v9fs_vfs_symlink - helper function to create symlinks |
1672 | * @dir: directory inode containing symlink | 1677 | * @dir: directory inode containing symlink |
1673 | * @dentry: dentry for symlink | 1678 | * @dentry: dentry for symlink |
1674 | * @symname: symlink data | 1679 | * @symname: symlink data |
1675 | * | 1680 | * |
1676 | * See Also: 9P2000.u RFC for more information | 1681 | * See Also: 9P2000.u RFC for more information |
1677 | * | 1682 | * |
1678 | */ | 1683 | */ |
1679 | 1684 | ||
1680 | static int | 1685 | static int |
1681 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 1686 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) |
1682 | { | 1687 | { |
1683 | P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, | 1688 | P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, |
1684 | dentry->d_name.name, symname); | 1689 | dentry->d_name.name, symname); |
1685 | 1690 | ||
1686 | return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); | 1691 | return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); |
1687 | } | 1692 | } |
1688 | 1693 | ||
1689 | /** | 1694 | /** |
1690 | * v9fs_vfs_link - create a hardlink | 1695 | * v9fs_vfs_link - create a hardlink |
1691 | * @old_dentry: dentry for file to link to | 1696 | * @old_dentry: dentry for file to link to |
1692 | * @dir: inode destination for new link | 1697 | * @dir: inode destination for new link |
1693 | * @dentry: dentry for link | 1698 | * @dentry: dentry for link |
1694 | * | 1699 | * |
1695 | */ | 1700 | */ |
1696 | 1701 | ||
1697 | static int | 1702 | static int |
1698 | v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | 1703 | v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, |
1699 | struct dentry *dentry) | 1704 | struct dentry *dentry) |
1700 | { | 1705 | { |
1701 | int retval; | 1706 | int retval; |
1702 | struct p9_fid *oldfid; | 1707 | struct p9_fid *oldfid; |
1703 | char *name; | 1708 | char *name; |
1704 | 1709 | ||
1705 | P9_DPRINTK(P9_DEBUG_VFS, | 1710 | P9_DPRINTK(P9_DEBUG_VFS, |
1706 | " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 1711 | " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, |
1707 | old_dentry->d_name.name); | 1712 | old_dentry->d_name.name); |
1708 | 1713 | ||
1709 | oldfid = v9fs_fid_clone(old_dentry); | 1714 | oldfid = v9fs_fid_clone(old_dentry); |
1710 | if (IS_ERR(oldfid)) | 1715 | if (IS_ERR(oldfid)) |
1711 | return PTR_ERR(oldfid); | 1716 | return PTR_ERR(oldfid); |
1712 | 1717 | ||
1713 | name = __getname(); | 1718 | name = __getname(); |
1714 | if (unlikely(!name)) { | 1719 | if (unlikely(!name)) { |
1715 | retval = -ENOMEM; | 1720 | retval = -ENOMEM; |
1716 | goto clunk_fid; | 1721 | goto clunk_fid; |
1717 | } | 1722 | } |
1718 | 1723 | ||
1719 | sprintf(name, "%d\n", oldfid->fid); | 1724 | sprintf(name, "%d\n", oldfid->fid); |
1720 | retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name); | 1725 | retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name); |
1721 | __putname(name); | 1726 | __putname(name); |
1722 | 1727 | ||
1723 | clunk_fid: | 1728 | clunk_fid: |
1724 | p9_client_clunk(oldfid); | 1729 | p9_client_clunk(oldfid); |
1725 | return retval; | 1730 | return retval; |
1726 | } | 1731 | } |
1727 | 1732 | ||
1728 | /** | 1733 | /** |
1729 | * v9fs_vfs_link_dotl - create a hardlink for dotl | 1734 | * v9fs_vfs_link_dotl - create a hardlink for dotl |
1730 | * @old_dentry: dentry for file to link to | 1735 | * @old_dentry: dentry for file to link to |
1731 | * @dir: inode destination for new link | 1736 | * @dir: inode destination for new link |
1732 | * @dentry: dentry for link | 1737 | * @dentry: dentry for link |
1733 | * | 1738 | * |
1734 | */ | 1739 | */ |
1735 | 1740 | ||
1736 | static int | 1741 | static int |
1737 | v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, | 1742 | v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, |
1738 | struct dentry *dentry) | 1743 | struct dentry *dentry) |
1739 | { | 1744 | { |
1740 | int err; | 1745 | int err; |
1741 | struct p9_fid *dfid, *oldfid; | 1746 | struct p9_fid *dfid, *oldfid; |
1742 | char *name; | 1747 | char *name; |
1743 | struct v9fs_session_info *v9ses; | 1748 | struct v9fs_session_info *v9ses; |
1744 | struct dentry *dir_dentry; | 1749 | struct dentry *dir_dentry; |
1745 | 1750 | ||
1746 | P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n", | 1751 | P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n", |
1747 | dir->i_ino, old_dentry->d_name.name, | 1752 | dir->i_ino, old_dentry->d_name.name, |
1748 | dentry->d_name.name); | 1753 | dentry->d_name.name); |
1749 | 1754 | ||
1750 | v9ses = v9fs_inode2v9ses(dir); | 1755 | v9ses = v9fs_inode2v9ses(dir); |
1751 | dir_dentry = v9fs_dentry_from_dir_inode(dir); | 1756 | dir_dentry = v9fs_dentry_from_dir_inode(dir); |
1752 | dfid = v9fs_fid_lookup(dir_dentry); | 1757 | dfid = v9fs_fid_lookup(dir_dentry); |
1753 | if (IS_ERR(dfid)) | 1758 | if (IS_ERR(dfid)) |
1754 | return PTR_ERR(dfid); | 1759 | return PTR_ERR(dfid); |
1755 | 1760 | ||
1756 | oldfid = v9fs_fid_lookup(old_dentry); | 1761 | oldfid = v9fs_fid_lookup(old_dentry); |
1757 | if (IS_ERR(oldfid)) | 1762 | if (IS_ERR(oldfid)) |
1758 | return PTR_ERR(oldfid); | 1763 | return PTR_ERR(oldfid); |
1759 | 1764 | ||
1760 | name = (char *) dentry->d_name.name; | 1765 | name = (char *) dentry->d_name.name; |
1761 | 1766 | ||
1762 | err = p9_client_link(dfid, oldfid, (char *)dentry->d_name.name); | 1767 | err = p9_client_link(dfid, oldfid, (char *)dentry->d_name.name); |
1763 | 1768 | ||
1764 | if (err < 0) { | 1769 | if (err < 0) { |
1765 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_link failed %d\n", err); | 1770 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_link failed %d\n", err); |
1766 | return err; | 1771 | return err; |
1767 | } | 1772 | } |
1768 | 1773 | ||
1769 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { | 1774 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { |
1770 | /* Get the latest stat info from server. */ | 1775 | /* Get the latest stat info from server. */ |
1771 | struct p9_fid *fid; | 1776 | struct p9_fid *fid; |
1772 | struct p9_stat_dotl *st; | 1777 | struct p9_stat_dotl *st; |
1773 | 1778 | ||
1774 | fid = v9fs_fid_lookup(old_dentry); | 1779 | fid = v9fs_fid_lookup(old_dentry); |
1775 | if (IS_ERR(fid)) | 1780 | if (IS_ERR(fid)) |
1776 | return PTR_ERR(fid); | 1781 | return PTR_ERR(fid); |
1777 | 1782 | ||
1778 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); | 1783 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); |
1779 | if (IS_ERR(st)) | 1784 | if (IS_ERR(st)) |
1780 | return PTR_ERR(st); | 1785 | return PTR_ERR(st); |
1781 | 1786 | ||
1782 | v9fs_stat2inode_dotl(st, old_dentry->d_inode); | 1787 | v9fs_stat2inode_dotl(st, old_dentry->d_inode); |
1783 | 1788 | ||
1784 | kfree(st); | 1789 | kfree(st); |
1785 | } else { | 1790 | } else { |
1786 | /* Caching disabled. No need to get upto date stat info. | 1791 | /* Caching disabled. No need to get upto date stat info. |
1787 | * This dentry will be released immediately. So, just i_count++ | 1792 | * This dentry will be released immediately. So, just i_count++ |
1788 | */ | 1793 | */ |
1789 | atomic_inc(&old_dentry->d_inode->i_count); | 1794 | atomic_inc(&old_dentry->d_inode->i_count); |
1790 | } | 1795 | } |
1791 | 1796 | ||
1792 | dentry->d_op = old_dentry->d_op; | 1797 | dentry->d_op = old_dentry->d_op; |
1793 | d_instantiate(dentry, old_dentry->d_inode); | 1798 | d_instantiate(dentry, old_dentry->d_inode); |
1794 | 1799 | ||
1795 | return err; | 1800 | return err; |
1796 | } | 1801 | } |
1797 | 1802 | ||
1798 | /** | 1803 | /** |
1799 | * v9fs_vfs_mknod - create a special file | 1804 | * v9fs_vfs_mknod - create a special file |
1800 | * @dir: inode destination for new link | 1805 | * @dir: inode destination for new link |
1801 | * @dentry: dentry for file | 1806 | * @dentry: dentry for file |
1802 | * @mode: mode for creation | 1807 | * @mode: mode for creation |
1803 | * @rdev: device associated with special file | 1808 | * @rdev: device associated with special file |
1804 | * | 1809 | * |
1805 | */ | 1810 | */ |
1806 | 1811 | ||
1807 | static int | 1812 | static int |
1808 | v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | 1813 | v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) |
1809 | { | 1814 | { |
1810 | int retval; | 1815 | int retval; |
1811 | char *name; | 1816 | char *name; |
1812 | 1817 | ||
1813 | P9_DPRINTK(P9_DEBUG_VFS, | 1818 | P9_DPRINTK(P9_DEBUG_VFS, |
1814 | " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, | 1819 | " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, |
1815 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); | 1820 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); |
1816 | 1821 | ||
1817 | if (!new_valid_dev(rdev)) | 1822 | if (!new_valid_dev(rdev)) |
1818 | return -EINVAL; | 1823 | return -EINVAL; |
1819 | 1824 | ||
1820 | name = __getname(); | 1825 | name = __getname(); |
1821 | if (!name) | 1826 | if (!name) |
1822 | return -ENOMEM; | 1827 | return -ENOMEM; |
1823 | /* build extension */ | 1828 | /* build extension */ |
1824 | if (S_ISBLK(mode)) | 1829 | if (S_ISBLK(mode)) |
1825 | sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); | 1830 | sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); |
1826 | else if (S_ISCHR(mode)) | 1831 | else if (S_ISCHR(mode)) |
1827 | sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); | 1832 | sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); |
1828 | else if (S_ISFIFO(mode)) | 1833 | else if (S_ISFIFO(mode)) |
1829 | *name = 0; | 1834 | *name = 0; |
1830 | else if (S_ISSOCK(mode)) | 1835 | else if (S_ISSOCK(mode)) |
1831 | *name = 0; | 1836 | *name = 0; |
1832 | else { | 1837 | else { |
1833 | __putname(name); | 1838 | __putname(name); |
1834 | return -EINVAL; | 1839 | return -EINVAL; |
1835 | } | 1840 | } |
1836 | 1841 | ||
1837 | retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); | 1842 | retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); |
1838 | __putname(name); | 1843 | __putname(name); |
1839 | 1844 | ||
1840 | return retval; | 1845 | return retval; |
1841 | } | 1846 | } |
1842 | 1847 | ||
1843 | /** | 1848 | /** |
1844 | * v9fs_vfs_mknod_dotl - create a special file | 1849 | * v9fs_vfs_mknod_dotl - create a special file |
1845 | * @dir: inode destination for new link | 1850 | * @dir: inode destination for new link |
1846 | * @dentry: dentry for file | 1851 | * @dentry: dentry for file |
1847 | * @mode: mode for creation | 1852 | * @mode: mode for creation |
1848 | * @rdev: device associated with special file | 1853 | * @rdev: device associated with special file |
1849 | * | 1854 | * |
1850 | */ | 1855 | */ |
1851 | static int | 1856 | static int |
1852 | v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode, | 1857 | v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode, |
1853 | dev_t rdev) | 1858 | dev_t rdev) |
1854 | { | 1859 | { |
1855 | int err; | 1860 | int err; |
1856 | char *name; | 1861 | char *name; |
1857 | struct v9fs_session_info *v9ses; | 1862 | struct v9fs_session_info *v9ses; |
1858 | struct p9_fid *fid = NULL, *dfid = NULL; | 1863 | struct p9_fid *fid = NULL, *dfid = NULL; |
1859 | struct inode *inode; | 1864 | struct inode *inode; |
1860 | gid_t gid; | 1865 | gid_t gid; |
1861 | struct p9_qid qid; | 1866 | struct p9_qid qid; |
1862 | struct dentry *dir_dentry; | 1867 | struct dentry *dir_dentry; |
1863 | 1868 | ||
1864 | P9_DPRINTK(P9_DEBUG_VFS, | 1869 | P9_DPRINTK(P9_DEBUG_VFS, |
1865 | " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, | 1870 | " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, |
1866 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); | 1871 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); |
1867 | 1872 | ||
1868 | if (!new_valid_dev(rdev)) | 1873 | if (!new_valid_dev(rdev)) |
1869 | return -EINVAL; | 1874 | return -EINVAL; |
1870 | 1875 | ||
1871 | v9ses = v9fs_inode2v9ses(dir); | 1876 | v9ses = v9fs_inode2v9ses(dir); |
1872 | dir_dentry = v9fs_dentry_from_dir_inode(dir); | 1877 | dir_dentry = v9fs_dentry_from_dir_inode(dir); |
1873 | dfid = v9fs_fid_lookup(dir_dentry); | 1878 | dfid = v9fs_fid_lookup(dir_dentry); |
1874 | if (IS_ERR(dfid)) { | 1879 | if (IS_ERR(dfid)) { |
1875 | err = PTR_ERR(dfid); | 1880 | err = PTR_ERR(dfid); |
1876 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 1881 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); |
1877 | dfid = NULL; | 1882 | dfid = NULL; |
1878 | goto error; | 1883 | goto error; |
1879 | } | 1884 | } |
1880 | 1885 | ||
1881 | gid = v9fs_get_fsgid_for_create(dir); | 1886 | gid = v9fs_get_fsgid_for_create(dir); |
1882 | if (gid < 0) { | 1887 | if (gid < 0) { |
1883 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n"); | 1888 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n"); |
1884 | goto error; | 1889 | goto error; |
1885 | } | 1890 | } |
1886 | 1891 | ||
1887 | name = (char *) dentry->d_name.name; | 1892 | name = (char *) dentry->d_name.name; |
1888 | 1893 | ||
1889 | err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid); | 1894 | err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid); |
1890 | if (err < 0) | 1895 | if (err < 0) |
1891 | goto error; | 1896 | goto error; |
1892 | 1897 | ||
1893 | /* instantiate inode and assign the unopened fid to the dentry */ | 1898 | /* instantiate inode and assign the unopened fid to the dentry */ |
1894 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { | 1899 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { |
1895 | fid = p9_client_walk(dfid, 1, &name, 1); | 1900 | fid = p9_client_walk(dfid, 1, &name, 1); |
1896 | if (IS_ERR(fid)) { | 1901 | if (IS_ERR(fid)) { |
1897 | err = PTR_ERR(fid); | 1902 | err = PTR_ERR(fid); |
1898 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", | 1903 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", |
1899 | err); | 1904 | err); |
1900 | fid = NULL; | 1905 | fid = NULL; |
1901 | goto error; | 1906 | goto error; |
1902 | } | 1907 | } |
1903 | 1908 | ||
1904 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 1909 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); |
1905 | if (IS_ERR(inode)) { | 1910 | if (IS_ERR(inode)) { |
1906 | err = PTR_ERR(inode); | 1911 | err = PTR_ERR(inode); |
1907 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", | 1912 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", |
1908 | err); | 1913 | err); |
1909 | goto error; | 1914 | goto error; |
1910 | } | 1915 | } |
1911 | dentry->d_op = &v9fs_cached_dentry_operations; | 1916 | dentry->d_op = &v9fs_cached_dentry_operations; |
1912 | d_instantiate(dentry, inode); | 1917 | d_instantiate(dentry, inode); |
1913 | err = v9fs_fid_add(dentry, fid); | 1918 | err = v9fs_fid_add(dentry, fid); |
1914 | if (err < 0) | 1919 | if (err < 0) |
1915 | goto error; | 1920 | goto error; |
1916 | fid = NULL; | 1921 | fid = NULL; |
1917 | } else { | 1922 | } else { |
1918 | /* | 1923 | /* |
1919 | * Not in cached mode. No need to populate inode with stat. | 1924 | * Not in cached mode. No need to populate inode with stat. |
1920 | * socket syscall returns a fd, so we need instantiate | 1925 | * socket syscall returns a fd, so we need instantiate |
1921 | */ | 1926 | */ |
1922 | inode = v9fs_get_inode(dir->i_sb, mode); | 1927 | inode = v9fs_get_inode(dir->i_sb, mode); |
1923 | if (IS_ERR(inode)) { | 1928 | if (IS_ERR(inode)) { |
1924 | err = PTR_ERR(inode); | 1929 | err = PTR_ERR(inode); |
1925 | goto error; | 1930 | goto error; |
1926 | } | 1931 | } |
1927 | dentry->d_op = &v9fs_dentry_operations; | 1932 | dentry->d_op = &v9fs_dentry_operations; |
1928 | d_instantiate(dentry, inode); | 1933 | d_instantiate(dentry, inode); |
1929 | } | 1934 | } |
1930 | 1935 | ||
1931 | error: | 1936 | error: |
1932 | if (fid) | 1937 | if (fid) |
1933 | p9_client_clunk(fid); | 1938 | p9_client_clunk(fid); |
1934 | return err; | 1939 | return err; |
1935 | } | 1940 | } |
1936 | 1941 | ||
1937 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { | 1942 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { |
1938 | .create = v9fs_vfs_create, | 1943 | .create = v9fs_vfs_create, |
1939 | .lookup = v9fs_vfs_lookup, | 1944 | .lookup = v9fs_vfs_lookup, |
1940 | .symlink = v9fs_vfs_symlink, | 1945 | .symlink = v9fs_vfs_symlink, |
1941 | .link = v9fs_vfs_link, | 1946 | .link = v9fs_vfs_link, |
1942 | .unlink = v9fs_vfs_unlink, | 1947 | .unlink = v9fs_vfs_unlink, |
1943 | .mkdir = v9fs_vfs_mkdir, | 1948 | .mkdir = v9fs_vfs_mkdir, |
1944 | .rmdir = v9fs_vfs_rmdir, | 1949 | .rmdir = v9fs_vfs_rmdir, |
1945 | .mknod = v9fs_vfs_mknod_dotl, | 1950 | .mknod = v9fs_vfs_mknod, |
1946 | .rename = v9fs_vfs_rename, | 1951 | .rename = v9fs_vfs_rename, |
1947 | .getattr = v9fs_vfs_getattr, | 1952 | .getattr = v9fs_vfs_getattr, |
1948 | .setattr = v9fs_vfs_setattr, | 1953 | .setattr = v9fs_vfs_setattr, |
1949 | }; | 1954 | }; |
1950 | 1955 | ||
1951 | static const struct inode_operations v9fs_dir_inode_operations_dotl = { | 1956 | static const struct inode_operations v9fs_dir_inode_operations_dotl = { |
1952 | .create = v9fs_vfs_create_dotl, | 1957 | .create = v9fs_vfs_create_dotl, |
1953 | .lookup = v9fs_vfs_lookup, | 1958 | .lookup = v9fs_vfs_lookup, |
1954 | .link = v9fs_vfs_link_dotl, | 1959 | .link = v9fs_vfs_link_dotl, |
1955 | .symlink = v9fs_vfs_symlink_dotl, | 1960 | .symlink = v9fs_vfs_symlink_dotl, |
1956 | .unlink = v9fs_vfs_unlink, | 1961 | .unlink = v9fs_vfs_unlink, |
1957 | .mkdir = v9fs_vfs_mkdir_dotl, | 1962 | .mkdir = v9fs_vfs_mkdir_dotl, |
1958 | .rmdir = v9fs_vfs_rmdir, | 1963 | .rmdir = v9fs_vfs_rmdir, |
1959 | .mknod = v9fs_vfs_mknod_dotl, | 1964 | .mknod = v9fs_vfs_mknod_dotl, |
1960 | .rename = v9fs_vfs_rename, | 1965 | .rename = v9fs_vfs_rename, |
1961 | .getattr = v9fs_vfs_getattr_dotl, | 1966 | .getattr = v9fs_vfs_getattr_dotl, |
1962 | .setattr = v9fs_vfs_setattr_dotl, | 1967 | .setattr = v9fs_vfs_setattr_dotl, |
1963 | .setxattr = generic_setxattr, | 1968 | .setxattr = generic_setxattr, |
1964 | .getxattr = generic_getxattr, | 1969 | .getxattr = generic_getxattr, |
1965 | .removexattr = generic_removexattr, | 1970 | .removexattr = generic_removexattr, |
1966 | .listxattr = v9fs_listxattr, | 1971 | .listxattr = v9fs_listxattr, |
1967 | 1972 | ||
1968 | }; | 1973 | }; |
1969 | 1974 | ||
1970 | static const struct inode_operations v9fs_dir_inode_operations = { | 1975 | static const struct inode_operations v9fs_dir_inode_operations = { |
1971 | .create = v9fs_vfs_create, | 1976 | .create = v9fs_vfs_create, |
1972 | .lookup = v9fs_vfs_lookup, | 1977 | .lookup = v9fs_vfs_lookup, |
1973 | .unlink = v9fs_vfs_unlink, | 1978 | .unlink = v9fs_vfs_unlink, |
1974 | .mkdir = v9fs_vfs_mkdir, | 1979 | .mkdir = v9fs_vfs_mkdir, |
1975 | .rmdir = v9fs_vfs_rmdir, | 1980 | .rmdir = v9fs_vfs_rmdir, |
1976 | .mknod = v9fs_vfs_mknod, | 1981 | .mknod = v9fs_vfs_mknod, |
1977 | .rename = v9fs_vfs_rename, | 1982 | .rename = v9fs_vfs_rename, |
1978 | .getattr = v9fs_vfs_getattr, | 1983 | .getattr = v9fs_vfs_getattr, |
1979 | .setattr = v9fs_vfs_setattr, | 1984 | .setattr = v9fs_vfs_setattr, |
1980 | }; | 1985 | }; |
1981 | 1986 | ||
1982 | static const struct inode_operations v9fs_file_inode_operations = { | 1987 | static const struct inode_operations v9fs_file_inode_operations = { |
1983 | .getattr = v9fs_vfs_getattr, | 1988 | .getattr = v9fs_vfs_getattr, |
1984 | .setattr = v9fs_vfs_setattr, | 1989 | .setattr = v9fs_vfs_setattr, |
1985 | }; | 1990 | }; |
1986 | 1991 | ||
1987 | static const struct inode_operations v9fs_file_inode_operations_dotl = { | 1992 | static const struct inode_operations v9fs_file_inode_operations_dotl = { |
1988 | .getattr = v9fs_vfs_getattr_dotl, | 1993 | .getattr = v9fs_vfs_getattr_dotl, |
1989 | .setattr = v9fs_vfs_setattr_dotl, | 1994 | .setattr = v9fs_vfs_setattr_dotl, |
1990 | .setxattr = generic_setxattr, | 1995 | .setxattr = generic_setxattr, |
1991 | .getxattr = generic_getxattr, | 1996 | .getxattr = generic_getxattr, |
1992 | .removexattr = generic_removexattr, | 1997 | .removexattr = generic_removexattr, |
1993 | .listxattr = v9fs_listxattr, | 1998 | .listxattr = v9fs_listxattr, |
1994 | }; | 1999 | }; |
1995 | 2000 | ||
1996 | static const struct inode_operations v9fs_symlink_inode_operations = { | 2001 | static const struct inode_operations v9fs_symlink_inode_operations = { |
1997 | .readlink = generic_readlink, | 2002 | .readlink = generic_readlink, |
1998 | .follow_link = v9fs_vfs_follow_link, | 2003 | .follow_link = v9fs_vfs_follow_link, |
1999 | .put_link = v9fs_vfs_put_link, | 2004 | .put_link = v9fs_vfs_put_link, |
2000 | .getattr = v9fs_vfs_getattr, | 2005 | .getattr = v9fs_vfs_getattr, |
2001 | .setattr = v9fs_vfs_setattr, | 2006 | .setattr = v9fs_vfs_setattr, |
2002 | }; | 2007 | }; |
2003 | 2008 | ||
2004 | static const struct inode_operations v9fs_symlink_inode_operations_dotl = { | 2009 | static const struct inode_operations v9fs_symlink_inode_operations_dotl = { |
2005 | .readlink = generic_readlink, | 2010 | .readlink = generic_readlink, |
2006 | .follow_link = v9fs_vfs_follow_link, | 2011 | .follow_link = v9fs_vfs_follow_link, |
2007 | .put_link = v9fs_vfs_put_link, | 2012 | .put_link = v9fs_vfs_put_link, |
2008 | .getattr = v9fs_vfs_getattr_dotl, | 2013 | .getattr = v9fs_vfs_getattr_dotl, |
2009 | .setattr = v9fs_vfs_setattr_dotl, | 2014 | .setattr = v9fs_vfs_setattr_dotl, |
2010 | .setxattr = generic_setxattr, | 2015 | .setxattr = generic_setxattr, |
2011 | .getxattr = generic_getxattr, | 2016 | .getxattr = generic_getxattr, |
2012 | .removexattr = generic_removexattr, | 2017 | .removexattr = generic_removexattr, |
2013 | .listxattr = v9fs_listxattr, | 2018 | .listxattr = v9fs_listxattr, |
2014 | }; | 2019 | }; |
2015 | 2020 |
fs/9p/vfs_super.c
1 | /* | 1 | /* |
2 | * linux/fs/9p/vfs_super.c | 2 | * linux/fs/9p/vfs_super.c |
3 | * | 3 | * |
4 | * This file contians superblock ops for 9P2000. It is intended that | 4 | * This file contians superblock ops for 9P2000. It is intended that |
5 | * you mount this file system on directories. | 5 | * you mount this file system on directories. |
6 | * | 6 | * |
7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | 7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
8 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | 8 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 | 11 | * it under the terms of the GNU General Public License version 2 |
12 | * as published by the Free Software Foundation. | 12 | * as published by the Free Software Foundation. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, | 14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to: | 20 | * along with this program; if not, write to: |
21 | * Free Software Foundation | 21 | * Free Software Foundation |
22 | * 51 Franklin Street, Fifth Floor | 22 | * 51 Franklin Street, Fifth Floor |
23 | * Boston, MA 02111-1301 USA | 23 | * Boston, MA 02111-1301 USA |
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
30 | #include <linux/fs.h> | 30 | #include <linux/fs.h> |
31 | #include <linux/file.h> | 31 | #include <linux/file.h> |
32 | #include <linux/stat.h> | 32 | #include <linux/stat.h> |
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/inet.h> | 34 | #include <linux/inet.h> |
35 | #include <linux/pagemap.h> | 35 | #include <linux/pagemap.h> |
36 | #include <linux/seq_file.h> | 36 | #include <linux/seq_file.h> |
37 | #include <linux/mount.h> | 37 | #include <linux/mount.h> |
38 | #include <linux/idr.h> | 38 | #include <linux/idr.h> |
39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | #include <linux/statfs.h> | 41 | #include <linux/statfs.h> |
42 | #include <net/9p/9p.h> | 42 | #include <net/9p/9p.h> |
43 | #include <net/9p/client.h> | 43 | #include <net/9p/client.h> |
44 | 44 | ||
45 | #include "v9fs.h" | 45 | #include "v9fs.h" |
46 | #include "v9fs_vfs.h" | 46 | #include "v9fs_vfs.h" |
47 | #include "fid.h" | 47 | #include "fid.h" |
48 | #include "xattr.h" | 48 | #include "xattr.h" |
49 | 49 | ||
50 | static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; | 50 | static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; |
51 | 51 | ||
52 | /** | 52 | /** |
53 | * v9fs_set_super - set the superblock | 53 | * v9fs_set_super - set the superblock |
54 | * @s: super block | 54 | * @s: super block |
55 | * @data: file system specific data | 55 | * @data: file system specific data |
56 | * | 56 | * |
57 | */ | 57 | */ |
58 | 58 | ||
59 | static int v9fs_set_super(struct super_block *s, void *data) | 59 | static int v9fs_set_super(struct super_block *s, void *data) |
60 | { | 60 | { |
61 | s->s_fs_info = data; | 61 | s->s_fs_info = data; |
62 | return set_anon_super(s, data); | 62 | return set_anon_super(s, data); |
63 | } | 63 | } |
64 | 64 | ||
65 | /** | 65 | /** |
66 | * v9fs_fill_super - populate superblock with info | 66 | * v9fs_fill_super - populate superblock with info |
67 | * @sb: superblock | 67 | * @sb: superblock |
68 | * @v9ses: session information | 68 | * @v9ses: session information |
69 | * @flags: flags propagated from v9fs_get_sb() | 69 | * @flags: flags propagated from v9fs_get_sb() |
70 | * | 70 | * |
71 | */ | 71 | */ |
72 | 72 | ||
73 | static void | 73 | static void |
74 | v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, | 74 | v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, |
75 | int flags, void *data) | 75 | int flags, void *data) |
76 | { | 76 | { |
77 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 77 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
78 | sb->s_blocksize_bits = fls(v9ses->maxdata - 1); | 78 | sb->s_blocksize_bits = fls(v9ses->maxdata - 1); |
79 | sb->s_blocksize = 1 << sb->s_blocksize_bits; | 79 | sb->s_blocksize = 1 << sb->s_blocksize_bits; |
80 | sb->s_magic = V9FS_MAGIC; | 80 | sb->s_magic = V9FS_MAGIC; |
81 | if (v9fs_proto_dotl(v9ses)) { | 81 | if (v9fs_proto_dotl(v9ses)) { |
82 | sb->s_op = &v9fs_super_ops_dotl; | 82 | sb->s_op = &v9fs_super_ops_dotl; |
83 | sb->s_xattr = v9fs_xattr_handlers; | 83 | sb->s_xattr = v9fs_xattr_handlers; |
84 | } else | 84 | } else |
85 | sb->s_op = &v9fs_super_ops; | 85 | sb->s_op = &v9fs_super_ops; |
86 | sb->s_bdi = &v9ses->bdi; | 86 | sb->s_bdi = &v9ses->bdi; |
87 | 87 | ||
88 | sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC | | 88 | sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC | |
89 | MS_NOATIME; | 89 | MS_NOATIME; |
90 | 90 | ||
91 | save_mount_options(sb, data); | 91 | save_mount_options(sb, data); |
92 | } | 92 | } |
93 | 93 | ||
94 | /** | 94 | /** |
95 | * v9fs_get_sb - mount a superblock | 95 | * v9fs_get_sb - mount a superblock |
96 | * @fs_type: file system type | 96 | * @fs_type: file system type |
97 | * @flags: mount flags | 97 | * @flags: mount flags |
98 | * @dev_name: device name that was mounted | 98 | * @dev_name: device name that was mounted |
99 | * @data: mount options | 99 | * @data: mount options |
100 | * @mnt: mountpoint record to be instantiated | 100 | * @mnt: mountpoint record to be instantiated |
101 | * | 101 | * |
102 | */ | 102 | */ |
103 | 103 | ||
104 | static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | 104 | static int v9fs_get_sb(struct file_system_type *fs_type, int flags, |
105 | const char *dev_name, void *data, | 105 | const char *dev_name, void *data, |
106 | struct vfsmount *mnt) | 106 | struct vfsmount *mnt) |
107 | { | 107 | { |
108 | struct super_block *sb = NULL; | 108 | struct super_block *sb = NULL; |
109 | struct inode *inode = NULL; | 109 | struct inode *inode = NULL; |
110 | struct dentry *root = NULL; | 110 | struct dentry *root = NULL; |
111 | struct v9fs_session_info *v9ses = NULL; | 111 | struct v9fs_session_info *v9ses = NULL; |
112 | int mode = S_IRWXUGO | S_ISVTX; | 112 | int mode = S_IRWXUGO | S_ISVTX; |
113 | struct p9_fid *fid; | 113 | struct p9_fid *fid; |
114 | int retval = 0; | 114 | int retval = 0; |
115 | 115 | ||
116 | P9_DPRINTK(P9_DEBUG_VFS, " \n"); | 116 | P9_DPRINTK(P9_DEBUG_VFS, " \n"); |
117 | 117 | ||
118 | v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); | 118 | v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); |
119 | if (!v9ses) | 119 | if (!v9ses) |
120 | return -ENOMEM; | 120 | return -ENOMEM; |
121 | 121 | ||
122 | fid = v9fs_session_init(v9ses, dev_name, data); | 122 | fid = v9fs_session_init(v9ses, dev_name, data); |
123 | if (IS_ERR(fid)) { | 123 | if (IS_ERR(fid)) { |
124 | retval = PTR_ERR(fid); | 124 | retval = PTR_ERR(fid); |
125 | /* | ||
126 | * we need to call session_close to tear down some | ||
127 | * of the data structure setup by session_init | ||
128 | */ | ||
125 | goto close_session; | 129 | goto close_session; |
126 | } | 130 | } |
127 | 131 | ||
128 | sb = sget(fs_type, NULL, v9fs_set_super, v9ses); | 132 | sb = sget(fs_type, NULL, v9fs_set_super, v9ses); |
129 | if (IS_ERR(sb)) { | 133 | if (IS_ERR(sb)) { |
130 | retval = PTR_ERR(sb); | 134 | retval = PTR_ERR(sb); |
131 | goto clunk_fid; | 135 | goto clunk_fid; |
132 | } | 136 | } |
133 | v9fs_fill_super(sb, v9ses, flags, data); | 137 | v9fs_fill_super(sb, v9ses, flags, data); |
134 | 138 | ||
135 | inode = v9fs_get_inode(sb, S_IFDIR | mode); | 139 | inode = v9fs_get_inode(sb, S_IFDIR | mode); |
136 | if (IS_ERR(inode)) { | 140 | if (IS_ERR(inode)) { |
137 | retval = PTR_ERR(inode); | 141 | retval = PTR_ERR(inode); |
138 | goto release_sb; | 142 | goto release_sb; |
139 | } | 143 | } |
140 | 144 | ||
141 | root = d_alloc_root(inode); | 145 | root = d_alloc_root(inode); |
142 | if (!root) { | 146 | if (!root) { |
143 | iput(inode); | 147 | iput(inode); |
144 | retval = -ENOMEM; | 148 | retval = -ENOMEM; |
145 | goto release_sb; | 149 | goto release_sb; |
146 | } | 150 | } |
147 | |||
148 | sb->s_root = root; | 151 | sb->s_root = root; |
149 | 152 | ||
150 | if (v9fs_proto_dotl(v9ses)) { | 153 | if (v9fs_proto_dotl(v9ses)) { |
151 | struct p9_stat_dotl *st = NULL; | 154 | struct p9_stat_dotl *st = NULL; |
152 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); | 155 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); |
153 | if (IS_ERR(st)) { | 156 | if (IS_ERR(st)) { |
154 | retval = PTR_ERR(st); | 157 | retval = PTR_ERR(st); |
155 | goto clunk_fid; | 158 | goto release_sb; |
156 | } | 159 | } |
157 | 160 | ||
158 | v9fs_stat2inode_dotl(st, root->d_inode); | 161 | v9fs_stat2inode_dotl(st, root->d_inode); |
159 | kfree(st); | 162 | kfree(st); |
160 | } else { | 163 | } else { |
161 | struct p9_wstat *st = NULL; | 164 | struct p9_wstat *st = NULL; |
162 | st = p9_client_stat(fid); | 165 | st = p9_client_stat(fid); |
163 | if (IS_ERR(st)) { | 166 | if (IS_ERR(st)) { |
164 | retval = PTR_ERR(st); | 167 | retval = PTR_ERR(st); |
165 | goto clunk_fid; | 168 | goto release_sb; |
166 | } | 169 | } |
167 | 170 | ||
168 | root->d_inode->i_ino = v9fs_qid2ino(&st->qid); | 171 | root->d_inode->i_ino = v9fs_qid2ino(&st->qid); |
169 | v9fs_stat2inode(st, root->d_inode, sb); | 172 | v9fs_stat2inode(st, root->d_inode, sb); |
170 | 173 | ||
171 | p9stat_free(st); | 174 | p9stat_free(st); |
172 | kfree(st); | 175 | kfree(st); |
173 | } | 176 | } |
174 | 177 | ||
175 | v9fs_fid_add(root, fid); | 178 | v9fs_fid_add(root, fid); |
176 | 179 | ||
177 | P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); | 180 | P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); |
178 | simple_set_mnt(mnt, sb); | 181 | simple_set_mnt(mnt, sb); |
179 | return 0; | 182 | return 0; |
180 | 183 | ||
181 | clunk_fid: | 184 | clunk_fid: |
182 | p9_client_clunk(fid); | 185 | p9_client_clunk(fid); |
183 | |||
184 | close_session: | 186 | close_session: |
185 | v9fs_session_close(v9ses); | 187 | v9fs_session_close(v9ses); |
186 | kfree(v9ses); | 188 | kfree(v9ses); |
187 | return retval; | 189 | return retval; |
188 | |||
189 | release_sb: | 190 | release_sb: |
191 | /* | ||
192 | * we will do the session_close and root dentry release | ||
193 | * in the below call. But we need to clunk fid, because we haven't | ||
194 | * attached the fid to dentry so it won't get clunked | ||
195 | * automatically. | ||
196 | */ | ||
197 | p9_client_clunk(fid); | ||
190 | deactivate_locked_super(sb); | 198 | deactivate_locked_super(sb); |
191 | return retval; | 199 | return retval; |
192 | } | 200 | } |
193 | 201 | ||
194 | /** | 202 | /** |
195 | * v9fs_kill_super - Kill Superblock | 203 | * v9fs_kill_super - Kill Superblock |
196 | * @s: superblock | 204 | * @s: superblock |
197 | * | 205 | * |
198 | */ | 206 | */ |
199 | 207 | ||
200 | static void v9fs_kill_super(struct super_block *s) | 208 | static void v9fs_kill_super(struct super_block *s) |
201 | { | 209 | { |
202 | struct v9fs_session_info *v9ses = s->s_fs_info; | 210 | struct v9fs_session_info *v9ses = s->s_fs_info; |
203 | 211 | ||
204 | P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s); | 212 | P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s); |
205 | 213 | ||
206 | if (s->s_root) | 214 | if (s->s_root) |
207 | v9fs_dentry_release(s->s_root); /* clunk root */ | 215 | v9fs_dentry_release(s->s_root); /* clunk root */ |
208 | 216 | ||
209 | kill_anon_super(s); | 217 | kill_anon_super(s); |
210 | 218 | ||
211 | v9fs_session_cancel(v9ses); | 219 | v9fs_session_cancel(v9ses); |
212 | v9fs_session_close(v9ses); | 220 | v9fs_session_close(v9ses); |
213 | kfree(v9ses); | 221 | kfree(v9ses); |
214 | s->s_fs_info = NULL; | 222 | s->s_fs_info = NULL; |
215 | P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n"); | 223 | P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n"); |
216 | } | 224 | } |
217 | 225 | ||
218 | static void | 226 | static void |
219 | v9fs_umount_begin(struct super_block *sb) | 227 | v9fs_umount_begin(struct super_block *sb) |
220 | { | 228 | { |
221 | struct v9fs_session_info *v9ses; | 229 | struct v9fs_session_info *v9ses; |
222 | 230 | ||
223 | v9ses = sb->s_fs_info; | 231 | v9ses = sb->s_fs_info; |
224 | v9fs_session_begin_cancel(v9ses); | 232 | v9fs_session_begin_cancel(v9ses); |
225 | } | 233 | } |
226 | 234 | ||
227 | static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf) | 235 | static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf) |
228 | { | 236 | { |
229 | struct v9fs_session_info *v9ses; | 237 | struct v9fs_session_info *v9ses; |
230 | struct p9_fid *fid; | 238 | struct p9_fid *fid; |
231 | struct p9_rstatfs rs; | 239 | struct p9_rstatfs rs; |
232 | int res; | 240 | int res; |
233 | 241 | ||
234 | fid = v9fs_fid_lookup(dentry); | 242 | fid = v9fs_fid_lookup(dentry); |
235 | if (IS_ERR(fid)) { | 243 | if (IS_ERR(fid)) { |
236 | res = PTR_ERR(fid); | 244 | res = PTR_ERR(fid); |
237 | goto done; | 245 | goto done; |
238 | } | 246 | } |
239 | 247 | ||
240 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 248 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
241 | if (v9fs_proto_dotl(v9ses)) { | 249 | if (v9fs_proto_dotl(v9ses)) { |
242 | res = p9_client_statfs(fid, &rs); | 250 | res = p9_client_statfs(fid, &rs); |
243 | if (res == 0) { | 251 | if (res == 0) { |
244 | buf->f_type = rs.type; | 252 | buf->f_type = rs.type; |
245 | buf->f_bsize = rs.bsize; | 253 | buf->f_bsize = rs.bsize; |
246 | buf->f_blocks = rs.blocks; | 254 | buf->f_blocks = rs.blocks; |
247 | buf->f_bfree = rs.bfree; | 255 | buf->f_bfree = rs.bfree; |
248 | buf->f_bavail = rs.bavail; | 256 | buf->f_bavail = rs.bavail; |
249 | buf->f_files = rs.files; | 257 | buf->f_files = rs.files; |
250 | buf->f_ffree = rs.ffree; | 258 | buf->f_ffree = rs.ffree; |
251 | buf->f_fsid.val[0] = rs.fsid & 0xFFFFFFFFUL; | 259 | buf->f_fsid.val[0] = rs.fsid & 0xFFFFFFFFUL; |
252 | buf->f_fsid.val[1] = (rs.fsid >> 32) & 0xFFFFFFFFUL; | 260 | buf->f_fsid.val[1] = (rs.fsid >> 32) & 0xFFFFFFFFUL; |
253 | buf->f_namelen = rs.namelen; | 261 | buf->f_namelen = rs.namelen; |
254 | } | 262 | } |
255 | if (res != -ENOSYS) | 263 | if (res != -ENOSYS) |
256 | goto done; | 264 | goto done; |
257 | } | 265 | } |
258 | res = simple_statfs(dentry, buf); | 266 | res = simple_statfs(dentry, buf); |
259 | done: | 267 | done: |
260 | return res; | 268 | return res; |
261 | } | 269 | } |
262 | 270 | ||
263 | static const struct super_operations v9fs_super_ops = { | 271 | static const struct super_operations v9fs_super_ops = { |
264 | #ifdef CONFIG_9P_FSCACHE | 272 | #ifdef CONFIG_9P_FSCACHE |
265 | .alloc_inode = v9fs_alloc_inode, | 273 | .alloc_inode = v9fs_alloc_inode, |
266 | .destroy_inode = v9fs_destroy_inode, | 274 | .destroy_inode = v9fs_destroy_inode, |
267 | #endif | 275 | #endif |
268 | .statfs = simple_statfs, | 276 | .statfs = simple_statfs, |
269 | .evict_inode = v9fs_evict_inode, | 277 | .evict_inode = v9fs_evict_inode, |
270 | .show_options = generic_show_options, | 278 | .show_options = generic_show_options, |
271 | .umount_begin = v9fs_umount_begin, | 279 | .umount_begin = v9fs_umount_begin, |
272 | }; | 280 | }; |
273 | 281 | ||
274 | static const struct super_operations v9fs_super_ops_dotl = { | 282 | static const struct super_operations v9fs_super_ops_dotl = { |
275 | #ifdef CONFIG_9P_FSCACHE | 283 | #ifdef CONFIG_9P_FSCACHE |
276 | .alloc_inode = v9fs_alloc_inode, | 284 | .alloc_inode = v9fs_alloc_inode, |
277 | .destroy_inode = v9fs_destroy_inode, | 285 | .destroy_inode = v9fs_destroy_inode, |
278 | #endif | 286 | #endif |
279 | .statfs = v9fs_statfs, | 287 | .statfs = v9fs_statfs, |
280 | .evict_inode = v9fs_evict_inode, | 288 | .evict_inode = v9fs_evict_inode, |
281 | .show_options = generic_show_options, | 289 | .show_options = generic_show_options, |
282 | .umount_begin = v9fs_umount_begin, | 290 | .umount_begin = v9fs_umount_begin, |
283 | }; | 291 | }; |
284 | 292 | ||
285 | struct file_system_type v9fs_fs_type = { | 293 | struct file_system_type v9fs_fs_type = { |
286 | .name = "9p", | 294 | .name = "9p", |
287 | .get_sb = v9fs_get_sb, | 295 | .get_sb = v9fs_get_sb, |
288 | .kill_sb = v9fs_kill_super, | 296 | .kill_sb = v9fs_kill_super, |
289 | .owner = THIS_MODULE, | 297 | .owner = THIS_MODULE, |
net/9p/client.c
1 | /* | 1 | /* |
2 | * net/9p/clnt.c | 2 | * net/9p/clnt.c |
3 | * | 3 | * |
4 | * 9P Client | 4 | * 9P Client |
5 | * | 5 | * |
6 | * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> | 6 | * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> |
7 | * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> | 7 | * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 | 10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | 11 | * as published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to: | 19 | * along with this program; if not, write to: |
20 | * Free Software Foundation | 20 | * Free Software Foundation |
21 | * 51 Franklin Street, Fifth Floor | 21 | * 51 Franklin Street, Fifth Floor |
22 | * Boston, MA 02111-1301 USA | 22 | * Boston, MA 02111-1301 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/poll.h> | 29 | #include <linux/poll.h> |
30 | #include <linux/idr.h> | 30 | #include <linux/idr.h> |
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | #include <net/9p/9p.h> | 35 | #include <net/9p/9p.h> |
36 | #include <linux/parser.h> | 36 | #include <linux/parser.h> |
37 | #include <net/9p/client.h> | 37 | #include <net/9p/client.h> |
38 | #include <net/9p/transport.h> | 38 | #include <net/9p/transport.h> |
39 | #include "protocol.h" | 39 | #include "protocol.h" |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Client Option Parsing (code inspired by NFS code) | 42 | * Client Option Parsing (code inspired by NFS code) |
43 | * - a little lazy - parse all client options | 43 | * - a little lazy - parse all client options |
44 | */ | 44 | */ |
45 | 45 | ||
46 | enum { | 46 | enum { |
47 | Opt_msize, | 47 | Opt_msize, |
48 | Opt_trans, | 48 | Opt_trans, |
49 | Opt_legacy, | 49 | Opt_legacy, |
50 | Opt_version, | 50 | Opt_version, |
51 | Opt_err, | 51 | Opt_err, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static const match_table_t tokens = { | 54 | static const match_table_t tokens = { |
55 | {Opt_msize, "msize=%u"}, | 55 | {Opt_msize, "msize=%u"}, |
56 | {Opt_legacy, "noextend"}, | 56 | {Opt_legacy, "noextend"}, |
57 | {Opt_trans, "trans=%s"}, | 57 | {Opt_trans, "trans=%s"}, |
58 | {Opt_version, "version=%s"}, | 58 | {Opt_version, "version=%s"}, |
59 | {Opt_err, NULL}, | 59 | {Opt_err, NULL}, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | inline int p9_is_proto_dotl(struct p9_client *clnt) | 62 | inline int p9_is_proto_dotl(struct p9_client *clnt) |
63 | { | 63 | { |
64 | return (clnt->proto_version == p9_proto_2000L); | 64 | return (clnt->proto_version == p9_proto_2000L); |
65 | } | 65 | } |
66 | EXPORT_SYMBOL(p9_is_proto_dotl); | 66 | EXPORT_SYMBOL(p9_is_proto_dotl); |
67 | 67 | ||
68 | inline int p9_is_proto_dotu(struct p9_client *clnt) | 68 | inline int p9_is_proto_dotu(struct p9_client *clnt) |
69 | { | 69 | { |
70 | return (clnt->proto_version == p9_proto_2000u); | 70 | return (clnt->proto_version == p9_proto_2000u); |
71 | } | 71 | } |
72 | EXPORT_SYMBOL(p9_is_proto_dotu); | 72 | EXPORT_SYMBOL(p9_is_proto_dotu); |
73 | 73 | ||
74 | /* Interpret mount option for protocol version */ | 74 | /* Interpret mount option for protocol version */ |
75 | static int get_protocol_version(const substring_t *name) | 75 | static int get_protocol_version(const substring_t *name) |
76 | { | 76 | { |
77 | int version = -EINVAL; | 77 | int version = -EINVAL; |
78 | 78 | ||
79 | if (!strncmp("9p2000", name->from, name->to-name->from)) { | 79 | if (!strncmp("9p2000", name->from, name->to-name->from)) { |
80 | version = p9_proto_legacy; | 80 | version = p9_proto_legacy; |
81 | P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n"); | 81 | P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n"); |
82 | } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) { | 82 | } else if (!strncmp("9p2000.u", name->from, name->to-name->from)) { |
83 | version = p9_proto_2000u; | 83 | version = p9_proto_2000u; |
84 | P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n"); | 84 | P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n"); |
85 | } else if (!strncmp("9p2000.L", name->from, name->to-name->from)) { | 85 | } else if (!strncmp("9p2000.L", name->from, name->to-name->from)) { |
86 | version = p9_proto_2000L; | 86 | version = p9_proto_2000L; |
87 | P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n"); | 87 | P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n"); |
88 | } else { | 88 | } else { |
89 | P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ", | 89 | P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ", |
90 | name->from); | 90 | name->from); |
91 | } | 91 | } |
92 | return version; | 92 | return version; |
93 | } | 93 | } |
94 | 94 | ||
95 | static struct p9_req_t * | 95 | static struct p9_req_t * |
96 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); | 96 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); |
97 | 97 | ||
98 | /** | 98 | /** |
99 | * parse_options - parse mount options into client structure | 99 | * parse_options - parse mount options into client structure |
100 | * @opts: options string passed from mount | 100 | * @opts: options string passed from mount |
101 | * @clnt: existing v9fs client information | 101 | * @clnt: existing v9fs client information |
102 | * | 102 | * |
103 | * Return 0 upon success, -ERRNO upon failure | 103 | * Return 0 upon success, -ERRNO upon failure |
104 | */ | 104 | */ |
105 | 105 | ||
106 | static int parse_opts(char *opts, struct p9_client *clnt) | 106 | static int parse_opts(char *opts, struct p9_client *clnt) |
107 | { | 107 | { |
108 | char *options, *tmp_options; | 108 | char *options, *tmp_options; |
109 | char *p; | 109 | char *p; |
110 | substring_t args[MAX_OPT_ARGS]; | 110 | substring_t args[MAX_OPT_ARGS]; |
111 | int option; | 111 | int option; |
112 | int ret = 0; | 112 | int ret = 0; |
113 | 113 | ||
114 | clnt->proto_version = p9_proto_2000u; | 114 | clnt->proto_version = p9_proto_2000u; |
115 | clnt->msize = 8192; | 115 | clnt->msize = 8192; |
116 | 116 | ||
117 | if (!opts) | 117 | if (!opts) |
118 | return 0; | 118 | return 0; |
119 | 119 | ||
120 | tmp_options = kstrdup(opts, GFP_KERNEL); | 120 | tmp_options = kstrdup(opts, GFP_KERNEL); |
121 | if (!tmp_options) { | 121 | if (!tmp_options) { |
122 | P9_DPRINTK(P9_DEBUG_ERROR, | 122 | P9_DPRINTK(P9_DEBUG_ERROR, |
123 | "failed to allocate copy of option string\n"); | 123 | "failed to allocate copy of option string\n"); |
124 | return -ENOMEM; | 124 | return -ENOMEM; |
125 | } | 125 | } |
126 | options = tmp_options; | 126 | options = tmp_options; |
127 | 127 | ||
128 | while ((p = strsep(&options, ",")) != NULL) { | 128 | while ((p = strsep(&options, ",")) != NULL) { |
129 | int token; | 129 | int token; |
130 | if (!*p) | 130 | if (!*p) |
131 | continue; | 131 | continue; |
132 | token = match_token(p, tokens, args); | 132 | token = match_token(p, tokens, args); |
133 | if (token < Opt_trans) { | 133 | if (token < Opt_trans) { |
134 | int r = match_int(&args[0], &option); | 134 | int r = match_int(&args[0], &option); |
135 | if (r < 0) { | 135 | if (r < 0) { |
136 | P9_DPRINTK(P9_DEBUG_ERROR, | 136 | P9_DPRINTK(P9_DEBUG_ERROR, |
137 | "integer field, but no integer?\n"); | 137 | "integer field, but no integer?\n"); |
138 | ret = r; | 138 | ret = r; |
139 | continue; | 139 | continue; |
140 | } | 140 | } |
141 | } | 141 | } |
142 | switch (token) { | 142 | switch (token) { |
143 | case Opt_msize: | 143 | case Opt_msize: |
144 | clnt->msize = option; | 144 | clnt->msize = option; |
145 | break; | 145 | break; |
146 | case Opt_trans: | 146 | case Opt_trans: |
147 | clnt->trans_mod = v9fs_get_trans_by_name(&args[0]); | 147 | clnt->trans_mod = v9fs_get_trans_by_name(&args[0]); |
148 | if(clnt->trans_mod == NULL) { | 148 | if(clnt->trans_mod == NULL) { |
149 | P9_DPRINTK(P9_DEBUG_ERROR, | 149 | P9_DPRINTK(P9_DEBUG_ERROR, |
150 | "Could not find request transport: %s\n", | 150 | "Could not find request transport: %s\n", |
151 | (char *) &args[0]); | 151 | (char *) &args[0]); |
152 | ret = -EINVAL; | 152 | ret = -EINVAL; |
153 | goto free_and_return; | 153 | goto free_and_return; |
154 | } | 154 | } |
155 | break; | 155 | break; |
156 | case Opt_legacy: | 156 | case Opt_legacy: |
157 | clnt->proto_version = p9_proto_legacy; | 157 | clnt->proto_version = p9_proto_legacy; |
158 | break; | 158 | break; |
159 | case Opt_version: | 159 | case Opt_version: |
160 | ret = get_protocol_version(&args[0]); | 160 | ret = get_protocol_version(&args[0]); |
161 | if (ret == -EINVAL) | 161 | if (ret == -EINVAL) |
162 | goto free_and_return; | 162 | goto free_and_return; |
163 | clnt->proto_version = ret; | 163 | clnt->proto_version = ret; |
164 | break; | 164 | break; |
165 | default: | 165 | default: |
166 | continue; | 166 | continue; |
167 | } | 167 | } |
168 | } | 168 | } |
169 | 169 | ||
170 | free_and_return: | 170 | free_and_return: |
171 | kfree(tmp_options); | 171 | kfree(tmp_options); |
172 | return ret; | 172 | return ret; |
173 | } | 173 | } |
174 | 174 | ||
175 | /** | 175 | /** |
176 | * p9_tag_alloc - lookup/allocate a request by tag | 176 | * p9_tag_alloc - lookup/allocate a request by tag |
177 | * @c: client session to lookup tag within | 177 | * @c: client session to lookup tag within |
178 | * @tag: numeric id for transaction | 178 | * @tag: numeric id for transaction |
179 | * | 179 | * |
180 | * this is a simple array lookup, but will grow the | 180 | * this is a simple array lookup, but will grow the |
181 | * request_slots as necessary to accomodate transaction | 181 | * request_slots as necessary to accomodate transaction |
182 | * ids which did not previously have a slot. | 182 | * ids which did not previously have a slot. |
183 | * | 183 | * |
184 | * this code relies on the client spinlock to manage locks, its | 184 | * this code relies on the client spinlock to manage locks, its |
185 | * possible we should switch to something else, but I'd rather | 185 | * possible we should switch to something else, but I'd rather |
186 | * stick with something low-overhead for the common case. | 186 | * stick with something low-overhead for the common case. |
187 | * | 187 | * |
188 | */ | 188 | */ |
189 | 189 | ||
190 | static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | 190 | static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) |
191 | { | 191 | { |
192 | unsigned long flags; | 192 | unsigned long flags; |
193 | int row, col; | 193 | int row, col; |
194 | struct p9_req_t *req; | 194 | struct p9_req_t *req; |
195 | 195 | ||
196 | /* This looks up the original request by tag so we know which | 196 | /* This looks up the original request by tag so we know which |
197 | * buffer to read the data into */ | 197 | * buffer to read the data into */ |
198 | tag++; | 198 | tag++; |
199 | 199 | ||
200 | if (tag >= c->max_tag) { | 200 | if (tag >= c->max_tag) { |
201 | spin_lock_irqsave(&c->lock, flags); | 201 | spin_lock_irqsave(&c->lock, flags); |
202 | /* check again since original check was outside of lock */ | 202 | /* check again since original check was outside of lock */ |
203 | while (tag >= c->max_tag) { | 203 | while (tag >= c->max_tag) { |
204 | row = (tag / P9_ROW_MAXTAG); | 204 | row = (tag / P9_ROW_MAXTAG); |
205 | c->reqs[row] = kcalloc(P9_ROW_MAXTAG, | 205 | c->reqs[row] = kcalloc(P9_ROW_MAXTAG, |
206 | sizeof(struct p9_req_t), GFP_ATOMIC); | 206 | sizeof(struct p9_req_t), GFP_ATOMIC); |
207 | 207 | ||
208 | if (!c->reqs[row]) { | 208 | if (!c->reqs[row]) { |
209 | printk(KERN_ERR "Couldn't grow tag array\n"); | 209 | printk(KERN_ERR "Couldn't grow tag array\n"); |
210 | spin_unlock_irqrestore(&c->lock, flags); | 210 | spin_unlock_irqrestore(&c->lock, flags); |
211 | return ERR_PTR(-ENOMEM); | 211 | return ERR_PTR(-ENOMEM); |
212 | } | 212 | } |
213 | for (col = 0; col < P9_ROW_MAXTAG; col++) { | 213 | for (col = 0; col < P9_ROW_MAXTAG; col++) { |
214 | c->reqs[row][col].status = REQ_STATUS_IDLE; | 214 | c->reqs[row][col].status = REQ_STATUS_IDLE; |
215 | c->reqs[row][col].tc = NULL; | 215 | c->reqs[row][col].tc = NULL; |
216 | } | 216 | } |
217 | c->max_tag += P9_ROW_MAXTAG; | 217 | c->max_tag += P9_ROW_MAXTAG; |
218 | } | 218 | } |
219 | spin_unlock_irqrestore(&c->lock, flags); | 219 | spin_unlock_irqrestore(&c->lock, flags); |
220 | } | 220 | } |
221 | row = tag / P9_ROW_MAXTAG; | 221 | row = tag / P9_ROW_MAXTAG; |
222 | col = tag % P9_ROW_MAXTAG; | 222 | col = tag % P9_ROW_MAXTAG; |
223 | 223 | ||
224 | req = &c->reqs[row][col]; | 224 | req = &c->reqs[row][col]; |
225 | if (!req->tc) { | 225 | if (!req->tc) { |
226 | req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); | 226 | req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); |
227 | if (!req->wq) { | 227 | if (!req->wq) { |
228 | printk(KERN_ERR "Couldn't grow tag array\n"); | 228 | printk(KERN_ERR "Couldn't grow tag array\n"); |
229 | return ERR_PTR(-ENOMEM); | 229 | return ERR_PTR(-ENOMEM); |
230 | } | 230 | } |
231 | init_waitqueue_head(req->wq); | 231 | init_waitqueue_head(req->wq); |
232 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | 232 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, |
233 | GFP_KERNEL); | 233 | GFP_KERNEL); |
234 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | 234 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, |
235 | GFP_KERNEL); | 235 | GFP_KERNEL); |
236 | if ((!req->tc) || (!req->rc)) { | 236 | if ((!req->tc) || (!req->rc)) { |
237 | printk(KERN_ERR "Couldn't grow tag array\n"); | 237 | printk(KERN_ERR "Couldn't grow tag array\n"); |
238 | kfree(req->tc); | 238 | kfree(req->tc); |
239 | kfree(req->rc); | 239 | kfree(req->rc); |
240 | kfree(req->wq); | 240 | kfree(req->wq); |
241 | req->tc = req->rc = NULL; | 241 | req->tc = req->rc = NULL; |
242 | req->wq = NULL; | 242 | req->wq = NULL; |
243 | return ERR_PTR(-ENOMEM); | 243 | return ERR_PTR(-ENOMEM); |
244 | } | 244 | } |
245 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); | 245 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); |
246 | req->tc->capacity = c->msize; | 246 | req->tc->capacity = c->msize; |
247 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); | 247 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); |
248 | req->rc->capacity = c->msize; | 248 | req->rc->capacity = c->msize; |
249 | } | 249 | } |
250 | 250 | ||
251 | p9pdu_reset(req->tc); | 251 | p9pdu_reset(req->tc); |
252 | p9pdu_reset(req->rc); | 252 | p9pdu_reset(req->rc); |
253 | 253 | ||
254 | req->tc->tag = tag-1; | 254 | req->tc->tag = tag-1; |
255 | req->status = REQ_STATUS_ALLOC; | 255 | req->status = REQ_STATUS_ALLOC; |
256 | 256 | ||
257 | return &c->reqs[row][col]; | 257 | return &c->reqs[row][col]; |
258 | } | 258 | } |
259 | 259 | ||
260 | /** | 260 | /** |
261 | * p9_tag_lookup - lookup a request by tag | 261 | * p9_tag_lookup - lookup a request by tag |
262 | * @c: client session to lookup tag within | 262 | * @c: client session to lookup tag within |
263 | * @tag: numeric id for transaction | 263 | * @tag: numeric id for transaction |
264 | * | 264 | * |
265 | */ | 265 | */ |
266 | 266 | ||
267 | struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) | 267 | struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) |
268 | { | 268 | { |
269 | int row, col; | 269 | int row, col; |
270 | 270 | ||
271 | /* This looks up the original request by tag so we know which | 271 | /* This looks up the original request by tag so we know which |
272 | * buffer to read the data into */ | 272 | * buffer to read the data into */ |
273 | tag++; | 273 | tag++; |
274 | 274 | ||
275 | BUG_ON(tag >= c->max_tag); | 275 | BUG_ON(tag >= c->max_tag); |
276 | 276 | ||
277 | row = tag / P9_ROW_MAXTAG; | 277 | row = tag / P9_ROW_MAXTAG; |
278 | col = tag % P9_ROW_MAXTAG; | 278 | col = tag % P9_ROW_MAXTAG; |
279 | 279 | ||
280 | return &c->reqs[row][col]; | 280 | return &c->reqs[row][col]; |
281 | } | 281 | } |
282 | EXPORT_SYMBOL(p9_tag_lookup); | 282 | EXPORT_SYMBOL(p9_tag_lookup); |
283 | 283 | ||
284 | /** | 284 | /** |
285 | * p9_tag_init - setup tags structure and contents | 285 | * p9_tag_init - setup tags structure and contents |
286 | * @c: v9fs client struct | 286 | * @c: v9fs client struct |
287 | * | 287 | * |
288 | * This initializes the tags structure for each client instance. | 288 | * This initializes the tags structure for each client instance. |
289 | * | 289 | * |
290 | */ | 290 | */ |
291 | 291 | ||
292 | static int p9_tag_init(struct p9_client *c) | 292 | static int p9_tag_init(struct p9_client *c) |
293 | { | 293 | { |
294 | int err = 0; | 294 | int err = 0; |
295 | 295 | ||
296 | c->tagpool = p9_idpool_create(); | 296 | c->tagpool = p9_idpool_create(); |
297 | if (IS_ERR(c->tagpool)) { | 297 | if (IS_ERR(c->tagpool)) { |
298 | err = PTR_ERR(c->tagpool); | 298 | err = PTR_ERR(c->tagpool); |
299 | c->tagpool = NULL; | 299 | c->tagpool = NULL; |
300 | goto error; | 300 | goto error; |
301 | } | 301 | } |
302 | 302 | ||
303 | p9_idpool_get(c->tagpool); /* reserve tag 0 */ | 303 | p9_idpool_get(c->tagpool); /* reserve tag 0 */ |
304 | 304 | ||
305 | c->max_tag = 0; | 305 | c->max_tag = 0; |
306 | error: | 306 | error: |
307 | return err; | 307 | return err; |
308 | } | 308 | } |
309 | 309 | ||
310 | /** | 310 | /** |
311 | * p9_tag_cleanup - cleans up tags structure and reclaims resources | 311 | * p9_tag_cleanup - cleans up tags structure and reclaims resources |
312 | * @c: v9fs client struct | 312 | * @c: v9fs client struct |
313 | * | 313 | * |
314 | * This frees resources associated with the tags structure | 314 | * This frees resources associated with the tags structure |
315 | * | 315 | * |
316 | */ | 316 | */ |
317 | static void p9_tag_cleanup(struct p9_client *c) | 317 | static void p9_tag_cleanup(struct p9_client *c) |
318 | { | 318 | { |
319 | int row, col; | 319 | int row, col; |
320 | 320 | ||
321 | /* check to insure all requests are idle */ | 321 | /* check to insure all requests are idle */ |
322 | for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { | 322 | for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { |
323 | for (col = 0; col < P9_ROW_MAXTAG; col++) { | 323 | for (col = 0; col < P9_ROW_MAXTAG; col++) { |
324 | if (c->reqs[row][col].status != REQ_STATUS_IDLE) { | 324 | if (c->reqs[row][col].status != REQ_STATUS_IDLE) { |
325 | P9_DPRINTK(P9_DEBUG_MUX, | 325 | P9_DPRINTK(P9_DEBUG_MUX, |
326 | "Attempting to cleanup non-free tag %d,%d\n", | 326 | "Attempting to cleanup non-free tag %d,%d\n", |
327 | row, col); | 327 | row, col); |
328 | /* TODO: delay execution of cleanup */ | 328 | /* TODO: delay execution of cleanup */ |
329 | return; | 329 | return; |
330 | } | 330 | } |
331 | } | 331 | } |
332 | } | 332 | } |
333 | 333 | ||
334 | if (c->tagpool) | 334 | if (c->tagpool) { |
335 | p9_idpool_put(0, c->tagpool); /* free reserved tag 0 */ | ||
335 | p9_idpool_destroy(c->tagpool); | 336 | p9_idpool_destroy(c->tagpool); |
337 | } | ||
336 | 338 | ||
337 | /* free requests associated with tags */ | 339 | /* free requests associated with tags */ |
338 | for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { | 340 | for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { |
339 | for (col = 0; col < P9_ROW_MAXTAG; col++) { | 341 | for (col = 0; col < P9_ROW_MAXTAG; col++) { |
340 | kfree(c->reqs[row][col].wq); | 342 | kfree(c->reqs[row][col].wq); |
341 | kfree(c->reqs[row][col].tc); | 343 | kfree(c->reqs[row][col].tc); |
342 | kfree(c->reqs[row][col].rc); | 344 | kfree(c->reqs[row][col].rc); |
343 | } | 345 | } |
344 | kfree(c->reqs[row]); | 346 | kfree(c->reqs[row]); |
345 | } | 347 | } |
346 | c->max_tag = 0; | 348 | c->max_tag = 0; |
347 | } | 349 | } |
348 | 350 | ||
349 | /** | 351 | /** |
350 | * p9_free_req - free a request and clean-up as necessary | 352 | * p9_free_req - free a request and clean-up as necessary |
351 | * c: client state | 353 | * c: client state |
352 | * r: request to release | 354 | * r: request to release |
353 | * | 355 | * |
354 | */ | 356 | */ |
355 | 357 | ||
356 | static void p9_free_req(struct p9_client *c, struct p9_req_t *r) | 358 | static void p9_free_req(struct p9_client *c, struct p9_req_t *r) |
357 | { | 359 | { |
358 | int tag = r->tc->tag; | 360 | int tag = r->tc->tag; |
359 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag); | 361 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag); |
360 | 362 | ||
361 | r->status = REQ_STATUS_IDLE; | 363 | r->status = REQ_STATUS_IDLE; |
362 | if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool)) | 364 | if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool)) |
363 | p9_idpool_put(tag, c->tagpool); | 365 | p9_idpool_put(tag, c->tagpool); |
364 | } | 366 | } |
365 | 367 | ||
366 | /** | 368 | /** |
367 | * p9_client_cb - call back from transport to client | 369 | * p9_client_cb - call back from transport to client |
368 | * c: client state | 370 | * c: client state |
369 | * req: request received | 371 | * req: request received |
370 | * | 372 | * |
371 | */ | 373 | */ |
372 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req) | 374 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req) |
373 | { | 375 | { |
374 | P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); | 376 | P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); |
375 | wake_up(req->wq); | 377 | wake_up(req->wq); |
376 | P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); | 378 | P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag); |
377 | } | 379 | } |
378 | EXPORT_SYMBOL(p9_client_cb); | 380 | EXPORT_SYMBOL(p9_client_cb); |
379 | 381 | ||
380 | /** | 382 | /** |
381 | * p9_parse_header - parse header arguments out of a packet | 383 | * p9_parse_header - parse header arguments out of a packet |
382 | * @pdu: packet to parse | 384 | * @pdu: packet to parse |
383 | * @size: size of packet | 385 | * @size: size of packet |
384 | * @type: type of request | 386 | * @type: type of request |
385 | * @tag: tag of packet | 387 | * @tag: tag of packet |
386 | * @rewind: set if we need to rewind offset afterwards | 388 | * @rewind: set if we need to rewind offset afterwards |
387 | */ | 389 | */ |
388 | 390 | ||
389 | int | 391 | int |
390 | p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, | 392 | p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, |
391 | int rewind) | 393 | int rewind) |
392 | { | 394 | { |
393 | int8_t r_type; | 395 | int8_t r_type; |
394 | int16_t r_tag; | 396 | int16_t r_tag; |
395 | int32_t r_size; | 397 | int32_t r_size; |
396 | int offset = pdu->offset; | 398 | int offset = pdu->offset; |
397 | int err; | 399 | int err; |
398 | 400 | ||
399 | pdu->offset = 0; | 401 | pdu->offset = 0; |
400 | if (pdu->size == 0) | 402 | if (pdu->size == 0) |
401 | pdu->size = 7; | 403 | pdu->size = 7; |
402 | 404 | ||
403 | err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag); | 405 | err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag); |
404 | if (err) | 406 | if (err) |
405 | goto rewind_and_exit; | 407 | goto rewind_and_exit; |
406 | 408 | ||
407 | pdu->size = r_size; | 409 | pdu->size = r_size; |
408 | pdu->id = r_type; | 410 | pdu->id = r_type; |
409 | pdu->tag = r_tag; | 411 | pdu->tag = r_tag; |
410 | 412 | ||
411 | P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size, | 413 | P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size, |
412 | pdu->id, pdu->tag); | 414 | pdu->id, pdu->tag); |
413 | 415 | ||
414 | if (type) | 416 | if (type) |
415 | *type = r_type; | 417 | *type = r_type; |
416 | if (tag) | 418 | if (tag) |
417 | *tag = r_tag; | 419 | *tag = r_tag; |
418 | if (size) | 420 | if (size) |
419 | *size = r_size; | 421 | *size = r_size; |
420 | 422 | ||
421 | 423 | ||
422 | rewind_and_exit: | 424 | rewind_and_exit: |
423 | if (rewind) | 425 | if (rewind) |
424 | pdu->offset = offset; | 426 | pdu->offset = offset; |
425 | return err; | 427 | return err; |
426 | } | 428 | } |
427 | EXPORT_SYMBOL(p9_parse_header); | 429 | EXPORT_SYMBOL(p9_parse_header); |
428 | 430 | ||
429 | /** | 431 | /** |
430 | * p9_check_errors - check 9p packet for error return and process it | 432 | * p9_check_errors - check 9p packet for error return and process it |
431 | * @c: current client instance | 433 | * @c: current client instance |
432 | * @req: request to parse and check for error conditions | 434 | * @req: request to parse and check for error conditions |
433 | * | 435 | * |
434 | * returns error code if one is discovered, otherwise returns 0 | 436 | * returns error code if one is discovered, otherwise returns 0 |
435 | * | 437 | * |
436 | * this will have to be more complicated if we have multiple | 438 | * this will have to be more complicated if we have multiple |
437 | * error packet types | 439 | * error packet types |
438 | */ | 440 | */ |
439 | 441 | ||
440 | static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | 442 | static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) |
441 | { | 443 | { |
442 | int8_t type; | 444 | int8_t type; |
443 | int err; | 445 | int err; |
444 | 446 | ||
445 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); | 447 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); |
446 | if (err) { | 448 | if (err) { |
447 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); | 449 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); |
448 | return err; | 450 | return err; |
449 | } | 451 | } |
450 | 452 | ||
451 | if (type == P9_RERROR) { | 453 | if (type == P9_RERROR) { |
452 | int ecode; | 454 | int ecode; |
453 | char *ename; | 455 | char *ename; |
454 | 456 | ||
455 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | 457 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", |
456 | &ename, &ecode); | 458 | &ename, &ecode); |
457 | if (err) { | 459 | if (err) { |
458 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", | 460 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", |
459 | err); | 461 | err); |
460 | return err; | 462 | return err; |
461 | } | 463 | } |
462 | 464 | ||
463 | if (p9_is_proto_dotu(c) || | 465 | if (p9_is_proto_dotu(c) || |
464 | p9_is_proto_dotl(c)) | 466 | p9_is_proto_dotl(c)) |
465 | err = -ecode; | 467 | err = -ecode; |
466 | 468 | ||
467 | if (!err || !IS_ERR_VALUE(err)) | 469 | if (!err || !IS_ERR_VALUE(err)) |
468 | err = p9_errstr2errno(ename, strlen(ename)); | 470 | err = p9_errstr2errno(ename, strlen(ename)); |
469 | 471 | ||
470 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | 472 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); |
471 | 473 | ||
472 | kfree(ename); | 474 | kfree(ename); |
473 | } else | 475 | } else |
474 | err = 0; | 476 | err = 0; |
475 | 477 | ||
476 | return err; | 478 | return err; |
477 | } | 479 | } |
478 | 480 | ||
479 | /** | 481 | /** |
480 | * p9_client_flush - flush (cancel) a request | 482 | * p9_client_flush - flush (cancel) a request |
481 | * @c: client state | 483 | * @c: client state |
482 | * @oldreq: request to cancel | 484 | * @oldreq: request to cancel |
483 | * | 485 | * |
484 | * This sents a flush for a particular requests and links | 486 | * This sents a flush for a particular requests and links |
485 | * the flush request to the original request. The current | 487 | * the flush request to the original request. The current |
486 | * code only supports a single flush request although the protocol | 488 | * code only supports a single flush request although the protocol |
487 | * allows for multiple flush requests to be sent for a single request. | 489 | * allows for multiple flush requests to be sent for a single request. |
488 | * | 490 | * |
489 | */ | 491 | */ |
490 | 492 | ||
491 | static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) | 493 | static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) |
492 | { | 494 | { |
493 | struct p9_req_t *req; | 495 | struct p9_req_t *req; |
494 | int16_t oldtag; | 496 | int16_t oldtag; |
495 | int err; | 497 | int err; |
496 | 498 | ||
497 | err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1); | 499 | err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1); |
498 | if (err) | 500 | if (err) |
499 | return err; | 501 | return err; |
500 | 502 | ||
501 | P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag); | 503 | P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag); |
502 | 504 | ||
503 | req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag); | 505 | req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag); |
504 | if (IS_ERR(req)) | 506 | if (IS_ERR(req)) |
505 | return PTR_ERR(req); | 507 | return PTR_ERR(req); |
506 | 508 | ||
507 | 509 | ||
508 | /* if we haven't received a response for oldreq, | 510 | /* if we haven't received a response for oldreq, |
509 | remove it from the list. */ | 511 | remove it from the list. */ |
510 | spin_lock(&c->lock); | 512 | spin_lock(&c->lock); |
511 | if (oldreq->status == REQ_STATUS_FLSH) | 513 | if (oldreq->status == REQ_STATUS_FLSH) |
512 | list_del(&oldreq->req_list); | 514 | list_del(&oldreq->req_list); |
513 | spin_unlock(&c->lock); | 515 | spin_unlock(&c->lock); |
514 | 516 | ||
515 | p9_free_req(c, req); | 517 | p9_free_req(c, req); |
516 | return 0; | 518 | return 0; |
517 | } | 519 | } |
518 | 520 | ||
519 | /** | 521 | /** |
520 | * p9_client_rpc - issue a request and wait for a response | 522 | * p9_client_rpc - issue a request and wait for a response |
521 | * @c: client session | 523 | * @c: client session |
522 | * @type: type of request | 524 | * @type: type of request |
523 | * @fmt: protocol format string (see protocol.c) | 525 | * @fmt: protocol format string (see protocol.c) |
524 | * | 526 | * |
525 | * Returns request structure (which client must free using p9_free_req) | 527 | * Returns request structure (which client must free using p9_free_req) |
526 | */ | 528 | */ |
527 | 529 | ||
528 | static struct p9_req_t * | 530 | static struct p9_req_t * |
529 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | 531 | p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) |
530 | { | 532 | { |
531 | va_list ap; | 533 | va_list ap; |
532 | int tag, err; | 534 | int tag, err; |
533 | struct p9_req_t *req; | 535 | struct p9_req_t *req; |
534 | unsigned long flags; | 536 | unsigned long flags; |
535 | int sigpending; | 537 | int sigpending; |
536 | 538 | ||
537 | P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); | 539 | P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); |
538 | 540 | ||
539 | /* we allow for any status other than disconnected */ | 541 | /* we allow for any status other than disconnected */ |
540 | if (c->status == Disconnected) | 542 | if (c->status == Disconnected) |
541 | return ERR_PTR(-EIO); | 543 | return ERR_PTR(-EIO); |
542 | 544 | ||
543 | /* if status is begin_disconnected we allow only clunk request */ | 545 | /* if status is begin_disconnected we allow only clunk request */ |
544 | if ((c->status == BeginDisconnect) && (type != P9_TCLUNK)) | 546 | if ((c->status == BeginDisconnect) && (type != P9_TCLUNK)) |
545 | return ERR_PTR(-EIO); | 547 | return ERR_PTR(-EIO); |
546 | 548 | ||
547 | if (signal_pending(current)) { | 549 | if (signal_pending(current)) { |
548 | sigpending = 1; | 550 | sigpending = 1; |
549 | clear_thread_flag(TIF_SIGPENDING); | 551 | clear_thread_flag(TIF_SIGPENDING); |
550 | } else | 552 | } else |
551 | sigpending = 0; | 553 | sigpending = 0; |
552 | 554 | ||
553 | tag = P9_NOTAG; | 555 | tag = P9_NOTAG; |
554 | if (type != P9_TVERSION) { | 556 | if (type != P9_TVERSION) { |
555 | tag = p9_idpool_get(c->tagpool); | 557 | tag = p9_idpool_get(c->tagpool); |
556 | if (tag < 0) | 558 | if (tag < 0) |
557 | return ERR_PTR(-ENOMEM); | 559 | return ERR_PTR(-ENOMEM); |
558 | } | 560 | } |
559 | 561 | ||
560 | req = p9_tag_alloc(c, tag); | 562 | req = p9_tag_alloc(c, tag); |
561 | if (IS_ERR(req)) | 563 | if (IS_ERR(req)) |
562 | return req; | 564 | return req; |
563 | 565 | ||
564 | /* marshall the data */ | 566 | /* marshall the data */ |
565 | p9pdu_prepare(req->tc, tag, type); | 567 | p9pdu_prepare(req->tc, tag, type); |
566 | va_start(ap, fmt); | 568 | va_start(ap, fmt); |
567 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); | 569 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); |
568 | va_end(ap); | 570 | va_end(ap); |
569 | p9pdu_finalize(req->tc); | 571 | p9pdu_finalize(req->tc); |
570 | 572 | ||
571 | err = c->trans_mod->request(c, req); | 573 | err = c->trans_mod->request(c, req); |
572 | if (err < 0) { | 574 | if (err < 0) { |
573 | c->status = Disconnected; | 575 | c->status = Disconnected; |
574 | goto reterr; | 576 | goto reterr; |
575 | } | 577 | } |
576 | 578 | ||
577 | P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag); | 579 | P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag); |
578 | err = wait_event_interruptible(*req->wq, | 580 | err = wait_event_interruptible(*req->wq, |
579 | req->status >= REQ_STATUS_RCVD); | 581 | req->status >= REQ_STATUS_RCVD); |
580 | P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d\n", | 582 | P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d\n", |
581 | req->wq, tag, err); | 583 | req->wq, tag, err); |
582 | 584 | ||
583 | if (req->status == REQ_STATUS_ERROR) { | 585 | if (req->status == REQ_STATUS_ERROR) { |
584 | P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); | 586 | P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); |
585 | err = req->t_err; | 587 | err = req->t_err; |
586 | } | 588 | } |
587 | 589 | ||
588 | if ((err == -ERESTARTSYS) && (c->status == Connected)) { | 590 | if ((err == -ERESTARTSYS) && (c->status == Connected)) { |
589 | P9_DPRINTK(P9_DEBUG_MUX, "flushing\n"); | 591 | P9_DPRINTK(P9_DEBUG_MUX, "flushing\n"); |
590 | sigpending = 1; | 592 | sigpending = 1; |
591 | clear_thread_flag(TIF_SIGPENDING); | 593 | clear_thread_flag(TIF_SIGPENDING); |
592 | 594 | ||
593 | if (c->trans_mod->cancel(c, req)) | 595 | if (c->trans_mod->cancel(c, req)) |
594 | p9_client_flush(c, req); | 596 | p9_client_flush(c, req); |
595 | 597 | ||
596 | /* if we received the response anyway, don't signal error */ | 598 | /* if we received the response anyway, don't signal error */ |
597 | if (req->status == REQ_STATUS_RCVD) | 599 | if (req->status == REQ_STATUS_RCVD) |
598 | err = 0; | 600 | err = 0; |
599 | } | 601 | } |
600 | 602 | ||
601 | if (sigpending) { | 603 | if (sigpending) { |
602 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 604 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
603 | recalc_sigpending(); | 605 | recalc_sigpending(); |
604 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 606 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
605 | } | 607 | } |
606 | 608 | ||
607 | if (err < 0) | 609 | if (err < 0) |
608 | goto reterr; | 610 | goto reterr; |
609 | 611 | ||
610 | err = p9_check_errors(c, req); | 612 | err = p9_check_errors(c, req); |
611 | if (!err) { | 613 | if (!err) { |
612 | P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type); | 614 | P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type); |
613 | return req; | 615 | return req; |
614 | } | 616 | } |
615 | 617 | ||
616 | reterr: | 618 | reterr: |
617 | P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type, | 619 | P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type, |
618 | err); | 620 | err); |
619 | p9_free_req(c, req); | 621 | p9_free_req(c, req); |
620 | return ERR_PTR(err); | 622 | return ERR_PTR(err); |
621 | } | 623 | } |
622 | 624 | ||
623 | static struct p9_fid *p9_fid_create(struct p9_client *clnt) | 625 | static struct p9_fid *p9_fid_create(struct p9_client *clnt) |
624 | { | 626 | { |
625 | int ret; | 627 | int ret; |
626 | struct p9_fid *fid; | 628 | struct p9_fid *fid; |
627 | unsigned long flags; | 629 | unsigned long flags; |
628 | 630 | ||
629 | P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt); | 631 | P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt); |
630 | fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); | 632 | fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL); |
631 | if (!fid) | 633 | if (!fid) |
632 | return ERR_PTR(-ENOMEM); | 634 | return ERR_PTR(-ENOMEM); |
633 | 635 | ||
634 | ret = p9_idpool_get(clnt->fidpool); | 636 | ret = p9_idpool_get(clnt->fidpool); |
635 | if (ret < 0) { | 637 | if (ret < 0) { |
636 | ret = -ENOSPC; | 638 | ret = -ENOSPC; |
637 | goto error; | 639 | goto error; |
638 | } | 640 | } |
639 | fid->fid = ret; | 641 | fid->fid = ret; |
640 | 642 | ||
641 | memset(&fid->qid, 0, sizeof(struct p9_qid)); | 643 | memset(&fid->qid, 0, sizeof(struct p9_qid)); |
642 | fid->mode = -1; | 644 | fid->mode = -1; |
643 | fid->uid = current_fsuid(); | 645 | fid->uid = current_fsuid(); |
644 | fid->clnt = clnt; | 646 | fid->clnt = clnt; |
645 | fid->rdir = NULL; | 647 | fid->rdir = NULL; |
646 | spin_lock_irqsave(&clnt->lock, flags); | 648 | spin_lock_irqsave(&clnt->lock, flags); |
647 | list_add(&fid->flist, &clnt->fidlist); | 649 | list_add(&fid->flist, &clnt->fidlist); |
648 | spin_unlock_irqrestore(&clnt->lock, flags); | 650 | spin_unlock_irqrestore(&clnt->lock, flags); |
649 | 651 | ||
650 | return fid; | 652 | return fid; |
651 | 653 | ||
652 | error: | 654 | error: |
653 | kfree(fid); | 655 | kfree(fid); |
654 | return ERR_PTR(ret); | 656 | return ERR_PTR(ret); |
655 | } | 657 | } |
656 | 658 | ||
657 | static void p9_fid_destroy(struct p9_fid *fid) | 659 | static void p9_fid_destroy(struct p9_fid *fid) |
658 | { | 660 | { |
659 | struct p9_client *clnt; | 661 | struct p9_client *clnt; |
660 | unsigned long flags; | 662 | unsigned long flags; |
661 | 663 | ||
662 | P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid); | 664 | P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid); |
663 | clnt = fid->clnt; | 665 | clnt = fid->clnt; |
664 | p9_idpool_put(fid->fid, clnt->fidpool); | 666 | p9_idpool_put(fid->fid, clnt->fidpool); |
665 | spin_lock_irqsave(&clnt->lock, flags); | 667 | spin_lock_irqsave(&clnt->lock, flags); |
666 | list_del(&fid->flist); | 668 | list_del(&fid->flist); |
667 | spin_unlock_irqrestore(&clnt->lock, flags); | 669 | spin_unlock_irqrestore(&clnt->lock, flags); |
668 | kfree(fid->rdir); | 670 | kfree(fid->rdir); |
669 | kfree(fid); | 671 | kfree(fid); |
670 | } | 672 | } |
671 | 673 | ||
672 | int p9_client_version(struct p9_client *c) | 674 | int p9_client_version(struct p9_client *c) |
673 | { | 675 | { |
674 | int err = 0; | 676 | int err = 0; |
675 | struct p9_req_t *req; | 677 | struct p9_req_t *req; |
676 | char *version; | 678 | char *version; |
677 | int msize; | 679 | int msize; |
678 | 680 | ||
679 | P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n", | 681 | P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n", |
680 | c->msize, c->proto_version); | 682 | c->msize, c->proto_version); |
681 | 683 | ||
682 | switch (c->proto_version) { | 684 | switch (c->proto_version) { |
683 | case p9_proto_2000L: | 685 | case p9_proto_2000L: |
684 | req = p9_client_rpc(c, P9_TVERSION, "ds", | 686 | req = p9_client_rpc(c, P9_TVERSION, "ds", |
685 | c->msize, "9P2000.L"); | 687 | c->msize, "9P2000.L"); |
686 | break; | 688 | break; |
687 | case p9_proto_2000u: | 689 | case p9_proto_2000u: |
688 | req = p9_client_rpc(c, P9_TVERSION, "ds", | 690 | req = p9_client_rpc(c, P9_TVERSION, "ds", |
689 | c->msize, "9P2000.u"); | 691 | c->msize, "9P2000.u"); |
690 | break; | 692 | break; |
691 | case p9_proto_legacy: | 693 | case p9_proto_legacy: |
692 | req = p9_client_rpc(c, P9_TVERSION, "ds", | 694 | req = p9_client_rpc(c, P9_TVERSION, "ds", |
693 | c->msize, "9P2000"); | 695 | c->msize, "9P2000"); |
694 | break; | 696 | break; |
695 | default: | 697 | default: |
696 | return -EINVAL; | 698 | return -EINVAL; |
697 | break; | 699 | break; |
698 | } | 700 | } |
699 | 701 | ||
700 | if (IS_ERR(req)) | 702 | if (IS_ERR(req)) |
701 | return PTR_ERR(req); | 703 | return PTR_ERR(req); |
702 | 704 | ||
703 | err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version); | 705 | err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version); |
704 | if (err) { | 706 | if (err) { |
705 | P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); | 707 | P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); |
706 | p9pdu_dump(1, req->rc); | 708 | p9pdu_dump(1, req->rc); |
707 | goto error; | 709 | goto error; |
708 | } | 710 | } |
709 | 711 | ||
710 | P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); | 712 | P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); |
711 | if (!strncmp(version, "9P2000.L", 8)) | 713 | if (!strncmp(version, "9P2000.L", 8)) |
712 | c->proto_version = p9_proto_2000L; | 714 | c->proto_version = p9_proto_2000L; |
713 | else if (!strncmp(version, "9P2000.u", 8)) | 715 | else if (!strncmp(version, "9P2000.u", 8)) |
714 | c->proto_version = p9_proto_2000u; | 716 | c->proto_version = p9_proto_2000u; |
715 | else if (!strncmp(version, "9P2000", 6)) | 717 | else if (!strncmp(version, "9P2000", 6)) |
716 | c->proto_version = p9_proto_legacy; | 718 | c->proto_version = p9_proto_legacy; |
717 | else { | 719 | else { |
718 | err = -EREMOTEIO; | 720 | err = -EREMOTEIO; |
719 | goto error; | 721 | goto error; |
720 | } | 722 | } |
721 | 723 | ||
722 | if (msize < c->msize) | 724 | if (msize < c->msize) |
723 | c->msize = msize; | 725 | c->msize = msize; |
724 | 726 | ||
725 | error: | 727 | error: |
726 | kfree(version); | 728 | kfree(version); |
727 | p9_free_req(c, req); | 729 | p9_free_req(c, req); |
728 | 730 | ||
729 | return err; | 731 | return err; |
730 | } | 732 | } |
731 | EXPORT_SYMBOL(p9_client_version); | 733 | EXPORT_SYMBOL(p9_client_version); |
732 | 734 | ||
733 | struct p9_client *p9_client_create(const char *dev_name, char *options) | 735 | struct p9_client *p9_client_create(const char *dev_name, char *options) |
734 | { | 736 | { |
735 | int err; | 737 | int err; |
736 | struct p9_client *clnt; | 738 | struct p9_client *clnt; |
737 | 739 | ||
738 | err = 0; | 740 | err = 0; |
739 | clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); | 741 | clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); |
740 | if (!clnt) | 742 | if (!clnt) |
741 | return ERR_PTR(-ENOMEM); | 743 | return ERR_PTR(-ENOMEM); |
742 | 744 | ||
743 | clnt->trans_mod = NULL; | 745 | clnt->trans_mod = NULL; |
744 | clnt->trans = NULL; | 746 | clnt->trans = NULL; |
745 | spin_lock_init(&clnt->lock); | 747 | spin_lock_init(&clnt->lock); |
746 | INIT_LIST_HEAD(&clnt->fidlist); | 748 | INIT_LIST_HEAD(&clnt->fidlist); |
747 | 749 | ||
748 | p9_tag_init(clnt); | 750 | p9_tag_init(clnt); |
749 | 751 | ||
750 | err = parse_opts(options, clnt); | 752 | err = parse_opts(options, clnt); |
751 | if (err < 0) | 753 | if (err < 0) |
752 | goto free_client; | 754 | goto free_client; |
753 | 755 | ||
754 | if (!clnt->trans_mod) | 756 | if (!clnt->trans_mod) |
755 | clnt->trans_mod = v9fs_get_default_trans(); | 757 | clnt->trans_mod = v9fs_get_default_trans(); |
756 | 758 | ||
757 | if (clnt->trans_mod == NULL) { | 759 | if (clnt->trans_mod == NULL) { |
758 | err = -EPROTONOSUPPORT; | 760 | err = -EPROTONOSUPPORT; |
759 | P9_DPRINTK(P9_DEBUG_ERROR, | 761 | P9_DPRINTK(P9_DEBUG_ERROR, |
760 | "No transport defined or default transport\n"); | 762 | "No transport defined or default transport\n"); |
761 | goto free_client; | 763 | goto free_client; |
762 | } | 764 | } |
763 | 765 | ||
764 | clnt->fidpool = p9_idpool_create(); | 766 | clnt->fidpool = p9_idpool_create(); |
765 | if (IS_ERR(clnt->fidpool)) { | 767 | if (IS_ERR(clnt->fidpool)) { |
766 | err = PTR_ERR(clnt->fidpool); | 768 | err = PTR_ERR(clnt->fidpool); |
767 | clnt->fidpool = NULL; | 769 | clnt->fidpool = NULL; |
768 | goto put_trans; | 770 | goto put_trans; |
769 | } | 771 | } |
770 | 772 | ||
771 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n", | 773 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n", |
772 | clnt, clnt->trans_mod, clnt->msize, clnt->proto_version); | 774 | clnt, clnt->trans_mod, clnt->msize, clnt->proto_version); |
773 | 775 | ||
774 | err = clnt->trans_mod->create(clnt, dev_name, options); | 776 | err = clnt->trans_mod->create(clnt, dev_name, options); |
775 | if (err) | 777 | if (err) |
776 | goto destroy_fidpool; | 778 | goto destroy_fidpool; |
777 | 779 | ||
778 | if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) | 780 | if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize) |
779 | clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; | 781 | clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ; |
780 | 782 | ||
781 | err = p9_client_version(clnt); | 783 | err = p9_client_version(clnt); |
782 | if (err) | 784 | if (err) |
783 | goto close_trans; | 785 | goto close_trans; |
784 | 786 | ||
785 | return clnt; | 787 | return clnt; |
786 | 788 | ||
787 | close_trans: | 789 | close_trans: |
788 | clnt->trans_mod->close(clnt); | 790 | clnt->trans_mod->close(clnt); |
789 | destroy_fidpool: | 791 | destroy_fidpool: |
790 | p9_idpool_destroy(clnt->fidpool); | 792 | p9_idpool_destroy(clnt->fidpool); |
791 | put_trans: | 793 | put_trans: |
792 | v9fs_put_trans(clnt->trans_mod); | 794 | v9fs_put_trans(clnt->trans_mod); |
793 | free_client: | 795 | free_client: |
794 | kfree(clnt); | 796 | kfree(clnt); |
795 | return ERR_PTR(err); | 797 | return ERR_PTR(err); |
796 | } | 798 | } |
797 | EXPORT_SYMBOL(p9_client_create); | 799 | EXPORT_SYMBOL(p9_client_create); |
798 | 800 | ||
799 | void p9_client_destroy(struct p9_client *clnt) | 801 | void p9_client_destroy(struct p9_client *clnt) |
800 | { | 802 | { |
801 | struct p9_fid *fid, *fidptr; | 803 | struct p9_fid *fid, *fidptr; |
802 | 804 | ||
803 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt); | 805 | P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt); |
804 | 806 | ||
805 | if (clnt->trans_mod) | 807 | if (clnt->trans_mod) |
806 | clnt->trans_mod->close(clnt); | 808 | clnt->trans_mod->close(clnt); |
807 | 809 | ||
808 | v9fs_put_trans(clnt->trans_mod); | 810 | v9fs_put_trans(clnt->trans_mod); |
809 | 811 | ||
810 | list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) { | 812 | list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) { |
811 | printk(KERN_INFO "Found fid %d not clunked\n", fid->fid); | 813 | printk(KERN_INFO "Found fid %d not clunked\n", fid->fid); |
812 | p9_fid_destroy(fid); | 814 | p9_fid_destroy(fid); |
813 | } | 815 | } |
814 | 816 | ||
815 | if (clnt->fidpool) | 817 | if (clnt->fidpool) |
816 | p9_idpool_destroy(clnt->fidpool); | 818 | p9_idpool_destroy(clnt->fidpool); |
817 | 819 | ||
818 | p9_tag_cleanup(clnt); | 820 | p9_tag_cleanup(clnt); |
819 | 821 | ||
820 | kfree(clnt); | 822 | kfree(clnt); |
821 | } | 823 | } |
822 | EXPORT_SYMBOL(p9_client_destroy); | 824 | EXPORT_SYMBOL(p9_client_destroy); |
823 | 825 | ||
824 | void p9_client_disconnect(struct p9_client *clnt) | 826 | void p9_client_disconnect(struct p9_client *clnt) |
825 | { | 827 | { |
826 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); | 828 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); |
827 | clnt->status = Disconnected; | 829 | clnt->status = Disconnected; |
828 | } | 830 | } |
829 | EXPORT_SYMBOL(p9_client_disconnect); | 831 | EXPORT_SYMBOL(p9_client_disconnect); |
830 | 832 | ||
831 | void p9_client_begin_disconnect(struct p9_client *clnt) | 833 | void p9_client_begin_disconnect(struct p9_client *clnt) |
832 | { | 834 | { |
833 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); | 835 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); |
834 | clnt->status = BeginDisconnect; | 836 | clnt->status = BeginDisconnect; |
835 | } | 837 | } |
836 | EXPORT_SYMBOL(p9_client_begin_disconnect); | 838 | EXPORT_SYMBOL(p9_client_begin_disconnect); |
837 | 839 | ||
838 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | 840 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, |
839 | char *uname, u32 n_uname, char *aname) | 841 | char *uname, u32 n_uname, char *aname) |
840 | { | 842 | { |
841 | int err; | 843 | int err; |
842 | struct p9_req_t *req; | 844 | struct p9_req_t *req; |
843 | struct p9_fid *fid; | 845 | struct p9_fid *fid; |
844 | struct p9_qid qid; | 846 | struct p9_qid qid; |
845 | 847 | ||
846 | P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", | 848 | P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", |
847 | afid ? afid->fid : -1, uname, aname); | 849 | afid ? afid->fid : -1, uname, aname); |
848 | err = 0; | 850 | err = 0; |
849 | 851 | ||
850 | fid = p9_fid_create(clnt); | 852 | fid = p9_fid_create(clnt); |
851 | if (IS_ERR(fid)) { | 853 | if (IS_ERR(fid)) { |
852 | err = PTR_ERR(fid); | 854 | err = PTR_ERR(fid); |
853 | fid = NULL; | 855 | fid = NULL; |
854 | goto error; | 856 | goto error; |
855 | } | 857 | } |
856 | 858 | ||
857 | req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid, | 859 | req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid, |
858 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); | 860 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); |
859 | if (IS_ERR(req)) { | 861 | if (IS_ERR(req)) { |
860 | err = PTR_ERR(req); | 862 | err = PTR_ERR(req); |
861 | goto error; | 863 | goto error; |
862 | } | 864 | } |
863 | 865 | ||
864 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); | 866 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); |
865 | if (err) { | 867 | if (err) { |
866 | p9pdu_dump(1, req->rc); | 868 | p9pdu_dump(1, req->rc); |
867 | p9_free_req(clnt, req); | 869 | p9_free_req(clnt, req); |
868 | goto error; | 870 | goto error; |
869 | } | 871 | } |
870 | 872 | ||
871 | P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n", | 873 | P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n", |
872 | qid.type, | 874 | qid.type, |
873 | (unsigned long long)qid.path, | 875 | (unsigned long long)qid.path, |
874 | qid.version); | 876 | qid.version); |
875 | 877 | ||
876 | memmove(&fid->qid, &qid, sizeof(struct p9_qid)); | 878 | memmove(&fid->qid, &qid, sizeof(struct p9_qid)); |
877 | 879 | ||
878 | p9_free_req(clnt, req); | 880 | p9_free_req(clnt, req); |
879 | return fid; | 881 | return fid; |
880 | 882 | ||
881 | error: | 883 | error: |
882 | if (fid) | 884 | if (fid) |
883 | p9_fid_destroy(fid); | 885 | p9_fid_destroy(fid); |
884 | return ERR_PTR(err); | 886 | return ERR_PTR(err); |
885 | } | 887 | } |
886 | EXPORT_SYMBOL(p9_client_attach); | 888 | EXPORT_SYMBOL(p9_client_attach); |
887 | 889 | ||
888 | struct p9_fid * | 890 | struct p9_fid * |
889 | p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname) | 891 | p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname) |
890 | { | 892 | { |
891 | int err; | 893 | int err; |
892 | struct p9_req_t *req; | 894 | struct p9_req_t *req; |
893 | struct p9_qid qid; | 895 | struct p9_qid qid; |
894 | struct p9_fid *afid; | 896 | struct p9_fid *afid; |
895 | 897 | ||
896 | P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname); | 898 | P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname); |
897 | err = 0; | 899 | err = 0; |
898 | 900 | ||
899 | afid = p9_fid_create(clnt); | 901 | afid = p9_fid_create(clnt); |
900 | if (IS_ERR(afid)) { | 902 | if (IS_ERR(afid)) { |
901 | err = PTR_ERR(afid); | 903 | err = PTR_ERR(afid); |
902 | afid = NULL; | 904 | afid = NULL; |
903 | goto error; | 905 | goto error; |
904 | } | 906 | } |
905 | 907 | ||
906 | req = p9_client_rpc(clnt, P9_TAUTH, "dss?d", | 908 | req = p9_client_rpc(clnt, P9_TAUTH, "dss?d", |
907 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); | 909 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); |
908 | if (IS_ERR(req)) { | 910 | if (IS_ERR(req)) { |
909 | err = PTR_ERR(req); | 911 | err = PTR_ERR(req); |
910 | goto error; | 912 | goto error; |
911 | } | 913 | } |
912 | 914 | ||
913 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); | 915 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid); |
914 | if (err) { | 916 | if (err) { |
915 | p9pdu_dump(1, req->rc); | 917 | p9pdu_dump(1, req->rc); |
916 | p9_free_req(clnt, req); | 918 | p9_free_req(clnt, req); |
917 | goto error; | 919 | goto error; |
918 | } | 920 | } |
919 | 921 | ||
920 | P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n", | 922 | P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n", |
921 | qid.type, | 923 | qid.type, |
922 | (unsigned long long)qid.path, | 924 | (unsigned long long)qid.path, |
923 | qid.version); | 925 | qid.version); |
924 | 926 | ||
925 | memmove(&afid->qid, &qid, sizeof(struct p9_qid)); | 927 | memmove(&afid->qid, &qid, sizeof(struct p9_qid)); |
926 | p9_free_req(clnt, req); | 928 | p9_free_req(clnt, req); |
927 | return afid; | 929 | return afid; |
928 | 930 | ||
929 | error: | 931 | error: |
930 | if (afid) | 932 | if (afid) |
931 | p9_fid_destroy(afid); | 933 | p9_fid_destroy(afid); |
932 | return ERR_PTR(err); | 934 | return ERR_PTR(err); |
933 | } | 935 | } |
934 | EXPORT_SYMBOL(p9_client_auth); | 936 | EXPORT_SYMBOL(p9_client_auth); |
935 | 937 | ||
936 | struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, | 938 | struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, |
937 | int clone) | 939 | int clone) |
938 | { | 940 | { |
939 | int err; | 941 | int err; |
940 | struct p9_client *clnt; | 942 | struct p9_client *clnt; |
941 | struct p9_fid *fid; | 943 | struct p9_fid *fid; |
942 | struct p9_qid *wqids; | 944 | struct p9_qid *wqids; |
943 | struct p9_req_t *req; | 945 | struct p9_req_t *req; |
944 | int16_t nwqids, count; | 946 | int16_t nwqids, count; |
945 | 947 | ||
946 | err = 0; | 948 | err = 0; |
949 | wqids = NULL; | ||
947 | clnt = oldfid->clnt; | 950 | clnt = oldfid->clnt; |
948 | if (clone) { | 951 | if (clone) { |
949 | fid = p9_fid_create(clnt); | 952 | fid = p9_fid_create(clnt); |
950 | if (IS_ERR(fid)) { | 953 | if (IS_ERR(fid)) { |
951 | err = PTR_ERR(fid); | 954 | err = PTR_ERR(fid); |
952 | fid = NULL; | 955 | fid = NULL; |
953 | goto error; | 956 | goto error; |
954 | } | 957 | } |
955 | 958 | ||
956 | fid->uid = oldfid->uid; | 959 | fid->uid = oldfid->uid; |
957 | } else | 960 | } else |
958 | fid = oldfid; | 961 | fid = oldfid; |
959 | 962 | ||
960 | 963 | ||
961 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", | 964 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", |
962 | oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); | 965 | oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); |
963 | 966 | ||
964 | req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, | 967 | req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, |
965 | nwname, wnames); | 968 | nwname, wnames); |
966 | if (IS_ERR(req)) { | 969 | if (IS_ERR(req)) { |
967 | err = PTR_ERR(req); | 970 | err = PTR_ERR(req); |
968 | goto error; | 971 | goto error; |
969 | } | 972 | } |
970 | 973 | ||
971 | err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids); | 974 | err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids); |
972 | if (err) { | 975 | if (err) { |
973 | p9pdu_dump(1, req->rc); | 976 | p9pdu_dump(1, req->rc); |
974 | p9_free_req(clnt, req); | 977 | p9_free_req(clnt, req); |
975 | goto clunk_fid; | 978 | goto clunk_fid; |
976 | } | 979 | } |
977 | p9_free_req(clnt, req); | 980 | p9_free_req(clnt, req); |
978 | 981 | ||
979 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); | 982 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); |
980 | 983 | ||
981 | if (nwqids != nwname) { | 984 | if (nwqids != nwname) { |
982 | err = -ENOENT; | 985 | err = -ENOENT; |
983 | goto clunk_fid; | 986 | goto clunk_fid; |
984 | } | 987 | } |
985 | 988 | ||
986 | for (count = 0; count < nwqids; count++) | 989 | for (count = 0; count < nwqids; count++) |
987 | P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n", | 990 | P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n", |
988 | count, wqids[count].type, | 991 | count, wqids[count].type, |
989 | (unsigned long long)wqids[count].path, | 992 | (unsigned long long)wqids[count].path, |
990 | wqids[count].version); | 993 | wqids[count].version); |
991 | 994 | ||
992 | if (nwname) | 995 | if (nwname) |
993 | memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); | 996 | memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); |
994 | else | 997 | else |
995 | fid->qid = oldfid->qid; | 998 | fid->qid = oldfid->qid; |
996 | 999 | ||
1000 | kfree(wqids); | ||
997 | return fid; | 1001 | return fid; |
998 | 1002 | ||
999 | clunk_fid: | 1003 | clunk_fid: |
1004 | kfree(wqids); | ||
1000 | p9_client_clunk(fid); | 1005 | p9_client_clunk(fid); |
1001 | fid = NULL; | 1006 | fid = NULL; |
1002 | 1007 | ||
1003 | error: | 1008 | error: |
1004 | if (fid && (fid != oldfid)) | 1009 | if (fid && (fid != oldfid)) |
1005 | p9_fid_destroy(fid); | 1010 | p9_fid_destroy(fid); |
1006 | 1011 | ||
1007 | return ERR_PTR(err); | 1012 | return ERR_PTR(err); |
1008 | } | 1013 | } |
1009 | EXPORT_SYMBOL(p9_client_walk); | 1014 | EXPORT_SYMBOL(p9_client_walk); |
1010 | 1015 | ||
1011 | int p9_client_open(struct p9_fid *fid, int mode) | 1016 | int p9_client_open(struct p9_fid *fid, int mode) |
1012 | { | 1017 | { |
1013 | int err; | 1018 | int err; |
1014 | struct p9_client *clnt; | 1019 | struct p9_client *clnt; |
1015 | struct p9_req_t *req; | 1020 | struct p9_req_t *req; |
1016 | struct p9_qid qid; | 1021 | struct p9_qid qid; |
1017 | int iounit; | 1022 | int iounit; |
1018 | 1023 | ||
1019 | clnt = fid->clnt; | 1024 | clnt = fid->clnt; |
1020 | P9_DPRINTK(P9_DEBUG_9P, ">>> %s fid %d mode %d\n", | 1025 | P9_DPRINTK(P9_DEBUG_9P, ">>> %s fid %d mode %d\n", |
1021 | p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode); | 1026 | p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode); |
1022 | err = 0; | 1027 | err = 0; |
1023 | 1028 | ||
1024 | if (fid->mode != -1) | 1029 | if (fid->mode != -1) |
1025 | return -EINVAL; | 1030 | return -EINVAL; |
1026 | 1031 | ||
1027 | if (p9_is_proto_dotl(clnt)) | 1032 | if (p9_is_proto_dotl(clnt)) |
1028 | req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode); | 1033 | req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode); |
1029 | else | 1034 | else |
1030 | req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); | 1035 | req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); |
1031 | if (IS_ERR(req)) { | 1036 | if (IS_ERR(req)) { |
1032 | err = PTR_ERR(req); | 1037 | err = PTR_ERR(req); |
1033 | goto error; | 1038 | goto error; |
1034 | } | 1039 | } |
1035 | 1040 | ||
1036 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); | 1041 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); |
1037 | if (err) { | 1042 | if (err) { |
1038 | p9pdu_dump(1, req->rc); | 1043 | p9pdu_dump(1, req->rc); |
1039 | goto free_and_error; | 1044 | goto free_and_error; |
1040 | } | 1045 | } |
1041 | 1046 | ||
1042 | P9_DPRINTK(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n", | 1047 | P9_DPRINTK(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n", |
1043 | p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type, | 1048 | p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type, |
1044 | (unsigned long long)qid.path, qid.version, iounit); | 1049 | (unsigned long long)qid.path, qid.version, iounit); |
1045 | 1050 | ||
1046 | fid->mode = mode; | 1051 | fid->mode = mode; |
1047 | fid->iounit = iounit; | 1052 | fid->iounit = iounit; |
1048 | 1053 | ||
1049 | free_and_error: | 1054 | free_and_error: |
1050 | p9_free_req(clnt, req); | 1055 | p9_free_req(clnt, req); |
1051 | error: | 1056 | error: |
1052 | return err; | 1057 | return err; |
1053 | } | 1058 | } |
1054 | EXPORT_SYMBOL(p9_client_open); | 1059 | EXPORT_SYMBOL(p9_client_open); |
1055 | 1060 | ||
1056 | int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, | 1061 | int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, |
1057 | gid_t gid, struct p9_qid *qid) | 1062 | gid_t gid, struct p9_qid *qid) |
1058 | { | 1063 | { |
1059 | int err = 0; | 1064 | int err = 0; |
1060 | struct p9_client *clnt; | 1065 | struct p9_client *clnt; |
1061 | struct p9_req_t *req; | 1066 | struct p9_req_t *req; |
1062 | int iounit; | 1067 | int iounit; |
1063 | 1068 | ||
1064 | P9_DPRINTK(P9_DEBUG_9P, | 1069 | P9_DPRINTK(P9_DEBUG_9P, |
1065 | ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n", | 1070 | ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n", |
1066 | ofid->fid, name, flags, mode, gid); | 1071 | ofid->fid, name, flags, mode, gid); |
1067 | clnt = ofid->clnt; | 1072 | clnt = ofid->clnt; |
1068 | 1073 | ||
1069 | if (ofid->mode != -1) | 1074 | if (ofid->mode != -1) |
1070 | return -EINVAL; | 1075 | return -EINVAL; |
1071 | 1076 | ||
1072 | req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags, | 1077 | req = p9_client_rpc(clnt, P9_TLCREATE, "dsddd", ofid->fid, name, flags, |
1073 | mode, gid); | 1078 | mode, gid); |
1074 | if (IS_ERR(req)) { | 1079 | if (IS_ERR(req)) { |
1075 | err = PTR_ERR(req); | 1080 | err = PTR_ERR(req); |
1076 | goto error; | 1081 | goto error; |
1077 | } | 1082 | } |
1078 | 1083 | ||
1079 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit); | 1084 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit); |
1080 | if (err) { | 1085 | if (err) { |
1081 | p9pdu_dump(1, req->rc); | 1086 | p9pdu_dump(1, req->rc); |
1082 | goto free_and_error; | 1087 | goto free_and_error; |
1083 | } | 1088 | } |
1084 | 1089 | ||
1085 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n", | 1090 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n", |
1086 | qid->type, | 1091 | qid->type, |
1087 | (unsigned long long)qid->path, | 1092 | (unsigned long long)qid->path, |
1088 | qid->version, iounit); | 1093 | qid->version, iounit); |
1089 | 1094 | ||
1090 | ofid->mode = mode; | 1095 | ofid->mode = mode; |
1091 | ofid->iounit = iounit; | 1096 | ofid->iounit = iounit; |
1092 | 1097 | ||
1093 | free_and_error: | 1098 | free_and_error: |
1094 | p9_free_req(clnt, req); | 1099 | p9_free_req(clnt, req); |
1095 | error: | 1100 | error: |
1096 | return err; | 1101 | return err; |
1097 | } | 1102 | } |
1098 | EXPORT_SYMBOL(p9_client_create_dotl); | 1103 | EXPORT_SYMBOL(p9_client_create_dotl); |
1099 | 1104 | ||
1100 | int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, | 1105 | int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, |
1101 | char *extension) | 1106 | char *extension) |
1102 | { | 1107 | { |
1103 | int err; | 1108 | int err; |
1104 | struct p9_client *clnt; | 1109 | struct p9_client *clnt; |
1105 | struct p9_req_t *req; | 1110 | struct p9_req_t *req; |
1106 | struct p9_qid qid; | 1111 | struct p9_qid qid; |
1107 | int iounit; | 1112 | int iounit; |
1108 | 1113 | ||
1109 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n", | 1114 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n", |
1110 | fid->fid, name, perm, mode); | 1115 | fid->fid, name, perm, mode); |
1111 | err = 0; | 1116 | err = 0; |
1112 | clnt = fid->clnt; | 1117 | clnt = fid->clnt; |
1113 | 1118 | ||
1114 | if (fid->mode != -1) | 1119 | if (fid->mode != -1) |
1115 | return -EINVAL; | 1120 | return -EINVAL; |
1116 | 1121 | ||
1117 | req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm, | 1122 | req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm, |
1118 | mode, extension); | 1123 | mode, extension); |
1119 | if (IS_ERR(req)) { | 1124 | if (IS_ERR(req)) { |
1120 | err = PTR_ERR(req); | 1125 | err = PTR_ERR(req); |
1121 | goto error; | 1126 | goto error; |
1122 | } | 1127 | } |
1123 | 1128 | ||
1124 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); | 1129 | err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit); |
1125 | if (err) { | 1130 | if (err) { |
1126 | p9pdu_dump(1, req->rc); | 1131 | p9pdu_dump(1, req->rc); |
1127 | goto free_and_error; | 1132 | goto free_and_error; |
1128 | } | 1133 | } |
1129 | 1134 | ||
1130 | P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", | 1135 | P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", |
1131 | qid.type, | 1136 | qid.type, |
1132 | (unsigned long long)qid.path, | 1137 | (unsigned long long)qid.path, |
1133 | qid.version, iounit); | 1138 | qid.version, iounit); |
1134 | 1139 | ||
1135 | fid->mode = mode; | 1140 | fid->mode = mode; |
1136 | fid->iounit = iounit; | 1141 | fid->iounit = iounit; |
1137 | 1142 | ||
1138 | free_and_error: | 1143 | free_and_error: |
1139 | p9_free_req(clnt, req); | 1144 | p9_free_req(clnt, req); |
1140 | error: | 1145 | error: |
1141 | return err; | 1146 | return err; |
1142 | } | 1147 | } |
1143 | EXPORT_SYMBOL(p9_client_fcreate); | 1148 | EXPORT_SYMBOL(p9_client_fcreate); |
1144 | 1149 | ||
1145 | int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid, | 1150 | int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid, |
1146 | struct p9_qid *qid) | 1151 | struct p9_qid *qid) |
1147 | { | 1152 | { |
1148 | int err = 0; | 1153 | int err = 0; |
1149 | struct p9_client *clnt; | 1154 | struct p9_client *clnt; |
1150 | struct p9_req_t *req; | 1155 | struct p9_req_t *req; |
1151 | 1156 | ||
1152 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s symtgt %s\n", | 1157 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s symtgt %s\n", |
1153 | dfid->fid, name, symtgt); | 1158 | dfid->fid, name, symtgt); |
1154 | clnt = dfid->clnt; | 1159 | clnt = dfid->clnt; |
1155 | 1160 | ||
1156 | req = p9_client_rpc(clnt, P9_TSYMLINK, "dssd", dfid->fid, name, symtgt, | 1161 | req = p9_client_rpc(clnt, P9_TSYMLINK, "dssd", dfid->fid, name, symtgt, |
1157 | gid); | 1162 | gid); |
1158 | if (IS_ERR(req)) { | 1163 | if (IS_ERR(req)) { |
1159 | err = PTR_ERR(req); | 1164 | err = PTR_ERR(req); |
1160 | goto error; | 1165 | goto error; |
1161 | } | 1166 | } |
1162 | 1167 | ||
1163 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); | 1168 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); |
1164 | if (err) { | 1169 | if (err) { |
1165 | p9pdu_dump(1, req->rc); | 1170 | p9pdu_dump(1, req->rc); |
1166 | goto free_and_error; | 1171 | goto free_and_error; |
1167 | } | 1172 | } |
1168 | 1173 | ||
1169 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n", | 1174 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n", |
1170 | qid->type, (unsigned long long)qid->path, qid->version); | 1175 | qid->type, (unsigned long long)qid->path, qid->version); |
1171 | 1176 | ||
1172 | free_and_error: | 1177 | free_and_error: |
1173 | p9_free_req(clnt, req); | 1178 | p9_free_req(clnt, req); |
1174 | error: | 1179 | error: |
1175 | return err; | 1180 | return err; |
1176 | } | 1181 | } |
1177 | EXPORT_SYMBOL(p9_client_symlink); | 1182 | EXPORT_SYMBOL(p9_client_symlink); |
1178 | 1183 | ||
1179 | int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname) | 1184 | int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname) |
1180 | { | 1185 | { |
1181 | struct p9_client *clnt; | 1186 | struct p9_client *clnt; |
1182 | struct p9_req_t *req; | 1187 | struct p9_req_t *req; |
1183 | 1188 | ||
1184 | P9_DPRINTK(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n", | 1189 | P9_DPRINTK(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n", |
1185 | dfid->fid, oldfid->fid, newname); | 1190 | dfid->fid, oldfid->fid, newname); |
1186 | clnt = dfid->clnt; | 1191 | clnt = dfid->clnt; |
1187 | req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid, | 1192 | req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid, |
1188 | newname); | 1193 | newname); |
1189 | if (IS_ERR(req)) | 1194 | if (IS_ERR(req)) |
1190 | return PTR_ERR(req); | 1195 | return PTR_ERR(req); |
1191 | 1196 | ||
1192 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLINK\n"); | 1197 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLINK\n"); |
1193 | p9_free_req(clnt, req); | 1198 | p9_free_req(clnt, req); |
1194 | return 0; | 1199 | return 0; |
1195 | } | 1200 | } |
1196 | EXPORT_SYMBOL(p9_client_link); | 1201 | EXPORT_SYMBOL(p9_client_link); |
1197 | 1202 | ||
1198 | int p9_client_clunk(struct p9_fid *fid) | 1203 | int p9_client_clunk(struct p9_fid *fid) |
1199 | { | 1204 | { |
1200 | int err; | 1205 | int err; |
1201 | struct p9_client *clnt; | 1206 | struct p9_client *clnt; |
1202 | struct p9_req_t *req; | 1207 | struct p9_req_t *req; |
1203 | 1208 | ||
1204 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); | 1209 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); |
1205 | err = 0; | 1210 | err = 0; |
1206 | clnt = fid->clnt; | 1211 | clnt = fid->clnt; |
1207 | 1212 | ||
1208 | req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid); | 1213 | req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid); |
1209 | if (IS_ERR(req)) { | 1214 | if (IS_ERR(req)) { |
1210 | err = PTR_ERR(req); | 1215 | err = PTR_ERR(req); |
1211 | goto error; | 1216 | goto error; |
1212 | } | 1217 | } |
1213 | 1218 | ||
1214 | P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); | 1219 | P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); |
1215 | 1220 | ||
1216 | p9_free_req(clnt, req); | 1221 | p9_free_req(clnt, req); |
1217 | p9_fid_destroy(fid); | 1222 | p9_fid_destroy(fid); |
1218 | 1223 | ||
1219 | error: | 1224 | error: |
1220 | return err; | 1225 | return err; |
1221 | } | 1226 | } |
1222 | EXPORT_SYMBOL(p9_client_clunk); | 1227 | EXPORT_SYMBOL(p9_client_clunk); |
1223 | 1228 | ||
1224 | int p9_client_remove(struct p9_fid *fid) | 1229 | int p9_client_remove(struct p9_fid *fid) |
1225 | { | 1230 | { |
1226 | int err; | 1231 | int err; |
1227 | struct p9_client *clnt; | 1232 | struct p9_client *clnt; |
1228 | struct p9_req_t *req; | 1233 | struct p9_req_t *req; |
1229 | 1234 | ||
1230 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid); | 1235 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid); |
1231 | err = 0; | 1236 | err = 0; |
1232 | clnt = fid->clnt; | 1237 | clnt = fid->clnt; |
1233 | 1238 | ||
1234 | req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid); | 1239 | req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid); |
1235 | if (IS_ERR(req)) { | 1240 | if (IS_ERR(req)) { |
1236 | err = PTR_ERR(req); | 1241 | err = PTR_ERR(req); |
1237 | goto error; | 1242 | goto error; |
1238 | } | 1243 | } |
1239 | 1244 | ||
1240 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); | 1245 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); |
1241 | 1246 | ||
1242 | p9_free_req(clnt, req); | 1247 | p9_free_req(clnt, req); |
1243 | error: | 1248 | error: |
1244 | p9_fid_destroy(fid); | 1249 | p9_fid_destroy(fid); |
1245 | return err; | 1250 | return err; |
1246 | } | 1251 | } |
1247 | EXPORT_SYMBOL(p9_client_remove); | 1252 | EXPORT_SYMBOL(p9_client_remove); |
1248 | 1253 | ||
1249 | int | 1254 | int |
1250 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | 1255 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, |
1251 | u32 count) | 1256 | u32 count) |
1252 | { | 1257 | { |
1253 | int err, rsize, total; | 1258 | int err, rsize, total; |
1254 | struct p9_client *clnt; | 1259 | struct p9_client *clnt; |
1255 | struct p9_req_t *req; | 1260 | struct p9_req_t *req; |
1256 | char *dataptr; | 1261 | char *dataptr; |
1257 | 1262 | ||
1258 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, | 1263 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, |
1259 | (long long unsigned) offset, count); | 1264 | (long long unsigned) offset, count); |
1260 | err = 0; | 1265 | err = 0; |
1261 | clnt = fid->clnt; | 1266 | clnt = fid->clnt; |
1262 | total = 0; | 1267 | total = 0; |
1263 | 1268 | ||
1264 | rsize = fid->iounit; | 1269 | rsize = fid->iounit; |
1265 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | 1270 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
1266 | rsize = clnt->msize - P9_IOHDRSZ; | 1271 | rsize = clnt->msize - P9_IOHDRSZ; |
1267 | 1272 | ||
1268 | if (count < rsize) | 1273 | if (count < rsize) |
1269 | rsize = count; | 1274 | rsize = count; |
1270 | 1275 | ||
1271 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); | 1276 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); |
1272 | if (IS_ERR(req)) { | 1277 | if (IS_ERR(req)) { |
1273 | err = PTR_ERR(req); | 1278 | err = PTR_ERR(req); |
1274 | goto error; | 1279 | goto error; |
1275 | } | 1280 | } |
1276 | 1281 | ||
1277 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); | 1282 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); |
1278 | if (err) { | 1283 | if (err) { |
1279 | p9pdu_dump(1, req->rc); | 1284 | p9pdu_dump(1, req->rc); |
1280 | goto free_and_error; | 1285 | goto free_and_error; |
1281 | } | 1286 | } |
1282 | 1287 | ||
1283 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1288 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1284 | 1289 | ||
1285 | if (data) { | 1290 | if (data) { |
1286 | memmove(data, dataptr, count); | 1291 | memmove(data, dataptr, count); |
1287 | } | 1292 | } |
1288 | 1293 | ||
1289 | if (udata) { | 1294 | if (udata) { |
1290 | err = copy_to_user(udata, dataptr, count); | 1295 | err = copy_to_user(udata, dataptr, count); |
1291 | if (err) { | 1296 | if (err) { |
1292 | err = -EFAULT; | 1297 | err = -EFAULT; |
1293 | goto free_and_error; | 1298 | goto free_and_error; |
1294 | } | 1299 | } |
1295 | } | 1300 | } |
1296 | 1301 | ||
1297 | p9_free_req(clnt, req); | 1302 | p9_free_req(clnt, req); |
1298 | return count; | 1303 | return count; |
1299 | 1304 | ||
1300 | free_and_error: | 1305 | free_and_error: |
1301 | p9_free_req(clnt, req); | 1306 | p9_free_req(clnt, req); |
1302 | error: | 1307 | error: |
1303 | return err; | 1308 | return err; |
1304 | } | 1309 | } |
1305 | EXPORT_SYMBOL(p9_client_read); | 1310 | EXPORT_SYMBOL(p9_client_read); |
1306 | 1311 | ||
1307 | int | 1312 | int |
1308 | p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | 1313 | p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, |
1309 | u64 offset, u32 count) | 1314 | u64 offset, u32 count) |
1310 | { | 1315 | { |
1311 | int err, rsize, total; | 1316 | int err, rsize, total; |
1312 | struct p9_client *clnt; | 1317 | struct p9_client *clnt; |
1313 | struct p9_req_t *req; | 1318 | struct p9_req_t *req; |
1314 | 1319 | ||
1315 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", | 1320 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", |
1316 | fid->fid, (long long unsigned) offset, count); | 1321 | fid->fid, (long long unsigned) offset, count); |
1317 | err = 0; | 1322 | err = 0; |
1318 | clnt = fid->clnt; | 1323 | clnt = fid->clnt; |
1319 | total = 0; | 1324 | total = 0; |
1320 | 1325 | ||
1321 | rsize = fid->iounit; | 1326 | rsize = fid->iounit; |
1322 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | 1327 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
1323 | rsize = clnt->msize - P9_IOHDRSZ; | 1328 | rsize = clnt->msize - P9_IOHDRSZ; |
1324 | 1329 | ||
1325 | if (count < rsize) | 1330 | if (count < rsize) |
1326 | rsize = count; | 1331 | rsize = count; |
1327 | if (data) | 1332 | if (data) |
1328 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, | 1333 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, |
1329 | rsize, data); | 1334 | rsize, data); |
1330 | else | 1335 | else |
1331 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, | 1336 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, |
1332 | rsize, udata); | 1337 | rsize, udata); |
1333 | if (IS_ERR(req)) { | 1338 | if (IS_ERR(req)) { |
1334 | err = PTR_ERR(req); | 1339 | err = PTR_ERR(req); |
1335 | goto error; | 1340 | goto error; |
1336 | } | 1341 | } |
1337 | 1342 | ||
1338 | err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); | 1343 | err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); |
1339 | if (err) { | 1344 | if (err) { |
1340 | p9pdu_dump(1, req->rc); | 1345 | p9pdu_dump(1, req->rc); |
1341 | goto free_and_error; | 1346 | goto free_and_error; |
1342 | } | 1347 | } |
1343 | 1348 | ||
1344 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); | 1349 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); |
1345 | 1350 | ||
1346 | p9_free_req(clnt, req); | 1351 | p9_free_req(clnt, req); |
1347 | return count; | 1352 | return count; |
1348 | 1353 | ||
1349 | free_and_error: | 1354 | free_and_error: |
1350 | p9_free_req(clnt, req); | 1355 | p9_free_req(clnt, req); |
1351 | error: | 1356 | error: |
1352 | return err; | 1357 | return err; |
1353 | } | 1358 | } |
1354 | EXPORT_SYMBOL(p9_client_write); | 1359 | EXPORT_SYMBOL(p9_client_write); |
1355 | 1360 | ||
1356 | struct p9_wstat *p9_client_stat(struct p9_fid *fid) | 1361 | struct p9_wstat *p9_client_stat(struct p9_fid *fid) |
1357 | { | 1362 | { |
1358 | int err; | 1363 | int err; |
1359 | struct p9_client *clnt; | 1364 | struct p9_client *clnt; |
1360 | struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); | 1365 | struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); |
1361 | struct p9_req_t *req; | 1366 | struct p9_req_t *req; |
1362 | u16 ignored; | 1367 | u16 ignored; |
1363 | 1368 | ||
1364 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); | 1369 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); |
1365 | 1370 | ||
1366 | if (!ret) | 1371 | if (!ret) |
1367 | return ERR_PTR(-ENOMEM); | 1372 | return ERR_PTR(-ENOMEM); |
1368 | 1373 | ||
1369 | err = 0; | 1374 | err = 0; |
1370 | clnt = fid->clnt; | 1375 | clnt = fid->clnt; |
1371 | 1376 | ||
1372 | req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid); | 1377 | req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid); |
1373 | if (IS_ERR(req)) { | 1378 | if (IS_ERR(req)) { |
1374 | err = PTR_ERR(req); | 1379 | err = PTR_ERR(req); |
1375 | goto error; | 1380 | goto error; |
1376 | } | 1381 | } |
1377 | 1382 | ||
1378 | err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret); | 1383 | err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret); |
1379 | if (err) { | 1384 | if (err) { |
1380 | p9pdu_dump(1, req->rc); | 1385 | p9pdu_dump(1, req->rc); |
1381 | p9_free_req(clnt, req); | 1386 | p9_free_req(clnt, req); |
1382 | goto error; | 1387 | goto error; |
1383 | } | 1388 | } |
1384 | 1389 | ||
1385 | P9_DPRINTK(P9_DEBUG_9P, | 1390 | P9_DPRINTK(P9_DEBUG_9P, |
1386 | "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n" | 1391 | "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n" |
1387 | "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" | 1392 | "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" |
1388 | "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n" | 1393 | "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n" |
1389 | "<<< uid=%d gid=%d n_muid=%d\n", | 1394 | "<<< uid=%d gid=%d n_muid=%d\n", |
1390 | ret->size, ret->type, ret->dev, ret->qid.type, | 1395 | ret->size, ret->type, ret->dev, ret->qid.type, |
1391 | (unsigned long long)ret->qid.path, ret->qid.version, ret->mode, | 1396 | (unsigned long long)ret->qid.path, ret->qid.version, ret->mode, |
1392 | ret->atime, ret->mtime, (unsigned long long)ret->length, | 1397 | ret->atime, ret->mtime, (unsigned long long)ret->length, |
1393 | ret->name, ret->uid, ret->gid, ret->muid, ret->extension, | 1398 | ret->name, ret->uid, ret->gid, ret->muid, ret->extension, |
1394 | ret->n_uid, ret->n_gid, ret->n_muid); | 1399 | ret->n_uid, ret->n_gid, ret->n_muid); |
1395 | 1400 | ||
1396 | p9_free_req(clnt, req); | 1401 | p9_free_req(clnt, req); |
1397 | return ret; | 1402 | return ret; |
1398 | 1403 | ||
1399 | error: | 1404 | error: |
1400 | kfree(ret); | 1405 | kfree(ret); |
1401 | return ERR_PTR(err); | 1406 | return ERR_PTR(err); |
1402 | } | 1407 | } |
1403 | EXPORT_SYMBOL(p9_client_stat); | 1408 | EXPORT_SYMBOL(p9_client_stat); |
1404 | 1409 | ||
1405 | struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, | 1410 | struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, |
1406 | u64 request_mask) | 1411 | u64 request_mask) |
1407 | { | 1412 | { |
1408 | int err; | 1413 | int err; |
1409 | struct p9_client *clnt; | 1414 | struct p9_client *clnt; |
1410 | struct p9_stat_dotl *ret = kmalloc(sizeof(struct p9_stat_dotl), | 1415 | struct p9_stat_dotl *ret = kmalloc(sizeof(struct p9_stat_dotl), |
1411 | GFP_KERNEL); | 1416 | GFP_KERNEL); |
1412 | struct p9_req_t *req; | 1417 | struct p9_req_t *req; |
1413 | 1418 | ||
1414 | P9_DPRINTK(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n", | 1419 | P9_DPRINTK(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n", |
1415 | fid->fid, request_mask); | 1420 | fid->fid, request_mask); |
1416 | 1421 | ||
1417 | if (!ret) | 1422 | if (!ret) |
1418 | return ERR_PTR(-ENOMEM); | 1423 | return ERR_PTR(-ENOMEM); |
1419 | 1424 | ||
1420 | err = 0; | 1425 | err = 0; |
1421 | clnt = fid->clnt; | 1426 | clnt = fid->clnt; |
1422 | 1427 | ||
1423 | req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask); | 1428 | req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask); |
1424 | if (IS_ERR(req)) { | 1429 | if (IS_ERR(req)) { |
1425 | err = PTR_ERR(req); | 1430 | err = PTR_ERR(req); |
1426 | goto error; | 1431 | goto error; |
1427 | } | 1432 | } |
1428 | 1433 | ||
1429 | err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret); | 1434 | err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret); |
1430 | if (err) { | 1435 | if (err) { |
1431 | p9pdu_dump(1, req->rc); | 1436 | p9pdu_dump(1, req->rc); |
1432 | p9_free_req(clnt, req); | 1437 | p9_free_req(clnt, req); |
1433 | goto error; | 1438 | goto error; |
1434 | } | 1439 | } |
1435 | 1440 | ||
1436 | P9_DPRINTK(P9_DEBUG_9P, | 1441 | P9_DPRINTK(P9_DEBUG_9P, |
1437 | "<<< RGETATTR st_result_mask=%lld\n" | 1442 | "<<< RGETATTR st_result_mask=%lld\n" |
1438 | "<<< qid=%x.%llx.%x\n" | 1443 | "<<< qid=%x.%llx.%x\n" |
1439 | "<<< st_mode=%8.8x st_nlink=%llu\n" | 1444 | "<<< st_mode=%8.8x st_nlink=%llu\n" |
1440 | "<<< st_uid=%d st_gid=%d\n" | 1445 | "<<< st_uid=%d st_gid=%d\n" |
1441 | "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n" | 1446 | "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n" |
1442 | "<<< st_atime_sec=%lld st_atime_nsec=%lld\n" | 1447 | "<<< st_atime_sec=%lld st_atime_nsec=%lld\n" |
1443 | "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n" | 1448 | "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n" |
1444 | "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n" | 1449 | "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n" |
1445 | "<<< st_btime_sec=%lld st_btime_nsec=%lld\n" | 1450 | "<<< st_btime_sec=%lld st_btime_nsec=%lld\n" |
1446 | "<<< st_gen=%lld st_data_version=%lld", | 1451 | "<<< st_gen=%lld st_data_version=%lld", |
1447 | ret->st_result_mask, ret->qid.type, ret->qid.path, | 1452 | ret->st_result_mask, ret->qid.type, ret->qid.path, |
1448 | ret->qid.version, ret->st_mode, ret->st_nlink, ret->st_uid, | 1453 | ret->qid.version, ret->st_mode, ret->st_nlink, ret->st_uid, |
1449 | ret->st_gid, ret->st_rdev, ret->st_size, ret->st_blksize, | 1454 | ret->st_gid, ret->st_rdev, ret->st_size, ret->st_blksize, |
1450 | ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec, | 1455 | ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec, |
1451 | ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec, | 1456 | ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec, |
1452 | ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec, | 1457 | ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec, |
1453 | ret->st_gen, ret->st_data_version); | 1458 | ret->st_gen, ret->st_data_version); |
1454 | 1459 | ||
1455 | p9_free_req(clnt, req); | 1460 | p9_free_req(clnt, req); |
1456 | return ret; | 1461 | return ret; |
1457 | 1462 | ||
1458 | error: | 1463 | error: |
1459 | kfree(ret); | 1464 | kfree(ret); |
1460 | return ERR_PTR(err); | 1465 | return ERR_PTR(err); |
1461 | } | 1466 | } |
1462 | EXPORT_SYMBOL(p9_client_getattr_dotl); | 1467 | EXPORT_SYMBOL(p9_client_getattr_dotl); |
1463 | 1468 | ||
1464 | static int p9_client_statsize(struct p9_wstat *wst, int proto_version) | 1469 | static int p9_client_statsize(struct p9_wstat *wst, int proto_version) |
1465 | { | 1470 | { |
1466 | int ret; | 1471 | int ret; |
1467 | 1472 | ||
1468 | /* NOTE: size shouldn't include its own length */ | 1473 | /* NOTE: size shouldn't include its own length */ |
1469 | /* size[2] type[2] dev[4] qid[13] */ | 1474 | /* size[2] type[2] dev[4] qid[13] */ |
1470 | /* mode[4] atime[4] mtime[4] length[8]*/ | 1475 | /* mode[4] atime[4] mtime[4] length[8]*/ |
1471 | /* name[s] uid[s] gid[s] muid[s] */ | 1476 | /* name[s] uid[s] gid[s] muid[s] */ |
1472 | ret = 2+4+13+4+4+4+8+2+2+2+2; | 1477 | ret = 2+4+13+4+4+4+8+2+2+2+2; |
1473 | 1478 | ||
1474 | if (wst->name) | 1479 | if (wst->name) |
1475 | ret += strlen(wst->name); | 1480 | ret += strlen(wst->name); |
1476 | if (wst->uid) | 1481 | if (wst->uid) |
1477 | ret += strlen(wst->uid); | 1482 | ret += strlen(wst->uid); |
1478 | if (wst->gid) | 1483 | if (wst->gid) |
1479 | ret += strlen(wst->gid); | 1484 | ret += strlen(wst->gid); |
1480 | if (wst->muid) | 1485 | if (wst->muid) |
1481 | ret += strlen(wst->muid); | 1486 | ret += strlen(wst->muid); |
1482 | 1487 | ||
1483 | if ((proto_version == p9_proto_2000u) || | 1488 | if ((proto_version == p9_proto_2000u) || |
1484 | (proto_version == p9_proto_2000L)) { | 1489 | (proto_version == p9_proto_2000L)) { |
1485 | ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ | 1490 | ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ |
1486 | if (wst->extension) | 1491 | if (wst->extension) |
1487 | ret += strlen(wst->extension); | 1492 | ret += strlen(wst->extension); |
1488 | } | 1493 | } |
1489 | 1494 | ||
1490 | return ret; | 1495 | return ret; |
1491 | } | 1496 | } |
1492 | 1497 | ||
1493 | int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) | 1498 | int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) |
1494 | { | 1499 | { |
1495 | int err; | 1500 | int err; |
1496 | struct p9_req_t *req; | 1501 | struct p9_req_t *req; |
1497 | struct p9_client *clnt; | 1502 | struct p9_client *clnt; |
1498 | 1503 | ||
1499 | err = 0; | 1504 | err = 0; |
1500 | clnt = fid->clnt; | 1505 | clnt = fid->clnt; |
1501 | wst->size = p9_client_statsize(wst, clnt->proto_version); | 1506 | wst->size = p9_client_statsize(wst, clnt->proto_version); |
1502 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); | 1507 | P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); |
1503 | P9_DPRINTK(P9_DEBUG_9P, | 1508 | P9_DPRINTK(P9_DEBUG_9P, |
1504 | " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" | 1509 | " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" |
1505 | " mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" | 1510 | " mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" |
1506 | " name=%s uid=%s gid=%s muid=%s extension=(%s)\n" | 1511 | " name=%s uid=%s gid=%s muid=%s extension=(%s)\n" |
1507 | " uid=%d gid=%d n_muid=%d\n", | 1512 | " uid=%d gid=%d n_muid=%d\n", |
1508 | wst->size, wst->type, wst->dev, wst->qid.type, | 1513 | wst->size, wst->type, wst->dev, wst->qid.type, |
1509 | (unsigned long long)wst->qid.path, wst->qid.version, wst->mode, | 1514 | (unsigned long long)wst->qid.path, wst->qid.version, wst->mode, |
1510 | wst->atime, wst->mtime, (unsigned long long)wst->length, | 1515 | wst->atime, wst->mtime, (unsigned long long)wst->length, |
1511 | wst->name, wst->uid, wst->gid, wst->muid, wst->extension, | 1516 | wst->name, wst->uid, wst->gid, wst->muid, wst->extension, |
1512 | wst->n_uid, wst->n_gid, wst->n_muid); | 1517 | wst->n_uid, wst->n_gid, wst->n_muid); |
1513 | 1518 | ||
1514 | req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size+2, wst); | 1519 | req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size+2, wst); |
1515 | if (IS_ERR(req)) { | 1520 | if (IS_ERR(req)) { |
1516 | err = PTR_ERR(req); | 1521 | err = PTR_ERR(req); |
1517 | goto error; | 1522 | goto error; |
1518 | } | 1523 | } |
1519 | 1524 | ||
1520 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid); | 1525 | P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid); |
1521 | 1526 | ||
1522 | p9_free_req(clnt, req); | 1527 | p9_free_req(clnt, req); |
1523 | error: | 1528 | error: |
1524 | return err; | 1529 | return err; |
1525 | } | 1530 | } |
1526 | EXPORT_SYMBOL(p9_client_wstat); | 1531 | EXPORT_SYMBOL(p9_client_wstat); |
1527 | 1532 | ||
1528 | int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr) | 1533 | int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr) |
1529 | { | 1534 | { |
1530 | int err; | 1535 | int err; |
1531 | struct p9_req_t *req; | 1536 | struct p9_req_t *req; |
1532 | struct p9_client *clnt; | 1537 | struct p9_client *clnt; |
1533 | 1538 | ||
1534 | err = 0; | 1539 | err = 0; |
1535 | clnt = fid->clnt; | 1540 | clnt = fid->clnt; |
1536 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid); | 1541 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid); |
1537 | P9_DPRINTK(P9_DEBUG_9P, | 1542 | P9_DPRINTK(P9_DEBUG_9P, |
1538 | " valid=%x mode=%x uid=%d gid=%d size=%lld\n" | 1543 | " valid=%x mode=%x uid=%d gid=%d size=%lld\n" |
1539 | " atime_sec=%lld atime_nsec=%lld\n" | 1544 | " atime_sec=%lld atime_nsec=%lld\n" |
1540 | " mtime_sec=%lld mtime_nsec=%lld\n", | 1545 | " mtime_sec=%lld mtime_nsec=%lld\n", |
1541 | p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid, | 1546 | p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid, |
1542 | p9attr->size, p9attr->atime_sec, p9attr->atime_nsec, | 1547 | p9attr->size, p9attr->atime_sec, p9attr->atime_nsec, |
1543 | p9attr->mtime_sec, p9attr->mtime_nsec); | 1548 | p9attr->mtime_sec, p9attr->mtime_nsec); |
1544 | 1549 | ||
1545 | req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr); | 1550 | req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr); |
1546 | 1551 | ||
1547 | if (IS_ERR(req)) { | 1552 | if (IS_ERR(req)) { |
1548 | err = PTR_ERR(req); | 1553 | err = PTR_ERR(req); |
1549 | goto error; | 1554 | goto error; |
1550 | } | 1555 | } |
1551 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid); | 1556 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid); |
1552 | p9_free_req(clnt, req); | 1557 | p9_free_req(clnt, req); |
1553 | error: | 1558 | error: |
1554 | return err; | 1559 | return err; |
1555 | } | 1560 | } |
1556 | EXPORT_SYMBOL(p9_client_setattr); | 1561 | EXPORT_SYMBOL(p9_client_setattr); |
1557 | 1562 | ||
1558 | int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) | 1563 | int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) |
1559 | { | 1564 | { |
1560 | int err; | 1565 | int err; |
1561 | struct p9_req_t *req; | 1566 | struct p9_req_t *req; |
1562 | struct p9_client *clnt; | 1567 | struct p9_client *clnt; |
1563 | 1568 | ||
1564 | err = 0; | 1569 | err = 0; |
1565 | clnt = fid->clnt; | 1570 | clnt = fid->clnt; |
1566 | 1571 | ||
1567 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid); | 1572 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid); |
1568 | 1573 | ||
1569 | req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid); | 1574 | req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid); |
1570 | if (IS_ERR(req)) { | 1575 | if (IS_ERR(req)) { |
1571 | err = PTR_ERR(req); | 1576 | err = PTR_ERR(req); |
1572 | goto error; | 1577 | goto error; |
1573 | } | 1578 | } |
1574 | 1579 | ||
1575 | err = p9pdu_readf(req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type, | 1580 | err = p9pdu_readf(req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type, |
1576 | &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail, | 1581 | &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail, |
1577 | &sb->files, &sb->ffree, &sb->fsid, &sb->namelen); | 1582 | &sb->files, &sb->ffree, &sb->fsid, &sb->namelen); |
1578 | if (err) { | 1583 | if (err) { |
1579 | p9pdu_dump(1, req->rc); | 1584 | p9pdu_dump(1, req->rc); |
1580 | p9_free_req(clnt, req); | 1585 | p9_free_req(clnt, req); |
1581 | goto error; | 1586 | goto error; |
1582 | } | 1587 | } |
1583 | 1588 | ||
1584 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld " | 1589 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld " |
1585 | "blocks %llu bfree %llu bavail %llu files %llu ffree %llu " | 1590 | "blocks %llu bfree %llu bavail %llu files %llu ffree %llu " |
1586 | "fsid %llu namelen %ld\n", | 1591 | "fsid %llu namelen %ld\n", |
1587 | fid->fid, (long unsigned int)sb->type, (long int)sb->bsize, | 1592 | fid->fid, (long unsigned int)sb->type, (long int)sb->bsize, |
1588 | sb->blocks, sb->bfree, sb->bavail, sb->files, sb->ffree, | 1593 | sb->blocks, sb->bfree, sb->bavail, sb->files, sb->ffree, |
1589 | sb->fsid, (long int)sb->namelen); | 1594 | sb->fsid, (long int)sb->namelen); |
1590 | 1595 | ||
1591 | p9_free_req(clnt, req); | 1596 | p9_free_req(clnt, req); |
1592 | error: | 1597 | error: |
1593 | return err; | 1598 | return err; |
1594 | } | 1599 | } |
1595 | EXPORT_SYMBOL(p9_client_statfs); | 1600 | EXPORT_SYMBOL(p9_client_statfs); |
1596 | 1601 | ||
1597 | int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name) | 1602 | int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name) |
1598 | { | 1603 | { |
1599 | int err; | 1604 | int err; |
1600 | struct p9_req_t *req; | 1605 | struct p9_req_t *req; |
1601 | struct p9_client *clnt; | 1606 | struct p9_client *clnt; |
1602 | 1607 | ||
1603 | err = 0; | 1608 | err = 0; |
1604 | clnt = fid->clnt; | 1609 | clnt = fid->clnt; |
1605 | 1610 | ||
1606 | P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n", | 1611 | P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n", |
1607 | fid->fid, newdirfid->fid, name); | 1612 | fid->fid, newdirfid->fid, name); |
1608 | 1613 | ||
1609 | req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid, | 1614 | req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid, |
1610 | newdirfid->fid, name); | 1615 | newdirfid->fid, name); |
1611 | if (IS_ERR(req)) { | 1616 | if (IS_ERR(req)) { |
1612 | err = PTR_ERR(req); | 1617 | err = PTR_ERR(req); |
1613 | goto error; | 1618 | goto error; |
1614 | } | 1619 | } |
1615 | 1620 | ||
1616 | P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid); | 1621 | P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid); |
1617 | 1622 | ||
1618 | p9_free_req(clnt, req); | 1623 | p9_free_req(clnt, req); |
1619 | error: | 1624 | error: |
1620 | return err; | 1625 | return err; |
1621 | } | 1626 | } |
1622 | EXPORT_SYMBOL(p9_client_rename); | 1627 | EXPORT_SYMBOL(p9_client_rename); |
1623 | 1628 | ||
1624 | /* | 1629 | /* |
1625 | * An xattrwalk without @attr_name gives the fid for the lisxattr namespace | 1630 | * An xattrwalk without @attr_name gives the fid for the lisxattr namespace |
1626 | */ | 1631 | */ |
1627 | struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, | 1632 | struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, |
1628 | const char *attr_name, u64 *attr_size) | 1633 | const char *attr_name, u64 *attr_size) |
1629 | { | 1634 | { |
1630 | int err; | 1635 | int err; |
1631 | struct p9_req_t *req; | 1636 | struct p9_req_t *req; |
1632 | struct p9_client *clnt; | 1637 | struct p9_client *clnt; |
1633 | struct p9_fid *attr_fid; | 1638 | struct p9_fid *attr_fid; |
1634 | 1639 | ||
1635 | err = 0; | 1640 | err = 0; |
1636 | clnt = file_fid->clnt; | 1641 | clnt = file_fid->clnt; |
1637 | attr_fid = p9_fid_create(clnt); | 1642 | attr_fid = p9_fid_create(clnt); |
1638 | if (IS_ERR(attr_fid)) { | 1643 | if (IS_ERR(attr_fid)) { |
1639 | err = PTR_ERR(attr_fid); | 1644 | err = PTR_ERR(attr_fid); |
1640 | attr_fid = NULL; | 1645 | attr_fid = NULL; |
1641 | goto error; | 1646 | goto error; |
1642 | } | 1647 | } |
1643 | P9_DPRINTK(P9_DEBUG_9P, | 1648 | P9_DPRINTK(P9_DEBUG_9P, |
1644 | ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n", | 1649 | ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n", |
1645 | file_fid->fid, attr_fid->fid, attr_name); | 1650 | file_fid->fid, attr_fid->fid, attr_name); |
1646 | 1651 | ||
1647 | req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds", | 1652 | req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds", |
1648 | file_fid->fid, attr_fid->fid, attr_name); | 1653 | file_fid->fid, attr_fid->fid, attr_name); |
1649 | if (IS_ERR(req)) { | 1654 | if (IS_ERR(req)) { |
1650 | err = PTR_ERR(req); | 1655 | err = PTR_ERR(req); |
1651 | goto error; | 1656 | goto error; |
1652 | } | 1657 | } |
1653 | err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size); | 1658 | err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size); |
1654 | if (err) { | 1659 | if (err) { |
1655 | p9pdu_dump(1, req->rc); | 1660 | p9pdu_dump(1, req->rc); |
1656 | p9_free_req(clnt, req); | 1661 | p9_free_req(clnt, req); |
1657 | goto clunk_fid; | 1662 | goto clunk_fid; |
1658 | } | 1663 | } |
1659 | p9_free_req(clnt, req); | 1664 | p9_free_req(clnt, req); |
1660 | P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRWALK fid %d size %llu\n", | 1665 | P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRWALK fid %d size %llu\n", |
1661 | attr_fid->fid, *attr_size); | 1666 | attr_fid->fid, *attr_size); |
1662 | return attr_fid; | 1667 | return attr_fid; |
1663 | clunk_fid: | 1668 | clunk_fid: |
1664 | p9_client_clunk(attr_fid); | 1669 | p9_client_clunk(attr_fid); |
1665 | attr_fid = NULL; | 1670 | attr_fid = NULL; |
1666 | error: | 1671 | error: |
1667 | if (attr_fid && (attr_fid != file_fid)) | 1672 | if (attr_fid && (attr_fid != file_fid)) |
1668 | p9_fid_destroy(attr_fid); | 1673 | p9_fid_destroy(attr_fid); |
1669 | 1674 | ||
1670 | return ERR_PTR(err); | 1675 | return ERR_PTR(err); |
1671 | } | 1676 | } |
1672 | EXPORT_SYMBOL_GPL(p9_client_xattrwalk); | 1677 | EXPORT_SYMBOL_GPL(p9_client_xattrwalk); |
1673 | 1678 | ||
1674 | int p9_client_xattrcreate(struct p9_fid *fid, const char *name, | 1679 | int p9_client_xattrcreate(struct p9_fid *fid, const char *name, |
1675 | u64 attr_size, int flags) | 1680 | u64 attr_size, int flags) |
1676 | { | 1681 | { |
1677 | int err; | 1682 | int err; |
1678 | struct p9_req_t *req; | 1683 | struct p9_req_t *req; |
1679 | struct p9_client *clnt; | 1684 | struct p9_client *clnt; |
1680 | 1685 | ||
1681 | P9_DPRINTK(P9_DEBUG_9P, | 1686 | P9_DPRINTK(P9_DEBUG_9P, |
1682 | ">>> TXATTRCREATE fid %d name %s size %lld flag %d\n", | 1687 | ">>> TXATTRCREATE fid %d name %s size %lld flag %d\n", |
1683 | fid->fid, name, (long long)attr_size, flags); | 1688 | fid->fid, name, (long long)attr_size, flags); |
1684 | err = 0; | 1689 | err = 0; |
1685 | clnt = fid->clnt; | 1690 | clnt = fid->clnt; |
1686 | req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd", | 1691 | req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd", |
1687 | fid->fid, name, attr_size, flags); | 1692 | fid->fid, name, attr_size, flags); |
1688 | if (IS_ERR(req)) { | 1693 | if (IS_ERR(req)) { |
1689 | err = PTR_ERR(req); | 1694 | err = PTR_ERR(req); |
1690 | goto error; | 1695 | goto error; |
1691 | } | 1696 | } |
1692 | P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid); | 1697 | P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid); |
1693 | p9_free_req(clnt, req); | 1698 | p9_free_req(clnt, req); |
1694 | error: | 1699 | error: |
1695 | return err; | 1700 | return err; |
1696 | } | 1701 | } |
1697 | EXPORT_SYMBOL_GPL(p9_client_xattrcreate); | 1702 | EXPORT_SYMBOL_GPL(p9_client_xattrcreate); |
1698 | 1703 | ||
1699 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | 1704 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) |
1700 | { | 1705 | { |
1701 | int err, rsize, total; | 1706 | int err, rsize, total; |
1702 | struct p9_client *clnt; | 1707 | struct p9_client *clnt; |
1703 | struct p9_req_t *req; | 1708 | struct p9_req_t *req; |
1704 | char *dataptr; | 1709 | char *dataptr; |
1705 | 1710 | ||
1706 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", | 1711 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", |
1707 | fid->fid, (long long unsigned) offset, count); | 1712 | fid->fid, (long long unsigned) offset, count); |
1708 | 1713 | ||
1709 | err = 0; | 1714 | err = 0; |
1710 | clnt = fid->clnt; | 1715 | clnt = fid->clnt; |
1711 | total = 0; | 1716 | total = 0; |
1712 | 1717 | ||
1713 | rsize = fid->iounit; | 1718 | rsize = fid->iounit; |
1714 | if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ) | 1719 | if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ) |
1715 | rsize = clnt->msize - P9_READDIRHDRSZ; | 1720 | rsize = clnt->msize - P9_READDIRHDRSZ; |
1716 | 1721 | ||
1717 | if (count < rsize) | 1722 | if (count < rsize) |
1718 | rsize = count; | 1723 | rsize = count; |
1719 | 1724 | ||
1720 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize); | 1725 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize); |
1721 | if (IS_ERR(req)) { | 1726 | if (IS_ERR(req)) { |
1722 | err = PTR_ERR(req); | 1727 | err = PTR_ERR(req); |
1723 | goto error; | 1728 | goto error; |
1724 | } | 1729 | } |
1725 | 1730 | ||
1726 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); | 1731 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); |
1727 | if (err) { | 1732 | if (err) { |
1728 | p9pdu_dump(1, req->rc); | 1733 | p9pdu_dump(1, req->rc); |
1729 | goto free_and_error; | 1734 | goto free_and_error; |
1730 | } | 1735 | } |
1731 | 1736 | ||
1732 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); | 1737 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); |
1733 | 1738 | ||
1734 | if (data) | 1739 | if (data) |
1735 | memmove(data, dataptr, count); | 1740 | memmove(data, dataptr, count); |
1736 | 1741 | ||
1737 | p9_free_req(clnt, req); | 1742 | p9_free_req(clnt, req); |
1738 | return count; | 1743 | return count; |
1739 | 1744 | ||
1740 | free_and_error: | 1745 | free_and_error: |
1741 | p9_free_req(clnt, req); | 1746 | p9_free_req(clnt, req); |
1742 | error: | 1747 | error: |
1743 | return err; | 1748 | return err; |
1744 | } | 1749 | } |
1745 | EXPORT_SYMBOL(p9_client_readdir); | 1750 | EXPORT_SYMBOL(p9_client_readdir); |
1746 | 1751 | ||
1747 | int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode, | 1752 | int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode, |
1748 | dev_t rdev, gid_t gid, struct p9_qid *qid) | 1753 | dev_t rdev, gid_t gid, struct p9_qid *qid) |
1749 | { | 1754 | { |
1750 | int err; | 1755 | int err; |
1751 | struct p9_client *clnt; | 1756 | struct p9_client *clnt; |
1752 | struct p9_req_t *req; | 1757 | struct p9_req_t *req; |
1753 | 1758 | ||
1754 | err = 0; | 1759 | err = 0; |
1755 | clnt = fid->clnt; | 1760 | clnt = fid->clnt; |
1756 | P9_DPRINTK(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d " | 1761 | P9_DPRINTK(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d " |
1757 | "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev)); | 1762 | "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev)); |
1758 | req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode, | 1763 | req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode, |
1759 | MAJOR(rdev), MINOR(rdev), gid); | 1764 | MAJOR(rdev), MINOR(rdev), gid); |
1760 | if (IS_ERR(req)) | 1765 | if (IS_ERR(req)) |
1761 | return PTR_ERR(req); | 1766 | return PTR_ERR(req); |
1762 | 1767 | ||
1763 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); | 1768 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); |
1764 | if (err) { | 1769 | if (err) { |
1765 | p9pdu_dump(1, req->rc); | 1770 | p9pdu_dump(1, req->rc); |
1766 | goto error; | 1771 | goto error; |
1767 | } | 1772 | } |
1768 | P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type, | 1773 | P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type, |
1769 | (unsigned long long)qid->path, qid->version); | 1774 | (unsigned long long)qid->path, qid->version); |
1770 | 1775 | ||
1771 | error: | 1776 | error: |
1772 | p9_free_req(clnt, req); | 1777 | p9_free_req(clnt, req); |
1773 | return err; | 1778 | return err; |
1774 | 1779 | ||
1775 | } | 1780 | } |
1776 | EXPORT_SYMBOL(p9_client_mknod_dotl); | 1781 | EXPORT_SYMBOL(p9_client_mknod_dotl); |
1777 | 1782 | ||
1778 | int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, | 1783 | int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, |
1779 | gid_t gid, struct p9_qid *qid) | 1784 | gid_t gid, struct p9_qid *qid) |
1780 | { | 1785 | { |
1781 | int err; | 1786 | int err; |
1782 | struct p9_client *clnt; | 1787 | struct p9_client *clnt; |
1783 | struct p9_req_t *req; | 1788 | struct p9_req_t *req; |
1784 | 1789 | ||
1785 | err = 0; | 1790 | err = 0; |
1786 | clnt = fid->clnt; | 1791 | clnt = fid->clnt; |
1787 | P9_DPRINTK(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n", | 1792 | P9_DPRINTK(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n", |
1788 | fid->fid, name, mode, gid); | 1793 | fid->fid, name, mode, gid); |
1789 | req = p9_client_rpc(clnt, P9_TMKDIR, "dsdd", fid->fid, name, mode, | 1794 | req = p9_client_rpc(clnt, P9_TMKDIR, "dsdd", fid->fid, name, mode, |
1790 | gid); | 1795 | gid); |
1791 | if (IS_ERR(req)) | 1796 | if (IS_ERR(req)) |
1792 | return PTR_ERR(req); | 1797 | return PTR_ERR(req); |
1793 | 1798 | ||
1794 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); | 1799 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); |
1795 | if (err) { | 1800 | if (err) { |
1796 | p9pdu_dump(1, req->rc); | 1801 | p9pdu_dump(1, req->rc); |
1797 | goto error; | 1802 | goto error; |
1798 | } | 1803 | } |
1799 | P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type, | 1804 | P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type, |
1800 | (unsigned long long)qid->path, qid->version); | 1805 | (unsigned long long)qid->path, qid->version); |
1801 | 1806 | ||
1802 | error: | 1807 | error: |
1803 | p9_free_req(clnt, req); | 1808 | p9_free_req(clnt, req); |
1804 | return err; | 1809 | return err; |
1805 | 1810 | ||
1806 | } | 1811 | } |
1807 | EXPORT_SYMBOL(p9_client_mkdir_dotl); | 1812 | EXPORT_SYMBOL(p9_client_mkdir_dotl); |
1808 | 1813 |