summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/fs/sdev_impl.h
blob: 7bf24fb96a24e59f6b2fca931672641879940d56 (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
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_SDEV_IMPL_H
#define	_SYS_SDEV_IMPL_H

#ifdef __cplusplus
extern "C" {
#endif

#include <rpc/rpc.h>
#include <sys/dirent.h>
#include <sys/vfs.h>
#include <sys/vfs_opreg.h>
#include <sys/list.h>
#include <sys/nvpair.h>

/*
 * sdev_nodes are the file-system specific part of the
 * vnodes for the device filesystem.
 *
 * The device filesystem exports two node types:
 *
 * VDIR nodes		to represent directories
 * VCHR & VBLK nodes	to represent devices
 */

/*
 * /dev mount arguments
 */
struct sdev_mountargs {
	uint64_t sdev_attrdir;
};


/*
 * Nvpair names of profile information (list of device files available) of
 * non-global /dev mounts.  These strings must be unique among them.
 */
#define	SDEV_NVNAME_MOUNTPT	"prof_mountpt"
#define	SDEV_NVNAME_INCLUDE	"prof_include"
#define	SDEV_NVNAME_EXCLUDE	"prof_exclude"
#define	SDEV_NVNAME_SYMLINK	"prof_symlink"
#define	SDEV_NVNAME_MAP		"prof_map"

/*
 * supported devfsadm_cmd
 */
#define	DEVFSADMD_RUN_ALL	1
#define	DEVFSADMD_NS_LOOKUP	2
#define	DEVFSADMD_NS_READDIR	3

/*
 * supported protocols
 */
typedef enum devname_spec {
	DEVNAME_NS_NONE = 0,
	DEVNAME_NS_PATH,	/* physical /devices path */
	DEVNAME_NS_DEV		/* /dev path */
} devname_spec_t;

/*
 * devfsadm_error codes
 */
#define	DEVFSADM_RUN_INVALID		1
#define	DEVFSADM_RUN_EPERM		2
#define	DEVFSADM_RUN_NOTSUP		3
#define	DEVFSADM_NS_FAILED		4

typedef struct sdev_ns_handle {
	char	ns_name[MAXPATHLEN];	/* device to be looked up */
	char	ns_map[MAXPATHLEN];
} sdev_ns_handle_t;

typedef struct sdev_lkp_handle {
	devname_spec_t	devfsadm_spec;	/* returned path property */
	char	devfsadm_link[MAXPATHLEN]; /* symlink destination */
} sdev_lkp_handle_t;

typedef struct sdev_rdr_handle {
	uint32_t ns_mapcount;	/* number of entries in the map */
	uint32_t maplist_size;
} sdev_rdr_handle_t;

/*
 * devfsadm/devname door data structures
 */
typedef struct sdev_door_arg {
	uint8_t devfsadm_cmd;	/* what to do for devfsadm[d] */
	sdev_ns_handle_t ns_hdl;
} sdev_door_arg_t;

typedef struct sdev_door_res {
	int32_t devfsadm_error;
	sdev_lkp_handle_t ns_lkp_hdl;
	sdev_rdr_handle_t ns_rdr_hdl;
} sdev_door_res_t;

#ifdef _KERNEL

struct sdev_dprof {
	int has_glob;
	nvlist_t *dev_name;
	nvlist_t *dev_map;
	nvlist_t *dev_symlink;
	nvlist_t *dev_glob_incdir;
	nvlist_t *dev_glob_excdir;
};

/*
 * devname_handle_t
 */
struct devname_handle {
	struct sdev_node *dh_data;	/* the sdev_node */
	devname_spec_t dh_spec;
	void    *dh_args;
};
typedef struct devname_handle devname_handle_t;

/*
 * Per-instance node data for the global zone instance
 * Only one mount of /dev in the global zone
 */
typedef struct sdev_global_data {
	struct devname_handle sdev_ghandle;
	struct devname_nsmap *sdev_gmapinfo;	/* VDIR name service info */
	ulong_t		sdev_dir_ggen;		/* name space generation # */
} sdev_global_data_t;

/*
 * Per-instance node data - profile data per non-global zone mount instance
 */
typedef struct sdev_local_data {
	ulong_t sdev_dir_lgen;		/* cached generation # of /dev dir */
	ulong_t sdev_devtree_lgen;	/* cached generation # of devtree */
	struct sdev_node *sdev_lorigin;	/* corresponding global sdev_node */
	struct sdev_dprof sdev_lprof;	/* profile for multi-inst */
} sdev_local_data_t;

/*
 * /dev filesystem sdev_node defines
 */
typedef struct sdev_node {
	char		*sdev_name;	/* node name */
	size_t		sdev_namelen;	/* strlen(sdev_name) */
	char		*sdev_path;	/* absolute path */
	char		*sdev_symlink;	/* source for a symlink */
	struct vnode	*sdev_vnode;	/* vnode */

	krwlock_t	sdev_contents;	/* rw lock for this data structure */
	struct sdev_node *sdev_dotdot;	/* parent */

	avl_tree_t	sdev_entries;	/* VDIR: contents as avl tree */
	avl_node_t	sdev_avllink;	/* avl node linkage */

	struct vnode	*sdev_attrvp;	/* backing store vnode if persisted */
	struct vattr	*sdev_attr;	/* memory copy of the vattr */

	ino64_t		sdev_ino;	/* inode */
	uint_t		sdev_nlink;	/* link count */
	int		sdev_state;	/* state of this node */
	int		sdev_flags;	/* flags bit */

	kmutex_t	sdev_lookup_lock; /* node creation synch lock */
	kcondvar_t	sdev_lookup_cv;	/* node creation sync cv */
	int		sdev_lookup_flags; /* node creation flags */

	/* per-instance data, either global or non-global zone */
	union {
		struct sdev_global_data	sdev_globaldata;
		struct sdev_local_data	sdev_localdata;
	} sdev_instance_data;

	void		*sdev_private;
} sdev_node_t;

#define	sdev_ldata sdev_instance_data.sdev_localdata
#define	sdev_gdata sdev_instance_data.sdev_globaldata

#define	sdev_handle		sdev_gdata.sdev_ghandle
#define	sdev_mapinfo		sdev_gdata.sdev_gmapinfo
#define	sdev_gdir_gen		sdev_gdata.sdev_dir_ggen

#define	sdev_ldir_gen		sdev_ldata.sdev_dir_lgen
#define	sdev_devtree_gen	sdev_ldata.sdev_devtree_lgen
#define	sdev_origin		sdev_ldata.sdev_lorigin
#define	sdev_prof		sdev_ldata.sdev_lprof

/*
 * Directory contents traversal
 */
#define	SDEV_FIRST_ENTRY(ddv)		avl_first(&(ddv)->sdev_entries)
#define	SDEV_NEXT_ENTRY(ddv, dv)	AVL_NEXT(&(ddv)->sdev_entries, (dv))

/*
 * sdev_state
 *
 * A sdev_node may go through 3 states:
 *	SDEV_INIT: When a new /dev file is first looked up, a sdev_node
 *		   is allocated, initialized and added to the directory's
 *		   sdev_node cache. A node at this state will also
 *		   have the SDEV_LOOKUP flag set.
 *
 *		   Other threads that are trying to look up a node at
 *		   this state will be blocked until the SDEV_LOOKUP flag
 *		   is cleared.
 *
 *		   When the SDEV_LOOKUP flag is cleared, the node may
 *		   transition into the SDEV_READY state for a successful
 *		   lookup or the node is removed from the directory cache
 *		   and destroyed if the named node can not be found.
 *		   An ENOENT error is returned for the second case.
 *
 *	SDEV_READY: A /dev file has been successfully looked up and
 *		    associated with a vnode. The /dev file is available
 *		    for the supported /dev filesystem operations.
 *
 *	SDEV_ZOMBIE: Deletion of a /dev file has been explicitely issued
 *		    to an SDEV_READY node. The node is transitioned into
 *		    the SDEV_ZOMBIE state if the vnode reference count
 *		    is still held. A SDEV_ZOMBIE node does not support
 *		    any of the /dev filesystem operations. A SDEV_ZOMBIE
 *		    node is removed from the directory cache and destroyed
 *		    once the reference count reaches "zero".
 */
typedef enum {
	SDEV_ZOMBIE = -1,
	SDEV_INIT = 0,
	SDEV_READY
} sdev_node_state_t;

/* sdev_flags */
#define	SDEV_BUILD		0x0001	/* directory cache out-of-date */
#define	SDEV_STALE		0x0002	/* stale sdev nodes */
#define	SDEV_GLOBAL		0x0004	/* global /dev nodes */
#define	SDEV_PERSIST		0x0008	/* backing store persisted node */
#define	SDEV_NO_NCACHE		0x0010	/* do not include in neg. cache */
#define	SDEV_DYNAMIC		0x0020	/* special-purpose vnode ops */
					/* (ex: pts) */
#define	SDEV_VTOR		0x0040	/* validate sdev_nodes during search */
#define	SDEV_ATTR_INVALID	0x0080	/* invalid node attributes, */
					/* need update */

/* sdev_lookup_flags */
#define	SDEV_LOOKUP	0x0001	/* node creation in progress */
#define	SDEV_READDIR	0x0002	/* VDIR readdir in progress */
#define	SDEV_LGWAITING	0x0004	/* waiting for devfsadm completion */

#define	SDEV_VTOR_INVALID	-1
#define	SDEV_VTOR_SKIP		0
#define	SDEV_VTOR_VALID		1

/* convenient macros */
#define	SDEV_IS_GLOBAL(dv)	\
	(dv->sdev_flags & SDEV_GLOBAL)
#define	SDEV_IS_PERSIST(dv)	\
	(dv->sdev_flags & SDEV_PERSIST)
#define	SDEV_IS_DYNAMIC(dv)	\
	(dv->sdev_flags & SDEV_DYNAMIC)
#define	SDEV_IS_NO_NCACHE(dv)	\
	(dv->sdev_flags & SDEV_NO_NCACHE)

#define	SDEV_IS_LOOKUP(dv)	\
	(dv->sdev_lookup_flags & SDEV_LOOKUP)
#define	SDEV_IS_READDIR(dv)	\
	(dv->sdev_lookup_flags & SDEV_READDIR)
#define	SDEV_IS_LGWAITING(dv)	\
	(dv->sdev_lookup_flags  & SDEV_LGWAITING)

#define	SDEVTOV(n)	((struct vnode *)(n)->sdev_vnode)
#define	VTOSDEV(vp)	((struct sdev_node *)(vp)->v_data)
#define	VN_HELD(v)	((v)->v_count != 0)
#define	SDEV_HELD(dv)	(VN_HELD(SDEVTOV(dv)))
#define	SDEV_HOLD(dv)	VN_HOLD(SDEVTOV(dv))
#define	SDEV_RELE(dv)	VN_RELE(SDEVTOV(dv))
#define	SDEV_SIMPLE_RELE(dv)	{	\
	mutex_enter(&SDEVTOV(dv)->v_lock);	\
	SDEVTOV(dv)->v_count--;	\
	mutex_exit(&SDEVTOV(dv)->v_lock);	\
}

#define	SDEV_ACL_FLAVOR(vp)	(VFSTOSDEVFS(vp->v_vfsp)->sdev_acl_flavor)

/*
 * some defaults
 */
#define	SDEV_ROOTINO		((ino_t)2)
#define	SDEV_UID_DEFAULT	(0)
#define	SDEV_GID_DEFAULT	(3)
#define	SDEV_DIRMODE_DEFAULT	(S_IFDIR |0755)
#define	SDEV_DEVMODE_DEFAULT	(0600)
#define	SDEV_LNKMODE_DEFAULT	(S_IFLNK | 0777)

extern struct vattr sdev_vattr_dir;
extern struct vattr sdev_vattr_lnk;
extern struct vattr sdev_vattr_blk;
extern struct vattr sdev_vattr_chr;

/*
 * devname_lookup_func()
 */
extern int devname_lookup_func(struct sdev_node *, char *, struct vnode **,
    struct cred *, int (*)(struct sdev_node *, char *, void **, struct cred *,
    void *, char *), int);

/*
 * flags used by devname_lookup_func callbacks
 */
#define	SDEV_PATH	0x1	/* callback returning /devices physical path */
#define	SDEV_VNODE	0x2	/* callback returning backing store vnode */
#define	SDEV_VATTR	0x4	/* callback returning node vattr */
#define	SDEV_VLINK	0x8	/* callback returning /dev link */

/*
 * devname_readdir_func()
 */
extern int devname_readdir_func(vnode_t *, uio_t *, cred_t *, int *, int);

/*
 * flags for devname_readdir_func
 */
#define	SDEV_BROWSE	0x1	/* fetch all entries from backing store */

/*
 * devname_setattr_func()
 */
extern int devname_setattr_func(struct vnode *, struct vattr *, int,
    struct cred *, int (*)(struct sdev_node *, struct vattr *, int), int);

/*
 * devname_inactive_func()
 */
extern void devname_inactive_func(struct vnode *, struct cred *,
    void (*)(struct vnode *));

/*
 * /dev file system instance defines
 */
/*
 * /dev version of vfs_data
 */
struct sdev_data {
	struct sdev_data	*sdev_prev;
	struct sdev_data	*sdev_next;
	struct sdev_node	*sdev_root;
	struct vfs		*sdev_vfsp;
	struct sdev_mountargs	*sdev_mountargs;
	ulong_t			sdev_acl_flavor;
};

#define	VFSTOSDEVFS(vfsp)	((struct sdev_data *)((vfsp)->vfs_data))

/*
 * sdev_fid overlays the fid structure (for VFS_VGET)
 */
struct sdev_fid {
	uint16_t	sdevfid_len;
	ino32_t		sdevfid_ino;
	int32_t		sdevfid_gen;
};

/*
 * devfsadm and devname communication defines
 */
typedef enum {
	DEVNAME_DEVFSADM_STOPPED = 0,	/* devfsadm has never run */
	DEVNAME_DEVFSADM_RUNNING,	/* devfsadm is running */
	DEVNAME_DEVFSADM_RUN		/* devfsadm ran once */
} devname_devfsadm_state_t;

extern volatile uint_t  devfsadm_state; /* atomic mask for devfsadm status */

#define	DEVNAME_DEVFSADM_SET_RUNNING(devfsadm_state)	\
	devfsadm_state = DEVNAME_DEVFSADM_RUNNING
#define	DEVNAME_DEVFSADM_SET_STOP(devfsadm_state)	\
	devfsadm_state = DEVNAME_DEVFSADM_STOPPED
#define	DEVNAME_DEVFSADM_SET_RUN(devfsadm_state)	\
	devfsadm_state = DEVNAME_DEVFSADM_RUN
#define	DEVNAME_DEVFSADM_IS_RUNNING(devfsadm_state)	\
	devfsadm_state == DEVNAME_DEVFSADM_RUNNING
#define	DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state)	\
	(devfsadm_state == DEVNAME_DEVFSADM_RUN)

#define	SDEV_BLOCK_OTHERS(dv, cmd)	{	\
	ASSERT(MUTEX_HELD(&dv->sdev_lookup_lock));	\
	dv->sdev_lookup_flags |= cmd;			\
}
extern void sdev_unblock_others(struct sdev_node *, uint_t);
#define	SDEV_UNBLOCK_OTHERS(dv, cmd)	{	\
	sdev_unblock_others(dv, cmd);		\
}

