diff options
Diffstat (limited to 'fs/9p/vfs_inode.c')
-rw-r--r-- | fs/9p/vfs_inode.c | 617 |
1 files changed, 209 insertions, 408 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 0ea965c3bb7d..d933ef1fbd8a 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include "v9fs.h" | 40 | #include "v9fs.h" |
41 | #include "9p.h" | 41 | #include "9p.h" |
42 | #include "v9fs_vfs.h" | 42 | #include "v9fs_vfs.h" |
43 | #include "conv.h" | ||
44 | #include "fid.h" | 43 | #include "fid.h" |
45 | 44 | ||
46 | static struct inode_operations v9fs_dir_inode_operations; | 45 | static struct inode_operations v9fs_dir_inode_operations; |
@@ -127,100 +126,32 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) | |||
127 | } | 126 | } |
128 | 127 | ||
129 | /** | 128 | /** |
130 | * v9fs_blank_mistat - helper function to setup a 9P stat structure | 129 | * v9fs_blank_wstat - helper function to setup a 9P stat structure |
131 | * @v9ses: 9P session info (for determining extended mode) | 130 | * @v9ses: 9P session info (for determining extended mode) |
132 | * @mistat: structure to initialize | 131 | * @wstat: structure to initialize |
133 | * | 132 | * |
134 | */ | 133 | */ |
135 | 134 | ||
136 | static void | 135 | static void |
137 | v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat) | 136 | v9fs_blank_wstat(struct v9fs_wstat *wstat) |
138 | { | 137 | { |
139 | mistat->type = ~0; | 138 | wstat->type = ~0; |
140 | mistat->dev = ~0; | 139 | wstat->dev = ~0; |
141 | mistat->qid.type = ~0; | 140 | wstat->qid.type = ~0; |
142 | mistat->qid.version = ~0; | 141 | wstat->qid.version = ~0; |
143 | *((long long *)&mistat->qid.path) = ~0; | 142 | *((long long *)&wstat->qid.path) = ~0; |
144 | mistat->mode = ~0; | 143 | wstat->mode = ~0; |
145 | mistat->atime = ~0; | 144 | wstat->atime = ~0; |
146 | mistat->mtime = ~0; | 145 | wstat->mtime = ~0; |
147 | mistat->length = ~0; | 146 | wstat->length = ~0; |
148 | mistat->name = mistat->data; | 147 | wstat->name = NULL; |
149 | mistat->uid = mistat->data; | 148 | wstat->uid = NULL; |
150 | mistat->gid = mistat->data; | 149 | wstat->gid = NULL; |
151 | mistat->muid = mistat->data; | 150 | wstat->muid = NULL; |
152 | if (v9ses->extended) { | 151 | wstat->n_uid = ~0; |
153 | mistat->n_uid = ~0; | 152 | wstat->n_gid = ~0; |
154 | mistat->n_gid = ~0; | 153 | wstat->n_muid = ~0; |
155 | mistat->n_muid = ~0; | 154 | wstat->extension = NULL; |
156 | mistat->extension = mistat->data; | ||
157 | } | ||
158 | *mistat->data = 0; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * v9fs_mistat2unix - convert mistat to unix stat | ||
163 | * @mistat: Plan 9 metadata (mistat) structure | ||
164 | * @buf: unix metadata (stat) structure to populate | ||
165 | * @sb: superblock | ||
166 | * | ||
167 | */ | ||
168 | |||
169 | static void | ||
170 | v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf, | ||
171 | struct super_block *sb) | ||
172 | { | ||
173 | struct v9fs_session_info *v9ses = sb ? sb->s_fs_info : NULL; | ||
174 | |||
175 | buf->st_nlink = 1; | ||
176 | |||
177 | buf->st_atime = mistat->atime; | ||
178 | buf->st_mtime = mistat->mtime; | ||
179 | buf->st_ctime = mistat->mtime; | ||
180 | |||
181 | buf->st_uid = (unsigned short)-1; | ||
182 | buf->st_gid = (unsigned short)-1; | ||
183 | |||
184 | if (v9ses && v9ses->extended) { | ||
185 | /* TODO: string to uid mapping via user-space daemon */ | ||
186 | if (mistat->n_uid != -1) | ||
187 | sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid); | ||
188 | |||
189 | if (mistat->n_gid != -1) | ||
190 | sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid); | ||
191 | } | ||
192 | |||
193 | if (buf->st_uid == (unsigned short)-1) | ||
194 | buf->st_uid = v9ses->uid; | ||
195 | if (buf->st_gid == (unsigned short)-1) | ||
196 | buf->st_gid = v9ses->gid; | ||
197 | |||
198 | buf->st_mode = p9mode2unixmode(v9ses, mistat->mode); | ||
199 | if ((S_ISBLK(buf->st_mode)) || (S_ISCHR(buf->st_mode))) { | ||
200 | char type = 0; | ||
201 | int major = -1; | ||
202 | int minor = -1; | ||
203 | sscanf(mistat->extension, "%c %u %u", &type, &major, &minor); | ||
204 | switch (type) { | ||
205 | case 'c': | ||
206 | buf->st_mode &= ~S_IFBLK; | ||
207 | buf->st_mode |= S_IFCHR; | ||
208 | break; | ||
209 | case 'b': | ||
210 | break; | ||
211 | default: | ||
212 | dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n", | ||
213 | type, mistat->extension); | ||
214 | }; | ||
215 | buf->st_rdev = MKDEV(major, minor); | ||
216 | } else | ||
217 | buf->st_rdev = 0; | ||
218 | |||
219 | buf->st_size = mistat->length; | ||
220 | |||
221 | buf->st_blksize = sb->s_blocksize; | ||
222 | buf->st_blocks = | ||
223 | (buf->st_size + buf->st_blksize - 1) >> sb->s_blocksize_bits; | ||
224 | } | 155 | } |
225 | 156 | ||
226 | /** | 157 | /** |
@@ -312,12 +243,12 @@ v9fs_create(struct inode *dir, | |||
312 | struct inode *file_inode = NULL; | 243 | struct inode *file_inode = NULL; |
313 | struct v9fs_fcall *fcall = NULL; | 244 | struct v9fs_fcall *fcall = NULL; |
314 | struct v9fs_qid qid; | 245 | struct v9fs_qid qid; |
315 | struct stat newstat; | ||
316 | int dirfidnum = -1; | 246 | int dirfidnum = -1; |
317 | long newfid = -1; | 247 | long newfid = -1; |
318 | int result = 0; | 248 | int result = 0; |
319 | unsigned int iounit = 0; | 249 | unsigned int iounit = 0; |
320 | int wfidno = -1; | 250 | int wfidno = -1; |
251 | int err; | ||
321 | 252 | ||
322 | perm = unixmode2p9mode(v9ses, perm); | 253 | perm = unixmode2p9mode(v9ses, perm); |
323 | 254 | ||
@@ -349,57 +280,64 @@ v9fs_create(struct inode *dir, | |||
349 | 280 | ||
350 | result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); | 281 | result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); |
351 | if (result < 0) { | 282 | if (result < 0) { |
352 | dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); | 283 | PRINT_FCALL_ERROR("clone error", fcall); |
353 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 284 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
354 | newfid = -1; | 285 | newfid = -1; |
355 | goto CleanUpFid; | 286 | goto CleanUpFid; |
356 | } | 287 | } |
357 | 288 | ||
358 | kfree(fcall); | 289 | kfree(fcall); |
290 | fcall = NULL; | ||
359 | 291 | ||
360 | result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, | 292 | result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, |
361 | perm, open_mode, &fcall); | 293 | perm, open_mode, &fcall); |
362 | if (result < 0) { | 294 | if (result < 0) { |
363 | dprintk(DEBUG_ERROR, "create fails: %s(%d)\n", | 295 | PRINT_FCALL_ERROR("create fails", fcall); |
364 | FCALL_ERROR(fcall), result); | ||
365 | |||
366 | goto CleanUpFid; | 296 | goto CleanUpFid; |
367 | } | 297 | } |
368 | 298 | ||
369 | iounit = fcall->params.rcreate.iounit; | 299 | iounit = fcall->params.rcreate.iounit; |
370 | qid = fcall->params.rcreate.qid; | 300 | qid = fcall->params.rcreate.qid; |
371 | kfree(fcall); | 301 | kfree(fcall); |
302 | fcall = NULL; | ||
372 | 303 | ||
373 | fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); | 304 | if (!(perm&V9FS_DMDIR)) { |
374 | dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); | 305 | fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); |
375 | if (!fid) { | 306 | dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); |
376 | result = -ENOMEM; | 307 | if (!fid) { |
377 | goto CleanUpFid; | 308 | result = -ENOMEM; |
378 | } | 309 | goto CleanUpFid; |
310 | } | ||
379 | 311 | ||
380 | fid->qid = qid; | 312 | fid->qid = qid; |
381 | fid->iounit = iounit; | 313 | fid->iounit = iounit; |
314 | } else { | ||
315 | err = v9fs_t_clunk(v9ses, newfid); | ||
316 | newfid = -1; | ||
317 | if (err < 0) | ||
318 | dprintk(DEBUG_ERROR, "clunk for mkdir failed: %d\n", err); | ||
319 | } | ||
382 | 320 | ||
383 | /* walk to the newly created file and put the fid in the dentry */ | 321 | /* walk to the newly created file and put the fid in the dentry */ |
384 | wfidno = v9fs_get_idpool(&v9ses->fidpool); | 322 | wfidno = v9fs_get_idpool(&v9ses->fidpool); |
385 | if (newfid < 0) { | 323 | if (wfidno < 0) { |
386 | eprintk(KERN_WARNING, "no free fids available\n"); | 324 | eprintk(KERN_WARNING, "no free fids available\n"); |
387 | return -ENOSPC; | 325 | return -ENOSPC; |
388 | } | 326 | } |
389 | 327 | ||
390 | result = v9fs_t_walk(v9ses, dirfidnum, wfidno, | 328 | result = v9fs_t_walk(v9ses, dirfidnum, wfidno, |
391 | (char *) file_dentry->d_name.name, NULL); | 329 | (char *) file_dentry->d_name.name, &fcall); |
392 | if (result < 0) { | 330 | if (result < 0) { |
393 | dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); | 331 | PRINT_FCALL_ERROR("clone error", fcall); |
394 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | 332 | v9fs_put_idpool(wfidno, &v9ses->fidpool); |
395 | wfidno = -1; | 333 | wfidno = -1; |
396 | goto CleanUpFid; | 334 | goto CleanUpFid; |
397 | } | 335 | } |
336 | kfree(fcall); | ||
337 | fcall = NULL; | ||
398 | 338 | ||
399 | if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { | 339 | if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { |
400 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) { | 340 | v9fs_put_idpool(wfidno, &v9ses->fidpool); |
401 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | ||
402 | } | ||
403 | 341 | ||
404 | goto CleanUpFid; | 342 | goto CleanUpFid; |
405 | } | 343 | } |
@@ -409,62 +347,43 @@ v9fs_create(struct inode *dir, | |||
409 | (perm & V9FS_DMDEVICE)) | 347 | (perm & V9FS_DMDEVICE)) |
410 | return 0; | 348 | return 0; |
411 | 349 | ||
412 | result = v9fs_t_stat(v9ses, newfid, &fcall); | 350 | result = v9fs_t_stat(v9ses, wfidno, &fcall); |
413 | if (result < 0) { | 351 | if (result < 0) { |
414 | dprintk(DEBUG_ERROR, "stat error: %s(%d)\n", FCALL_ERROR(fcall), | 352 | PRINT_FCALL_ERROR("stat error", fcall); |
415 | result); | ||
416 | goto CleanUpFid; | 353 | goto CleanUpFid; |
417 | } | 354 | } |
418 | 355 | ||
419 | v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb); | ||
420 | 356 | ||
421 | file_inode = v9fs_get_inode(sb, newstat.st_mode); | 357 | file_inode = v9fs_get_inode(sb, |
358 | p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode)); | ||
359 | |||
422 | if ((!file_inode) || IS_ERR(file_inode)) { | 360 | if ((!file_inode) || IS_ERR(file_inode)) { |
423 | dprintk(DEBUG_ERROR, "create inode failed\n"); | 361 | dprintk(DEBUG_ERROR, "create inode failed\n"); |
424 | result = -EBADF; | 362 | result = -EBADF; |
425 | goto CleanUpFid; | 363 | goto CleanUpFid; |
426 | } | 364 | } |
427 | 365 | ||
428 | v9fs_mistat2inode(fcall->params.rstat.stat, file_inode, sb); | 366 | v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb); |
429 | kfree(fcall); | 367 | kfree(fcall); |
430 | fcall = NULL; | 368 | fcall = NULL; |
431 | file_dentry->d_op = &v9fs_dentry_operations; | 369 | file_dentry->d_op = &v9fs_dentry_operations; |
432 | d_instantiate(file_dentry, file_inode); | 370 | d_instantiate(file_dentry, file_inode); |
433 | 371 | ||
434 | if (perm & V9FS_DMDIR) { | ||
435 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) | ||
436 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
437 | else | ||
438 | dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n", | ||
439 | FCALL_ERROR(fcall)); | ||
440 | kfree(fcall); | ||
441 | fid->fidopen = 0; | ||
442 | fid->fidcreate = 0; | ||
443 | d_drop(file_dentry); | ||
444 | } | ||
445 | |||
446 | return 0; | 372 | return 0; |
447 | 373 | ||
448 | CleanUpFid: | 374 | CleanUpFid: |
449 | kfree(fcall); | 375 | kfree(fcall); |
376 | fcall = NULL; | ||
450 | 377 | ||
451 | if (newfid >= 0) { | 378 | if (newfid >= 0) { |
452 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) | 379 | err = v9fs_t_clunk(v9ses, newfid); |
453 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 380 | if (err < 0) |
454 | else | 381 | dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); |
455 | dprintk(DEBUG_ERROR, "clunk failed: %s\n", | ||
456 | FCALL_ERROR(fcall)); | ||
457 | |||
458 | kfree(fcall); | ||
459 | } | 382 | } |
460 | if (wfidno >= 0) { | 383 | if (wfidno >= 0) { |
461 | if (!v9fs_t_clunk(v9ses, wfidno, &fcall)) | 384 | err = v9fs_t_clunk(v9ses, wfidno); |
462 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | 385 | if (err < 0) |
463 | else | 386 | dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); |
464 | dprintk(DEBUG_ERROR, "clunk failed: %s\n", | ||
465 | FCALL_ERROR(fcall)); | ||
466 | |||
467 | kfree(fcall); | ||
468 | } | 387 | } |
469 | return result; | 388 | return result; |
470 | } | 389 | } |
@@ -509,10 +428,9 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | |||
509 | } | 428 | } |
510 | 429 | ||
511 | result = v9fs_t_remove(v9ses, fid, &fcall); | 430 | result = v9fs_t_remove(v9ses, fid, &fcall); |
512 | if (result < 0) | 431 | if (result < 0) { |
513 | dprintk(DEBUG_ERROR, "remove of file fails: %s(%d)\n", | 432 | PRINT_FCALL_ERROR("remove fails", fcall); |
514 | FCALL_ERROR(fcall), result); | 433 | } else { |
515 | else { | ||
516 | v9fs_put_idpool(fid, &v9ses->fidpool); | 434 | v9fs_put_idpool(fid, &v9ses->fidpool); |
517 | v9fs_fid_destroy(v9fid); | 435 | v9fs_fid_destroy(v9fid); |
518 | } | 436 | } |
@@ -567,7 +485,6 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
567 | struct v9fs_fid *fid; | 485 | struct v9fs_fid *fid; |
568 | struct inode *inode; | 486 | struct inode *inode; |
569 | struct v9fs_fcall *fcall = NULL; | 487 | struct v9fs_fcall *fcall = NULL; |
570 | struct stat newstat; | ||
571 | int dirfidnum = -1; | 488 | int dirfidnum = -1; |
572 | int newfid = -1; | 489 | int newfid = -1; |
573 | int result = 0; | 490 | int result = 0; |
@@ -620,8 +537,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
620 | goto FreeFcall; | 537 | goto FreeFcall; |
621 | } | 538 | } |
622 | 539 | ||
623 | v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb); | 540 | inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses, |
624 | inode = v9fs_get_inode(sb, newstat.st_mode); | 541 | fcall->params.rstat.stat.mode)); |
625 | 542 | ||
626 | if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { | 543 | if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { |
627 | eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", | 544 | eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", |
@@ -631,7 +548,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
631 | goto FreeFcall; | 548 | goto FreeFcall; |
632 | } | 549 | } |
633 | 550 | ||
634 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); | 551 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); |
635 | 552 | ||
636 | fid = v9fs_fid_create(dentry, v9ses, newfid, 0); | 553 | fid = v9fs_fid_create(dentry, v9ses, newfid, 0); |
637 | if (fid == NULL) { | 554 | if (fid == NULL) { |
@@ -640,10 +557,10 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
640 | goto FreeFcall; | 557 | goto FreeFcall; |
641 | } | 558 | } |
642 | 559 | ||
643 | fid->qid = fcall->params.rstat.stat->qid; | 560 | fid->qid = fcall->params.rstat.stat.qid; |
644 | 561 | ||
645 | dentry->d_op = &v9fs_dentry_operations; | 562 | dentry->d_op = &v9fs_dentry_operations; |
646 | v9fs_mistat2inode(fcall->params.rstat.stat, inode, inode->i_sb); | 563 | v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); |
647 | 564 | ||
648 | d_add(dentry, inode); | 565 | d_add(dentry, inode); |
649 | kfree(fcall); | 566 | kfree(fcall); |
@@ -699,7 +616,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
699 | v9fs_fid_lookup(old_dentry->d_parent); | 616 | v9fs_fid_lookup(old_dentry->d_parent); |
700 | struct v9fs_fid *newdirfid = | 617 | struct v9fs_fid *newdirfid = |
701 | v9fs_fid_lookup(new_dentry->d_parent); | 618 | v9fs_fid_lookup(new_dentry->d_parent); |
702 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | 619 | struct v9fs_wstat wstat; |
703 | struct v9fs_fcall *fcall = NULL; | 620 | struct v9fs_fcall *fcall = NULL; |
704 | int fid = -1; | 621 | int fid = -1; |
705 | int olddirfidnum = -1; | 622 | int olddirfidnum = -1; |
@@ -708,9 +625,6 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
708 | 625 | ||
709 | dprintk(DEBUG_VFS, "\n"); | 626 | dprintk(DEBUG_VFS, "\n"); |
710 | 627 | ||
711 | if (!mistat) | ||
712 | return -ENOMEM; | ||
713 | |||
714 | if ((!oldfid) || (!olddirfid) || (!newdirfid)) { | 628 | if ((!oldfid) || (!olddirfid) || (!newdirfid)) { |
715 | dprintk(DEBUG_ERROR, "problem with arguments\n"); | 629 | dprintk(DEBUG_ERROR, "problem with arguments\n"); |
716 | return -EBADF; | 630 | return -EBADF; |
@@ -734,26 +648,15 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
734 | goto FreeFcallnBail; | 648 | goto FreeFcallnBail; |
735 | } | 649 | } |
736 | 650 | ||
737 | v9fs_blank_mistat(v9ses, mistat); | 651 | v9fs_blank_wstat(&wstat); |
652 | wstat.muid = v9ses->name; | ||
653 | wstat.name = (char *) new_dentry->d_name.name; | ||
738 | 654 | ||
739 | strcpy(mistat->data + 1, v9ses->name); | 655 | retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); |
740 | mistat->name = mistat->data + 1 + strlen(v9ses->name); | ||
741 | |||
742 | if (new_dentry->d_name.len > | ||
743 | (v9ses->maxdata - strlen(v9ses->name) - sizeof(struct v9fs_stat))) { | ||
744 | dprintk(DEBUG_ERROR, "new name too long\n"); | ||
745 | goto FreeFcallnBail; | ||
746 | } | ||
747 | |||
748 | strcpy(mistat->name, new_dentry->d_name.name); | ||
749 | retval = v9fs_t_wstat(v9ses, fid, mistat, &fcall); | ||
750 | 656 | ||
751 | FreeFcallnBail: | 657 | FreeFcallnBail: |
752 | kfree(mistat); | ||
753 | |||
754 | if (retval < 0) | 658 | if (retval < 0) |
755 | dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", | 659 | PRINT_FCALL_ERROR("wstat error", fcall); |
756 | FCALL_ERROR(fcall)); | ||
757 | 660 | ||
758 | kfree(fcall); | 661 | kfree(fcall); |
759 | return retval; | 662 | return retval; |
@@ -788,7 +691,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
788 | if (err < 0) | 691 | if (err < 0) |
789 | dprintk(DEBUG_ERROR, "stat error\n"); | 692 | dprintk(DEBUG_ERROR, "stat error\n"); |
790 | else { | 693 | else { |
791 | v9fs_mistat2inode(fcall->params.rstat.stat, dentry->d_inode, | 694 | v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode, |
792 | dentry->d_inode->i_sb); | 695 | dentry->d_inode->i_sb); |
793 | generic_fillattr(dentry->d_inode, stat); | 696 | generic_fillattr(dentry->d_inode, stat); |
794 | } | 697 | } |
@@ -809,57 +712,44 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
809 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 712 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
810 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); | 713 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
811 | struct v9fs_fcall *fcall = NULL; | 714 | struct v9fs_fcall *fcall = NULL; |
812 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | 715 | struct v9fs_wstat wstat; |
813 | int res = -EPERM; | 716 | int res = -EPERM; |
814 | 717 | ||
815 | dprintk(DEBUG_VFS, "\n"); | 718 | dprintk(DEBUG_VFS, "\n"); |
816 | 719 | ||
817 | if (!mistat) | ||
818 | return -ENOMEM; | ||
819 | |||
820 | if (!fid) { | 720 | if (!fid) { |
821 | dprintk(DEBUG_ERROR, | 721 | dprintk(DEBUG_ERROR, |
822 | "Couldn't find fid associated with dentry\n"); | 722 | "Couldn't find fid associated with dentry\n"); |
823 | return -EBADF; | 723 | return -EBADF; |
824 | } | 724 | } |
825 | 725 | ||
826 | v9fs_blank_mistat(v9ses, mistat); | 726 | v9fs_blank_wstat(&wstat); |
827 | if (iattr->ia_valid & ATTR_MODE) | 727 | if (iattr->ia_valid & ATTR_MODE) |
828 | mistat->mode = unixmode2p9mode(v9ses, iattr->ia_mode); | 728 | wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); |
829 | 729 | ||
830 | if (iattr->ia_valid & ATTR_MTIME) | 730 | if (iattr->ia_valid & ATTR_MTIME) |
831 | mistat->mtime = iattr->ia_mtime.tv_sec; | 731 | wstat.mtime = iattr->ia_mtime.tv_sec; |
832 | 732 | ||
833 | if (iattr->ia_valid & ATTR_ATIME) | 733 | if (iattr->ia_valid & ATTR_ATIME) |
834 | mistat->atime = iattr->ia_atime.tv_sec; | 734 | wstat.atime = iattr->ia_atime.tv_sec; |
835 | 735 | ||
836 | if (iattr->ia_valid & ATTR_SIZE) | 736 | if (iattr->ia_valid & ATTR_SIZE) |
837 | mistat->length = iattr->ia_size; | 737 | wstat.length = iattr->ia_size; |
838 | 738 | ||
839 | if (v9ses->extended) { | 739 | if (v9ses->extended) { |
840 | char *ptr = mistat->data+1; | 740 | if (iattr->ia_valid & ATTR_UID) |
841 | 741 | wstat.n_uid = iattr->ia_uid; | |
842 | if (iattr->ia_valid & ATTR_UID) { | ||
843 | mistat->uid = ptr; | ||
844 | ptr += 1+sprintf(ptr, "%08x", iattr->ia_uid); | ||
845 | mistat->n_uid = iattr->ia_uid; | ||
846 | } | ||
847 | 742 | ||
848 | if (iattr->ia_valid & ATTR_GID) { | 743 | if (iattr->ia_valid & ATTR_GID) |
849 | mistat->gid = ptr; | 744 | wstat.n_gid = iattr->ia_gid; |
850 | ptr += 1+sprintf(ptr, "%08x", iattr->ia_gid); | ||
851 | mistat->n_gid = iattr->ia_gid; | ||
852 | } | ||
853 | } | 745 | } |
854 | 746 | ||
855 | res = v9fs_t_wstat(v9ses, fid->fid, mistat, &fcall); | 747 | res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); |
856 | 748 | ||
857 | if (res < 0) | 749 | if (res < 0) |
858 | dprintk(DEBUG_ERROR, "wstat error: %s\n", FCALL_ERROR(fcall)); | 750 | PRINT_FCALL_ERROR("wstat error", fcall); |
859 | 751 | ||
860 | kfree(mistat); | ||
861 | kfree(fcall); | 752 | kfree(fcall); |
862 | |||
863 | if (res >= 0) | 753 | if (res >= 0) |
864 | res = inode_setattr(dentry->d_inode, iattr); | 754 | res = inode_setattr(dentry->d_inode, iattr); |
865 | 755 | ||
@@ -867,51 +757,47 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
867 | } | 757 | } |
868 | 758 | ||
869 | /** | 759 | /** |
870 | * v9fs_mistat2inode - populate an inode structure with mistat info | 760 | * v9fs_stat2inode - populate an inode structure with mistat info |
871 | * @mistat: Plan 9 metadata (mistat) structure | 761 | * @stat: Plan 9 metadata (mistat) structure |
872 | * @inode: inode to populate | 762 | * @inode: inode to populate |
873 | * @sb: superblock of filesystem | 763 | * @sb: superblock of filesystem |
874 | * | 764 | * |
875 | */ | 765 | */ |
876 | 766 | ||
877 | void | 767 | void |
878 | v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode, | 768 | v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, |
879 | struct super_block *sb) | 769 | struct super_block *sb) |
880 | { | 770 | { |
771 | int n; | ||
772 | char ext[32]; | ||
881 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 773 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
882 | 774 | ||
883 | inode->i_nlink = 1; | 775 | inode->i_nlink = 1; |
884 | 776 | ||
885 | inode->i_atime.tv_sec = mistat->atime; | 777 | inode->i_atime.tv_sec = stat->atime; |
886 | inode->i_mtime.tv_sec = mistat->mtime; | 778 | inode->i_mtime.tv_sec = stat->mtime; |
887 | inode->i_ctime.tv_sec = mistat->mtime; | 779 | inode->i_ctime.tv_sec = stat->mtime; |
888 | 780 | ||
889 | inode->i_uid = -1; | 781 | inode->i_uid = v9ses->uid; |
890 | inode->i_gid = -1; | 782 | inode->i_gid = v9ses->gid; |
891 | 783 | ||
892 | if (v9ses->extended) { | 784 | if (v9ses->extended) { |
893 | /* TODO: string to uid mapping via user-space daemon */ | 785 | inode->i_uid = stat->n_uid; |
894 | inode->i_uid = mistat->n_uid; | 786 | inode->i_gid = stat->n_gid; |
895 | inode->i_gid = mistat->n_gid; | ||
896 | |||
897 | if (mistat->n_uid == -1) | ||
898 | sscanf(mistat->uid, "%x", &inode->i_uid); | ||
899 | |||
900 | if (mistat->n_gid == -1) | ||
901 | sscanf(mistat->gid, "%x", &inode->i_gid); | ||
902 | } | 787 | } |
903 | 788 | ||
904 | if (inode->i_uid == -1) | 789 | inode->i_mode = p9mode2unixmode(v9ses, stat->mode); |
905 | inode->i_uid = v9ses->uid; | ||
906 | if (inode->i_gid == -1) | ||
907 | inode->i_gid = v9ses->gid; | ||
908 | |||
909 | inode->i_mode = p9mode2unixmode(v9ses, mistat->mode); | ||
910 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { | 790 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { |
911 | char type = 0; | 791 | char type = 0; |
912 | int major = -1; | 792 | int major = -1; |
913 | int minor = -1; | 793 | int minor = -1; |
914 | sscanf(mistat->extension, "%c %u %u", &type, &major, &minor); | 794 | |
795 | n = stat->extension.len; | ||
796 | if (n > sizeof(ext)-1) | ||
797 | n = sizeof(ext)-1; | ||
798 | memmove(ext, stat->extension.str, n); | ||
799 | ext[n] = 0; | ||
800 | sscanf(ext, "%c %u %u", &type, &major, &minor); | ||
915 | switch (type) { | 801 | switch (type) { |
916 | case 'c': | 802 | case 'c': |
917 | inode->i_mode &= ~S_IFBLK; | 803 | inode->i_mode &= ~S_IFBLK; |
@@ -920,14 +806,14 @@ v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode, | |||
920 | case 'b': | 806 | case 'b': |
921 | break; | 807 | break; |
922 | default: | 808 | default: |
923 | dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n", | 809 | dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n", |
924 | type, mistat->extension); | 810 | type, stat->extension.len, stat->extension.str); |
925 | }; | 811 | }; |
926 | inode->i_rdev = MKDEV(major, minor); | 812 | inode->i_rdev = MKDEV(major, minor); |
927 | } else | 813 | } else |
928 | inode->i_rdev = 0; | 814 | inode->i_rdev = 0; |
929 | 815 | ||
930 | inode->i_size = mistat->length; | 816 | inode->i_size = stat->length; |
931 | 817 | ||
932 | inode->i_blksize = sb->s_blocksize; | 818 | inode->i_blksize = sb->s_blocksize; |
933 | inode->i_blocks = | 819 | inode->i_blocks = |
@@ -955,71 +841,6 @@ ino_t v9fs_qid2ino(struct v9fs_qid *qid) | |||
955 | } | 841 | } |
956 | 842 | ||
957 | /** | 843 | /** |
958 | * v9fs_vfs_symlink - helper function to create symlinks | ||
959 | * @dir: directory inode containing symlink | ||
960 | * @dentry: dentry for symlink | ||
961 | * @symname: symlink data | ||
962 | * | ||
963 | * See 9P2000.u RFC for more information | ||
964 | * | ||
965 | */ | ||
966 | |||
967 | static int | ||
968 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | ||
969 | { | ||
970 | int retval = -EPERM; | ||
971 | struct v9fs_fid *newfid; | ||
972 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | ||
973 | struct v9fs_fcall *fcall = NULL; | ||
974 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | ||
975 | |||
976 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | ||
977 | symname); | ||
978 | |||
979 | if (!mistat) | ||
980 | return -ENOMEM; | ||
981 | |||
982 | if (!v9ses->extended) { | ||
983 | dprintk(DEBUG_ERROR, "not extended\n"); | ||
984 | goto FreeFcall; | ||
985 | } | ||
986 | |||
987 | /* issue a create */ | ||
988 | retval = v9fs_create(dir, dentry, S_IFLNK, 0); | ||
989 | if (retval != 0) | ||
990 | goto FreeFcall; | ||
991 | |||
992 | newfid = v9fs_fid_lookup(dentry); | ||
993 | |||
994 | /* issue a twstat */ | ||
995 | v9fs_blank_mistat(v9ses, mistat); | ||
996 | strcpy(mistat->data + 1, symname); | ||
997 | mistat->extension = mistat->data + 1; | ||
998 | retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); | ||
999 | if (retval < 0) { | ||
1000 | dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", | ||
1001 | FCALL_ERROR(fcall)); | ||
1002 | goto FreeFcall; | ||
1003 | } | ||
1004 | |||
1005 | kfree(fcall); | ||
1006 | |||
1007 | if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { | ||
1008 | dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", | ||
1009 | FCALL_ERROR(fcall)); | ||
1010 | goto FreeFcall; | ||
1011 | } | ||
1012 | |||
1013 | d_drop(dentry); /* FID - will this also clunk? */ | ||
1014 | |||
1015 | FreeFcall: | ||
1016 | kfree(mistat); | ||
1017 | kfree(fcall); | ||
1018 | |||
1019 | return retval; | ||
1020 | } | ||
1021 | |||
1022 | /** | ||
1023 | * v9fs_readlink - read a symlink's location (internal version) | 844 | * v9fs_readlink - read a symlink's location (internal version) |
1024 | * @dentry: dentry for symlink | 845 | * @dentry: dentry for symlink |
1025 | * @buffer: buffer to load symlink location into | 846 | * @buffer: buffer to load symlink location into |
@@ -1058,16 +879,17 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
1058 | if (!fcall) | 879 | if (!fcall) |
1059 | return -EIO; | 880 | return -EIO; |
1060 | 881 | ||
1061 | if (!(fcall->params.rstat.stat->mode & V9FS_DMSYMLINK)) { | 882 | if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { |
1062 | retval = -EINVAL; | 883 | retval = -EINVAL; |
1063 | goto FreeFcall; | 884 | goto FreeFcall; |
1064 | } | 885 | } |
1065 | 886 | ||
1066 | /* copy extension buffer into buffer */ | 887 | /* copy extension buffer into buffer */ |
1067 | if (strlen(fcall->params.rstat.stat->extension) < buflen) | 888 | if (fcall->params.rstat.stat.extension.len < buflen) |
1068 | buflen = strlen(fcall->params.rstat.stat->extension); | 889 | buflen = fcall->params.rstat.stat.extension.len; |
1069 | 890 | ||
1070 | memcpy(buffer, fcall->params.rstat.stat->extension, buflen + 1); | 891 | memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); |
892 | buffer[buflen-1] = 0; | ||
1071 | 893 | ||
1072 | retval = buflen; | 894 | retval = buflen; |
1073 | 895 | ||
@@ -1157,6 +979,77 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void | |||
1157 | __putname(s); | 979 | __putname(s); |
1158 | } | 980 | } |
1159 | 981 | ||
982 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | ||
983 | int mode, const char *extension) | ||
984 | { | ||
985 | int err, retval; | ||
986 | struct v9fs_session_info *v9ses; | ||
987 | struct v9fs_fcall *fcall; | ||
988 | struct v9fs_fid *fid; | ||
989 | struct v9fs_wstat wstat; | ||
990 | |||
991 | v9ses = v9fs_inode2v9ses(dir); | ||
992 | retval = -EPERM; | ||
993 | fcall = NULL; | ||
994 | |||
995 | if (!v9ses->extended) { | ||
996 | dprintk(DEBUG_ERROR, "not extended\n"); | ||
997 | goto free_mem; | ||
998 | } | ||
999 | |||
1000 | /* issue a create */ | ||
1001 | retval = v9fs_create(dir, dentry, mode, 0); | ||
1002 | if (retval != 0) | ||
1003 | goto free_mem; | ||
1004 | |||
1005 | fid = v9fs_fid_get_created(dentry); | ||
1006 | if (!fid) { | ||
1007 | dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); | ||
1008 | goto free_mem; | ||
1009 | } | ||
1010 | |||
1011 | /* issue a Twstat */ | ||
1012 | v9fs_blank_wstat(&wstat); | ||
1013 | wstat.muid = v9ses->name; | ||
1014 | wstat.extension = (char *) extension; | ||
1015 | retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); | ||
1016 | if (retval < 0) { | ||
1017 | PRINT_FCALL_ERROR("wstat error", fcall); | ||
1018 | goto free_mem; | ||
1019 | } | ||
1020 | |||
1021 | err = v9fs_t_clunk(v9ses, fid->fid); | ||
1022 | if (err < 0) { | ||
1023 | dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); | ||
1024 | goto free_mem; | ||
1025 | } | ||
1026 | |||
1027 | d_drop(dentry); /* FID - will this also clunk? */ | ||
1028 | |||
1029 | free_mem: | ||
1030 | kfree(fcall); | ||
1031 | return retval; | ||
1032 | } | ||
1033 | |||
1034 | /** | ||
1035 | * v9fs_vfs_symlink - helper function to create symlinks | ||
1036 | * @dir: directory inode containing symlink | ||
1037 | * @dentry: dentry for symlink | ||
1038 | * @symname: symlink data | ||
1039 | * | ||
1040 | * See 9P2000.u RFC for more information | ||
1041 | * | ||
1042 | */ | ||
1043 | |||
1044 | static int | ||
1045 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | ||
1046 | { | ||
1047 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | ||
1048 | symname); | ||
1049 | |||
1050 | return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); | ||
1051 | } | ||
1052 | |||
1160 | /** | 1053 | /** |
1161 | * v9fs_vfs_link - create a hardlink | 1054 | * v9fs_vfs_link - create a hardlink |
1162 | * @old_dentry: dentry for file to link to | 1055 | * @old_dentry: dentry for file to link to |
@@ -1173,64 +1066,24 @@ static int | |||
1173 | v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | 1066 | v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, |
1174 | struct dentry *dentry) | 1067 | struct dentry *dentry) |
1175 | { | 1068 | { |
1176 | int retval = -EPERM; | 1069 | int retval; |
1177 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | 1070 | struct v9fs_fid *oldfid; |
1178 | struct v9fs_fcall *fcall = NULL; | 1071 | char *name; |
1179 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | ||
1180 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); | ||
1181 | struct v9fs_fid *newfid = NULL; | ||
1182 | char *symname = __getname(); | ||
1183 | 1072 | ||
1184 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 1073 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, |
1185 | old_dentry->d_name.name); | 1074 | old_dentry->d_name.name); |
1186 | 1075 | ||
1187 | if (!v9ses->extended) { | 1076 | oldfid = v9fs_fid_lookup(old_dentry); |
1188 | dprintk(DEBUG_ERROR, "not extended\n"); | 1077 | if (!oldfid) { |
1189 | goto FreeMem; | 1078 | dprintk(DEBUG_ERROR, "can't find oldfid\n"); |
1190 | } | 1079 | return -EPERM; |
1191 | |||
1192 | /* get fid of old_dentry */ | ||
1193 | sprintf(symname, "hardlink(%d)\n", oldfid->fid); | ||
1194 | |||
1195 | /* issue a create */ | ||
1196 | retval = v9fs_create(dir, dentry, V9FS_DMLINK, 0); | ||
1197 | if (retval != 0) | ||
1198 | goto FreeMem; | ||
1199 | |||
1200 | newfid = v9fs_fid_lookup(dentry); | ||
1201 | if (!newfid) { | ||
1202 | dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); | ||
1203 | goto FreeMem; | ||
1204 | } | ||
1205 | |||
1206 | /* issue a twstat */ | ||
1207 | v9fs_blank_mistat(v9ses, mistat); | ||
1208 | strcpy(mistat->data + 1, symname); | ||
1209 | mistat->extension = mistat->data + 1; | ||
1210 | retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); | ||
1211 | if (retval < 0) { | ||
1212 | dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", | ||
1213 | FCALL_ERROR(fcall)); | ||
1214 | goto FreeMem; | ||
1215 | } | ||
1216 | |||
1217 | kfree(fcall); | ||
1218 | |||
1219 | if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { | ||
1220 | dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", | ||
1221 | FCALL_ERROR(fcall)); | ||
1222 | goto FreeMem; | ||
1223 | } | 1080 | } |
1224 | 1081 | ||
1225 | d_drop(dentry); /* FID - will this also clunk? */ | 1082 | name = __getname(); |
1226 | 1083 | sprintf(name, "hardlink(%d)\n", oldfid->fid); | |
1227 | kfree(fcall); | 1084 | retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); |
1228 | fcall = NULL; | 1085 | __putname(name); |
1229 | 1086 | ||
1230 | FreeMem: | ||
1231 | kfree(mistat); | ||
1232 | kfree(fcall); | ||
1233 | __putname(symname); | ||
1234 | return retval; | 1087 | return retval; |
1235 | } | 1088 | } |
1236 | 1089 | ||
@@ -1246,82 +1099,30 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
1246 | static int | 1099 | static int |
1247 | v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | 1100 | v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) |
1248 | { | 1101 | { |
1249 | int retval = -EPERM; | 1102 | int retval; |
1250 | struct v9fs_fid *newfid; | 1103 | char *name; |
1251 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | ||
1252 | struct v9fs_fcall *fcall = NULL; | ||
1253 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | ||
1254 | char *symname = __getname(); | ||
1255 | 1104 | ||
1256 | dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, | 1105 | dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, |
1257 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); | 1106 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); |
1258 | 1107 | ||
1259 | if (!mistat) | 1108 | if (!new_valid_dev(rdev)) |
1260 | return -ENOMEM; | 1109 | return -EINVAL; |
1261 | |||
1262 | if (!new_valid_dev(rdev)) { | ||
1263 | retval = -EINVAL; | ||
1264 | goto FreeMem; | ||
1265 | } | ||
1266 | |||
1267 | if (!v9ses->extended) { | ||
1268 | dprintk(DEBUG_ERROR, "not extended\n"); | ||
1269 | goto FreeMem; | ||
1270 | } | ||
1271 | |||
1272 | /* issue a create */ | ||
1273 | retval = v9fs_create(dir, dentry, mode, 0); | ||
1274 | |||
1275 | if (retval != 0) | ||
1276 | goto FreeMem; | ||
1277 | |||
1278 | newfid = v9fs_fid_lookup(dentry); | ||
1279 | if (!newfid) { | ||
1280 | dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n"); | ||
1281 | retval = -EINVAL; | ||
1282 | goto FreeMem; | ||
1283 | } | ||
1284 | 1110 | ||
1111 | name = __getname(); | ||
1285 | /* build extension */ | 1112 | /* build extension */ |
1286 | if (S_ISBLK(mode)) | 1113 | if (S_ISBLK(mode)) |
1287 | sprintf(symname, "b %u %u", MAJOR(rdev), MINOR(rdev)); | 1114 | sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); |
1288 | else if (S_ISCHR(mode)) | 1115 | else if (S_ISCHR(mode)) |
1289 | sprintf(symname, "c %u %u", MAJOR(rdev), MINOR(rdev)); | 1116 | sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); |
1290 | else if (S_ISFIFO(mode)) | 1117 | else if (S_ISFIFO(mode)) |
1291 | ; /* DO NOTHING */ | 1118 | *name = 0; |
1292 | else { | 1119 | else { |
1293 | retval = -EINVAL; | 1120 | __putname(name); |
1294 | goto FreeMem; | 1121 | return -EINVAL; |
1295 | } | ||
1296 | |||
1297 | if (!S_ISFIFO(mode)) { | ||
1298 | /* issue a twstat */ | ||
1299 | v9fs_blank_mistat(v9ses, mistat); | ||
1300 | strcpy(mistat->data + 1, symname); | ||
1301 | mistat->extension = mistat->data + 1; | ||
1302 | retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); | ||
1303 | if (retval < 0) { | ||
1304 | dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", | ||
1305 | FCALL_ERROR(fcall)); | ||
1306 | goto FreeMem; | ||
1307 | } | ||
1308 | } | 1122 | } |
1309 | 1123 | ||
1310 | /* need to update dcache so we show up */ | 1124 | retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); |
1311 | kfree(fcall); | 1125 | __putname(name); |
1312 | |||
1313 | if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { | ||
1314 | dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", | ||
1315 | FCALL_ERROR(fcall)); | ||
1316 | goto FreeMem; | ||
1317 | } | ||
1318 | |||
1319 | d_drop(dentry); /* FID - will this also clunk? */ | ||
1320 | |||
1321 | FreeMem: | ||
1322 | kfree(mistat); | ||
1323 | kfree(fcall); | ||
1324 | __putname(symname); | ||
1325 | 1126 | ||
1326 | return retval; | 1127 | return retval; |
1327 | } | 1128 | } |