1b94833c4SAndreas Jaekel #include <sys/modctl.h>
2b94833c4SAndreas Jaekel #include <sys/ddi.h>
3b94833c4SAndreas Jaekel #include <sys/sunddi.h>
4b94833c4SAndreas Jaekel #include <sys/conf.h>
5b94833c4SAndreas Jaekel #include <sys/devops.h>
6b94833c4SAndreas Jaekel #include <sys/stat.h>
7b94833c4SAndreas Jaekel #include <sys/zfs_znode.h>
8b94833c4SAndreas Jaekel #include <sys/time.h>
9b94833c4SAndreas Jaekel #include <sys/sa.h>
10b94833c4SAndreas Jaekel #include <sys/zap.h>
11b94833c4SAndreas Jaekel #include <sys/time.h>
12b94833c4SAndreas Jaekel #include <sys/dsl_dataset.h>
13b94833c4SAndreas Jaekel #include <sys/zfs_vfsops.h>
14b94833c4SAndreas Jaekel #include <sys/dmu.h>
15b94833c4SAndreas Jaekel #include <sys/dmu_objset.h>
16b94833c4SAndreas Jaekel #include <sys/dsl_dir.h>
17b94833c4SAndreas Jaekel
18b94833c4SAndreas Jaekel #include <getgen/getgen.h>
19b94833c4SAndreas Jaekel
20b94833c4SAndreas Jaekel /* per-instance context */
21b94833c4SAndreas Jaekel typedef struct gg_state {
22b94833c4SAndreas Jaekel kmutex_t mutex;
23b94833c4SAndreas Jaekel dev_info_t *dip;
24b94833c4SAndreas Jaekel boolean_t busy;
25b94833c4SAndreas Jaekel } gg_state_t;
26b94833c4SAndreas Jaekel
27b94833c4SAndreas Jaekel static void *statep;
28b94833c4SAndreas Jaekel static kmutex_t gg_mutex;
29b94833c4SAndreas Jaekel static int gg_instances = 0;
30b94833c4SAndreas Jaekel
31b94833c4SAndreas Jaekel int
gg_ioc_get_gen(intptr_t arg,int mode)32b94833c4SAndreas Jaekel gg_ioc_get_gen(intptr_t arg, int mode)
33b94833c4SAndreas Jaekel {
34b94833c4SAndreas Jaekel gg_ioctl_get_generation_t gg;
35b94833c4SAndreas Jaekel file_t *fp;
36b94833c4SAndreas Jaekel uint64_t gen;
37b94833c4SAndreas Jaekel uint64_t crtime[2];
38b94833c4SAndreas Jaekel int ret = 0;
3913f02022SAndreas Jaekel zfsvfs_t *zfsvfs = NULL;
40b94833c4SAndreas Jaekel objset_t *osp;
41b94833c4SAndreas Jaekel sa_attr_type_t *sa_table;
42b94833c4SAndreas Jaekel sa_handle_t *hdl;
43b94833c4SAndreas Jaekel dmu_buf_t *db;
44b94833c4SAndreas Jaekel sa_bulk_attr_t bulk[2];
45b94833c4SAndreas Jaekel int count = 0;
46b94833c4SAndreas Jaekel dmu_object_info_t doi;
47b94833c4SAndreas Jaekel timestruc_t crtime_s;
4813f02022SAndreas Jaekel znode_t *zp;
49*6af38117SDavid Hanisch dsl_dataset_phys_t *ds_phys;
50b94833c4SAndreas Jaekel
51b94833c4SAndreas Jaekel if (ddi_copyin((void *)arg, &gg, sizeof(gg), mode) != 0)
52b94833c4SAndreas Jaekel return EFAULT;
53b94833c4SAndreas Jaekel fp = getf(gg.fd);
54b94833c4SAndreas Jaekel if (fp == NULL)
55b94833c4SAndreas Jaekel return EBADF;
56b94833c4SAndreas Jaekel if (fp->f_vnode->v_vfsp->vfs_fstype != zfsfstype) {
57b94833c4SAndreas Jaekel ret = EINVAL;
58b94833c4SAndreas Jaekel goto out;
59b94833c4SAndreas Jaekel }
60b94833c4SAndreas Jaekel
6113f02022SAndreas Jaekel zp = (znode_t *)fp->f_vnode->v_data;
6213f02022SAndreas Jaekel /* modified version of ZFS_ENTER() macro - we need to clean up fp */
6313f02022SAndreas Jaekel zfsvfs = zp->z_zfsvfs;
6413f02022SAndreas Jaekel rrm_enter_read(&zfsvfs->z_teardown_lock, FTAG);
6513f02022SAndreas Jaekel if (zp->z_zfsvfs->z_unmounted) {
6613f02022SAndreas Jaekel ret = EIO;
6713f02022SAndreas Jaekel goto out;
6813f02022SAndreas Jaekel }
6913f02022SAndreas Jaekel /* modified version of ZFS_VERIFY_ZP() macro */
7013f02022SAndreas Jaekel if (zp->z_sa_hdl == NULL) {
7113f02022SAndreas Jaekel ret = EIO;
7213f02022SAndreas Jaekel goto out;
7313f02022SAndreas Jaekel }
74*6af38117SDavid Hanisch ds_phys = dsl_dataset_phys(zfsvfs->z_os->os_dsl_dataset);
7513f02022SAndreas Jaekel
76b94833c4SAndreas Jaekel /* get dataset name */
77b94833c4SAndreas Jaekel dsl_dataset_name(zfsvfs->z_os->os_dsl_dataset, gg.dataset);
78b94833c4SAndreas Jaekel
79b94833c4SAndreas Jaekel /* get guid */
80*6af38117SDavid Hanisch gg.guid = ds_phys->ds_guid;
81b94833c4SAndreas Jaekel
82*6af38117SDavid Hanisch if (gg.inode != 0) {
83b94833c4SAndreas Jaekel /* get generation and crtime */
84b94833c4SAndreas Jaekel osp = zfsvfs->z_os;
85*6af38117SDavid Hanisch ret = sa_setup(osp, gg.inode, zfs_attr_table, ZPL_END,
86*6af38117SDavid Hanisch &sa_table);
87b94833c4SAndreas Jaekel if (ret)
88b94833c4SAndreas Jaekel goto out;
89b94833c4SAndreas Jaekel ret = sa_buf_hold(osp, gg.inode, FTAG, &db);
90b94833c4SAndreas Jaekel if (ret)
91b94833c4SAndreas Jaekel goto out;
92b94833c4SAndreas Jaekel dmu_object_info_from_db(db, &doi);
93b94833c4SAndreas Jaekel if ((doi.doi_bonus_type != DMU_OT_SA &&
94b94833c4SAndreas Jaekel doi.doi_bonus_type != DMU_OT_ZNODE) ||
95b94833c4SAndreas Jaekel doi.doi_bonus_type == DMU_OT_ZNODE &&
96b94833c4SAndreas Jaekel doi.doi_bonus_size < sizeof (znode_phys_t)) {
97b94833c4SAndreas Jaekel sa_buf_rele(db, FTAG);
98b94833c4SAndreas Jaekel ret = ENOTSUP;
99b94833c4SAndreas Jaekel goto out;
100b94833c4SAndreas Jaekel }
101b94833c4SAndreas Jaekel ret = sa_handle_get(osp, gg.inode, NULL, SA_HDL_PRIVATE, &hdl);
102b94833c4SAndreas Jaekel if (ret) {
103b94833c4SAndreas Jaekel sa_buf_rele(db, FTAG);
104b94833c4SAndreas Jaekel goto out;
105b94833c4SAndreas Jaekel }
106b94833c4SAndreas Jaekel SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_GEN], NULL,
107b94833c4SAndreas Jaekel &gen, sizeof(gen));
108b94833c4SAndreas Jaekel SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_CRTIME], NULL,
109b94833c4SAndreas Jaekel &crtime, sizeof(crtime));
110b94833c4SAndreas Jaekel ret = sa_bulk_lookup(hdl, bulk, count);
111b94833c4SAndreas Jaekel sa_handle_destroy(hdl);
112b94833c4SAndreas Jaekel sa_buf_rele(db, FTAG);
113b94833c4SAndreas Jaekel if (ret)
114b94833c4SAndreas Jaekel goto out;
115b94833c4SAndreas Jaekel ZFS_TIME_DECODE(&crtime_s, crtime);
116b94833c4SAndreas Jaekel gg.generation = gen;
117b94833c4SAndreas Jaekel gg.crtime = crtime_s.tv_sec;
118*6af38117SDavid Hanisch } else {
119*6af38117SDavid Hanisch gg.generation = ds_phys->ds_bp.blk_birth;
120*6af38117SDavid Hanisch gg.crtime = 0;
121*6af38117SDavid Hanisch }
122b94833c4SAndreas Jaekel
123b94833c4SAndreas Jaekel ddi_copyout(&gg, (void *)arg, sizeof(gg), mode);
124b94833c4SAndreas Jaekel out:
12513f02022SAndreas Jaekel if (zfsvfs)
12613f02022SAndreas Jaekel ZFS_EXIT(zfsvfs);
127b94833c4SAndreas Jaekel releasef(gg.fd);
128b94833c4SAndreas Jaekel return ret;
129b94833c4SAndreas Jaekel }
130b94833c4SAndreas Jaekel
131b94833c4SAndreas Jaekel /* ARGSUSED */
132b94833c4SAndreas Jaekel static int
gg_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)133b94833c4SAndreas Jaekel gg_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
134b94833c4SAndreas Jaekel {
135b94833c4SAndreas Jaekel int instance;
136b94833c4SAndreas Jaekel
137b94833c4SAndreas Jaekel instance = getminor(dev);
138b94833c4SAndreas Jaekel if (ddi_get_soft_state(statep, instance) == NULL)
139b94833c4SAndreas Jaekel return (ENXIO);
140b94833c4SAndreas Jaekel /*
141b94833c4SAndreas Jaekel * all structures passed between kernel and userspace
142b94833c4SAndreas Jaekel * are compatible between 64 and 32 bit. Model
143b94833c4SAndreas Jaekel * conversion can be ignored.
144b94833c4SAndreas Jaekel */
145b94833c4SAndreas Jaekel switch (cmd) {
146b94833c4SAndreas Jaekel case GG_IOC_GET_GENERATION:
147b94833c4SAndreas Jaekel return gg_ioc_get_gen(arg, mode);
148b94833c4SAndreas Jaekel default:
149b94833c4SAndreas Jaekel /* generic "ioctl unknown" error */
150b94833c4SAndreas Jaekel return ENOTTY;
151b94833c4SAndreas Jaekel }
15241aa6ebdSSimon Klinkert /* NOTREACHED */
153b94833c4SAndreas Jaekel return (0);
154b94833c4SAndreas Jaekel }
155b94833c4SAndreas Jaekel
156b94833c4SAndreas Jaekel /* gg_close() is called when the final fd/reference is removed. */
157b94833c4SAndreas Jaekel /* ARGSUSED */
158b94833c4SAndreas Jaekel static int
gg_close(dev_t dev,int flag,int otyp,cred_t * crepd)159b94833c4SAndreas Jaekel gg_close(dev_t dev, int flag, int otyp, cred_t *crepd)
160b94833c4SAndreas Jaekel {
161b94833c4SAndreas Jaekel gg_state_t *sp;
162b94833c4SAndreas Jaekel int instance;
163b94833c4SAndreas Jaekel
164b94833c4SAndreas Jaekel instance = getminor(dev);
165b94833c4SAndreas Jaekel if ((sp = ddi_get_soft_state(statep, instance)) == NULL)
166b94833c4SAndreas Jaekel return (ENXIO);
167b94833c4SAndreas Jaekel if (otyp != OTYP_CHR)
168b94833c4SAndreas Jaekel return (EINVAL);
169b94833c4SAndreas Jaekel mutex_enter(&sp->mutex);
170b94833c4SAndreas Jaekel if (sp->busy != B_TRUE) {
171b94833c4SAndreas Jaekel mutex_exit(&sp->mutex);
172b94833c4SAndreas Jaekel return (EINVAL);
173b94833c4SAndreas Jaekel }
174b94833c4SAndreas Jaekel sp->busy = B_FALSE;
175b94833c4SAndreas Jaekel mutex_exit(&sp->mutex);
176b94833c4SAndreas Jaekel return (0);
177b94833c4SAndreas Jaekel }
178b94833c4SAndreas Jaekel
179b94833c4SAndreas Jaekel /* gg_open() is called every time the device is opened/mounted/duped. */
180b94833c4SAndreas Jaekel /* ARGSUSED */
181b94833c4SAndreas Jaekel static int
gg_open(dev_t * devp,int flag,int otyp,cred_t * credp)182b94833c4SAndreas Jaekel gg_open(dev_t *devp, int flag, int otyp, cred_t *credp)
183b94833c4SAndreas Jaekel {
184b94833c4SAndreas Jaekel gg_state_t *sp;
185b94833c4SAndreas Jaekel int instance;
186b94833c4SAndreas Jaekel
187b94833c4SAndreas Jaekel instance = getminor(*devp);
188b94833c4SAndreas Jaekel if ((sp = ddi_get_soft_state(statep, instance)) == NULL)
189b94833c4SAndreas Jaekel return (ENXIO);
190b94833c4SAndreas Jaekel if (otyp != OTYP_CHR)
191b94833c4SAndreas Jaekel return (EINVAL);
192b94833c4SAndreas Jaekel if (drv_priv(credp) != 0)
193b94833c4SAndreas Jaekel return (EPERM);
194b94833c4SAndreas Jaekel mutex_enter(&sp->mutex);
195b94833c4SAndreas Jaekel if ((flag & FEXCL) && (sp->busy == B_TRUE)) {
196b94833c4SAndreas Jaekel mutex_exit(&sp->mutex);
197b94833c4SAndreas Jaekel return (EBUSY);
198b94833c4SAndreas Jaekel }
199b94833c4SAndreas Jaekel sp->busy = B_TRUE;
200b94833c4SAndreas Jaekel mutex_exit(&sp->mutex);
201b94833c4SAndreas Jaekel return (0);
202b94833c4SAndreas Jaekel }
203b94833c4SAndreas Jaekel
204b94833c4SAndreas Jaekel static struct cb_ops gg_cb_ops = {
205b94833c4SAndreas Jaekel gg_open, /* open */
206b94833c4SAndreas Jaekel gg_close, /* close */
207b94833c4SAndreas Jaekel nodev, /* strategy */
208b94833c4SAndreas Jaekel nodev, /* print */
209b94833c4SAndreas Jaekel nodev, /* dump */
210b94833c4SAndreas Jaekel nodev, /* read */
211b94833c4SAndreas Jaekel nodev, /* write */
212b94833c4SAndreas Jaekel gg_ioctl, /* ioctl */
213b94833c4SAndreas Jaekel nodev, /* devmap */
214b94833c4SAndreas Jaekel nodev, /* mmap */
215b94833c4SAndreas Jaekel nodev, /* segmap */
216b94833c4SAndreas Jaekel nochpoll, /* chpoll */
217b94833c4SAndreas Jaekel ddi_prop_op, /* prop_op */
218b94833c4SAndreas Jaekel NULL, /* streamtab */
219b94833c4SAndreas Jaekel D_MP | D_64BIT, /* cb_flag */
220b94833c4SAndreas Jaekel CB_REV, /* cb_rev */
221b94833c4SAndreas Jaekel nodev, /* aread */
222b94833c4SAndreas Jaekel nodev, /* awrite */
223b94833c4SAndreas Jaekel };
224b94833c4SAndreas Jaekel
225b94833c4SAndreas Jaekel static int
gg_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)226b94833c4SAndreas Jaekel gg_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
227b94833c4SAndreas Jaekel {
228b94833c4SAndreas Jaekel int instance;
229b94833c4SAndreas Jaekel gg_state_t *sp;
230b94833c4SAndreas Jaekel /* called once per instance with DDI_DETACH,
231b94833c4SAndreas Jaekel may be called to suspend */
232b94833c4SAndreas Jaekel switch (cmd) {
233b94833c4SAndreas Jaekel case DDI_DETACH:
234b94833c4SAndreas Jaekel /* instance busy? */
235b94833c4SAndreas Jaekel instance = ddi_get_instance(dip);
236b94833c4SAndreas Jaekel if ((sp = ddi_get_soft_state(statep, instance)) == NULL)
237b94833c4SAndreas Jaekel return (DDI_FAILURE);
238b94833c4SAndreas Jaekel mutex_enter(&sp->mutex);
239b94833c4SAndreas Jaekel if (sp->busy == B_TRUE) {
240b94833c4SAndreas Jaekel mutex_exit(&sp->mutex);
241b94833c4SAndreas Jaekel return (DDI_FAILURE);
242b94833c4SAndreas Jaekel }
243b94833c4SAndreas Jaekel mutex_exit(&sp->mutex);
244b94833c4SAndreas Jaekel /* free resources allocated for this instance */
245b94833c4SAndreas Jaekel mutex_destroy(&sp->mutex);
246b94833c4SAndreas Jaekel ddi_remove_minor_node(dip, NULL);
247b94833c4SAndreas Jaekel ddi_soft_state_free(statep, instance);
248b94833c4SAndreas Jaekel mutex_enter(&gg_mutex);
249b94833c4SAndreas Jaekel gg_instances--;
250b94833c4SAndreas Jaekel mutex_exit(&gg_mutex);
251b94833c4SAndreas Jaekel return (DDI_SUCCESS);
252b94833c4SAndreas Jaekel case DDI_SUSPEND:
253b94833c4SAndreas Jaekel return (DDI_FAILURE);
254b94833c4SAndreas Jaekel default:
255b94833c4SAndreas Jaekel return (DDI_FAILURE);
256b94833c4SAndreas Jaekel }
257b94833c4SAndreas Jaekel }
258b94833c4SAndreas Jaekel
259b94833c4SAndreas Jaekel static int
gg_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)260b94833c4SAndreas Jaekel gg_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
261b94833c4SAndreas Jaekel {
262b94833c4SAndreas Jaekel /* called once per instance with DDI_ATTACH,
263b94833c4SAndreas Jaekel may be called to resume */
264b94833c4SAndreas Jaekel int instance;
265b94833c4SAndreas Jaekel gg_state_t *sp;
266b94833c4SAndreas Jaekel switch (cmd) {
267b94833c4SAndreas Jaekel case DDI_ATTACH:
268b94833c4SAndreas Jaekel instance = ddi_get_instance(dip);
269b94833c4SAndreas Jaekel if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS) {
270b94833c4SAndreas Jaekel return (DDI_FAILURE);
271b94833c4SAndreas Jaekel }
272b94833c4SAndreas Jaekel sp = ddi_get_soft_state(statep, instance);
273b94833c4SAndreas Jaekel ddi_set_driver_private(dip, sp);
274b94833c4SAndreas Jaekel sp->dip = dip;
275b94833c4SAndreas Jaekel sp->busy = B_FALSE;
276b94833c4SAndreas Jaekel if (ddi_create_minor_node(dip, ddi_get_name(dip),
277b94833c4SAndreas Jaekel S_IFCHR, instance, DDI_PSEUDO, 0) == DDI_FAILURE) {
278b94833c4SAndreas Jaekel ddi_soft_state_free(statep, instance);
279b94833c4SAndreas Jaekel return (DDI_FAILURE);
280b94833c4SAndreas Jaekel }
281b94833c4SAndreas Jaekel mutex_init(&sp->mutex, NULL, MUTEX_DRIVER, NULL);
282b94833c4SAndreas Jaekel ddi_report_dev(dip);
283b94833c4SAndreas Jaekel mutex_enter(&gg_mutex);
284b94833c4SAndreas Jaekel gg_instances++;
285b94833c4SAndreas Jaekel mutex_exit(&gg_mutex);
286b94833c4SAndreas Jaekel return (DDI_SUCCESS);
287b94833c4SAndreas Jaekel case DDI_RESUME:
288b94833c4SAndreas Jaekel return (DDI_SUCCESS);
289b94833c4SAndreas Jaekel default:
290b94833c4SAndreas Jaekel return (DDI_FAILURE);
291b94833c4SAndreas Jaekel }
292b94833c4SAndreas Jaekel }
293b94833c4SAndreas Jaekel
294b94833c4SAndreas Jaekel /* ARGSUSED */
295b94833c4SAndreas Jaekel static int
gg_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** resultp)296b94833c4SAndreas Jaekel gg_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **resultp)
297b94833c4SAndreas Jaekel {
298b94833c4SAndreas Jaekel int instance;
299b94833c4SAndreas Jaekel gg_state_t *sp;
300b94833c4SAndreas Jaekel switch (infocmd) {
301b94833c4SAndreas Jaekel case DDI_INFO_DEVT2DEVINFO:
302b94833c4SAndreas Jaekel /* arg is dev_t */
303b94833c4SAndreas Jaekel instance = getminor((dev_t)arg);
304b94833c4SAndreas Jaekel if ((sp = ddi_get_soft_state(statep, instance)) != NULL) {
305b94833c4SAndreas Jaekel mutex_enter(&sp->mutex);
306b94833c4SAndreas Jaekel *resultp = sp->dip;
307b94833c4SAndreas Jaekel mutex_exit(&sp->mutex);
308b94833c4SAndreas Jaekel return (DDI_SUCCESS);
309b94833c4SAndreas Jaekel }
310b94833c4SAndreas Jaekel *resultp = NULL;
311b94833c4SAndreas Jaekel return (DDI_FAILURE);
312b94833c4SAndreas Jaekel case DDI_INFO_DEVT2INSTANCE:
313b94833c4SAndreas Jaekel /* arg is dev_t */
314b94833c4SAndreas Jaekel instance = getminor((dev_t)arg);
315b94833c4SAndreas Jaekel *resultp = (void *)(uintptr_t)instance;
316b94833c4SAndreas Jaekel return (DDI_FAILURE);
317b94833c4SAndreas Jaekel }
318b94833c4SAndreas Jaekel return (DDI_FAILURE);
319b94833c4SAndreas Jaekel }
320b94833c4SAndreas Jaekel
321b94833c4SAndreas Jaekel static struct dev_ops gg_dev_ops = {
322b94833c4SAndreas Jaekel DEVO_REV, /* driver build revision */
323b94833c4SAndreas Jaekel 0, /* driver reference count */
324b94833c4SAndreas Jaekel gg_getinfo, /* getinfo */
325b94833c4SAndreas Jaekel nulldev, /* identify (obsolete) */
326b94833c4SAndreas Jaekel nulldev, /* probe (search for devices) */
327b94833c4SAndreas Jaekel gg_attach, /* attach */
328b94833c4SAndreas Jaekel gg_detach, /* detach */
329b94833c4SAndreas Jaekel nodev, /* reset (obsolete, use quiesce) */
330b94833c4SAndreas Jaekel &gg_cb_ops, /* character and block device ops */
331b94833c4SAndreas Jaekel NULL, /* bus driver ops */
332b94833c4SAndreas Jaekel NULL, /* power management, not needed */
333b94833c4SAndreas Jaekel ddi_quiesce_not_needed, /* quiesce */
334b94833c4SAndreas Jaekel };
335b94833c4SAndreas Jaekel
336b94833c4SAndreas Jaekel static struct modldrv gg_modldrv = {
337b94833c4SAndreas Jaekel &mod_driverops, /* all loadable modules use this */
338*6af38117SDavid Hanisch "getgen - znode info, v1.1", /* driver name and version info */
339b94833c4SAndreas Jaekel &gg_dev_ops /* ops method pointers */
340b94833c4SAndreas Jaekel };
341b94833c4SAndreas Jaekel
342b94833c4SAndreas Jaekel static struct modlinkage gg_modlinkage = {
343b94833c4SAndreas Jaekel MODREV_1, /* fixed value */
344b94833c4SAndreas Jaekel {
345b94833c4SAndreas Jaekel &gg_modldrv, /* driver linkage structure */
346b94833c4SAndreas Jaekel NULL /* list terminator */
347b94833c4SAndreas Jaekel }
348b94833c4SAndreas Jaekel };
349b94833c4SAndreas Jaekel
350b94833c4SAndreas Jaekel int
_init(void)351b94833c4SAndreas Jaekel _init(void)
352b94833c4SAndreas Jaekel {
353b94833c4SAndreas Jaekel int error;
354b94833c4SAndreas Jaekel
355b94833c4SAndreas Jaekel if ((error = ddi_soft_state_init(&statep, sizeof(gg_state_t), 1)) != 0)
356b94833c4SAndreas Jaekel return (error);
357b94833c4SAndreas Jaekel gg_instances = 0;
358b94833c4SAndreas Jaekel
359b94833c4SAndreas Jaekel mutex_init(&gg_mutex, NULL, MUTEX_DRIVER, NULL);
360b94833c4SAndreas Jaekel
361b94833c4SAndreas Jaekel if ((error = mod_install(&gg_modlinkage)) != 0) {
362b94833c4SAndreas Jaekel cmn_err(CE_WARN, "getgen: could not install module");
363b94833c4SAndreas Jaekel mutex_destroy(&gg_mutex);
364b94833c4SAndreas Jaekel ddi_soft_state_fini(&statep);
365b94833c4SAndreas Jaekel return (error);
366b94833c4SAndreas Jaekel }
367b94833c4SAndreas Jaekel return (0);
368b94833c4SAndreas Jaekel }
369b94833c4SAndreas Jaekel
370b94833c4SAndreas Jaekel int
_info(struct modinfo * modinfop)371b94833c4SAndreas Jaekel _info(struct modinfo *modinfop)
372b94833c4SAndreas Jaekel {
373b94833c4SAndreas Jaekel return (mod_info(&gg_modlinkage, modinfop));
374b94833c4SAndreas Jaekel }
375b94833c4SAndreas Jaekel
376b94833c4SAndreas Jaekel int
_fini(void)377b94833c4SAndreas Jaekel _fini(void)
378b94833c4SAndreas Jaekel {
379b94833c4SAndreas Jaekel int error = 0;
380b94833c4SAndreas Jaekel
381b94833c4SAndreas Jaekel mutex_enter(&gg_mutex);
382b94833c4SAndreas Jaekel if (gg_instances > 0) {
383b94833c4SAndreas Jaekel mutex_exit(&gg_mutex);
384b94833c4SAndreas Jaekel return (SET_ERROR(EBUSY));
385b94833c4SAndreas Jaekel }
386b94833c4SAndreas Jaekel mutex_exit(&gg_mutex);
387b94833c4SAndreas Jaekel
388b94833c4SAndreas Jaekel if ((error = mod_remove(&gg_modlinkage)) != 0) {
389b94833c4SAndreas Jaekel cmn_err(CE_WARN, "mod_remove failed: %d", error);
390b94833c4SAndreas Jaekel return (error);
391b94833c4SAndreas Jaekel }
392b94833c4SAndreas Jaekel
393b94833c4SAndreas Jaekel /* free resources */
394b94833c4SAndreas Jaekel ddi_soft_state_fini(&statep);
395b94833c4SAndreas Jaekel mutex_destroy(&gg_mutex);
396b94833c4SAndreas Jaekel
397b94833c4SAndreas Jaekel return (0);
398b94833c4SAndreas Jaekel }
399b94833c4SAndreas Jaekel
400