#define	SDEV_CLEAR_LOOKUP_FLAGS(dv, cmd)	{	\
	dv->sdev_lookup_flags &= ~cmd;	\
}

extern int sdev_wait4lookup(struct sdev_node *, int);
extern int devname_filename_register(int, char *);
extern int devname_nsmaps_register(char *, size_t);
extern void sdev_devfsadm_lockinit(void);
extern void sdev_devfsadm_lockdestroy(void);
extern void devname_add_devfsadm_node(char *);
extern void sdev_devfsadmd_thread(struct sdev_node *, struct sdev_node *,
    struct cred *);
extern int devname_profile_update(char *, size_t);
extern struct sdev_data *sdev_find_mntinfo(char *);
void sdev_mntinfo_rele(struct sdev_data *);
extern struct vnodeops *devpts_getvnodeops(void);
extern struct vnodeops *devvt_getvnodeops(void);

/*
 * Directory Based Device Naming (DBNR) defines
 */

#define	ETC_DEV_DIR		"/etc/dev"
#define	DEVNAME_NSCONFIG	"sdev_nsconfig_mod"

/*
 * directory name rule
 */
struct devname_nsmap {
	struct devname_nsmap	*prev;	/* previous entry */
	struct devname_nsmap	*next;	/* next entry */
	char	*dir_name;	/* /dev subdir name, e.g. /dev/disk */
	char	*dir_module;	/* devname module impl the operations */
	char	*dir_map;	/* dev naming rules, e.g. /etc/dev/disks */
	struct devname_ops *dir_ops;	/* directory specific vnode ops */
	char    *dir_newmodule; /* to be reloaded  */
	char    *dir_newmap;    /* to be reloaded */
	int	dir_invalid;    /* map entry obsolete */
	int	dir_maploaded;	/* map contents read */
	krwlock_t dir_lock;	/* protects the data structure */
};

