summaryrefslogtreecommitdiff
path: root/sys/fs/puffs/puffs_sys.h
blob: c2e8d1e25d02c43f166ba23937b0a28fd1878659 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/*	$NetBSD: puffs_sys.h,v 1.89 2015/02/15 20:21:29 manu Exp $	*/

/*
 * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
 *
 * Development of this software was supported by the
 * Google Summer of Code program and the Ulla Tuominen Foundation.
 * The Google SoC project was mentored by Bill Studenmund.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef _PUFFS_SYS_H_
#define _PUFFS_SYS_H_

#include <sys/param.h>
#include <sys/select.h>
#include <sys/kauth.h>
#include <sys/mutex.h>
#include <sys/queue.h>
#include <sys/pool.h>

#include <fs/puffs/puffs_msgif.h>

#include <miscfs/genfs/genfs_node.h>

extern int (**puffs_vnodeop_p)(void *);
extern int (**puffs_specop_p)(void *);
extern int (**puffs_fifoop_p)(void *);

extern const struct vnodeopv_desc puffs_vnodeop_opv_desc;
extern const struct vnodeopv_desc puffs_specop_opv_desc;
extern const struct vnodeopv_desc puffs_fifoop_opv_desc;
extern const struct vnodeopv_desc puffs_msgop_opv_desc;

extern struct pool puffs_pnpool;
extern struct pool puffs_vapool;

#ifdef DEBUG
#ifndef PUFFSDEBUG
#define PUFFSDEBUG
#endif
#endif

#ifdef PUFFSDEBUG
extern int puffsdebug; /* puffs_subr.c */
#define DPRINTF(x) do { \
		if (puffsdebug > 0) printf x; \
	} while (/*CONSTCOND*/0)
#define DPRINTF_VERBOSE(x) do { \
		if (puffsdebug > 1) printf x; \
	} while (/*CONSTCOND*/0)
#else
#define DPRINTF(x) ((void)0)
#define DPRINTF_VERBOSE(x) ((void)0)
#endif

#define MPTOPUFFSMP(mp) ((struct puffs_mount *)((mp)->mnt_data))
#define PMPTOMP(pmp) (pmp->pmp_mp)
#define VPTOPP(vp) ((struct puffs_node *)(vp)->v_data)
#define VPTOPNC(vp) (((struct puffs_node *)(vp)->v_data)->pn_cookie)
#define VPTOPUFFSMP(vp) ((struct puffs_mount*)((struct puffs_node*)vp->v_data))

/* we don't pass the kernel overlay to userspace */
#define PUFFS_TOFHSIZE(s) ((s)==0 ? (s) : (s)+4)
#define PUFFS_FROMFHSIZE(s) ((s)==0 ? (s) : (s)-4)

