xref: /qemu/hw/9pfs/codir.c (revision c3b21fb1)
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