/*
 * name-property pairs to be looked up
 */
typedef struct devname_lkp_arg {
	char *devname_dir;	/* the directory to look */
	char *devname_name;	/* the device name to be looked up */
	char *devname_map;	/* the directory device naming map */
	int reserved;
} devname_lkp_arg_t;

/*
 * name-value-property restured
 */
typedef struct devname_lkp_result {
	devname_spec_t	devname_spec;	/* link to /devices or /dev */
	char	*devname_link;		/* the source path */
	int	reserved;
} devname_lkp_result_t;

/*
 * directory name-value populating results
 */
typedef struct devname_rdr_result {
	uint32_t	ns_mapcount;
} devname_rdr_result_t;

/*
 * sdev_nsrdr work
 */
typedef struct sdev_nsrdr_work {
	char *dir_name;
	char *dir_map;
	struct sdev_node *dir_dv;
	devname_rdr_result_t **result;
	struct sdev_nsrdr_work *next;
} sdev_nsrdr_work_t;


/*
 * boot states - warning, the ordering here is significant
 *
 * the difference between "system available" and "boot complete"
 * is a debounce timeout to catch some daemon issuing a readdir
 * triggering a nuisance implict reconfig on each boot.
 */
#define	SDEV_BOOT_STATE_INITIAL		0
#define	SDEV_BOOT_STATE_RECONFIG	1	/* reconfig */
#define	SDEV_BOOT_STATE_SYSAVAIL	2	/* system available */
#define	SDEV_BOOT_STATE_COMPLETE	3	/* boot complete */

