1dcb9dbe3SAneesh Kumar K.V /*
2af8b38b0SGreg Kurz * 9p backend
3dcb9dbe3SAneesh Kumar K.V *
4dcb9dbe3SAneesh Kumar K.V * Copyright IBM, Corp. 2011
5dcb9dbe3SAneesh Kumar K.V *
6dcb9dbe3SAneesh Kumar K.V * Authors:
7dcb9dbe3SAneesh Kumar K.V * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
8dcb9dbe3SAneesh Kumar K.V *
9dcb9dbe3SAneesh Kumar K.V * This work is licensed under the terms of the GNU GPL, version 2. See
10dcb9dbe3SAneesh Kumar K.V * the COPYING file in the top-level directory.
11dcb9dbe3SAneesh Kumar K.V *
12dcb9dbe3SAneesh Kumar K.V */
13dcb9dbe3SAneesh Kumar K.V
146f569084SChristian Schoenebeck /*
156f569084SChristian Schoenebeck * Not so fast! You might want to read the 9p developer docs first:
166f569084SChristian Schoenebeck * https://wiki.qemu.org/Documentation/9p
176f569084SChristian Schoenebeck */
186f569084SChristian Schoenebeck
19fbc04127SPeter Maydell #include "qemu/osdep.h"
20dcb9dbe3SAneesh Kumar K.V #include "fsdev/qemu-fsdev.h"
211de7afc9SPaolo Bonzini #include "qemu/thread.h"
22db725815SMarkus Armbruster #include "qemu/main-loop.h"
23fe52840cSWei Liu #include "coth.h"
246b3b279bSKeno Fischer #include "9p-xattr.h"
256b3b279bSKeno Fischer #include "9p-util.h"
26dcb9dbe3SAneesh Kumar K.V
27dd8151f4SChristian Schoenebeck /*
28dd8151f4SChristian Schoenebeck * Intended to be called from bottom-half (e.g. background I/O thread)
29dd8151f4SChristian Schoenebeck * context.
30dd8151f4SChristian Schoenebeck */
do_readdir(V9fsPDU * pdu,V9fsFidState * fidp,struct dirent ** dent)31dd8151f4SChristian Schoenebeck static int do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent **dent)
32dcb9dbe3SAneesh Kumar K.V {
33dd8151f4SChristian Schoenebeck int err = 0;
34bccacf6cSAneesh Kumar K.V V9fsState *s = pdu->s;
35635324e8SGreg Kurz struct dirent *entry;
36635324e8SGreg Kurz
37dcb9dbe3SAneesh Kumar K.V errno = 0;
38635324e8SGreg Kurz entry = s->ops->readdir(&s->ctx, &fidp->fs);
39635324e8SGreg Kurz if (!entry && errno) {
40dd8151f4SChristian Schoenebeck *dent = NULL;
41dcb9dbe3SAneesh Kumar K.V err = -errno;
42dcb9dbe3SAneesh Kumar K.V } else {
43635324e8SGreg Kurz *dent = entry;
44dcb9dbe3SAneesh Kumar K.V }
45dd8151f4SChristian Schoenebeck return err;
46dd8151f4SChristian Schoenebeck }
47dd8151f4SChristian Schoenebeck
482149675bSChristian Schoenebeck /*
492149675bSChristian Schoenebeck * TODO: This will be removed for performance reasons.
502149675bSChristian Schoenebeck * Use v9fs_co_readdir_many() instead.
512149675bSChristian Schoenebeck */
v9fs_co_readdir(V9fsPDU * pdu,V9fsFidState * fidp,struct dirent ** dent)52dd8151f4SChristian Schoenebeck int coroutine_fn v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
53dd8151f4SChristian Schoenebeck struct dirent **dent)
54dd8151f4SChristian Schoenebeck {
55dd8151f4SChristian Schoenebeck int err;
56dd8151f4SChristian Schoenebeck
57dd8151f4SChristian Schoenebeck if (v9fs_request_cancelled(pdu)) {
58dd8151f4SChristian Schoenebeck return -EINTR;
59dd8151f4SChristian Schoenebeck }
60dd8151f4SChristian Schoenebeck v9fs_co_run_in_worker({
61dd8151f4SChristian Schoenebeck err = do_readdir(pdu, fidp, dent);
62dcb9dbe3SAneesh Kumar K.V });
63dcb9dbe3SAneesh Kumar K.V return err;
64dcb9dbe3SAneesh Kumar K.V }
65dcb9dbe3SAneesh Kumar K.V
662149675bSChristian Schoenebeck /*
672149675bSChristian Schoenebeck * This is solely executed on a background IO thread.
682149675bSChristian Schoenebeck *
692149675bSChristian Schoenebeck * See v9fs_co_readdir_many() (as its only user) below for details.
702149675bSChristian Schoenebeck */
71c3b21fb1SPaolo Bonzini static int coroutine_fn
do_readdir_many(V9fsPDU * pdu,V9fsFidState * fidp,struct V9fsDirEnt ** entries,off_t offset,int32_t maxsize,bool dostat)72c3b21fb1SPaolo Bonzini do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, struct V9fsDirEnt **entries,
73c3b21fb1SPaolo Bonzini off_t offset, int32_t maxsize, bool dostat)
742149675bSChristian Schoenebeck {
752149675bSChristian Schoenebeck V9fsState *s = pdu->s;
762149675bSChristian Schoenebeck V9fsString name;
772149675bSChristian Schoenebeck int len, err = 0;
782149675bSChristian Schoenebeck int32_t size = 0;
792149675bSChristian Schoenebeck off_t saved_dir_pos;
802149675bSChristian Schoenebeck struct dirent *dent;
812149675bSChristian Schoenebeck struct V9fsDirEnt *e = NULL;
822149675bSChristian Schoenebeck V9fsPath path;
832149675bSChristian Schoenebeck struct stat stbuf;
842149675bSChristian Schoenebeck
852149675bSChristian Schoenebeck *entries = NULL;
862149675bSChristian Schoenebeck v9fs_path_init(&path);
872149675bSChristian Schoenebeck
882149675bSChristian Schoenebeck /*
892149675bSChristian Schoenebeck * TODO: Here should be a warn_report_once() if lock failed.
902149675bSChristian Schoenebeck *
912149675bSChristian Schoenebeck * With a good 9p client we should not get into concurrency here,
922149675bSChristian Schoenebeck * because a good client would not use the same fid for concurrent
932149675bSChristian Schoenebeck * requests. We do the lock here for safety reasons though. However
942149675bSChristian Schoenebeck * the client would then suffer performance issues, so better log that
952149675bSChristian Schoenebeck * issue here.
962149675bSChristian Schoenebeck */
972149675bSChristian Schoenebeck v9fs_readdir_lock(&fidp->fs.dir);
982149675bSChristian Schoenebeck
992149675bSChristian Schoenebeck /* seek directory to requested initial position */
1002149675bSChristian Schoenebeck if (offset == 0) {
1012149675bSChristian Schoenebeck s->ops->rewinddir(&s->ctx, &fidp->fs);
1022149675bSChristian Schoenebeck } else {
1032149675bSChristian Schoenebeck s->ops->seekdir(&s->ctx, &fidp->fs, offset);
1042149675bSChristian Schoenebeck }
1052149675bSChristian Schoenebeck
1062149675bSChristian Schoenebeck /* save the directory position */
1072149675bSChristian Schoenebeck saved_dir_pos = s->ops->telldir(&s->ctx, &fidp->fs);
1082149675bSChristian Schoenebeck if (saved_dir_pos < 0) {
1092149675bSChristian Schoenebeck err = saved_dir_pos;
1102149675bSChristian Schoenebeck goto out;
1112149675bSChristian Schoenebeck }
1122149675bSChristian Schoenebeck
1132149675bSChristian Schoenebeck while (true) {
1142149675bSChristian Schoenebeck /* interrupt loop if request was cancelled by a Tflush request */
1152149675bSChristian Schoenebeck if (v9fs_request_cancelled(pdu)) {
1162149675bSChristian Schoenebeck err = -EINTR;
1172149675bSChristian Schoenebeck break;
1182149675bSChristian Schoenebeck }
1192149675bSChristian Schoenebeck
1202149675bSChristian Schoenebeck /* get directory entry from fs driver */
1212149675bSChristian Schoenebeck err = do_readdir(pdu, fidp, &dent);
1222149675bSChristian Schoenebeck if (err || !dent) {
1232149675bSChristian Schoenebeck break;
1242149675bSChristian Schoenebeck }
1252149675bSChristian Schoenebeck
1262149675bSChristian Schoenebeck /*
1272149675bSChristian Schoenebeck * stop this loop as soon as it would exceed the allowed maximum
1282149675bSChristian Schoenebeck * response message size for the directory entries collected so far,
1292149675bSChristian Schoenebeck * because anything beyond that size would need to be discarded by
1302149675bSChristian Schoenebeck * 9p controller (main thread / top half) anyway
1312149675bSChristian Schoenebeck */
1322149675bSChristian Schoenebeck v9fs_string_init(&name);
1332149675bSChristian Schoenebeck v9fs_string_sprintf(&name, "%s", dent->d_name);
1342149675bSChristian Schoenebeck len = v9fs_readdir_response_size(&name);
1352149675bSChristian Schoenebeck v9fs_string_free(&name);
1362149675bSChristian Schoenebeck if (size + len > maxsize) {
1372149675bSChristian Schoenebeck /* this is not an error case actually */
1382149675bSChristian Schoenebeck break;
1392149675bSChristian Schoenebeck }
1402149675bSChristian Schoenebeck
1412149675bSChristian Schoenebeck /* append next node to result chain */
1422149675bSChristian Schoenebeck if (!e) {
1431366244aSMarkus Armbruster *entries = e = g_new0(V9fsDirEnt, 1);
1442149675bSChristian Schoenebeck } else {
1451366244aSMarkus Armbruster e = e->next = g_new0(V9fsDirEnt, 1);
1462149675bSChristian Schoenebeck }
147e64e27d5SVitaly Chikunov e->dent = qemu_dirent_dup(dent);
1482149675bSChristian Schoenebeck
1492149675bSChristian Schoenebeck /* perform a full stat() for directory entry if requested by caller */
1502149675bSChristian Schoenebeck if (dostat) {
1512149675bSChristian Schoenebeck err = s->ops->name_to_path(
1522149675bSChristian Schoenebeck &s->ctx, &fidp->path, dent->d_name, &path
1532149675bSChristian Schoenebeck );
1542149675bSChristian Schoenebeck if (err < 0) {
1552149675bSChristian Schoenebeck err = -errno;
1562149675bSChristian Schoenebeck break;
1572149675bSChristian Schoenebeck }
1582149675bSChristian Schoenebeck
1592149675bSChristian Schoenebeck err = s->ops->lstat(&s->ctx, &path, &stbuf);
1602149675bSChristian Schoenebeck if (err < 0) {
1612149675bSChristian Schoenebeck err = -errno;
1622149675bSChristian Schoenebeck break;
1632149675bSChristian Schoenebeck }
1642149675bSChristian Schoenebeck
1651366244aSMarkus Armbruster e->st = g_new0(struct stat, 1);
1662149675bSChristian Schoenebeck memcpy(e->st, &stbuf, sizeof(struct stat));
1672149675bSChristian Schoenebeck }
1682149675bSChristian Schoenebeck
1692149675bSChristian Schoenebeck size += len;
1706b3b279bSKeno Fischer saved_dir_pos = qemu_dirent_off(dent);
1712149675bSChristian Schoenebeck }
1722149675bSChristian Schoenebeck
1732149675bSChristian Schoenebeck /* restore (last) saved position */
1742149675bSChristian Schoenebeck s->ops->seekdir(&s->ctx, &fidp->fs, saved_dir_pos);
1752149675bSChristian Schoenebeck
1762149675bSChristian Schoenebeck out:
1772149675bSChristian Schoenebeck v9fs_readdir_unlock(&fidp->fs.dir);
1782149675bSChristian Schoenebeck v9fs_path_free(&path);
1792149675bSChristian Schoenebeck if (err < 0) {
1802149675bSChristian Schoenebeck return err;
1812149675bSChristian Schoenebeck }
1822149675bSChristian Schoenebeck return size;
1832149675bSChristian Schoenebeck }
1842149675bSChristian Schoenebeck
1852149675bSChristian Schoenebeck /**
1861a7f2400SChristian Schoenebeck * v9fs_co_readdir_many() - Reads multiple directory entries in one rush.
1871a7f2400SChristian Schoenebeck *
1881a7f2400SChristian Schoenebeck * @pdu: the causing 9p (T_readdir) client request
1891a7f2400SChristian Schoenebeck * @fidp: already opened directory where readdir shall be performed on
1901a7f2400SChristian Schoenebeck * @entries: output for directory entries (must not be NULL)
1911a7f2400SChristian Schoenebeck * @offset: initial position inside the directory the function shall
1921a7f2400SChristian Schoenebeck * seek to before retrieving the directory entries
1931a7f2400SChristian Schoenebeck * @maxsize: maximum result message body size (in bytes)
1941a7f2400SChristian Schoenebeck * @dostat: whether a stat() should be performed and returned for
1951a7f2400SChristian Schoenebeck * each directory entry
1961a7f2400SChristian Schoenebeck * Return: resulting response message body size (in bytes) on success,
1971a7f2400SChristian Schoenebeck * negative error code otherwise
1982149675bSChristian Schoenebeck *
1992149675bSChristian Schoenebeck * Retrieves the requested (max. amount of) directory entries from the fs
2002149675bSChristian Schoenebeck * driver. This function must only be called by the main IO thread (top half).
2012149675bSChristian Schoenebeck * Internally this function call will be dispatched to a background IO thread
2022149675bSChristian Schoenebeck * (bottom half) where it is eventually executed by the fs driver.
2032149675bSChristian Schoenebeck *
2041a7f2400SChristian Schoenebeck * Acquiring multiple directory entries in one rush from the fs
2052149675bSChristian Schoenebeck * driver, instead of retrieving each directory entry individually, is very
2062149675bSChristian Schoenebeck * beneficial from performance point of view. Because for every fs driver
2072149675bSChristian Schoenebeck * request latency is added, which in practice could lead to overall
2082149675bSChristian Schoenebeck * latencies of several hundred ms for reading all entries (of just a single
2092149675bSChristian Schoenebeck * directory) if every directory entry was individually requested from fs
2102149675bSChristian Schoenebeck * driver.
2112149675bSChristian Schoenebeck *
2121a7f2400SChristian Schoenebeck * NOTE: You must ALWAYS call v9fs_free_dirents(entries) after calling
2132149675bSChristian Schoenebeck * v9fs_co_readdir_many(), both on success and on error cases of this
2141a7f2400SChristian Schoenebeck * function, to avoid memory leaks once @entries are no longer needed.
2152149675bSChristian Schoenebeck */
v9fs_co_readdir_many(V9fsPDU * pdu,V9fsFidState * fidp,struct V9fsDirEnt ** entries,off_t offset,int32_t maxsize,bool dostat)2162149675bSChristian Schoenebeck int coroutine_fn v9fs_co_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp,
2172149675bSChristian Schoenebeck struct V9fsDirEnt **entries,
2182149675bSChristian Schoenebeck off_t offset, int32_t maxsize,
2192149675bSChristian Schoenebeck bool dostat)
2202149675bSChristian Schoenebeck {
2212149675bSChristian Schoenebeck int err = 0;
2222149675bSChristian Schoenebeck
2232149675bSChristian Schoenebeck if (v9fs_request_cancelled(pdu)) {
2242149675bSChristian Schoenebeck return -EINTR;
2252149675bSChristian Schoenebeck }
2262149675bSChristian Schoenebeck v9fs_co_run_in_worker({
2272149675bSChristian Schoenebeck err = do_readdir_many(pdu, fidp, entries, offset, maxsize, dostat);
2282149675bSChristian Schoenebeck });
2292149675bSChristian Schoenebeck return err;
2302149675bSChristian Schoenebeck }
2312149675bSChristian Schoenebeck
v9fs_co_telldir(V9fsPDU * pdu,V9fsFidState * fidp)232bccacf6cSAneesh Kumar K.V off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
233dcb9dbe3SAneesh Kumar K.V {
234dcb9dbe3SAneesh Kumar K.V off_t err;
235bccacf6cSAneesh Kumar K.V V9fsState *s = pdu->s;
236dcb9dbe3SAneesh Kumar K.V
237bccacf6cSAneesh Kumar K.V if (v9fs_request_cancelled(pdu)) {
238bccacf6cSAneesh Kumar K.V return -EINTR;
239bccacf6cSAneesh Kumar K.V }
240dcb9dbe3SAneesh Kumar K.V v9fs_co_run_in_worker(
241dcb9dbe3SAneesh Kumar K.V {
242cc720ddbSAneesh Kumar K.V err = s->ops->telldir(&s->ctx, &fidp->fs);
243dcb9dbe3SAneesh Kumar K.V if (err < 0) {
244dcb9dbe3SAneesh Kumar K.V err = -errno;
245dcb9dbe3SAneesh Kumar K.V }
246dcb9dbe3SAneesh Kumar K.V });
247dcb9dbe3SAneesh Kumar K.V return err;
248dcb9dbe3SAneesh Kumar K.V }
249dcb9dbe3SAneesh Kumar K.V
v9fs_co_seekdir(V9fsPDU * pdu,V9fsFidState * fidp,off_t offset)2505bdade66SGreg Kurz void coroutine_fn v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp,
2515bdade66SGreg Kurz off_t offset)
252dcb9dbe3SAneesh Kumar K.V {
253bccacf6cSAneesh Kumar K.V V9fsState *s = pdu->s;
254bccacf6cSAneesh Kumar K.V if (v9fs_request_cancelled(pdu)) {
255bccacf6cSAneesh Kumar K.V return;
256bccacf6cSAneesh Kumar K.V }
257dcb9dbe3SAneesh Kumar K.V v9fs_co_run_in_worker(
258dcb9dbe3SAneesh Kumar K.V {
259cc720ddbSAneesh Kumar K.V s->ops->seekdir(&s->ctx, &fidp->fs, offset);
260dcb9dbe3SAneesh Kumar K.V });
261dcb9dbe3SAneesh Kumar K.V }
262dcb9dbe3SAneesh Kumar K.V
v9fs_co_rewinddir(V9fsPDU * pdu,V9fsFidState * fidp)2635bdade66SGreg Kurz void coroutine_fn v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
264dcb9dbe3SAneesh Kumar K.V {
265bccacf6cSAneesh Kumar K.V V9fsState *s = pdu->s;
266bccacf6cSAneesh Kumar K.V if (v9fs_request_cancelled(pdu)) {
267bccacf6cSAneesh Kumar K.V return;
268bccacf6cSAneesh Kumar K.V }
269dcb9dbe3SAneesh Kumar K.V v9fs_co_run_in_worker(
270dcb9dbe3SAneesh Kumar K.V {
271cc720ddbSAneesh Kumar K.V s->ops->rewinddir(&s->ctx, &fidp->fs);
272dcb9dbe3SAneesh Kumar K.V });
273dcb9dbe3SAneesh Kumar K.V }
274d0884642SVenkateswararao Jujjuri
v9fs_co_mkdir(V9fsPDU * pdu,V9fsFidState * fidp,V9fsString * name,mode_t mode,uid_t uid,gid_t gid,struct stat * stbuf)2755bdade66SGreg Kurz int coroutine_fn v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp,
2765bdade66SGreg Kurz V9fsString *name, mode_t mode, uid_t uid,
2775bdade66SGreg Kurz gid_t gid, struct stat *stbuf)
278d0884642SVenkateswararao Jujjuri {
279d0884642SVenkateswararao Jujjuri int err;
280d0884642SVenkateswararao Jujjuri FsCred cred;
2812289be19SAneesh Kumar K.V V9fsPath path;
282bccacf6cSAneesh Kumar K.V V9fsState *s = pdu->s;
283d0884642SVenkateswararao Jujjuri
284bccacf6cSAneesh Kumar K.V if (v9fs_request_cancelled(pdu)) {
2853a93113aSDong Xu Wang return -EINTR;
286bccacf6cSAneesh Kumar K.V }
287d0884642SVenkateswararao Jujjuri cred_init(&cred);
288d0884642SVenkateswararao Jujjuri cred.fc_mode = mode;
289d0884642SVenkateswararao Jujjuri cred.fc_uid = uid;
290d0884642SVenkateswararao Jujjuri cred.fc_gid = gid;
291532decb7SAneesh Kumar K.V v9fs_path_read_lock(s);
292d0884642SVenkateswararao Jujjuri v9fs_co_run_in_worker(
293d0884642SVenkateswararao Jujjuri {
2942289be19SAneesh Kumar K.V err = s->ops->mkdir(&s->ctx, &fidp->path, name->data, &cred);
29502cb7f3aSAneesh Kumar K.V if (err < 0) {
29602cb7f3aSAneesh Kumar K.V err = -errno;
29702cb7f3aSAneesh Kumar K.V } else {
2982289be19SAneesh Kumar K.V v9fs_path_init(&path);
2992289be19SAneesh Kumar K.V err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
3002289be19SAneesh Kumar K.V if (!err) {
3012289be19SAneesh Kumar K.V err = s->ops->lstat(&s->ctx, &path, stbuf);
302d0884642SVenkateswararao Jujjuri if (err < 0) {
303d0884642SVenkateswararao Jujjuri err = -errno;
304d0884642SVenkateswararao Jujjuri }
30502cb7f3aSAneesh Kumar K.V }
3062289be19SAneesh Kumar K.V v9fs_path_free(&path);
3072289be19SAneesh Kumar K.V }
308d0884642SVenkateswararao Jujjuri });
309532decb7SAneesh Kumar K.V v9fs_path_unlock(s);
310d0884642SVenkateswararao Jujjuri return err;
311d0884642SVenkateswararao Jujjuri }
312f6b7f0abSAneesh Kumar K.V
v9fs_co_opendir(V9fsPDU * pdu,V9fsFidState * fidp)3135bdade66SGreg Kurz int coroutine_fn v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
314f6b7f0abSAneesh Kumar K.V {
315f6b7f0abSAneesh Kumar K.V int err;
316bccacf6cSAneesh Kumar K.V V9fsState *s = pdu->s;
317f6b7f0abSAneesh Kumar K.V
318bccacf6cSAneesh Kumar K.V if (v9fs_request_cancelled(pdu)) {
3193a93113aSDong Xu Wang return -EINTR;
320bccacf6cSAneesh Kumar K.V }
321532decb7SAneesh Kumar K.V v9fs_path_read_lock(s);
322f6b7f0abSAneesh Kumar K.V v9fs_co_run_in_worker(
323f6b7f0abSAneesh Kumar K.V {
324cc720ddbSAneesh Kumar K.V err = s->ops->opendir(&s->ctx, &fidp->path, &fidp->fs);
325cc720ddbSAneesh Kumar K.V if (err < 0) {
326f6b7f0abSAneesh Kumar K.V err = -errno;
327f6b7f0abSAneesh Kumar K.V } else {
328f6b7f0abSAneesh Kumar K.V err = 0;
329f6b7f0abSAneesh Kumar K.V }
330f6b7f0abSAneesh Kumar K.V });
331532decb7SAneesh Kumar K.V v9fs_path_unlock(s);
33295f65511SAneesh Kumar K.V if (!err) {
33395f65511SAneesh Kumar K.V total_open_fd++;
33495f65511SAneesh Kumar K.V if (total_open_fd > open_fd_hw) {
335bccacf6cSAneesh Kumar K.V v9fs_reclaim_fd(pdu);
33695f65511SAneesh Kumar K.V }
33795f65511SAneesh Kumar K.V }
338f6b7f0abSAneesh Kumar K.V return err;
339f6b7f0abSAneesh Kumar K.V }
340bed4352cSAneesh Kumar K.V
v9fs_co_closedir(V9fsPDU * pdu,V9fsFidOpenState * fs)3415bdade66SGreg Kurz int coroutine_fn v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs)
342bed4352cSAneesh Kumar K.V {
343bed4352cSAneesh Kumar K.V int err;
344bccacf6cSAneesh Kumar K.V V9fsState *s = pdu->s;
345bed4352cSAneesh Kumar K.V
346bccacf6cSAneesh Kumar K.V if (v9fs_request_cancelled(pdu)) {
3473a93113aSDong Xu Wang return -EINTR;
348bccacf6cSAneesh Kumar K.V }
349bed4352cSAneesh Kumar K.V v9fs_co_run_in_worker(
350bed4352cSAneesh Kumar K.V {
351cc720ddbSAneesh Kumar K.V err = s->ops->closedir(&s->ctx, fs);
352bed4352cSAneesh Kumar K.V if (err < 0) {
353bed4352cSAneesh Kumar K.V err = -errno;
354bed4352cSAneesh Kumar K.V }
355bed4352cSAneesh Kumar K.V });
35695f65511SAneesh Kumar K.V if (!err) {
35795f65511SAneesh Kumar K.V total_open_fd--;
35895f65511SAneesh Kumar K.V }
359bed4352cSAneesh Kumar K.V return err;
360bed4352cSAneesh Kumar K.V }
361