aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/9p/v9fs_vfs.h1
-rw-r--r--fs/9p/vfs_inode.c177
-rw-r--r--fs/9p/vfs_super.c43
-rw-r--r--include/net/9p/9p.h44
-rw-r--r--include/net/9p/client.h3
-rw-r--r--net/9p/client.c59
-rw-r--r--net/9p/protocol.c28
7 files changed, 321 insertions, 34 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 32ef4009d030..f47c6bbb01b3 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -55,6 +55,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode);
55void v9fs_clear_inode(struct inode *inode); 55void v9fs_clear_inode(struct inode *inode);
56ino_t v9fs_qid2ino(struct p9_qid *qid); 56ino_t v9fs_qid2ino(struct p9_qid *qid);
57void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); 57void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
58void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *);
58int v9fs_dir_release(struct inode *inode, struct file *filp); 59int v9fs_dir_release(struct inode *inode, struct file *filp);
59int v9fs_file_open(struct inode *inode, struct file *file); 60int v9fs_file_open(struct inode *inode, struct file *file);
60void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat); 61void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 4331b3b5ee1c..afcb8d889382 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -396,23 +396,14 @@ void v9fs_clear_inode(struct inode *inode)
396#endif 396#endif
397} 397}
398 398
399/**
400 * v9fs_inode_from_fid - populate an inode by issuing a attribute request
401 * @v9ses: session information
402 * @fid: fid to issue attribute request for
403 * @sb: superblock on which to create inode
404 *
405 */
406
407static struct inode * 399static struct inode *
408v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, 400v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid,
409 struct super_block *sb) 401 struct super_block *sb)
410{ 402{
411 int err, umode; 403 int err, umode;
412 struct inode *ret; 404 struct inode *ret = NULL;
413 struct p9_wstat *st; 405 struct p9_wstat *st;
414 406
415 ret = NULL;
416 st = p9_client_stat(fid); 407 st = p9_client_stat(fid);
417 if (IS_ERR(st)) 408 if (IS_ERR(st))
418 return ERR_CAST(st); 409 return ERR_CAST(st);
@@ -433,15 +424,62 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
433#endif 424#endif
434 p9stat_free(st); 425 p9stat_free(st);
435 kfree(st); 426 kfree(st);
436
437 return ret; 427 return ret;
438
439error: 428error:
440 p9stat_free(st); 429 p9stat_free(st);
441 kfree(st); 430 kfree(st);
442 return ERR_PTR(err); 431 return ERR_PTR(err);
443} 432}
444 433
434static struct inode *
435v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
436 struct super_block *sb)
437{
438 struct inode *ret = NULL;
439 int err;
440 struct p9_stat_dotl *st;
441
442 st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
443 if (IS_ERR(st))
444 return ERR_CAST(st);
445
446 ret = v9fs_get_inode(sb, st->st_mode);
447 if (IS_ERR(ret)) {
448 err = PTR_ERR(ret);
449 goto error;
450 }
451
452 v9fs_stat2inode_dotl(st, ret);
453 ret->i_ino = v9fs_qid2ino(&st->qid);
454#ifdef CONFIG_9P_FSCACHE
455 v9fs_vcookie_set_qid(ret, &st->qid);
456 v9fs_cache_inode_get_cookie(ret);
457#endif
458 kfree(st);
459 return ret;
460error:
461 kfree(st);
462 return ERR_PTR(err);
463}
464
465/**
466 * v9fs_inode_from_fid - Helper routine to populate an inode by
467 * issuing a attribute request
468 * @v9ses: session information
469 * @fid: fid to issue attribute request for
470 * @sb: superblock on which to create inode
471 *
472 */
473static inline struct inode *
474v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
475 struct super_block *sb)
476{
477 if (v9fs_proto_dotl(v9ses))
478 return v9fs_inode_dotl(v9ses, fid, sb);
479 else
480 return v9fs_inode(v9ses, fid, sb);
481}
482
445/** 483/**
446 * v9fs_remove - helper function to remove files and directories 484 * v9fs_remove - helper function to remove files and directories
447 * @dir: directory inode that is being deleted 485 * @dir: directory inode that is being deleted
@@ -853,6 +891,42 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
853 return 0; 891 return 0;
854} 892}
855 893
894static int
895v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
896 struct kstat *stat)
897{
898 int err;
899 struct v9fs_session_info *v9ses;
900 struct p9_fid *fid;
901 struct p9_stat_dotl *st;
902
903 P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
904 err = -EPERM;
905 v9ses = v9fs_inode2v9ses(dentry->d_inode);
906 if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
907 return simple_getattr(mnt, dentry, stat);
908
909 fid = v9fs_fid_lookup(dentry);
910 if (IS_ERR(fid))
911 return PTR_ERR(fid);
912
913 /* Ask for all the fields in stat structure. Server will return
914 * whatever it supports
915 */
916
917 st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
918 if (IS_ERR(st))
919 return PTR_ERR(st);
920
921 v9fs_stat2inode_dotl(st, dentry->d_inode);
922 generic_fillattr(dentry->d_inode, stat);
923 /* Change block size to what the server returned */
924 stat->blksize = st->st_blksize;
925
926 kfree(st);
927 return 0;
928}
929
856/** 930/**
857 * v9fs_vfs_setattr - set file metadata 931 * v9fs_vfs_setattr - set file metadata
858 * @dentry: file whose metadata to set 932 * @dentry: file whose metadata to set
@@ -980,6 +1054,77 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
980} 1054}
981 1055
982/** 1056/**
1057 * v9fs_stat2inode_dotl - populate an inode structure with stat info
1058 * @stat: stat structure
1059 * @inode: inode to populate
1060 * @sb: superblock of filesystem
1061 *
1062 */
1063
1064void
1065v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
1066{
1067
1068 if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
1069 inode->i_atime.tv_sec = stat->st_atime_sec;
1070 inode->i_atime.tv_nsec = stat->st_atime_nsec;
1071 inode->i_mtime.tv_sec = stat->st_mtime_sec;
1072 inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
1073 inode->i_ctime.tv_sec = stat->st_ctime_sec;
1074 inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
1075 inode->i_uid = stat->st_uid;
1076 inode->i_gid = stat->st_gid;
1077 inode->i_nlink = stat->st_nlink;
1078 inode->i_mode = stat->st_mode;
1079 inode->i_rdev = new_decode_dev(stat->st_rdev);
1080
1081 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode)))
1082 init_special_inode(inode, inode->i_mode, inode->i_rdev);
1083
1084 i_size_write(inode, stat->st_size);
1085 inode->i_blocks = stat->st_blocks;
1086 } else {
1087 if (stat->st_result_mask & P9_STATS_ATIME) {
1088 inode->i_atime.tv_sec = stat->st_atime_sec;
1089 inode->i_atime.tv_nsec = stat->st_atime_nsec;
1090 }
1091 if (stat->st_result_mask & P9_STATS_MTIME) {
1092 inode->i_mtime.tv_sec = stat->st_mtime_sec;
1093 inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
1094 }
1095 if (stat->st_result_mask & P9_STATS_CTIME) {
1096 inode->i_ctime.tv_sec = stat->st_ctime_sec;
1097 inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
1098 }
1099 if (stat->st_result_mask & P9_STATS_UID)
1100 inode->i_uid = stat->st_uid;
1101 if (stat->st_result_mask & P9_STATS_GID)
1102 inode->i_gid = stat->st_gid;
1103 if (stat->st_result_mask & P9_STATS_NLINK)
1104 inode->i_nlink = stat->st_nlink;
1105 if (stat->st_result_mask & P9_STATS_MODE) {
1106 inode->i_mode = stat->st_mode;
1107 if ((S_ISBLK(inode->i_mode)) ||
1108 (S_ISCHR(inode->i_mode)))
1109 init_special_inode(inode, inode->i_mode,
1110 inode->i_rdev);
1111 }
1112 if (stat->st_result_mask & P9_STATS_RDEV)
1113 inode->i_rdev = new_decode_dev(stat->st_rdev);
1114 if (stat->st_result_mask & P9_STATS_SIZE)
1115 i_size_write(inode, stat->st_size);
1116 if (stat->st_result_mask & P9_STATS_BLOCKS)
1117 inode->i_blocks = stat->st_blocks;
1118 }
1119 if (stat->st_result_mask & P9_STATS_GEN)
1120 inode->i_generation = stat->st_gen;
1121
1122 /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
1123 * because the inode structure does not have fields for them.
1124 */
1125}
1126
1127/**
983 * v9fs_qid2ino - convert qid into inode number 1128 * v9fs_qid2ino - convert qid into inode number
984 * @qid: qid to hash 1129 * @qid: qid to hash
985 * 1130 *
@@ -1254,7 +1399,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = {
1254 .rmdir = v9fs_vfs_rmdir, 1399 .rmdir = v9fs_vfs_rmdir,
1255 .mknod = v9fs_vfs_mknod, 1400 .mknod = v9fs_vfs_mknod,
1256 .rename = v9fs_vfs_rename, 1401 .rename = v9fs_vfs_rename,
1257 .getattr = v9fs_vfs_getattr, 1402 .getattr = v9fs_vfs_getattr_dotl,
1258 .setattr = v9fs_vfs_setattr, 1403 .setattr = v9fs_vfs_setattr,
1259}; 1404};
1260 1405
@@ -1276,7 +1421,7 @@ static const struct inode_operations v9fs_file_inode_operations = {
1276}; 1421};
1277 1422
1278static const struct inode_operations v9fs_file_inode_operations_dotl = { 1423static const struct inode_operations v9fs_file_inode_operations_dotl = {
1279 .getattr = v9fs_vfs_getattr, 1424 .getattr = v9fs_vfs_getattr_dotl,
1280 .setattr = v9fs_vfs_setattr, 1425 .setattr = v9fs_vfs_setattr,
1281}; 1426};
1282 1427
@@ -1292,6 +1437,6 @@ static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
1292 .readlink = generic_readlink, 1437 .readlink = generic_readlink,
1293 .follow_link = v9fs_vfs_follow_link, 1438 .follow_link = v9fs_vfs_follow_link,
1294 .put_link = v9fs_vfs_put_link, 1439 .put_link = v9fs_vfs_put_link,
1295 .getattr = v9fs_vfs_getattr, 1440 .getattr = v9fs_vfs_getattr_dotl,
1296 .setattr = v9fs_vfs_setattr, 1441 .setattr = v9fs_vfs_setattr,
1297}; 1442};
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index be74d020436e..3623f692b448 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -107,7 +107,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
107 struct inode *inode = NULL; 107 struct inode *inode = NULL;
108 struct dentry *root = NULL; 108 struct dentry *root = NULL;
109 struct v9fs_session_info *v9ses = NULL; 109 struct v9fs_session_info *v9ses = NULL;
110 struct p9_wstat *st = NULL;
111 int mode = S_IRWXUGO | S_ISVTX; 110 int mode = S_IRWXUGO | S_ISVTX;
112 struct p9_fid *fid; 111 struct p9_fid *fid;
113 int retval = 0; 112 int retval = 0;
@@ -124,16 +123,10 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
124 goto close_session; 123 goto close_session;
125 } 124 }
126 125
127 st = p9_client_stat(fid);
128 if (IS_ERR(st)) {
129 retval = PTR_ERR(st);
130 goto clunk_fid;
131 }
132
133 sb = sget(fs_type, NULL, v9fs_set_super, v9ses); 126 sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
134 if (IS_ERR(sb)) { 127 if (IS_ERR(sb)) {
135 retval = PTR_ERR(sb); 128 retval = PTR_ERR(sb);
136 goto free_stat; 129 goto clunk_fid;
137 } 130 }
138 v9fs_fill_super(sb, v9ses, flags, data); 131 v9fs_fill_super(sb, v9ses, flags, data);
139 132
@@ -151,22 +144,38 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
151 } 144 }
152 145
153 sb->s_root = root; 146 sb->s_root = root;
154 root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
155 147
156 v9fs_stat2inode(st, root->d_inode, sb); 148 if (v9fs_proto_dotl(v9ses)) {
149 struct p9_stat_dotl *st = NULL;
150 st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
151 if (IS_ERR(st)) {
152 retval = PTR_ERR(st);
153 goto clunk_fid;
154 }
155
156 v9fs_stat2inode_dotl(st, root->d_inode);
157 kfree(st);
158 } else {
159 struct p9_wstat *st = NULL;
160 st = p9_client_stat(fid);
161 if (IS_ERR(st)) {
162 retval = PTR_ERR(st);
163 goto clunk_fid;
164 }
165
166 root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
167 v9fs_stat2inode(st, root->d_inode, sb);
168
169 p9stat_free(st);
170 kfree(st);
171 }
157 172
158 v9fs_fid_add(root, fid); 173 v9fs_fid_add(root, fid);
159 p9stat_free(st);
160 kfree(st);
161 174
162P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); 175P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
163 simple_set_mnt(mnt, sb); 176 simple_set_mnt(mnt, sb);
164 return 0; 177 return 0;
165 178
166free_stat:
167 p9stat_free(st);
168 kfree(st);
169
170clunk_fid: 179clunk_fid:
171 p9_client_clunk(fid); 180 p9_client_clunk(fid);
172 181
@@ -176,8 +185,6 @@ close_session:
176 return retval; 185 return retval;
177 186
178release_sb: 187release_sb:
179 p9stat_free(st);
180 kfree(st);
181 deactivate_locked_super(sb); 188 deactivate_locked_super(sb);
182 return retval; 189 return retval;
183} 190}
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index f1b0b310265d..ab12e1c9cc7e 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -133,6 +133,8 @@ enum p9_msg_t {
133 P9_RSTATFS, 133 P9_RSTATFS,
134 P9_TRENAME = 20, 134 P9_TRENAME = 20,
135 P9_RRENAME, 135 P9_RRENAME,
136 P9_TGETATTR = 24,
137 P9_RGETATTR,
136 P9_TREADDIR = 40, 138 P9_TREADDIR = 40,
137 P9_RREADDIR, 139 P9_RREADDIR,
138 P9_TVERSION = 100, 140 P9_TVERSION = 100,
@@ -362,6 +364,48 @@ struct p9_wstat {
362 u32 n_muid; /* 9p2000.u extensions */ 364 u32 n_muid; /* 9p2000.u extensions */
363}; 365};
364 366
367struct p9_stat_dotl {
368 u64 st_result_mask;
369 struct p9_qid qid;
370 u32 st_mode;
371 u32 st_uid;
372 u32 st_gid;
373 u64 st_nlink;
374 u64 st_rdev;
375 u64 st_size;
376 u64 st_blksize;
377 u64 st_blocks;
378 u64 st_atime_sec;
379 u64 st_atime_nsec;
380 u64 st_mtime_sec;
381 u64 st_mtime_nsec;
382 u64 st_ctime_sec;
383 u64 st_ctime_nsec;
384 u64 st_btime_sec;
385 u64 st_btime_nsec;
386 u64 st_gen;
387 u64 st_data_version;
388};
389
390#define P9_STATS_MODE 0x00000001ULL
391#define P9_STATS_NLINK 0x00000002ULL
392#define P9_STATS_UID 0x00000004ULL
393#define P9_STATS_GID 0x00000008ULL
394#define P9_STATS_RDEV 0x00000010ULL
395#define P9_STATS_ATIME 0x00000020ULL
396#define P9_STATS_MTIME 0x00000040ULL
397#define P9_STATS_CTIME 0x00000080ULL
398#define P9_STATS_INO 0x00000100ULL
399#define P9_STATS_SIZE 0x00000200ULL
400#define P9_STATS_BLOCKS 0x00000400ULL
401
402#define P9_STATS_BTIME 0x00000800ULL
403#define P9_STATS_GEN 0x00001000ULL
404#define P9_STATS_DATA_VERSION 0x00002000ULL
405
406#define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
407#define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
408
365/* Structures for Protocol Operations */ 409/* Structures for Protocol Operations */
366struct p9_tstatfs { 410struct p9_tstatfs {
367 u32 fid; 411 u32 fid;
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 2ec93685e6db..6462eec435bc 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -238,6 +238,9 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
238struct p9_wstat *p9_client_stat(struct p9_fid *fid); 238struct p9_wstat *p9_client_stat(struct p9_fid *fid);
239int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); 239int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
240 240
241struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
242 u64 request_mask);
243
241struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); 244struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
242void p9_client_cb(struct p9_client *c, struct p9_req_t *req); 245void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
243 246
diff --git a/net/9p/client.c b/net/9p/client.c
index 4ff068e98f76..5e97118da3bf 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1303,6 +1303,65 @@ error:
1303} 1303}
1304EXPORT_SYMBOL(p9_client_stat); 1304EXPORT_SYMBOL(p9_client_stat);
1305 1305
1306struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
1307 u64 request_mask)
1308{
1309 int err;
1310 struct p9_client *clnt;
1311 struct p9_stat_dotl *ret = kmalloc(sizeof(struct p9_stat_dotl),
1312 GFP_KERNEL);
1313 struct p9_req_t *req;
1314
1315 P9_DPRINTK(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
1316 fid->fid, request_mask);
1317
1318 if (!ret)
1319 return ERR_PTR(-ENOMEM);
1320
1321 err = 0;
1322 clnt = fid->clnt;
1323
1324 req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask);
1325 if (IS_ERR(req)) {
1326 err = PTR_ERR(req);
1327 goto error;
1328 }
1329
1330 err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret);
1331 if (err) {
1332 p9pdu_dump(1, req->rc);
1333 p9_free_req(clnt, req);
1334 goto error;
1335 }
1336
1337 P9_DPRINTK(P9_DEBUG_9P,
1338 "<<< RGETATTR st_result_mask=%lld\n"
1339 "<<< qid=%x.%llx.%x\n"
1340 "<<< st_mode=%8.8x st_nlink=%llu\n"
1341 "<<< st_uid=%d st_gid=%d\n"
1342 "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n"
1343 "<<< st_atime_sec=%lld st_atime_nsec=%lld\n"
1344 "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n"
1345 "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n"
1346 "<<< st_btime_sec=%lld st_btime_nsec=%lld\n"
1347 "<<< st_gen=%lld st_data_version=%lld",
1348 ret->st_result_mask, ret->qid.type, ret->qid.path,
1349 ret->qid.version, ret->st_mode, ret->st_nlink, ret->st_uid,
1350 ret->st_gid, ret->st_rdev, ret->st_size, ret->st_blksize,
1351 ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec,
1352 ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec,
1353 ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec,
1354 ret->st_gen, ret->st_data_version);
1355
1356 p9_free_req(clnt, req);
1357 return ret;
1358
1359error:
1360 kfree(ret);
1361 return ERR_PTR(err);
1362}
1363EXPORT_SYMBOL(p9_client_getattr_dotl);
1364
1306static int p9_client_statsize(struct p9_wstat *wst, int proto_version) 1365static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
1307{ 1366{
1308 int ret; 1367 int ret;
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index b645c8263538..3e4f77695891 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -141,6 +141,7 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
141 D - data blob (int32_t size followed by void *, results are not freed) 141 D - data blob (int32_t size followed by void *, results are not freed)
142 T - array of strings (int16_t count, followed by strings) 142 T - array of strings (int16_t count, followed by strings)
143 R - array of qids (int16_t count, followed by qids) 143 R - array of qids (int16_t count, followed by qids)
144 A - stat for 9p2000.L (p9_stat_dotl)
144 ? - if optional = 1, continue parsing 145 ? - if optional = 1, continue parsing
145*/ 146*/
146 147
@@ -340,6 +341,33 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
340 } 341 }
341 } 342 }
342 break; 343 break;
344 case 'A': {
345 struct p9_stat_dotl *stbuf =
346 va_arg(ap, struct p9_stat_dotl *);
347
348 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
349 errcode =
350 p9pdu_readf(pdu, proto_version,
351 "qQdddqqqqqqqqqqqqqqq",
352 &stbuf->st_result_mask,
353 &stbuf->qid,
354 &stbuf->st_mode,
355 &stbuf->st_uid, &stbuf->st_gid,
356 &stbuf->st_nlink,
357 &stbuf->st_rdev, &stbuf->st_size,
358 &stbuf->st_blksize, &stbuf->st_blocks,
359 &stbuf->st_atime_sec,
360 &stbuf->st_atime_nsec,
361 &stbuf->st_mtime_sec,
362 &stbuf->st_mtime_nsec,
363 &stbuf->st_ctime_sec,
364 &stbuf->st_ctime_nsec,
365 &stbuf->st_btime_sec,
366 &stbuf->st_btime_nsec,
367 &stbuf->st_gen,
368 &stbuf->st_data_version);
369 }
370 break;
343 case '?': 371 case '?':
344 if ((proto_version != p9_proto_2000u) && 372 if ((proto_version != p9_proto_2000u) &&
345 (proto_version != p9_proto_2000L)) 373 (proto_version != p9_proto_2000L))