/*
 * Negative cache list and list element
 * The mutex protects the flags against multiple accesses and
 * must only be acquired when already holding the r/w lock.
 */
typedef struct sdev_nc_list {
	list_t		ncl_list;	/* the list itself */
	kmutex_t	ncl_mutex;	/* protects ncl_flags */
	krwlock_t	ncl_lock;	/* protects ncl_list */
	int		ncl_flags;
	int		ncl_nentries;
} sdev_nc_list_t;

typedef struct sdev_nc_node {
	char		*ncn_name;	/* name of the node */
	int		ncn_flags;	/* state information */
	int		ncn_expirecnt;	/* remove once expired */
	list_node_t	ncn_link;	/* link to next in list */
} sdev_nc_node_t;

/* ncl_flags */
#define	NCL_LIST_DIRTY		0x01	/* needs to be flushed */
#define	NCL_LIST_WRITING	0x02	/* write in progress */
#define	NCL_LIST_WENABLE	0x04	/* write-enabled post boot */

/* ncn_flags */
#define	NCN_ACTIVE	0x01	/* a lookup has occurred */
#define	NCN_SRC_STORE	0x02	/* src: persistent store */
#define	NCN_SRC_CURRENT	0x04	/* src: current boot */

/* sdev_lookup_failed flags */
#define	SLF_NO_NCACHE	0x01	/* node should not be added to ncache */
#define	SLF_REBUILT	0x02	/* reconfig performed during lookup attempt */

