diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 8094d2c6c438..683596797b51 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -145,6 +145,8 @@ struct FileOperations
                     const struct timespec *);
     int (*fchown)(FsContext *, int, V9fsFidOpenState *, FsCred *);
     int (*fchmod)(FsContext *, int, V9fsFidOpenState *, FsCred *);
+    ssize_t (*fgetxattr)(FsContext *, int, V9fsFidOpenState *,
+                         const char *, void *, size_t);
     void *opaque;
 };
 
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c
index f345217aa8e1..3153acff663c 100644
--- a/hw/9pfs/9p-handle.c
+++ b/hw/9pfs/9p-handle.c
@@ -477,6 +477,16 @@ static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
     return ret;
 }
 
+static ssize_t handle_fgetxattr(FsContext *ctx, int fid_type,
+                                V9fsFidOpenState *fs, const char *name,
+                                void *value, size_t size)
+{
+    int fd;
+
+    fd = v9fs_get_fd_fid(fid_type, fs);
+    return fgetxattr(fd, name, value, size);
+}
+
 static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
                                  void *value, size_t size)
 {
@@ -736,4 +746,5 @@ FileOperations handle_ops = {
     .futimens     = handle_futimens,
     .fchown       = handle_fchown,
     .fchmod       = handle_fchmod,
+    .fgetxattr    = handle_fgetxattr,
 };
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index e51c58037266..206849a3ed83 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -1104,6 +1104,16 @@ static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
     return v9fs_get_xattr(ctx, -1, path, name, value, size);
 }
 
+static ssize_t local_fgetxattr(FsContext *ctx, int fid_type,
+                               V9fsFidOpenState *fs, const char *name,
+                               void *value, size_t size)
+{
+    int fd;
+
+    fd = v9fs_get_fd_fid(fid_type, fs);
+    return v9fs_get_xattr(ctx, fd, NULL, name, value, size);
+}
+
 static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
                                 void *value, size_t size)
 {
@@ -1357,4 +1367,5 @@ FileOperations local_ops = {
     .futimens = local_futimens,
     .fchown = local_fchown,
     .fchmod = local_fchmod,
+    .fgetxattr = local_fgetxattr,
 };
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
index dec4a861a073..074799027873 100644
--- a/hw/9pfs/9p-proxy.c
+++ b/hw/9pfs/9p-proxy.c
@@ -17,6 +17,7 @@
 #include "qemu/error-report.h"
 #include "fsdev/qemu-fsdev.h"
 #include "9p-proxy.h"
+#include "qemu/xattr.h"
 
 typedef struct V9fsProxy {
     int sockfd;
@@ -1006,6 +1007,16 @@ static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
     return retval;
 }
 
+static ssize_t proxy_fgetxattr(FsContext *ctx, int fid_type,
+                               V9fsFidOpenState *fs, const char *name,
+                               void *value, size_t size)
+{
+    int fd;
+
+    fd = v9fs_get_fd_fid(fid_type, fs);
+    return fgetxattr(fd, name, value, size);
+}
+
 static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
                                 void *value, size_t size)
 {
@@ -1251,4 +1262,5 @@ FileOperations proxy_ops = {
     .futimens     = proxy_futimens,
     .fchown       = proxy_fchown,
     .fchmod       = proxy_fchmod,
+    .fgetxattr    = proxy_fgetxattr,
 };
diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index ec2e301de8c6..24505fc2f621 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -464,6 +464,14 @@ static ssize_t synth_lgetxattr(FsContext *ctx, V9fsPath *path,
     return -1;
 }
 
+static ssize_t synth_fgetxattr(FsContext *ctx, int fid_type,
+                               V9fsFidOpenState *fs, const char *name,
+                               void *value, size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
 static ssize_t synth_llistxattr(FsContext *ctx, V9fsPath *path,
                                      void *value, size_t size)
 {
@@ -598,4 +606,5 @@ FileOperations synth_ops = {
     .futimens     = synth_futimens,
     .fchown       = synth_fchown,
     .fchmod       = synth_fchmod,
+    .fgetxattr    = synth_fgetxattr,
 };
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index d02f95634b97..435100f85be3 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -3115,6 +3115,16 @@ out_nofid:
     v9fs_string_free(&name);
 }
 
+static int v9fs_do_getxattr(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name,
+                            void *value, size_t size)
+{
+    if (fid_has_file(fidp)) {
+        return v9fs_co_fgetxattr(pdu, fidp, name, value, size);
+    } else {
+        return v9fs_co_lgetxattr(pdu, &fidp->path, name, value, size);
+    }
+}
+
 static void v9fs_xattrwalk(void *opaque)
 {
     int64_t size;
@@ -3181,10 +3191,9 @@ static void v9fs_xattrwalk(void *opaque)
     } else {
         /*
          * specific xattr fid. We check for xattr
-         * presence also collect the xattr size
+         * presence also collect the xattr size.
          */
-        size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
-                                 &name, NULL, 0);
+        size = v9fs_do_getxattr(pdu, xattr_fidp, &name, NULL, 0);
         if (size < 0) {
             err = size;
             clunk_fid(s, xattr_fidp->fid);
@@ -3196,9 +3205,9 @@ static void v9fs_xattrwalk(void *opaque)
         xattr_fidp->fs.xattr.len = size;
         if (size) {
             xattr_fidp->fs.xattr.value = g_malloc(size);
-            err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
-                                    &name, xattr_fidp->fs.xattr.value,
-                                    xattr_fidp->fs.xattr.len);
+            err = v9fs_do_getxattr(pdu, xattr_fidp, &name,
+                                   xattr_fidp->fs.xattr.value,
+                                   xattr_fidp->fs.xattr.len);
             if (err < 0) {
                 clunk_fid(s, xattr_fidp->fid);
                 goto out;
diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h
index ee819a7eed54..2e507939d01d 100644
--- a/hw/9pfs/coth.h
+++ b/hw/9pfs/coth.h
@@ -98,5 +98,7 @@ extern int v9fs_co_ftruncate(V9fsPDU *, V9fsFidState *, off_t);
 extern int v9fs_co_futimens(V9fsPDU *, V9fsFidState *, struct timespec [2]);
 extern int v9fs_co_fchown(V9fsPDU *, V9fsFidState *, uid_t, gid_t);
 extern int v9fs_co_fchmod(V9fsPDU *, V9fsFidState *, mode_t);
+extern int v9fs_co_fgetxattr(V9fsPDU *, V9fsFidState *, V9fsString *, void *,
+                             size_t);
 
 #endif
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index 133c4ead37b6..72e3f38fb371 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -61,6 +61,28 @@ int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path,
     return err;
 }
 
+int v9fs_co_fgetxattr(V9fsPDU *pdu, V9fsFidState *fidp,
+                      V9fsString *xattr_name,
+                      void *value, size_t size)
+{
+    int err;
+    V9fsState *s = pdu->s;
+
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->fgetxattr(&s->ctx, fidp->fid_type, &fidp->fs,
+                                    xattr_name->data,
+                                    value, size);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
 int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path,
                       V9fsString *xattr_name, void *value,
                       size_t size, int flags)
