xref: /openbmc/qemu/hw/9pfs/cofile.c (revision 54d50be6)
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, V9fsFidState *fidp, 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, &fidp->fs, 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             err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
94             if (err == -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             err = s->ops->open2(&s->ctx, &fidp->path,
134                                 name->data, flags, &cred, &fidp->fs);
135             if (err < 0) {
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);
145                     } else {
146                         v9fs_path_copy(&fidp->path, &path);
147                     }
148                 } else {
149                     s->ops->close(&s->ctx, &fidp->fs);
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, V9fsFidOpenState *fs)
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, fs);
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 err;
188     V9fsState *s = pdu->s;
189 
190     if (v9fs_request_cancelled(pdu)) {
191         return -EINTR;
192     }
193     v9fs_co_run_in_worker(
194         {
195             err = s->ops->fsync(&s->ctx, &fidp->fs, datasync);
196             if (err < 0) {
197                 err = -errno;
198             }
199         });
200     return err;
201 }
202 
203 int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
204                  V9fsFidState *newdirfid, V9fsString *name)
205 {
206     int err;
207     V9fsState *s = pdu->s;
208 
209     if (v9fs_request_cancelled(pdu)) {
210         return -EINTR;
211     }
212     v9fs_path_read_lock(s);
213     v9fs_co_run_in_worker(
214         {
215             err = s->ops->link(&s->ctx, &oldfid->path,
216                                &newdirfid->path, name->data);
217             if (err < 0) {
218                 err = -errno;
219             }
220         });
221     v9fs_path_unlock(s);
222     return err;
223 }
224 
225 int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
226                     struct iovec *iov, int iovcnt, int64_t offset)
227 {
228     int err;
229     V9fsState *s = pdu->s;
230 
231     if (v9fs_request_cancelled(pdu)) {
232         return -EINTR;
233     }
234     v9fs_co_run_in_worker(
235         {
236             err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
237             if (err < 0) {
238                 err = -errno;
239             }
240         });
241     return err;
242 }
243 
244 int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
245                    struct iovec *iov, int iovcnt, int64_t offset)
246 {
247     int err;
248     V9fsState *s = pdu->s;
249 
250     if (v9fs_request_cancelled(pdu)) {
251         return -EINTR;
252     }
253     v9fs_co_run_in_worker(
254         {
255             err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
256             if (err < 0) {
257                 err = -errno;
258             }
259         });
260     return err;
261 }
262