/*
 * The nvlist name and nvpair identifiers in the
 * /etc/devices/devname_cache nvlist format
 */
#define	DP_DEVNAME_ID			"devname"
#define	DP_DEVNAME_NCACHE_ID		"ncache"
#define	DP_DEVNAME_NC_EXPIRECNT_ID	"expire-counts"

/* devname-cache list element */
typedef struct nvp_devname {
	char			**nvp_paths;
	int			*nvp_expirecnts;
	int			nvp_npaths;
	list_node_t		nvp_link;
} nvp_devname_t;

/*
 * name service globals and prototypes
 */

extern struct devname_ops *devname_ns_ops;
extern int devname_nsmaps_loaded;
extern kmutex_t devname_nsmaps_lock;

extern void sdev_invalidate_nsmaps(void);
extern void sdev_validate_nsmaps(void);
extern int sdev_module_register(char *, struct devname_ops *);
extern struct devname_nsmap *sdev_get_nsmap_by_dir(char *, int);
extern struct devname_nsmap *sdev_get_nsmap_by_module(char *);
extern void sdev_dispatch_to_nsrdr_thread(struct sdev_node *, char *,
    devname_rdr_result_t *);
extern void sdev_insert_nsmap(char *, char *, char *);
extern int devname_nsmap_lookup(devname_lkp_arg_t *, devname_lkp_result_t **);
extern struct devname_nsmap *sdev_get_map(struct sdev_node *, int);
extern int sdev_nsmaps_loaded(void);
extern void sdev_replace_nsmap(struct devname_nsmap *, char *, char *);
extern int sdev_nsmaps_reloaded(void);
extern int devname_get_dir_nsmap(devname_handle_t *, struct devname_nsmap **);

