diff options
author | Venkateswararao Jujjuri (JV) <jvrao@linux.vnet.ibm.com> | 2010-06-09 18:59:31 -0400 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@gmail.com> | 2010-08-02 15:28:29 -0400 |
commit | 50cc42ff3d7bc48a436c5a0413459ca7841b505f (patch) | |
tree | 7209ab2807e3a284c1fbd36dd885e34b81809b0d | |
parent | 652df9a7fd03cb47a3f663f0c08a2bd086505e9b (diff) |
9p: Define and implement TSYMLINK for 9P2000.L
Create a symbolic link
SYNOPSIS
size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4]
size[4] Rsymlink tag[2] qid[13]
DESCRIPTION
Create a symbolic link named 'name' pointing to 'symtgt'.
gid represents the effective group id of the caller.
The permissions of a symbolic link are irrelevant hence it is omitted
from the protocol.
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Reviewed-by: Sripathi Kodi <sripathik@in.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
-rw-r--r-- | fs/9p/vfs_inode.c | 101 | ||||
-rw-r--r-- | include/net/9p/9p.h | 4 | ||||
-rw-r--r-- | include/net/9p/client.h | 2 | ||||
-rw-r--r-- | net/9p/client.c | 34 |
4 files changed, 137 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, |
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 5985c0f83db3..44a6883d7144 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h | |||
@@ -88,6 +88,8 @@ do { \ | |||
88 | * enum p9_msg_t - 9P message types | 88 | * enum p9_msg_t - 9P message types |
89 | * @P9_TSTATFS: file system status request | 89 | * @P9_TSTATFS: file system status request |
90 | * @P9_RSTATFS: file system status response | 90 | * @P9_RSTATFS: file system status response |
91 | * @P9_TSYMLINK: make symlink request | ||
92 | * @P9_RSYMLINK: make symlink response | ||
91 | * @P9_TRENAME: rename request | 93 | * @P9_TRENAME: rename request |
92 | * @P9_RRENAME: rename response | 94 | * @P9_RRENAME: rename response |
93 | * @P9_TVERSION: version handshake request | 95 | * @P9_TVERSION: version handshake request |
@@ -131,6 +133,8 @@ do { \ | |||
131 | enum p9_msg_t { | 133 | enum p9_msg_t { |
132 | P9_TSTATFS = 8, | 134 | P9_TSTATFS = 8, |
133 | P9_RSTATFS, | 135 | P9_RSTATFS, |
136 | P9_TSYMLINK = 16, | ||
137 | P9_RSYMLINK, | ||
134 | P9_TRENAME = 20, | 138 | P9_TRENAME = 20, |
135 | P9_RRENAME, | 139 | P9_RRENAME, |
136 | P9_TGETATTR = 24, | 140 | P9_TGETATTR = 24, |
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index e36f11650e99..2e039730920e 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
@@ -227,6 +227,8 @@ int p9_client_open(struct p9_fid *fid, int mode); | |||
227 | int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, | 227 | int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, |
228 | char *extension); | 228 | char *extension); |
229 | int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname); | 229 | int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, char *newname); |
230 | int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid, | ||
231 | struct p9_qid *qid); | ||
230 | int p9_client_clunk(struct p9_fid *fid); | 232 | int p9_client_clunk(struct p9_fid *fid); |
231 | int p9_client_remove(struct p9_fid *fid); | 233 | int p9_client_remove(struct p9_fid *fid); |
232 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, | 234 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, |
diff --git a/net/9p/client.c b/net/9p/client.c index ad1c4489ab4d..e37e64cb9394 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -1095,6 +1095,40 @@ error: | |||
1095 | } | 1095 | } |
1096 | EXPORT_SYMBOL(p9_client_fcreate); | 1096 | EXPORT_SYMBOL(p9_client_fcreate); |
1097 | 1097 | ||
1098 | int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid, | ||
1099 | struct p9_qid *qid) | ||
1100 | { | ||
1101 | int err = 0; | ||
1102 | struct p9_client *clnt; | ||
1103 | struct p9_req_t *req; | ||
1104 | |||
1105 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s symtgt %s\n", | ||
1106 | dfid->fid, name, symtgt); | ||
1107 | clnt = dfid->clnt; | ||
1108 | |||
1109 | req = p9_client_rpc(clnt, P9_TSYMLINK, "dssd", dfid->fid, name, symtgt, | ||
1110 | gid); | ||
1111 | if (IS_ERR(req)) { | ||
1112 | err = PTR_ERR(req); | ||
1113 | goto error; | ||
1114 | } | ||
1115 | |||
1116 | err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid); | ||
1117 | if (err) { | ||
1118 | p9pdu_dump(1, req->rc); | ||
1119 | goto free_and_error; | ||
1120 | } | ||
1121 | |||
1122 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n", | ||
1123 | qid->type, (unsigned long long)qid->path, qid->version); | ||
1124 | |||
1125 | free_and_error: | ||
1126 | p9_free_req(clnt, req); | ||
1127 | error: | ||
1128 | return err; | ||
1129 | } | ||
1130 | EXPORT_SYMBOL(p9_client_symlink); | ||
1131 | |||
1098 | int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname) | 1132 | int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname) |
1099 | { | 1133 | { |
1100 | struct p9_client *clnt; | 1134 | struct p9_client *clnt; |