diff options
Diffstat (limited to 'fs/9p/vfs_inode.c')
| -rw-r--r-- | fs/9p/vfs_inode.c | 101 |
1 files changed, 97 insertions, 4 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index e6ece237241f..a7319364544b 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
| @@ -1245,7 +1245,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
| 1245 | if (IS_ERR(fid)) | 1245 | if (IS_ERR(fid)) |
| 1246 | return PTR_ERR(fid); | 1246 | return PTR_ERR(fid); |
| 1247 | 1247 | ||
| 1248 | if (!v9fs_proto_dotu(v9ses)) | 1248 | if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) |
| 1249 | return -EBADF; | 1249 | return -EBADF; |
| 1250 | 1250 | ||
| 1251 | st = p9_client_stat(fid); | 1251 | st = p9_client_stat(fid); |
| @@ -1351,6 +1351,99 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | |||
| 1351 | } | 1351 | } |
| 1352 | 1352 | ||
| 1353 | /** | 1353 | /** |
| 1354 | * v9fs_vfs_symlink_dotl - helper function to create symlinks | ||
| 1355 | * @dir: directory inode containing symlink | ||
| 1356 | * @dentry: dentry for symlink | ||
| 1357 | * @symname: symlink data | ||
| 1358 | * | ||
| 1359 | * See Also: 9P2000.L RFC for more information | ||
| 1360 | * | ||
| 1361 | */ | ||
| 1362 | |||
| 1363 | static int | ||
| 1364 | v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | ||
| 1365 | const char *symname) | ||
| 1366 | { | ||
| 1367 | struct v9fs_session_info *v9ses; | ||
| 1368 | struct p9_fid *dfid; | ||
| 1369 | struct p9_fid *fid = NULL; | ||
| 1370 | struct inode *inode; | ||
| 1371 | struct p9_qid qid; | ||
| 1372 | char *name; | ||
| 1373 | int err; | ||
| 1374 | gid_t gid; | ||
| 1375 | |||
| 1376 | name = (char *) dentry->d_name.name; | ||
| 1377 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n", | ||
| 1378 | dir->i_ino, name, symname); | ||
| 1379 | v9ses = v9fs_inode2v9ses(dir); | ||
| 1380 | |||
| 1381 | dfid = v9fs_fid_lookup(dentry->d_parent); | ||
| 1382 | if (IS_ERR(dfid)) { | ||
| 1383 | err = PTR_ERR(dfid); | ||
| 1384 | P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | ||
| 1385 | return err; | ||
| 1386 | } | ||
| 1387 | |||
| 1388 | gid = v9fs_get_fsgid_for_create(dir); | ||
| 1389 | |||
| 1390 | if (gid < 0) { | ||
| 1391 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid); | ||
| 1392 | goto error; | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ | ||
| 1396 | err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid); | ||
| 1397 | |||
| 1398 | if (err < 0) { | ||
| 1399 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err); | ||
| 1400 | goto error; | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | if (v9ses->cache) { | ||
| 1404 | /* Now walk from the parent so we can get an unopened fid. */ | ||
| 1405 | fid = p9_client_walk(dfid, 1, &name, 1); | ||
| 1406 | if (IS_ERR(fid)) { | ||
| 1407 | err = PTR_ERR(fid); | ||
| 1408 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", | ||
| 1409 | err); | ||
| 1410 | fid = NULL; | ||
| 1411 | goto error; | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | /* instantiate inode and assign the unopened fid to dentry */ | ||
| 1415 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | ||
| 1416 | if (IS_ERR(inode)) { | ||
| 1417 | err = PTR_ERR(inode); | ||
| 1418 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", | ||
| 1419 | err); | ||
| 1420 | goto error; | ||
| 1421 | } | ||
| 1422 | dentry->d_op = &v9fs_cached_dentry_operations; | ||
| 1423 | d_instantiate(dentry, inode); | ||
| 1424 | err = v9fs_fid_add(dentry, fid); | ||
| 1425 | if (err < 0) | ||
| 1426 | goto error; | ||
| 1427 | fid = NULL; | ||
| 1428 | } else { | ||
| 1429 | /* Not in cached mode. No need to populate inode with stat */ | ||
| 1430 | inode = v9fs_get_inode(dir->i_sb, S_IFLNK); | ||
| 1431 | if (IS_ERR(inode)) { | ||
| 1432 | err = PTR_ERR(inode); | ||
| 1433 | goto error; | ||
| 1434 | } | ||
| 1435 | dentry->d_op = &v9fs_dentry_operations; | ||
| 1436 | d_instantiate(dentry, inode); | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | error: | ||
| 1440 | if (fid) | ||
| 1441 | p9_client_clunk(fid); | ||
| 1442 | |||
| 1443 | return err; | ||
| 1444 | } | ||
| 1445 | |||
| 1446 | /** | ||
| 1354 | * v9fs_vfs_symlink - helper function to create symlinks | 1447 | * v9fs_vfs_symlink - helper function to create symlinks |
| 1355 | * @dir: directory inode containing symlink | 1448 | * @dir: directory inode containing symlink |
| 1356 | * @dentry: dentry for symlink | 1449 | * @dentry: dentry for symlink |
| @@ -1527,7 +1620,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = { | |||
| 1527 | .create = v9fs_vfs_create, | 1620 | .create = v9fs_vfs_create, |
| 1528 | .lookup = v9fs_vfs_lookup, | 1621 | .lookup = v9fs_vfs_lookup, |
| 1529 | .symlink = v9fs_vfs_symlink, | 1622 | .symlink = v9fs_vfs_symlink, |
| 1530 | .link = v9fs_vfs_link_dotl, | 1623 | .link = v9fs_vfs_link, |
| 1531 | .unlink = v9fs_vfs_unlink, | 1624 | .unlink = v9fs_vfs_unlink, |
| 1532 | .mkdir = v9fs_vfs_mkdir, | 1625 | .mkdir = v9fs_vfs_mkdir, |
| 1533 | .rmdir = v9fs_vfs_rmdir, | 1626 | .rmdir = v9fs_vfs_rmdir, |
| @@ -1540,8 +1633,8 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = { | |||
| 1540 | static const struct inode_operations v9fs_dir_inode_operations_dotl = { | 1633 | static const struct inode_operations v9fs_dir_inode_operations_dotl = { |
| 1541 | .create = v9fs_vfs_create, | 1634 | .create = v9fs_vfs_create, |
| 1542 | .lookup = v9fs_vfs_lookup, | 1635 | .lookup = v9fs_vfs_lookup, |
| 1543 | .symlink = v9fs_vfs_symlink, | 1636 | .link = v9fs_vfs_link_dotl, |
| 1544 | .link = v9fs_vfs_link, | 1637 | .symlink = v9fs_vfs_symlink_dotl, |
| 1545 | .unlink = v9fs_vfs_unlink, | 1638 | .unlink = v9fs_vfs_unlink, |
| 1546 | .mkdir = v9fs_vfs_mkdir, | 1639 | .mkdir = v9fs_vfs_mkdir, |
| 1547 | .rmdir = v9fs_vfs_rmdir, | 1640 | .rmdir = v9fs_vfs_rmdir, |