/*
 * vnodeops and vfsops helpers
 */

typedef enum {
	SDEV_CACHE_ADD = 0,
	SDEV_CACHE_DELETE
} sdev_cache_ops_t;

extern struct sdev_node *sdev_cache_lookup(struct sdev_node *, char *);
extern int sdev_cache_update(struct sdev_node *, struct sdev_node **, char *,
    sdev_cache_ops_t);
extern void sdev_node_cache_init(void);
extern void sdev_node_cache_fini(void);
extern struct sdev_node *sdev_mkroot(struct vfs *, dev_t, struct vnode *,
    struct vnode *, struct cred *);
extern void sdev_filldir_dynamic(struct sdev_node *);
extern int sdev_mknode(struct sdev_node *, char *, struct sdev_node **,
    struct vattr *, struct vnode *, void *, struct cred *, sdev_node_state_t);
extern int sdev_nodeinit(struct sdev_node *, char *, struct sdev_node **,
    vattr_t *);
extern int sdev_nodeready(struct sdev_node *, vattr_t *, vnode_t *, void *,
    cred_t *);
extern int sdev_shadow_node(struct sdev_node *, struct cred *);
extern void sdev_nodedestroy(struct sdev_node *, uint_t);
extern void sdev_update_timestamps(struct vnode *, cred_t *, uint_t);
extern void sdev_vattr_merge(struct sdev_node *, struct vattr *);
extern void sdev_devstate_change(void);
extern int sdev_lookup_filter(sdev_node_t *, char *);
extern void sdev_lookup_failed(sdev_node_t *, char *, int);
extern int sdev_unlocked_access(void *, int, struct cred *);