#define ALLOPS(pmp) (pmp->pmp_flags & PUFFS_KFLAG_ALLOPS)
#define EXISTSOP(pmp, op) \
 (ALLOPS(pmp) || ((pmp)->pmp_vnopmask[PUFFS_VN_##op]))

#define PUFFS_USE_NAMECACHE(pmp)	\
    (((pmp)->pmp_flags & PUFFS_KFLAG_NOCACHE_NAME) == 0)
#define PUFFS_USE_PAGECACHE(pmp)	\
    (((pmp)->pmp_flags & PUFFS_KFLAG_NOCACHE_PAGE) == 0)
#define PUFFS_USE_FULLPNBUF(pmp)	\
    ((pmp)->pmp_flags & PUFFS_KFLAG_LOOKUP_FULLPNBUF)
#define PUFFS_USE_FS_TTL(pmp)	\
    ((pmp)->pmp_flags & PUFFS_KFLAG_CACHE_FS_TTL)
#define PUFFS_USE_DOTDOTCACHE(pmp)	\
    ((pmp)->pmp_flags & PUFFS_KFLAG_CACHE_DOTDOT)
#define PUFFS_USE_METAFLUSH(pmp)	\
    (((pmp)->pmp_flags & PUFFS_KFLAG_NOFLUSH_META) == 0)

#define PUFFS_WCACHEINFO(pmp)	(__USE(pmp), 0)

struct puffs_newcookie {
	puffs_cookie_t	pnc_cookie;

	LIST_ENTRY(puffs_newcookie) pnc_entries;
};

#define PUFFS_SOPREQ_EXPIRE_TIMEOUT 1000
extern int puffs_sopreq_expire_timeout;

enum puffs_sopreqtype {
	PUFFS_SOPREQSYS_EXIT,
	PUFFS_SOPREQ_FLUSH,
	PUFFS_SOPREQ_UNMOUNT,
	PUFFS_SOPREQ_EXPIRE,
};

struct puffs_sopreq {
	union {
		struct puffs_req preq;
		struct puffs_flush pf;
		puffs_cookie_t ck;
	} psopr_u;

	enum puffs_sopreqtype psopr_sopreq;
	TAILQ_ENTRY(puffs_sopreq) psopr_entries;
	int psopr_at;
};
#define psopr_preq psopr_u.preq
#define psopr_pf psopr_u.pf
#define psopr_ck psopr_u.ck

TAILQ_HEAD(puffs_wq, puffs_msgpark);
LIST_HEAD(puffs_node_hashlist, puffs_node);
struct puffs_mount {
	kmutex_t	 		pmp_lock;

	struct puffs_kargs		pmp_args;
#define pmp_flags pmp_args.pa_flags
#define pmp_vnopmask pmp_args.pa_vnopmask

	struct puffs_wq			pmp_msg_touser;
	int				pmp_msg_touser_count;
	kcondvar_t			pmp_msg_waiter_cv;
	size_t				pmp_msg_maxsize;

	struct puffs_wq			pmp_msg_replywait;

	struct mount			*pmp_mp;

	struct vnode			*pmp_root;
	puffs_cookie_t			pmp_root_cookie;
	enum vtype			pmp_root_vtype;
	vsize_t				pmp_root_vsize;
	dev_t				pmp_root_rdev;

	struct putter_instance		*pmp_pi;

	unsigned int			pmp_refcount;
	kcondvar_t			pmp_refcount_cv;

	kcondvar_t			pmp_unmounting_cv;
	uint8_t				pmp_unmounting;

	uint8_t				pmp_status;
	uint8_t				pmp_suspend;

	uint8_t				*pmp_curput;
	size_t				pmp_curres;
	void				*pmp_curopaq;

	uint64_t			pmp_nextmsgid;

	kmutex_t			pmp_sopmtx;
	kcondvar_t			pmp_sopcv;
	int				pmp_sopthrcount;
	TAILQ_HEAD(, puffs_sopreq)	pmp_sopfastreqs;
	TAILQ_HEAD(, puffs_sopreq)	pmp_sopnodereqs;
	bool				pmp_docompat;
};

#define PUFFSTAT_BEFOREINIT	0
#define PUFFSTAT_MOUNTING	1
#define PUFFSTAT_RUNNING	2
#define PUFFSTAT_DYING		3 /* Do you want your possessions identified? */


#define PNODE_NOREFS	0x001	/* no backend reference			*/
#define PNODE_DYING	0x002	/* NOREFS + inactive			*/
#define PNODE_FAF	0x004	/* issue all operations as FAF		*/
#define PNODE_DOINACT 	0x008	/* if inactive-on-demand, call inactive */
#define PNODE_SOPEXP	0x100	/* Node reclaim postponed in sop thread	*/
#define PNODE_RDIRECT	0x200	/* bypass page cache on read		*/
#define PNODE_WDIRECT	0x400	/* bypass page cache on write		*/

#define PNODE_METACACHE_ATIME	0x10	/* cache atime metadata */
#define PNODE_METACACHE_CTIME	0x20	/* cache atime metadata */
#define PNODE_METACACHE_MTIME	0x40	/* cache atime metadata */
#define PNODE_METACACHE_SIZE	0x80	/* cache atime metadata */
#define PNODE_METACACHE_MASK	0xf0

struct puffs_node {
	struct genfs_node pn_gnode;	/* genfs glue			*/

	kmutex_t	pn_mtx;
	int		pn_refcount;
	int		pn_nlookup;

	puffs_cookie_t	pn_cookie;	/* userspace pnode cookie	*/
	struct vnode	*pn_vp;		/* backpointer to vnode		*/
	uint32_t	pn_stat;	/* node status			*/

	struct selinfo	pn_sel;		/* for selecting on the node	*/
	short		pn_revents;	/* available events		*/

	/* metacache */
	struct timespec	pn_mc_atime;
	struct timespec	pn_mc_ctime;
	struct timespec	pn_mc_mtime;
	u_quad_t	pn_mc_size;

	voff_t		pn_serversize;

	struct lockf *	pn_lockf;

	kmutex_t	pn_sizemtx;	/* size modification mutex	*/
	
	int		pn_cn_timeout;	/* path cache */
	int		pn_cn_grace;	/* grace time before reclaim */
	int		pn_va_timeout;	/* attribute cache */
	struct vattr *	pn_va_cache;	/* attribute cache */
	struct vnode *  pn_parent;	/* parent cache */
};

typedef void (*parkdone_fn)(struct puffs_mount *, struct puffs_req *, void *);

struct puffs_msgpark;
void	puffs_msgif_init(void);
void	puffs_msgif_destroy(void);
int	puffs_msgmem_alloc(size_t, struct puffs_msgpark **, void **, int);
void	puffs_msgmem_release(struct puffs_msgpark *);

void	puffs_sop_thread(void *);

void	puffs_msg_setfaf(struct puffs_msgpark *);
void	puffs_msg_setdelta(struct puffs_msgpark *, size_t);
void	puffs_msg_setinfo(struct puffs_msgpark *, int, int, puffs_cookie_t);
void	puffs_msg_setcall(struct puffs_msgpark *, parkdone_fn, void *);

void	puffs_msg_enqueue(struct puffs_mount *, struct puffs_msgpark *);
int	puffs_msg_wait(struct puffs_mount *, struct puffs_msgpark *);
int	puffs_msg_wait2(struct puffs_mount *, struct puffs_msgpark *,
			struct puffs_node *, struct puffs_node *);

void	puffs_msg_sendresp(struct puffs_mount *, struct puffs_req *, int);

int	puffs_getvnode(struct mount *, puffs_cookie_t, enum vtype,
		       voff_t, dev_t, struct vnode **);
int	puffs_newnode(struct mount *, struct vnode *, struct vnode **,
		      puffs_cookie_t, struct componentname *,
		      enum vtype, dev_t);
void	puffs_putvnode(struct vnode *);

void	puffs_releasenode(struct puffs_node *);
void	puffs_referencenode(struct puffs_node *);

#define PUFFS_NOSUCHCOOKIE (-1)
int	puffs_cookie2vnode(struct puffs_mount *, puffs_cookie_t,
			   struct vnode **);
void	puffs_makecn(struct puffs_kcn *, struct puffs_kcred *,
		     const struct componentname *, int);
void	puffs_credcvt(struct puffs_kcred *, kauth_cred_t);

void	puffs_parkdone_asyncbioread(struct puffs_mount *,
				    struct puffs_req *, void *);
void	puffs_parkdone_asyncbiowrite(struct puffs_mount *,
				     struct puffs_req *, void *);
void	puffs_parkdone_poll(struct puffs_mount *, struct puffs_req *, void *);

void	puffs_mp_reference(struct puffs_mount *);
void	puffs_mp_release(struct puffs_mount *);

void	puffs_gop_size(struct vnode *, off_t, off_t *, int); 
void	puffs_gop_markupdate(struct vnode *, int);

void	puffs_senderr(struct puffs_mount *, int, int, const char *,
		      puffs_cookie_t);

bool	puffs_compat_outgoing(struct puffs_req *, struct puffs_req**, ssize_t*);
void	puffs_compat_incoming(struct puffs_req *, struct puffs_req *);

void	puffs_updatenode(struct puffs_node *, int, voff_t);
#define PUFFS_UPDATEATIME	0x01
#define PUFFS_UPDATECTIME	0x02
#define PUFFS_UPDATEMTIME	0x04
#define PUFFS_UPDATESIZE	0x08

void	puffs_userdead(struct puffs_mount *);

extern int (**puffs_vnodeop_p)(void *);

/* for putter */
int	puffs_msgif_getout(void *, size_t, int, uint8_t **, size_t *, void **);
void	puffs_msgif_releaseout(void *, void *, int);
int	puffs_msgif_dispatch(void *, struct putter_hdr *);
size_t	puffs_msgif_waitcount(void *);
int	puffs_msgif_close(void *);

static __inline int
checkerr(struct puffs_mount *pmp, int error, const char *str)
{

	if (error < 0 || error > ELAST) {
		puffs_senderr(pmp, PUFFS_ERR_ERROR, error, str, NULL);
		error = EPROTO;
	}

	return error;
}

#define PUFFS_MSG_VARS(type, a)						\
	struct puffs_##type##msg_##a *a##_msg;				\
	struct puffs_msgpark *park_##a = NULL

#define PUFFS_MSG_ALLOC(type, a)					\
	puffs_msgmem_alloc(sizeof(struct puffs_##type##msg_##a),	\
	    &park_##a, (void *)& a##_msg, 1)

#define PUFFS_MSG_RELEASE(a) 						\
do {									\
	if (park_##a) puffs_msgmem_release(park_##a);			\
} while (/*CONSTCOND*/0)

#define PUFFS_MSG_ENQUEUEWAIT_NOERROR(pmp, park)			\
do {									\
	puffs_msg_enqueue(pmp, park);					\
	puffs_msg_wait(pmp, park);					\
} while (/*CONSTCOND*/0)

#define PUFFS_MSG_ENQUEUEWAIT2_NOERROR(pmp, park, vp1, vp2)		\
do {									\
	puffs_msg_enqueue(pmp, park);					\
	puffs_msg_wait2(pmp, park, vp1, vp2);				\
} while (/*CONSTCOND*/0)

#define PUFFS_MSG_ENQUEUEWAIT(pmp, park, var)				\
do {									\
	puffs_msg_enqueue(pmp, park);					\
	var = puffs_msg_wait(pmp, park);				\
} while (/*CONSTCOND*/0)

#define PUFFS_MSG_ENQUEUEWAIT2(pmp, park, vp1, vp2, var)		\
do {									\
	puffs_msg_enqueue(pmp, park);					\
	var = puffs_msg_wait2(pmp, park, vp1, vp2);			\
} while (/*CONSTCOND*/0)

#endif /* _PUFFS_SYS_H_ */