xref: /openbmc/qemu/hw/9pfs/cofile.c (revision 7cd393ac1db87a5268173ce2286a4283c9e7a4a9)
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 "qemu-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     return err;
42 }
43 
44 int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
45 {
46     int err;
47     V9fsState *s = pdu->s;
48 
49     if (v9fs_request_cancelled(pdu)) {
50         return -EINTR;
51     }
52     v9fs_path_read_lock(s);
53     v9fs_co_run_in_worker(
54         {
55             err = s->ops->lstat(&s->ctx, path, stbuf);
56             if (err < 0) {
57                 err = -errno;
58             }
59         });
60     v9fs_path_unlock(s);
61     return err;
62 }
63 
64 int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
65 {
66     int err;
67     V9fsState *s = pdu->s;
68 
69     if (v9fs_request_cancelled(pdu)) {
70         return -EINTR;
71     }
72     v9fs_co_run_in_worker(
73         {
74             err = s->ops->fstat(&s->ctx, fd, stbuf);
75             if (err < 0) {
76                 err = -errno;
77             }
78         });
79     return err;
80 }
81 
82 int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
83 {
84     int err;
85     V9fsState *s = pdu->s;
86 
87     if (v9fs_request_cancelled(pdu)) {
88         return -EINTR;
89     }
90     v9fs_path_read_lock(s);
91     v9fs_co_run_in_worker(
92         {
93             fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
94             if (fidp->fs.fd == -1) {
95                 err = -errno;
96             } else {
97                 err = 0;
98             }
99         });
100     v9fs_path_unlock(s);
101     if (!err) {
102         total_open_fd++;
103         if (total_open_fd > open_fd_hw) {
104             v9fs_reclaim_fd(pdu);
105         }
106     }
107     return err;
108 }
109 
110 int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
111                   int flags, int mode, struct stat *stbuf)
112 {
113     int err;
114     FsCred cred;
115     V9fsPath path;
116     V9fsState *s = pdu->s;
117 
118     if (v9fs_request_cancelled(pdu)) {
119         return -EINTR;
120     }
121     cred_init(&cred);
122     cred.fc_mode = mode & 07777;
123     cred.fc_uid = fidp->uid;
124     cred.fc_gid = gid;
125     /*
126      * Hold the directory fid lock so that directory path name
127      * don't change. Read lock is fine because this fid cannot
128      * be used by any other operation.
129      */
130     v9fs_path_read_lock(s);
131     v9fs_co_run_in_worker(
132         {
133             fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
134                                         name->data, flags, &cred);
135             if (fidp->fs.fd == -1) {
136                 err = -errno;
137             } else {
138                 v9fs_path_init(&path);
139                 err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
140                 if (!err) {
141                     err = s->ops->lstat(&s->ctx, &path, stbuf);
142                     if (err < 0) {
143                         err = -errno;
144                         s->ops->close(&s->ctx, fidp->fs.fd);
145                     } else {
146                         v9fs_path_copy(&fidp->path, &path);
147                     }
148                 } else {
149                     s->ops->close(&s->ctx, fidp->fs.fd);
150                 }
151                 v9fs_path_free(&path);
152             }
153         });
154     v9fs_path_unlock(s);
155     if (!err) {
156         total_open_fd++;
157         if (total_open_fd > open_fd_hw) {
158             v9fs_reclaim_fd(pdu);
159         }
160     }
161     return err;
162 }
163 
164 int v9fs_co_close(V9fsPDU *pdu, int fd)
165 {
166     int err;
167     V9fsState *s = pdu->s;
168 
169     if (v9fs_request_cancelled(pdu)) {
170         return -EINTR;
171     }
172     v9fs_co_run_in_worker(
173         {
174             err = s->ops->close(&s->ctx, fd);
175             if (err < 0) {
176                 err = -errno;
177             }
178         });
179     if (!err) {
180         total_open_fd--;
181     }
182     return err;
183 }
184 
185 int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
186 {
187     int fd, err;
188     V9fsState *s = pdu->s;
189 
190     if (v9fs_request_cancelled(pdu)) {
191         return -EINTR;
192     }
193     fd = fidp->fs.fd;
194     v9fs_co_run_in_worker(
195         {
196             err = s->ops->fsync(&s->ctx, fd, datasync);
197             if (err < 0) {
198                 err = -errno;
199             }
200         });
201     return err;
202 }
203 
204 int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
205                  V9fsFidState *newdirfid, V9fsString *name)
206 {
207     int err;
208     V9fsState *s = pdu->s;
209 
210     if (v9fs_request_cancelled(pdu)) {
211         return -EINTR;
212     }
213     v9fs_path_read_lock(s);
214     v9fs_co_run_in_worker(
215         {
216             err = s->ops->link(&s->ctx, &oldfid->path,
217                                &newdirfid->path, name->data);
218             if (err < 0) {
219                 err = -errno;
220             }
221         });
222     v9fs_path_unlock(s);
223     return err;
224 }
225 
226 int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
227                     struct iovec *iov, int iovcnt, int64_t offset)
228 {
229     int fd, err;
230     V9fsState *s = pdu->s;
231 
232     if (v9fs_request_cancelled(pdu)) {
233         return -EINTR;
234     }
235     fd = fidp->fs.fd;
236     v9fs_co_run_in_worker(
237         {
238             err = s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
239             if (err < 0) {
240                 err = -errno;
241             }
242         });
243     return err;
244 }
245 
246 int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
247                    struct iovec *iov, int iovcnt, int64_t offset)
248 {
249     int fd, err;
250     V9fsState *s = pdu->s;
251 
252     if (v9fs_request_cancelled(pdu)) {
253         return -EINTR;
254     }
255     fd = fidp->fs.fd;
256     v9fs_co_run_in_worker(
257         {
258             err = s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
259             if (err < 0) {
260                 err = -errno;
261             }
262         });
263     return err;
264 }
265