xref: /openbmc/qemu/hw/9pfs/cofile.c (revision 14a650ec)
1 
2 /*
3  * Virtio 9p backend
4  *
5  * Copyright IBM, Corp. 2011
6  *
7  * Authors:
8  *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2.  See
11  * the COPYING file in the top-level directory.
12  *
13  */
14 
15 #include "fsdev/qemu-fsdev.h"
16 #include "qemu/thread.h"
17 #include "block/coroutine.h"
18 #include "virtio-9p-coth.h"
19 
20 int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
21                    V9fsStatDotl *v9stat)
22 {
23     int err = 0;
24     V9fsState *s = pdu->s;
25 
26     if (v9fs_request_cancelled(pdu)) {
27         return -EINTR;
28     }
29     if (s->ctx.exops.get_st_gen) {
30         v9fs_path_read_lock(s);
31         v9fs_co_run_in_worker(
32             {
33                 err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode,
34                                               &v9stat->st_gen);
35                 if (err < 0) {
36                     err = -errno;
37                 }
38             });
39         v9fs_path_unlock(s);
40     }
41     /* The ioctl may not be supported depending on the path */
42     if (err == -ENOTTY) {
43         err = 0;
44     }
45     return err;
46 }
47 
48 int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
49 {
50     int err;
51     V9fsState *s = pdu->s;
52 
53     if (v9fs_request_cancelled(pdu)) {
54         return -EINTR;
55     }
56     v9fs_path_read_lock(s);
57     v9fs_co_run_in_worker(
58         {
59             err = s->ops->lstat(&s->ctx, path, stbuf);
60             if (err < 0) {
61                 err = -errno;
62             }
63         });
64     v9fs_path_unlock(s);
65     return err;
66 }
67 
68 int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
69 {
70     int err;
71     V9fsState *s = pdu->s;
72 
73     if (v9fs_request_cancelled(pdu)) {
74         return -EINTR;
75     }
76     v9fs_co_run_in_worker(
77         {
78             err = s->ops->fstat(&s->ctx, fidp->fid_type, &fidp->fs, stbuf);
79             if (err < 0) {
80                 err = -errno;
81             }
82         });
83     /*
84      * Some FS driver (local:mapped-file) can't support fetching attributes
85      * using file descriptor. Use Path name in that case.
86      */
87     if (err == -EOPNOTSUPP) {
88         err = v9fs_co_lstat(pdu, &fidp->path, stbuf);
89         if (err == -ENOENT) {
90             /*
91              * fstat on an unlinked file. Work with partial results
92              * returned from s->ops->fstat
93              */
94             err = 0;
95         }
96     }
97     return err;
98 }
99 
100 int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
101 {
102     int err;
103     V9fsState *s = pdu->s;
104 
105     if (v9fs_request_cancelled(pdu)) {
106         return -EINTR;
107     }
108     v9fs_path_read_lock(s);
109     v9fs_co_run_in_worker(
110         {
111             err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
112             if (err == -1) {
113                 err = -errno;
114             } else {
115                 err = 0;
116             }
117         });
118     v9fs_path_unlock(s);
119     if (!err) {
120         total_open_fd++;
121         if (total_open_fd > open_fd_hw) {
122             v9fs_reclaim_fd(pdu);
123         }
124     }
125     return err;
126 }
127 
128 int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
129                   int flags, int mode, struct stat *stbuf)
130 {
131     int err;
132     FsCred cred;
133     V9fsPath path;
134     V9fsState *s = pdu->s;
135 
136     if (v9fs_request_cancelled(pdu)) {
137         return -EINTR;
138     }
139     cred_init(&cred);
140     cred.fc_mode = mode & 07777;
141     cred.fc_uid = fidp->uid;
142     cred.fc_gid = gid;
143     /*
144      * Hold the directory fid lock so that directory path name
145      * don't change. Read lock is fine because this fid cannot
146      * be used by any other operation.
147      */
148     v9fs_path_read_lock(s);
149     v9fs_co_run_in_worker(
150         {
151             err = s->ops->open2(&s->ctx, &fidp->path,
152                                 name->data, flags, &cred, &fidp->fs);
153             if (err < 0) {
154                 err = -errno;
155             } else {
156                 v9fs_path_init(&path);
157                 err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
158                 if (!err) {
159                     err = s->ops->lstat(&s->ctx, &path, stbuf);
160                     if (err < 0) {
161                         err = -errno;
162                         s->ops->close(&s->ctx, &fidp->fs);
163                     } else {
164                         v9fs_path_copy(&fidp->path, &path);
165                     }
166                 } else {
167                     s->ops->close(&s->ctx, &fidp->fs);
168                 }
169                 v9fs_path_free(&path);
170             }
171         });
172     v9fs_path_unlock(s);
173     if (!err) {
174         total_open_fd++;
175         if (total_open_fd > open_fd_hw) {
176             v9fs_reclaim_fd(pdu);
177         }
178     }
179     return err;
180 }
181 
182 int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
183 {
184     int err;
185     V9fsState *s = pdu->s;
186 
187     if (v9fs_request_cancelled(pdu)) {
188         return -EINTR;
189     }
190     v9fs_co_run_in_worker(
191         {
192             err = s->ops->close(&s->ctx, fs);
193             if (err < 0) {
194                 err = -errno;
195             }
196         });
197     if (!err) {
198         total_open_fd--;
199     }
200     return err;
201 }
202 
203 int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
204 {
205     int err;
206     V9fsState *s = pdu->s;
207 
208     if (v9fs_request_cancelled(pdu)) {
209         return -EINTR;
210     }
211     v9fs_co_run_in_worker(
212         {
213             err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync);
214             if (err < 0) {
215                 err = -errno;
216             }
217         });
218     return err;
219 }
220 
221 int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
222                  V9fsFidState *newdirfid, V9fsString *name)
223 {
224     int err;
225     V9fsState *s = pdu->s;
226 
227     if (v9fs_request_cancelled(pdu)) {
228         return -EINTR;
229     }
230     v9fs_path_read_lock(s);
231     v9fs_co_run_in_worker(
232         {
233             err = s->ops->link(&s->ctx, &oldfid->path,
234                                &newdirfid->path, name->data);
235             if (err < 0) {
236                 err = -errno;
237             }
238         });
239     v9fs_path_unlock(s);
240     return err;
241 }
242 
243 int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
244                     struct iovec *iov, int iovcnt, int64_t offset)
245 {
246     int err;
247     V9fsState *s = pdu->s;
248 
249     if (v9fs_request_cancelled(pdu)) {
250         return -EINTR;
251     }
252     v9fs_co_run_in_worker(
253         {
254             err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
255             if (err < 0) {
256                 err = -errno;
257             }
258         });
259     return err;
260 }
261 
262 int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
263                    struct iovec *iov, int iovcnt, int64_t offset)
264 {
265     int err;
266     V9fsState *s = pdu->s;
267 
268     if (v9fs_request_cancelled(pdu)) {
269         return -EINTR;
270     }
271     v9fs_co_run_in_worker(
272         {
273             err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
274             if (err < 0) {
275                 err = -errno;
276             }
277         });
278     return err;
279 }
280