client.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  1. /*
  2. * net/9p/clnt.c
  3. *
  4. * 9P Client
  5. *
  6. * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to:
  19. * Free Software Foundation
  20. * 51 Franklin Street, Fifth Floor
  21. * Boston, MA 02111-1301 USA
  22. *
  23. */
  24. #include <linux/module.h>
  25. #include <linux/errno.h>
  26. #include <linux/fs.h>
  27. #include <linux/idr.h>
  28. #include <linux/mutex.h>
  29. #include <linux/sched.h>
  30. #include <linux/uaccess.h>
  31. #include <net/9p/9p.h>
  32. #include <linux/parser.h>
  33. #include <net/9p/transport.h>
  34. #include <net/9p/conn.h>
  35. #include <net/9p/client.h>
  36. static struct p9_fid *p9_fid_create(struct p9_client *clnt);
  37. static void p9_fid_destroy(struct p9_fid *fid);
  38. static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
  39. /**
  40. * p9_client_rpc - sends 9P request and waits until a response is available.
  41. * The function can be interrupted.
  42. * @c: client data
  43. * @tc: request to be sent
  44. * @rc: pointer where a pointer to the response is stored
  45. */
  46. int
  47. p9_client_rpc(struct p9_client *c, struct p9_fcall *tc,
  48. struct p9_fcall **rc)
  49. {
  50. if (c->trans->rpc)
  51. return c->trans->rpc(c->trans, tc, rc, c->msize, c->dotu);
  52. else
  53. return p9_conn_rpc(c->conn, tc, rc);
  54. }
  55. struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
  56. int dotu)
  57. {
  58. int err, n;
  59. struct p9_client *clnt;
  60. struct p9_fcall *tc, *rc;
  61. struct p9_str *version;
  62. err = 0;
  63. tc = NULL;
  64. rc = NULL;
  65. clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
  66. if (!clnt)
  67. return ERR_PTR(-ENOMEM);
  68. P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
  69. clnt, trans, msize, dotu);
  70. spin_lock_init(&clnt->lock);
  71. clnt->trans = trans;
  72. clnt->msize = msize;
  73. clnt->dotu = dotu;
  74. INIT_LIST_HEAD(&clnt->fidlist);
  75. clnt->fidpool = p9_idpool_create();
  76. if (!clnt->fidpool) {
  77. err = PTR_ERR(clnt->fidpool);
  78. clnt->fidpool = NULL;
  79. goto error;
  80. }
  81. clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
  82. if (IS_ERR(clnt->conn)) {
  83. err = PTR_ERR(clnt->conn);
  84. clnt->conn = NULL;
  85. goto error;
  86. }
  87. tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
  88. if (IS_ERR(tc)) {
  89. err = PTR_ERR(tc);
  90. tc = NULL;
  91. goto error;
  92. }
  93. err = p9_client_rpc(clnt, tc, &rc);
  94. if (err)
  95. goto error;
  96. version = &rc->params.rversion.version;
  97. if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
  98. clnt->dotu = 1;
  99. else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
  100. clnt->dotu = 0;
  101. else {
  102. err = -EREMOTEIO;
  103. goto error;
  104. }
  105. n = rc->params.rversion.msize;
  106. if (n < clnt->msize)
  107. clnt->msize = n;
  108. kfree(tc);
  109. kfree(rc);
  110. return clnt;
  111. error:
  112. kfree(tc);
  113. kfree(rc);
  114. p9_client_destroy(clnt);
  115. return ERR_PTR(err);
  116. }
  117. EXPORT_SYMBOL(p9_client_create);
  118. void p9_client_destroy(struct p9_client *clnt)
  119. {
  120. struct p9_fid *fid, *fidptr;
  121. P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
  122. if (clnt->conn) {
  123. p9_conn_destroy(clnt->conn);
  124. clnt->conn = NULL;
  125. }
  126. if (clnt->trans) {
  127. clnt->trans->close(clnt->trans);
  128. kfree(clnt->trans);
  129. clnt->trans = NULL;
  130. }
  131. list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
  132. p9_fid_destroy(fid);
  133. if (clnt->fidpool)
  134. p9_idpool_destroy(clnt->fidpool);
  135. kfree(clnt);
  136. }
  137. EXPORT_SYMBOL(p9_client_destroy);
  138. void p9_client_disconnect(struct p9_client *clnt)
  139. {
  140. P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
  141. clnt->trans->status = Disconnected;
  142. p9_conn_cancel(clnt->conn, -EIO);
  143. }
  144. EXPORT_SYMBOL(p9_client_disconnect);
  145. struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
  146. char *uname, u32 n_uname, char *aname)
  147. {
  148. int err;
  149. struct p9_fcall *tc, *rc;
  150. struct p9_fid *fid;
  151. P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
  152. clnt, afid?afid->fid:-1, uname, aname);
  153. err = 0;
  154. tc = NULL;
  155. rc = NULL;
  156. fid = p9_fid_create(clnt);
  157. if (IS_ERR(fid)) {
  158. err = PTR_ERR(fid);
  159. fid = NULL;
  160. goto error;
  161. }
  162. tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
  163. n_uname, clnt->dotu);
  164. if (IS_ERR(tc)) {
  165. err = PTR_ERR(tc);
  166. tc = NULL;
  167. goto error;
  168. }
  169. err = p9_client_rpc(clnt, tc, &rc);
  170. if (err)
  171. goto error;
  172. memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
  173. kfree(tc);
  174. kfree(rc);
  175. return fid;
  176. error:
  177. kfree(tc);
  178. kfree(rc);
  179. if (fid)
  180. p9_fid_destroy(fid);
  181. return ERR_PTR(err);
  182. }
  183. EXPORT_SYMBOL(p9_client_attach);
  184. struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
  185. u32 n_uname, char *aname)
  186. {
  187. int err;
  188. struct p9_fcall *tc, *rc;
  189. struct p9_fid *fid;
  190. P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
  191. aname);
  192. err = 0;
  193. tc = NULL;
  194. rc = NULL;
  195. fid = p9_fid_create(clnt);
  196. if (IS_ERR(fid)) {
  197. err = PTR_ERR(fid);
  198. fid = NULL;
  199. goto error;
  200. }
  201. tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
  202. if (IS_ERR(tc)) {
  203. err = PTR_ERR(tc);
  204. tc = NULL;
  205. goto error;
  206. }
  207. err = p9_client_rpc(clnt, tc, &rc);
  208. if (err)
  209. goto error;
  210. memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
  211. kfree(tc);
  212. kfree(rc);
  213. return fid;
  214. error:
  215. kfree(tc);
  216. kfree(rc);
  217. if (fid)
  218. p9_fid_destroy(fid);
  219. return ERR_PTR(err);
  220. }
  221. EXPORT_SYMBOL(p9_client_auth);
  222. struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
  223. int clone)
  224. {
  225. int err;
  226. struct p9_fcall *tc, *rc;
  227. struct p9_client *clnt;
  228. struct p9_fid *fid;
  229. P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
  230. oldfid->fid, nwname, wnames?wnames[0]:NULL);
  231. err = 0;
  232. tc = NULL;
  233. rc = NULL;
  234. clnt = oldfid->clnt;
  235. if (clone) {
  236. fid = p9_fid_create(clnt);
  237. if (IS_ERR(fid)) {
  238. err = PTR_ERR(fid);
  239. fid = NULL;
  240. goto error;
  241. }
  242. fid->uid = oldfid->uid;
  243. } else
  244. fid = oldfid;
  245. tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
  246. if (IS_ERR(tc)) {
  247. err = PTR_ERR(tc);
  248. tc = NULL;
  249. goto error;
  250. }
  251. err = p9_client_rpc(clnt, tc, &rc);
  252. if (err) {
  253. if (rc && rc->id == P9_RWALK)
  254. goto clunk_fid;
  255. else
  256. goto error;
  257. }
  258. if (rc->params.rwalk.nwqid != nwname) {
  259. err = -ENOENT;
  260. goto clunk_fid;
  261. }
  262. if (nwname)
  263. memmove(&fid->qid,
  264. &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
  265. sizeof(struct p9_qid));
  266. else
  267. fid->qid = oldfid->qid;
  268. kfree(tc);
  269. kfree(rc);
  270. return fid;
  271. clunk_fid:
  272. kfree(tc);
  273. kfree(rc);
  274. rc = NULL;
  275. tc = p9_create_tclunk(fid->fid);
  276. if (IS_ERR(tc)) {
  277. err = PTR_ERR(tc);
  278. tc = NULL;
  279. goto error;
  280. }
  281. p9_client_rpc(clnt, tc, &rc);
  282. error:
  283. kfree(tc);
  284. kfree(rc);
  285. if (fid && (fid != oldfid))
  286. p9_fid_destroy(fid);
  287. return ERR_PTR(err);
  288. }
  289. EXPORT_SYMBOL(p9_client_walk);
  290. int p9_client_open(struct p9_fid *fid, int mode)
  291. {
  292. int err;
  293. struct p9_fcall *tc, *rc;
  294. struct p9_client *clnt;
  295. P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
  296. err = 0;
  297. tc = NULL;
  298. rc = NULL;
  299. clnt = fid->clnt;
  300. if (fid->mode != -1)
  301. return -EINVAL;
  302. tc = p9_create_topen(fid->fid, mode);
  303. if (IS_ERR(tc)) {
  304. err = PTR_ERR(tc);
  305. tc = NULL;
  306. goto done;
  307. }
  308. err = p9_client_rpc(clnt, tc, &rc);
  309. if (err)
  310. goto done;
  311. fid->mode = mode;
  312. fid->iounit = rc->params.ropen.iounit;
  313. done:
  314. kfree(tc);
  315. kfree(rc);
  316. return err;
  317. }
  318. EXPORT_SYMBOL(p9_client_open);
  319. int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
  320. char *extension)
  321. {
  322. int err;
  323. struct p9_fcall *tc, *rc;
  324. struct p9_client *clnt;
  325. P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
  326. name, perm, mode);
  327. err = 0;
  328. tc = NULL;
  329. rc = NULL;
  330. clnt = fid->clnt;
  331. if (fid->mode != -1)
  332. return -EINVAL;
  333. tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
  334. clnt->dotu);
  335. if (IS_ERR(tc)) {
  336. err = PTR_ERR(tc);
  337. tc = NULL;
  338. goto done;
  339. }
  340. err = p9_client_rpc(clnt, tc, &rc);
  341. if (err)
  342. goto done;
  343. fid->mode = mode;
  344. fid->iounit = rc->params.ropen.iounit;
  345. done:
  346. kfree(tc);
  347. kfree(rc);
  348. return err;
  349. }
  350. EXPORT_SYMBOL(p9_client_fcreate);
  351. int p9_client_clunk(struct p9_fid *fid)
  352. {
  353. int err;
  354. struct p9_fcall *tc, *rc;
  355. struct p9_client *clnt;
  356. P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
  357. err = 0;
  358. tc = NULL;
  359. rc = NULL;
  360. clnt = fid->clnt;
  361. tc = p9_create_tclunk(fid->fid);
  362. if (IS_ERR(tc)) {
  363. err = PTR_ERR(tc);
  364. tc = NULL;
  365. goto done;
  366. }
  367. err = p9_client_rpc(clnt, tc, &rc);
  368. if (err)
  369. goto done;
  370. p9_fid_destroy(fid);
  371. done:
  372. kfree(tc);
  373. kfree(rc);
  374. return err;
  375. }
  376. EXPORT_SYMBOL(p9_client_clunk);
  377. int p9_client_remove(struct p9_fid *fid)
  378. {
  379. int err;
  380. struct p9_fcall *tc, *rc;
  381. struct p9_client *clnt;
  382. P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
  383. err = 0;
  384. tc = NULL;
  385. rc = NULL;
  386. clnt = fid->clnt;
  387. tc = p9_create_tremove(fid->fid);
  388. if (IS_ERR(tc)) {
  389. err = PTR_ERR(tc);
  390. tc = NULL;
  391. goto done;
  392. }
  393. err = p9_client_rpc(clnt, tc, &rc);
  394. if (err)
  395. goto done;
  396. p9_fid_destroy(fid);
  397. done:
  398. kfree(tc);
  399. kfree(rc);
  400. return err;
  401. }
  402. EXPORT_SYMBOL(p9_client_remove);
  403. int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
  404. {
  405. int err, n, rsize, total;
  406. struct p9_fcall *tc, *rc;
  407. struct p9_client *clnt;
  408. P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
  409. (long long unsigned) offset, count);
  410. err = 0;
  411. tc = NULL;
  412. rc = NULL;
  413. clnt = fid->clnt;
  414. total = 0;
  415. rsize = fid->iounit;
  416. if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
  417. rsize = clnt->msize - P9_IOHDRSZ;
  418. do {
  419. if (count < rsize)
  420. rsize = count;
  421. tc = p9_create_tread(fid->fid, offset, rsize);
  422. if (IS_ERR(tc)) {
  423. err = PTR_ERR(tc);
  424. tc = NULL;
  425. goto error;
  426. }
  427. err = p9_client_rpc(clnt, tc, &rc);
  428. if (err)
  429. goto error;
  430. n = rc->params.rread.count;
  431. if (n > count)
  432. n = count;
  433. memmove(data, rc->params.rread.data, n);
  434. count -= n;
  435. data += n;
  436. offset += n;
  437. total += n;
  438. kfree(tc);
  439. tc = NULL;
  440. kfree(rc);
  441. rc = NULL;
  442. } while (count > 0 && n == rsize);
  443. return total;
  444. error:
  445. kfree(tc);
  446. kfree(rc);
  447. return err;
  448. }
  449. EXPORT_SYMBOL(p9_client_read);
  450. int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
  451. {
  452. int err, n, rsize, total;
  453. struct p9_fcall *tc, *rc;
  454. struct p9_client *clnt;
  455. P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
  456. (long long unsigned) offset, count);
  457. err = 0;
  458. tc = NULL;
  459. rc = NULL;
  460. clnt = fid->clnt;
  461. total = 0;
  462. rsize = fid->iounit;
  463. if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
  464. rsize = clnt->msize - P9_IOHDRSZ;
  465. do {
  466. if (count < rsize)
  467. rsize = count;
  468. tc = p9_create_twrite(fid->fid, offset, rsize, data);
  469. if (IS_ERR(tc)) {
  470. err = PTR_ERR(tc);
  471. tc = NULL;
  472. goto error;
  473. }
  474. err = p9_client_rpc(clnt, tc, &rc);
  475. if (err)
  476. goto error;
  477. n = rc->params.rread.count;
  478. count -= n;
  479. data += n;
  480. offset += n;
  481. total += n;
  482. kfree(tc);
  483. tc = NULL;
  484. kfree(rc);
  485. rc = NULL;
  486. } while (count > 0);
  487. return total;
  488. error:
  489. kfree(tc);
  490. kfree(rc);
  491. return err;
  492. }
  493. EXPORT_SYMBOL(p9_client_write);
  494. int
  495. p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
  496. {
  497. int err, n, rsize, total;
  498. struct p9_fcall *tc, *rc;
  499. struct p9_client *clnt;
  500. P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
  501. (long long unsigned) offset, count);
  502. err = 0;
  503. tc = NULL;
  504. rc = NULL;
  505. clnt = fid->clnt;
  506. total = 0;
  507. rsize = fid->iounit;
  508. if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
  509. rsize = clnt->msize - P9_IOHDRSZ;
  510. do {
  511. if (count < rsize)
  512. rsize = count;
  513. tc = p9_create_tread(fid->fid, offset, rsize);
  514. if (IS_ERR(tc)) {
  515. err = PTR_ERR(tc);
  516. tc = NULL;
  517. goto error;
  518. }
  519. err = p9_client_rpc(clnt, tc, &rc);
  520. if (err)
  521. goto error;
  522. n = rc->params.rread.count;
  523. if (n > count)
  524. n = count;
  525. err = copy_to_user(data, rc->params.rread.data, n);
  526. if (err) {
  527. err = -EFAULT;
  528. goto error;
  529. }
  530. count -= n;
  531. data += n;
  532. offset += n;
  533. total += n;
  534. kfree(tc);
  535. tc = NULL;
  536. kfree(rc);
  537. rc = NULL;
  538. } while (count > 0 && n == rsize);
  539. return total;
  540. error:
  541. kfree(tc);
  542. kfree(rc);
  543. return err;
  544. }
  545. EXPORT_SYMBOL(p9_client_uread);
  546. int
  547. p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
  548. u32 count)
  549. {
  550. int err, n, rsize, total;
  551. struct p9_fcall *tc, *rc;
  552. struct p9_client *clnt;
  553. P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
  554. (long long unsigned) offset, count);
  555. err = 0;
  556. tc = NULL;
  557. rc = NULL;
  558. clnt = fid->clnt;
  559. total = 0;
  560. rsize = fid->iounit;
  561. if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
  562. rsize = clnt->msize - P9_IOHDRSZ;
  563. do {
  564. if (count < rsize)
  565. rsize = count;
  566. tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
  567. if (IS_ERR(tc)) {
  568. err = PTR_ERR(tc);
  569. tc = NULL;
  570. goto error;
  571. }
  572. err = p9_client_rpc(clnt, tc, &rc);
  573. if (err)
  574. goto error;
  575. n = rc->params.rread.count;
  576. count -= n;
  577. data += n;
  578. offset += n;
  579. total += n;
  580. kfree(tc);
  581. tc = NULL;
  582. kfree(rc);
  583. rc = NULL;
  584. } while (count > 0);
  585. return total;
  586. error:
  587. kfree(tc);
  588. kfree(rc);
  589. return err;
  590. }
  591. EXPORT_SYMBOL(p9_client_uwrite);
  592. int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
  593. {
  594. int n, total;
  595. P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
  596. (long long unsigned) offset, count);
  597. n = 0;
  598. total = 0;
  599. while (count) {
  600. n = p9_client_read(fid, data, offset, count);
  601. if (n <= 0)
  602. break;
  603. data += n;
  604. offset += n;
  605. count -= n;
  606. total += n;
  607. }
  608. if (n < 0)
  609. total = n;
  610. return total;
  611. }
  612. EXPORT_SYMBOL(p9_client_readn);
  613. struct p9_stat *p9_client_stat(struct p9_fid *fid)
  614. {
  615. int err;
  616. struct p9_fcall *tc, *rc;
  617. struct p9_client *clnt;
  618. struct p9_stat *ret;
  619. P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
  620. err = 0;
  621. tc = NULL;
  622. rc = NULL;
  623. ret = NULL;
  624. clnt = fid->clnt;
  625. tc = p9_create_tstat(fid->fid);
  626. if (IS_ERR(tc)) {
  627. err = PTR_ERR(tc);
  628. tc = NULL;
  629. goto error;
  630. }
  631. err = p9_client_rpc(clnt, tc, &rc);
  632. if (err)
  633. goto error;
  634. ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
  635. if (IS_ERR(ret)) {
  636. err = PTR_ERR(ret);
  637. ret = NULL;
  638. goto error;
  639. }
  640. kfree(tc);
  641. kfree(rc);
  642. return ret;
  643. error:
  644. kfree(tc);
  645. kfree(rc);
  646. kfree(ret);
  647. return ERR_PTR(err);
  648. }
  649. EXPORT_SYMBOL(p9_client_stat);
  650. int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
  651. {
  652. int err;
  653. struct p9_fcall *tc, *rc;
  654. struct p9_client *clnt;
  655. P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
  656. err = 0;
  657. tc = NULL;
  658. rc = NULL;
  659. clnt = fid->clnt;
  660. tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
  661. if (IS_ERR(tc)) {
  662. err = PTR_ERR(tc);
  663. tc = NULL;
  664. goto done;
  665. }
  666. err = p9_client_rpc(clnt, tc, &rc);
  667. done:
  668. kfree(tc);
  669. kfree(rc);
  670. return err;
  671. }
  672. EXPORT_SYMBOL(p9_client_wstat);
  673. struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
  674. {
  675. int err, n, m;
  676. struct p9_fcall *tc, *rc;
  677. struct p9_client *clnt;
  678. struct p9_stat st, *ret;
  679. P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
  680. (long long unsigned) offset);
  681. err = 0;
  682. tc = NULL;
  683. rc = NULL;
  684. ret = NULL;
  685. clnt = fid->clnt;
  686. /* if the offset is below or above the current response, free it */
  687. if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
  688. offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
  689. fid->rdir_pos = 0;
  690. if (fid->rdir_fcall)
  691. fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
  692. kfree(fid->rdir_fcall);
  693. fid->rdir_fcall = NULL;
  694. if (offset < fid->rdir_fpos)
  695. fid->rdir_fpos = 0;
  696. }
  697. if (!fid->rdir_fcall) {
  698. n = fid->iounit;
  699. if (!n || n > clnt->msize-P9_IOHDRSZ)
  700. n = clnt->msize - P9_IOHDRSZ;
  701. while (1) {
  702. if (fid->rdir_fcall) {
  703. fid->rdir_fpos +=
  704. fid->rdir_fcall->params.rread.count;
  705. kfree(fid->rdir_fcall);
  706. fid->rdir_fcall = NULL;
  707. }
  708. tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
  709. if (IS_ERR(tc)) {
  710. err = PTR_ERR(tc);
  711. tc = NULL;
  712. goto error;
  713. }
  714. err = p9_client_rpc(clnt, tc, &rc);
  715. if (err)
  716. goto error;
  717. n = rc->params.rread.count;
  718. if (n == 0)
  719. goto done;
  720. fid->rdir_fcall = rc;
  721. rc = NULL;
  722. if (offset >= fid->rdir_fpos &&
  723. offset < fid->rdir_fpos+n)
  724. break;
  725. }
  726. fid->rdir_pos = 0;
  727. }
  728. m = offset - fid->rdir_fpos;
  729. if (m < 0)
  730. goto done;
  731. n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
  732. fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
  733. if (!n) {
  734. err = -EIO;
  735. goto error;
  736. }
  737. fid->rdir_pos += n;
  738. st.size = n;
  739. ret = p9_clone_stat(&st, clnt->dotu);
  740. if (IS_ERR(ret)) {
  741. err = PTR_ERR(ret);
  742. ret = NULL;
  743. goto error;
  744. }
  745. done:
  746. kfree(tc);
  747. kfree(rc);
  748. return ret;
  749. error:
  750. kfree(tc);
  751. kfree(rc);
  752. kfree(ret);
  753. return ERR_PTR(err);
  754. }
  755. EXPORT_SYMBOL(p9_client_dirread);
  756. static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
  757. {
  758. int n;
  759. char *p;
  760. struct p9_stat *ret;
  761. n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
  762. st->muid.len;
  763. if (dotu)
  764. n += st->extension.len;
  765. ret = kmalloc(n, GFP_KERNEL);
  766. if (!ret)
  767. return ERR_PTR(-ENOMEM);
  768. memmove(ret, st, sizeof(struct p9_stat));
  769. p = ((char *) ret) + sizeof(struct p9_stat);
  770. memmove(p, st->name.str, st->name.len);
  771. ret->name.str = p;
  772. p += st->name.len;
  773. memmove(p, st->uid.str, st->uid.len);
  774. ret->uid.str = p;
  775. p += st->uid.len;
  776. memmove(p, st->gid.str, st->gid.len);
  777. ret->gid.str = p;
  778. p += st->gid.len;
  779. memmove(p, st->muid.str, st->muid.len);
  780. ret->muid.str = p;
  781. p += st->muid.len;
  782. if (dotu) {
  783. memmove(p, st->extension.str, st->extension.len);
  784. ret->extension.str = p;
  785. p += st->extension.len;
  786. }
  787. return ret;
  788. }
  789. static struct p9_fid *p9_fid_create(struct p9_client *clnt)
  790. {
  791. int err;
  792. struct p9_fid *fid;
  793. P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
  794. fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
  795. if (!fid)
  796. return ERR_PTR(-ENOMEM);
  797. fid->fid = p9_idpool_get(clnt->fidpool);
  798. if (fid->fid < 0) {
  799. err = -ENOSPC;
  800. goto error;
  801. }
  802. memset(&fid->qid, 0, sizeof(struct p9_qid));
  803. fid->mode = -1;
  804. fid->rdir_fpos = 0;
  805. fid->rdir_pos = 0;
  806. fid->rdir_fcall = NULL;
  807. fid->uid = current->fsuid;
  808. fid->clnt = clnt;
  809. fid->aux = NULL;
  810. spin_lock(&clnt->lock);
  811. list_add(&fid->flist, &clnt->fidlist);
  812. spin_unlock(&clnt->lock);
  813. return fid;
  814. error:
  815. kfree(fid);
  816. return ERR_PTR(err);
  817. }
  818. static void p9_fid_destroy(struct p9_fid *fid)
  819. {
  820. struct p9_client *clnt;
  821. P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
  822. clnt = fid->clnt;
  823. p9_idpool_put(fid->fid, clnt->fidpool);
  824. spin_lock(&clnt->lock);
  825. list_del(&fid->flist);
  826. spin_unlock(&clnt->lock);
  827. kfree(fid->rdir_fcall);
  828. kfree(fid);
  829. }