#define	SDEV_ENFORCE	0x1
extern void sdev_stale(struct sdev_node *);
extern int sdev_cleandir(struct sdev_node *, char *, uint_t);
extern int sdev_rnmnode(struct sdev_node *, struct sdev_node *,
    struct sdev_node *, struct sdev_node **, char *, struct cred *);
extern size_t add_dir_entry(dirent64_t *, char *, size_t, ino_t, offset_t);
extern int sdev_to_vp(struct sdev_node *, struct vnode **);
extern ino_t sdev_mkino(struct sdev_node *);
extern int devname_backstore_lookup(struct sdev_node *, char *,
    struct vnode **);
extern int sdev_is_devfs_node(char *);
extern int sdev_copyin_mountargs(struct mounta *, struct sdev_mountargs *);
extern int sdev_reserve_subdirs(struct sdev_node *);
extern int prof_lookup();
extern void prof_filldir(struct sdev_node *);
extern int devpts_validate(struct sdev_node *dv);
extern int devnet_validate(struct sdev_node *dv);
extern int devvt_validate(struct sdev_node *dv);
extern void *sdev_get_vtor(struct sdev_node *dv);

/*
 * devinfo helpers
 */
extern int sdev_modctl_readdir(const char *, char ***, int *, int *, int);
extern void sdev_modctl_readdir_free(char **, int, int);
extern int sdev_modctl_devexists(const char *);

/*
 * ncache handlers
 */

extern void sdev_ncache_init(void);
extern void sdev_ncache_setup(void);
extern void sdev_ncache_teardown(void);
extern void sdev_nc_addname(sdev_nc_list_t *, sdev_node_t *, char *, int);
extern void sdev_nc_node_exists(sdev_node_t *);
extern void sdev_nc_path_exists(sdev_nc_list_t *, char *);
extern void sdev_modctl_dump_files(void);

/*
 * globals
 */
extern kmutex_t sdev_lock;
extern int devtype;
extern kmem_cache_t *sdev_node_cache;
extern struct vnodeops		*sdev_vnodeops;
extern struct vnodeops		*devpts_vnodeops;
extern struct vnodeops		*devnet_vnodeops;
extern struct vnodeops		*devvt_vnodeops;
extern struct sdev_data *sdev_origins; /* mount info for global /dev instance */
extern const fs_operation_def_t	sdev_vnodeops_tbl[];
extern const fs_operation_def_t	devpts_vnodeops_tbl[];
extern const fs_operation_def_t	devnet_vnodeops_tbl[];
extern const fs_operation_def_t	devvt_vnodeops_tbl[];
extern const fs_operation_def_t	devsys_vnodeops_tbl[];
extern const fs_operation_def_t	devpseudo_vnodeops_tbl[];

extern sdev_nc_list_t	*sdev_ncache;
extern int		sdev_reconfig_boot;
extern int		sdev_boot_state;
extern int		sdev_reconfig_verbose;
extern int		sdev_reconfig_disable;
extern int		sdev_nc_disable;
extern int		sdev_nc_disable_reset;
extern int		sdev_nc_verbose;

/*
 * misc. defines
 */
