1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * 9P Client Definitions |
4 | * |
5 | * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> |
6 | * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> |
7 | */ |
8 | |
9 | #ifndef NET_9P_CLIENT_H |
10 | #define NET_9P_CLIENT_H |
11 | |
12 | #include <linux/utsname.h> |
13 | #include <linux/idr.h> |
14 | #include <linux/tracepoint-defs.h> |
15 | |
16 | /* Number of requests per row */ |
17 | #define P9_ROW_MAXTAG 255 |
18 | |
19 | /** enum p9_proto_versions - 9P protocol versions |
20 | * @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u |
21 | * @p9_proto_2000u: 9P2000.u extension |
22 | * @p9_proto_2000L: 9P2000.L extension |
23 | */ |
24 | |
25 | enum p9_proto_versions { |
26 | p9_proto_legacy, |
27 | p9_proto_2000u, |
28 | p9_proto_2000L, |
29 | }; |
30 | |
31 | |
32 | /** |
33 | * enum p9_trans_status - different states of underlying transports |
34 | * @Connected: transport is connected and healthy |
35 | * @Disconnected: transport has been disconnected |
36 | * @Hung: transport is connected by wedged |
37 | * |
38 | * This enumeration details the various states a transport |
39 | * instatiation can be in. |
40 | */ |
41 | |
42 | enum p9_trans_status { |
43 | Connected, |
44 | BeginDisconnect, |
45 | Disconnected, |
46 | Hung, |
47 | }; |
48 | |
49 | /** |
50 | * enum p9_req_status_t - status of a request |
51 | * @REQ_STATUS_ALLOC: request has been allocated but not sent |
52 | * @REQ_STATUS_UNSENT: request waiting to be sent |
53 | * @REQ_STATUS_SENT: request sent to server |
54 | * @REQ_STATUS_RCVD: response received from server |
55 | * @REQ_STATUS_FLSHD: request has been flushed |
56 | * @REQ_STATUS_ERROR: request encountered an error on the client side |
57 | */ |
58 | |
59 | enum p9_req_status_t { |
60 | REQ_STATUS_ALLOC, |
61 | REQ_STATUS_UNSENT, |
62 | REQ_STATUS_SENT, |
63 | REQ_STATUS_RCVD, |
64 | REQ_STATUS_FLSHD, |
65 | REQ_STATUS_ERROR, |
66 | }; |
67 | |
68 | /** |
69 | * struct p9_req_t - request slots |
70 | * @status: status of this request slot |
71 | * @t_err: transport error |
72 | * @wq: wait_queue for the client to block on for this request |
73 | * @tc: the request fcall structure |
74 | * @rc: the response fcall structure |
75 | * @req_list: link for higher level objects to chain requests |
76 | */ |
77 | struct p9_req_t { |
78 | int status; |
79 | int t_err; |
80 | refcount_t refcount; |
81 | wait_queue_head_t wq; |
82 | struct p9_fcall tc; |
83 | struct p9_fcall rc; |
84 | struct list_head req_list; |
85 | }; |
86 | |
87 | /** |
88 | * struct p9_client - per client instance state |
89 | * @lock: protect @fids and @reqs |
90 | * @msize: maximum data size negotiated by protocol |
91 | * @proto_version: 9P protocol version to use |
92 | * @trans_mod: module API instantiated with this client |
93 | * @status: connection state |
94 | * @trans: tranport instance state and API |
95 | * @fids: All active FID handles |
96 | * @reqs: All active requests. |
97 | * @name: node name used as client id |
98 | * |
99 | * The client structure is used to keep track of various per-client |
100 | * state that has been instantiated. |
101 | */ |
102 | struct p9_client { |
103 | spinlock_t lock; |
104 | unsigned int msize; |
105 | unsigned char proto_version; |
106 | struct p9_trans_module *trans_mod; |
107 | enum p9_trans_status status; |
108 | void *trans; |
109 | struct kmem_cache *fcall_cache; |
110 | |
111 | union { |
112 | struct { |
113 | int rfd; |
114 | int wfd; |
115 | } fd; |
116 | struct { |
117 | u16 port; |
118 | bool privport; |
119 | |
120 | } tcp; |
121 | } trans_opts; |
122 | |
123 | struct idr fids; |
124 | struct idr reqs; |
125 | |
126 | char name[__NEW_UTS_LEN + 1]; |
127 | }; |
128 | |
129 | /** |
130 | * struct p9_fid - file system entity handle |
131 | * @clnt: back pointer to instantiating &p9_client |
132 | * @fid: numeric identifier for this handle |
133 | * @mode: current mode of this fid (enum?) |
134 | * @qid: the &p9_qid server identifier this handle points to |
135 | * @iounit: the server reported maximum transaction size for this file |
136 | * @uid: the numeric uid of the local user who owns this handle |
137 | * @rdir: readdir accounting structure (allocated on demand) |
138 | * @dlist: per-dentry fid tracking |
139 | * |
140 | * TODO: This needs lots of explanation. |
141 | */ |
142 | enum fid_source { |
143 | FID_FROM_OTHER, |
144 | FID_FROM_INODE, |
145 | FID_FROM_DENTRY, |
146 | }; |
147 | |
148 | struct p9_fid { |
149 | struct p9_client *clnt; |
150 | u32 fid; |
151 | refcount_t count; |
152 | int mode; |
153 | struct p9_qid qid; |
154 | u32 iounit; |
155 | kuid_t uid; |
156 | |
157 | void *rdir; |
158 | |
159 | struct hlist_node dlist; /* list of all fids attached to a dentry */ |
160 | struct hlist_node ilist; |
161 | }; |
162 | |
163 | /** |
164 | * struct p9_dirent - directory entry structure |
165 | * @qid: The p9 server qid for this dirent |
166 | * @d_off: offset to the next dirent |
167 | * @d_type: type of file |
168 | * @d_name: file name |
169 | */ |
170 | |
171 | struct p9_dirent { |
172 | struct p9_qid qid; |
173 | u64 d_off; |
174 | unsigned char d_type; |
175 | char d_name[256]; |
176 | }; |
177 | |
178 | struct iov_iter; |
179 | |
180 | int p9_show_client_options(struct seq_file *m, struct p9_client *clnt); |
181 | int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); |
182 | int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, |
183 | const char *name); |
184 | int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, |
185 | struct p9_fid *newdirfid, const char *new_name); |
186 | struct p9_client *p9_client_create(const char *dev_name, char *options); |
187 | void p9_client_destroy(struct p9_client *clnt); |
188 | void p9_client_disconnect(struct p9_client *clnt); |
189 | void p9_client_begin_disconnect(struct p9_client *clnt); |
190 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, |
191 | const char *uname, kuid_t n_uname, const char *aname); |
192 | struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, |
193 | const unsigned char * const *wnames, int clone); |
194 | int p9_client_open(struct p9_fid *fid, int mode); |
195 | int p9_client_fcreate(struct p9_fid *fid, const char *name, u32 perm, int mode, |
196 | char *extension); |
197 | int p9_client_link(struct p9_fid *fid, struct p9_fid *oldfid, const char *newname); |
198 | int p9_client_symlink(struct p9_fid *fid, const char *name, const char *symname, |
199 | kgid_t gid, struct p9_qid *qid); |
200 | int p9_client_create_dotl(struct p9_fid *ofid, const char *name, u32 flags, u32 mode, |
201 | kgid_t gid, struct p9_qid *qid); |
202 | int p9_client_clunk(struct p9_fid *fid); |
203 | int p9_client_fsync(struct p9_fid *fid, int datasync); |
204 | int p9_client_remove(struct p9_fid *fid); |
205 | int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags); |
206 | int p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err); |
207 | int p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, |
208 | int *err); |
209 | int p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err); |
210 | int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset); |
211 | int p9dirent_read(struct p9_client *clnt, char *buf, int len, |
212 | struct p9_dirent *dirent); |
213 | struct p9_wstat *p9_client_stat(struct p9_fid *fid); |
214 | int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); |
215 | int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *attr); |
216 | |
217 | struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, |
218 | u64 request_mask); |
219 | |
220 | int p9_client_mknod_dotl(struct p9_fid *oldfid, const char *name, int mode, |
221 | dev_t rdev, kgid_t gid, struct p9_qid *qid); |
222 | int p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode, |
223 | kgid_t gid, struct p9_qid *qid); |
224 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status); |
225 | int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl); |
226 | void p9_fcall_fini(struct p9_fcall *fc); |
227 | struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag); |
228 | |
229 | static inline void p9_req_get(struct p9_req_t *r) |
230 | { |
231 | refcount_inc(r: &r->refcount); |
232 | } |
233 | |
234 | static inline int p9_req_try_get(struct p9_req_t *r) |
235 | { |
236 | return refcount_inc_not_zero(r: &r->refcount); |
237 | } |
238 | |
239 | int p9_req_put(struct p9_client *c, struct p9_req_t *r); |
240 | |
241 | /* We cannot have the real tracepoints in header files, |
242 | * use a wrapper function */ |
243 | DECLARE_TRACEPOINT(9p_fid_ref); |
244 | void do_trace_9p_fid_get(struct p9_fid *fid); |
245 | void do_trace_9p_fid_put(struct p9_fid *fid); |
246 | |
247 | /* fid reference counting helpers: |
248 | * - fids used for any length of time should always be referenced through |
249 | * p9_fid_get(), and released with p9_fid_put() |
250 | * - v9fs_fid_lookup() or similar will automatically call get for you |
251 | * and also require a put |
252 | * - the *_fid_add() helpers will stash the fid in the inode, |
253 | * at which point it is the responsibility of evict_inode() |
254 | * to call the put |
255 | * - the last put will automatically send a clunk to the server |
256 | */ |
257 | static inline struct p9_fid *p9_fid_get(struct p9_fid *fid) |
258 | { |
259 | if (tracepoint_enabled(9p_fid_ref)) |
260 | do_trace_9p_fid_get(fid); |
261 | |
262 | refcount_inc(r: &fid->count); |
263 | |
264 | return fid; |
265 | } |
266 | |
267 | static inline int p9_fid_put(struct p9_fid *fid) |
268 | { |
269 | if (!fid || IS_ERR(ptr: fid)) |
270 | return 0; |
271 | |
272 | if (tracepoint_enabled(9p_fid_ref)) |
273 | do_trace_9p_fid_put(fid); |
274 | |
275 | if (!refcount_dec_and_test(r: &fid->count)) |
276 | return 0; |
277 | |
278 | return p9_client_clunk(fid); |
279 | } |
280 | |
281 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status); |
282 | |
283 | int (struct p9_fcall *pdu, int32_t *size, int8_t *type, |
284 | int16_t *tag, int rewind); |
285 | int p9stat_read(struct p9_client *clnt, char *buf, int len, |
286 | struct p9_wstat *st); |
287 | void p9stat_free(struct p9_wstat *stbuf); |
288 | |
289 | int p9_is_proto_dotu(struct p9_client *clnt); |
290 | int p9_is_proto_dotl(struct p9_client *clnt); |
291 | struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, |
292 | const char *attr_name, u64 *attr_size); |
293 | int p9_client_xattrcreate(struct p9_fid *fid, const char *name, |
294 | u64 attr_size, int flags); |
295 | int p9_client_readlink(struct p9_fid *fid, char **target); |
296 | |
297 | int p9_client_init(void); |
298 | void p9_client_exit(void); |
299 | |
300 | #endif /* NET_9P_CLIENT_H */ |
301 | |