#ifdef DEBUG
extern int sdev_debug;
#define	SDEV_DEBUG		0x01	/* error messages to console/log */
#define	SDEV_DEBUG_VOPS 	0x02	/* vnode ops errors */
#define	SDEV_DEBUG_DLF		0x04	/* trace devname_lookup_func */
#define	SDEV_DEBUG_DRF		0x08	/* trace devname_readdir_func */
#define	SDEV_DEBUG_NCACHE	0x10	/* negative cache tracing */
#define	SDEV_DEBUG_DEVFSADMD	0x20	/* comm. of devnamefs & devfsadm */
#define	SDEV_DEBUG_PTS		0x40	/* /dev/pts tracing */
#define	SDEV_DEBUG_RECONFIG	0x80	/* events triggering reconfig */
#define	SDEV_DEBUG_SDEV_NODE	0x100	/* trace sdev_node activities */
#define	SDEV_DEBUG_PROFILE	0x200	/* trace sdev_profile */
#define	SDEV_DEBUG_MODCTL	0x400	/* trace modctl activity */
#define	SDEV_DEBUG_FLK		0x800	/* trace failed lookups */
#define	SDEV_DEBUG_NET		0x1000	/* /dev/net tracing */

#define	sdcmn_err(args)  if (sdev_debug & SDEV_DEBUG) printf args
#define	sdcmn_err2(args) if (sdev_debug & SDEV_DEBUG_VOPS) printf args
#define	sdcmn_err3(args) if (sdev_debug & SDEV_DEBUG_DLF) printf args
#define	sdcmn_err4(args) if (sdev_debug & SDEV_DEBUG_DRF) printf args
#define	sdcmn_err5(args) if (sdev_debug & SDEV_DEBUG_NCACHE) printf args
#define	sdcmn_err6(args) if (sdev_debug & SDEV_DEBUG_DEVFSADMD) printf args
#define	sdcmn_err7(args) if (sdev_debug & SDEV_DEBUG_PTS) printf args
#define	sdcmn_err8(args) if (sdev_debug & SDEV_DEBUG_RECONFIG) printf args
#define	sdcmn_err9(args) if (sdev_debug & SDEV_DEBUG_SDEV_NODE) printf args
#define	sdcmn_err10(args) if (sdev_debug & SDEV_DEBUG_PROFILE) printf args
#define	sdcmn_err11(args) if (sdev_debug & SDEV_DEBUG_MODCTL) printf args
#define	sdcmn_err12(args) if (sdev_debug & SDEV_DEBUG_NET) printf args
#define	impossible(args) printf args
#else
#define	sdcmn_err(args)		/* does nothing */
#define	sdcmn_err2(args)	/* does nothing */
#define	sdcmn_err3(args)	/* does nothing */
#define	sdcmn_err4(args)	/* does nothing */
#define	sdcmn_err5(args)	/* does nothing */
#define	sdcmn_err6(args)	/* does nothing */
#define	sdcmn_err7(args)	/* does nothing */
#define	sdcmn_err8(args)	/* does nothing */
#define	sdcmn_err9(args)	/* does nothing */
#define	sdcmn_err10(args)	/* does nothing */
#define	sdcmn_err11(args)	/* does nothing */
#define	sdcmn_err12(args)	/* does nothing */
#define	impossible(args)	/* does nothing */
#endif

#ifdef DEBUG
#define	SD_TRACE_FAILED_LOOKUP(ddv, nm, retried)			\
	if ((sdev_debug & SDEV_DEBUG_FLK) ||				\
	    ((retried) && (sdev_debug & SDEV_DEBUG_RECONFIG))) {	\
		printf("lookup of %s/%s by %s failed, line %d\n",	\
		    (ddv)->sdev_name, (nm), curproc->p_user.u_comm,	\
		    __LINE__);						\
	}
#else
#define	SD_TRACE_FAILED_LOOKUP(ddv, nm, retried)
#endif

#endif	/* _KERNEL */

#ifdef __cplusplus
}
#endif

#endif	/* _SYS_SDEV_IMPL_H */