1372a60c3SAndreas Jaekel #include <sys/modctl.h>
2372a60c3SAndreas Jaekel #include <sys/ddi.h>
3372a60c3SAndreas Jaekel #include <sys/sunddi.h>
4372a60c3SAndreas Jaekel #include <sys/conf.h>
5372a60c3SAndreas Jaekel #include <sys/devops.h>
6372a60c3SAndreas Jaekel #include <sys/stat.h>
7372a60c3SAndreas Jaekel #include <sys/zfs_znode.h>
8372a60c3SAndreas Jaekel #include <sys/time.h>
9372a60c3SAndreas Jaekel #include <sys/sa.h>
10372a60c3SAndreas Jaekel #include <sys/zap.h>
11372a60c3SAndreas Jaekel #include <sys/time.h>
12372a60c3SAndreas Jaekel #include <sys/dsl_dataset.h>
13372a60c3SAndreas Jaekel #include <sys/zfs_vfsops.h>
14372a60c3SAndreas Jaekel #include <sys/dmu.h>
15372a60c3SAndreas Jaekel #include <sys/dmu_objset.h>
16372a60c3SAndreas Jaekel #include <sys/dsl_dir.h>
17372a60c3SAndreas Jaekel
18372a60c3SAndreas Jaekel #include <getgen/getgen.h>
19372a60c3SAndreas Jaekel
20372a60c3SAndreas Jaekel /* per-instance context */
21372a60c3SAndreas Jaekel typedef struct gg_state {
22372a60c3SAndreas Jaekel kmutex_t mutex;
23372a60c3SAndreas Jaekel dev_info_t *dip;
24372a60c3SAndreas Jaekel boolean_t busy;
25372a60c3SAndreas Jaekel } gg_state_t;
26372a60c3SAndreas Jaekel
27372a60c3SAndreas Jaekel static void *statep;
28372a60c3SAndreas Jaekel static kmutex_t gg_mutex;
29372a60c3SAndreas Jaekel static int gg_instances = 0;
30372a60c3SAndreas Jaekel
31372a60c3SAndreas Jaekel int
gg_ioc_get_gen(intptr_t arg,int mode)32372a60c3SAndreas Jaekel gg_ioc_get_gen(intptr_t arg, int mode)
33372a60c3SAndreas Jaekel {
34372a60c3SAndreas Jaekel gg_ioctl_get_generation_t gg;
35372a60c3SAndreas Jaekel file_t *fp;
36372a60c3SAndreas Jaekel uint64_t gen;
37372a60c3SAndreas Jaekel uint64_t crtime[2];
38372a60c3SAndreas Jaekel int ret = 0;
39819a7669SAndreas Jaekel zfsvfs_t *zfsvfs = NULL;
40372a60c3SAndreas Jaekel objset_t *osp;
41372a60c3SAndreas Jaekel sa_attr_type_t *sa_table;
42372a60c3SAndreas Jaekel sa_handle_t *hdl;
43372a60c3SAndreas Jaekel dmu_buf_t *db;
44372a60c3SAndreas Jaekel sa_bulk_attr_t bulk[2];
45372a60c3SAndreas Jaekel int count = 0;
46372a60c3SAndreas Jaekel dmu_object_info_t doi;
47372a60c3SAndreas Jaekel timestruc_t crtime_s;
48819a7669SAndreas Jaekel znode_t *zp;
49*03d38ed9SDavid Hanisch dsl_dataset_phys_t *ds_phys;
50372a60c3SAndreas Jaekel
51372a60c3SAndreas Jaekel if (ddi_copyin((void *)arg, &gg, sizeof(gg), mode) != 0)
52372a60c3SAndreas Jaekel return EFAULT;
53372a60c3SAndreas Jaekel fp = getf(gg.fd);
54372a60c3SAndreas Jaekel if (fp == NULL)
55372a60c3SAndreas Jaekel return EBADF;
56372a60c3SAndreas Jaekel if (fp->f_vnode->v_vfsp->vfs_fstype != zfsfstype) {
57372a60c3SAndreas Jaekel ret = EINVAL;
58372a60c3SAndreas Jaekel goto out;
59372a60c3SAndreas Jaekel }
60372a60c3SAndreas Jaekel
61819a7669SAndreas Jaekel zp = (znode_t *)fp->f_vnode->v_data;
62819a7669SAndreas Jaekel /* modified version of ZFS_ENTER() macro - we need to clean up fp */
63819a7669SAndreas Jaekel zfsvfs = zp->z_zfsvfs;
64819a7669SAndreas Jaekel rrm_enter_read(&zfsvfs->z_teardown_lock, FTAG);
65819a7669SAndreas Jaekel if (zp->z_zfsvfs->z_unmounted) {
66819a7669SAndreas Jaekel ret = EIO;
67819a7669SAndreas Jaekel goto out;
68819a7669SAndreas Jaekel }
69819a7669SAndreas Jaekel /* modified version of ZFS_VERIFY_ZP() macro */
70819a7669SAndreas Jaekel if (zp->z_sa_hdl == NULL) {
71819a7669SAndreas Jaekel ret = EIO;
72819a7669SAndreas Jaekel goto out;
73819a7669SAndreas Jaekel }
74*03d38ed9SDavid Hanisch ds_phys = dsl_dataset_phys(zfsvfs->z_os->os_dsl_dataset);
75819a7669SAndreas Jaekel
76372a60c3SAndreas Jaekel /* get dataset name */
77372a60c3SAndreas Jaekel dsl_dataset_name(zfsvfs->z_os->os_dsl_dataset, gg.dataset);
78372a60c3SAndreas Jaekel
79372a60c3SAndreas Jaekel /* get guid */
80*03d38ed9SDavid Hanisch gg.guid = ds_phys->ds_guid;
81372a60c3SAndreas Jaekel
82*03d38ed9SDavid Hanisch if (gg.inode != 0) {
83372a60c3SAndreas Jaekel /* get generation and crtime */
84372a60c3SAndreas Jaekel osp = zfsvfs->z_os;
85*03d38ed9SDavid Hanisch ret = sa_setup(osp, gg.inode, zfs_attr_table, ZPL_END,
86*03d38ed9SDavid Hanisch &sa_table);
87372a60c3SAndreas Jaekel if (ret)
88372a60c3SAndreas Jaekel goto out;
89372a60c3SAndreas Jaekel ret = sa_buf_hold(osp, gg.inode, FTAG, &db);
90372a60c3SAndreas Jaekel if (ret)
91372a60c3SAndreas Jaekel goto out;
92372a60c3SAndreas Jaekel dmu_object_info_from_db(db, &doi);
93372a60c3SAndreas Jaekel if ((doi.doi_bonus_type != DMU_OT_SA &&
94372a60c3SAndreas Jaekel doi.doi_bonus_type != DMU_OT_ZNODE) ||
95372a60c3SAndreas Jaekel doi.doi_bonus_type == DMU_OT_ZNODE &&
96372a60c3SAndreas Jaekel doi.doi_bonus_size < sizeof (znode_phys_t)) {
97372a60c3SAndreas Jaekel sa_buf_rele(db, FTAG);
98372a60c3SAndreas Jaekel ret = ENOTSUP;
99372a60c3SAndreas Jaekel goto out;
100372a60c3SAndreas Jaekel }
101372a60c3SAndreas Jaekel ret = sa_handle_get(osp, gg.inode, NULL, SA_HDL_PRIVATE, &hdl);
102372a60c3SAndreas Jaekel if (ret) {
103372a60c3SAndreas Jaekel sa_buf_rele(db, FTAG);
104372a60c3SAndreas Jaekel goto out;
105372a60c3SAndreas Jaekel }
106372a60c3SAndreas Jaekel SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_GEN], NULL,
107372a60c3SAndreas Jaekel &gen, sizeof(gen));
108372a60c3SAndreas Jaekel SA_ADD_BULK_ATTR(bulk, count, sa_table[ZPL_CRTIME], NULL,
109372a60c3SAndreas Jaekel &crtime, sizeof(crtime));
110372a60c3SAndreas Jaekel ret = sa_bulk_lookup(hdl, bulk, count);
111372a60c3SAndreas Jaekel sa_handle_destroy(hdl);
112372a60c3SAndreas Jaekel sa_buf_rele(db, FTAG);
113372a60c3SAndreas Jaekel if (ret)
114372a60c3SAndreas Jaekel goto out;
115372a60c3SAndreas Jaekel ZFS_TIME_DECODE(&crtime_s, crtime);
116372a60c3SAndreas Jaekel gg.generation = gen;
117372a60c3SAndreas Jaekel gg.crtime = crtime_s.tv_sec;
118*03d38ed9SDavid Hanisch } else {
119*03d38ed9SDavid Hanisch gg.generation = ds_phys->ds_bp.blk_birth;
120*03d38ed9SDavid Hanisch gg.crtime = 0;
121*03d38ed9SDavid Hanisch }
122372a60c3SAndreas Jaekel
123372a60c3SAndreas Jaekel ddi_copyout(&gg, (void *)arg, sizeof(gg), mode);
124372a60c3SAndreas Jaekel out:
125819a7669SAndreas Jaekel if (zfsvfs)
126819a7669SAndreas Jaekel ZFS_EXIT(zfsvfs);
127372a60c3SAndreas Jaekel releasef(gg.fd);
128372a60c3SAndreas Jaekel return ret;
129372a60c3SAndreas Jaekel }
130372a60c3SAndreas Jaekel
131372a60c3SAndreas Jaekel /* ARGSUSED */
132372a60c3SAndreas Jaekel static int
gg_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)133372a60c3SAndreas Jaekel gg_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
134372a60c3SAndreas Jaekel {
135372a60c3SAndreas Jaekel int instance;
136372a60c3SAndreas Jaekel
137372a60c3SAndreas Jaekel instance = getminor(dev);
138372a60c3SAndreas Jaekel if (ddi_get_soft_state(statep, instance) == NULL)
139372a60c3SAndreas Jaekel return (ENXIO);
140372a60c3SAndreas Jaekel /*
141372a60c3SAndreas Jaekel * all structures passed between kernel and userspace
142372a60c3SAndreas Jaekel * are compatible between 64 and 32 bit. Model
143372a60c3SAndreas Jaekel * conversion can be ignored.
144372a60c3SAndreas Jaekel */
145372a60c3SAndreas Jaekel switch (cmd) {
146372a60c3SAndreas Jaekel case GG_IOC_GET_GENERATION:
147372a60c3SAndreas Jaekel return gg_ioc_get_gen(arg, mode);
148372a60c3SAndreas Jaekel default:
149372a60c3SAndreas Jaekel /* generic "ioctl unknown" error */
150372a60c3SAndreas Jaekel return ENOTTY;
151372a60c3SAndreas Jaekel }
152df8caf2dSSimon Klinkert /* NOTREACHED */
153372a60c3SAndreas Jaekel return (0);
154372a60c3SAndreas Jaekel }
155372a60c3SAndreas Jaekel
156372a60c3SAndreas Jaekel /* gg_close() is called when the final fd/reference is removed. */
157372a60c3SAndreas Jaekel /* ARGSUSED */
158372a60c3SAndreas Jaekel static int
gg_close(dev_t dev,int flag,int otyp,cred_t * crepd)159372a60c3SAndreas Jaekel gg_close(dev_t dev, int flag, int otyp, cred_t *crepd)
160372a60c3SAndreas Jaekel {
161372a60c3SAndreas Jaekel gg_state_t *sp;
162372a60c3SAndreas Jaekel int instance;
163372a60c3SAndreas Jaekel
164372a60c3SAndreas Jaekel instance = getminor(dev);
165372a60c3SAndreas Jaekel if ((sp = ddi_get_soft_state(statep, instance)) == NULL)
166372a60c3SAndreas Jaekel return (ENXIO);
167372a60c3SAndreas Jaekel if (otyp != OTYP_CHR)
168372a60c3SAndreas Jaekel return (EINVAL);
169372a60c3SAndreas Jaekel mutex_enter(&sp->mutex);
170372a60c3SAndreas Jaekel if (sp->busy != B_TRUE) {
171372a60c3SAndreas Jaekel mutex_exit(&sp->mutex);
172372a60c3SAndreas Jaekel return (EINVAL);
173372a60c3SAndreas Jaekel }
174372a60c3SAndreas Jaekel sp->busy = B_FALSE;
175372a60c3SAndreas Jaekel mutex_exit(&sp->mutex);
176372a60c3SAndreas Jaekel return (0);
177372a60c3SAndreas Jaekel }
178372a60c3SAndreas Jaekel
179372a60c3SAndreas Jaekel /* gg_open() is called every time the device is opened/mounted/duped. */
180372a60c3SAndreas Jaekel /* ARGSUSED */
181372a60c3SAndreas Jaekel static int
gg_open(dev_t * devp,int flag,int otyp,cred_t * credp)182372a60c3SAndreas Jaekel gg_open(dev_t *devp, int flag, int otyp, cred_t *credp)
183372a60c3SAndreas Jaekel {
184372a60c3SAndreas Jaekel gg_state_t *sp;
185372a60c3SAndreas Jaekel int instance;
186372a60c3SAndreas Jaekel
187372a60c3SAndreas Jaekel instance = getminor(*devp);
188372a60c3SAndreas Jaekel if ((sp = ddi_get_soft_state(statep, instance)) == NULL)
189372a60c3SAndreas Jaekel return (ENXIO);
190372a60c3SAndreas Jaekel if (otyp != OTYP_CHR)
191372a60c3SAndreas Jaekel return (EINVAL);
192372a60c3SAndreas Jaekel if (drv_priv(credp) != 0)
193372a60c3SAndreas Jaekel return (EPERM);
194372a60c3SAndreas Jaekel mutex_enter(&sp->mutex);
195372a60c3SAndreas Jaekel if ((flag & FEXCL) && (sp->busy == B_TRUE)) {
196372a60c3SAndreas Jaekel mutex_exit(&sp->mutex);
197372a60c3SAndreas Jaekel return (EBUSY);
198372a60c3SAndreas Jaekel }
199372a60c3SAndreas Jaekel sp->busy = B_TRUE;
200372a60c3SAndreas Jaekel mutex_exit(&sp->mutex);
201372a60c3SAndreas Jaekel return (0);
202372a60c3SAndreas Jaekel }
203372a60c3SAndreas Jaekel
204372a60c3SAndreas Jaekel static struct cb_ops gg_cb_ops = {
205372a60c3SAndreas Jaekel gg_open, /* open */
206372a60c3SAndreas Jaekel gg_close, /* close */
207372a60c3SAndreas Jaekel nodev, /* strategy */
208372a60c3SAndreas Jaekel nodev, /* print */
209372a60c3SAndreas Jaekel nodev, /* dump */
210372a60c3SAndreas Jaekel nodev, /* read */
211372a60c3SAndreas Jaekel nodev, /* write */
212372a60c3SAndreas Jaekel gg_ioctl, /* ioctl */
213372a60c3SAndreas Jaekel nodev, /* devmap */
214372a60c3SAndreas Jaekel nodev, /* mmap */
215372a60c3SAndreas Jaekel nodev, /* segmap */
216372a60c3SAndreas Jaekel nochpoll, /* chpoll */
217372a60c3SAndreas Jaekel ddi_prop_op, /* prop_op */
218372a60c3SAndreas Jaekel NULL, /* streamtab */
219372a60c3SAndreas Jaekel D_MP | D_64BIT, /* cb_flag */
220372a60c3SAndreas Jaekel CB_REV, /* cb_rev */
221372a60c3SAndreas Jaekel nodev, /* aread */
222372a60c3SAndreas Jaekel nodev, /* awrite */
223372a60c3SAndreas Jaekel };
224372a60c3SAndreas Jaekel
225372a60c3SAndreas Jaekel static int
gg_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)226372a60c3SAndreas Jaekel gg_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
227372a60c3SAndreas Jaekel {
228372a60c3SAndreas Jaekel int instance;
229372a60c3SAndreas Jaekel gg_state_t *sp;
230372a60c3SAndreas Jaekel /* called once per instance with DDI_DETACH,
231372a60c3SAndreas Jaekel may be called to suspend */
232372a60c3SAndreas Jaekel switch (cmd) {
233372a60c3SAndreas Jaekel case DDI_DETACH:
234372a60c3SAndreas Jaekel /* instance busy? */
235372a60c3SAndreas Jaekel instance = ddi_get_instance(dip);
236372a60c3SAndreas Jaekel if ((sp = ddi_get_soft_state(statep, instance)) == NULL)
237372a60c3SAndreas Jaekel return (DDI_FAILURE);
238372a60c3SAndreas Jaekel mutex_enter(&sp->mutex);
239372a60c3SAndreas Jaekel if (sp->busy == B_TRUE) {
240372a60c3SAndreas Jaekel mutex_exit(&sp->mutex);
241372a60c3SAndreas Jaekel return (DDI_FAILURE);
242372a60c3SAndreas Jaekel }
243372a60c3SAndreas Jaekel mutex_exit(&sp->mutex);
244372a60c3SAndreas Jaekel /* free resources allocated for this instance */
245372a60c3SAndreas Jaekel mutex_destroy(&sp->mutex);
246372a60c3SAndreas Jaekel ddi_remove_minor_node(dip, NULL);
247372a60c3SAndreas Jaekel ddi_soft_state_free(statep, instance);
248372a60c3SAndreas Jaekel mutex_enter(&gg_mutex);
249372a60c3SAndreas Jaekel gg_instances--;
250372a60c3SAndreas Jaekel mutex_exit(&gg_mutex);
251372a60c3SAndreas Jaekel return (DDI_SUCCESS);
252372a60c3SAndreas Jaekel case DDI_SUSPEND:
253372a60c3SAndreas Jaekel return (DDI_FAILURE);
254372a60c3SAndreas Jaekel default:
255372a60c3SAndreas Jaekel return (DDI_FAILURE);
256372a60c3SAndreas Jaekel }
257372a60c3SAndreas Jaekel }
258372a60c3SAndreas Jaekel
259372a60c3SAndreas Jaekel static int
gg_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)260372a60c3SAndreas Jaekel gg_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
261372a60c3SAndreas Jaekel {
262372a60c3SAndreas Jaekel /* called once per instance with DDI_ATTACH,
263372a60c3SAndreas Jaekel may be called to resume */
264372a60c3SAndreas Jaekel int instance;
265372a60c3SAndreas Jaekel gg_state_t *sp;
266372a60c3SAndreas Jaekel switch (cmd) {
267372a60c3SAndreas Jaekel case DDI_ATTACH:
268372a60c3SAndreas Jaekel instance = ddi_get_instance(dip);
269372a60c3SAndreas Jaekel if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS) {
270372a60c3SAndreas Jaekel return (DDI_FAILURE);
271372a60c3SAndreas Jaekel }
272372a60c3SAndreas Jaekel sp = ddi_get_soft_state(statep, instance);
273372a60c3SAndreas Jaekel ddi_set_driver_private(dip, sp);
274372a60c3SAndreas Jaekel sp->dip = dip;
275372a60c3SAndreas Jaekel sp->busy = B_FALSE;
276372a60c3SAndreas Jaekel if (ddi_create_minor_node(dip, ddi_get_name(dip),
277372a60c3SAndreas Jaekel S_IFCHR, instance, DDI_PSEUDO, 0) == DDI_FAILURE) {
278372a60c3SAndreas Jaekel ddi_soft_state_free(statep, instance);
279372a60c3SAndreas Jaekel return (DDI_FAILURE);
280372a60c3SAndreas Jaekel }
281372a60c3SAndreas Jaekel mutex_init(&sp->mutex, NULL, MUTEX_DRIVER, NULL);
282372a60c3SAndreas Jaekel ddi_report_dev(dip);
283372a60c3SAndreas Jaekel mutex_enter(&gg_mutex);
284372a60c3SAndreas Jaekel gg_instances++;
285372a60c3SAndreas Jaekel mutex_exit(&gg_mutex);
286372a60c3SAndreas Jaekel return (DDI_SUCCESS);
287372a60c3SAndreas Jaekel case DDI_RESUME:
288372a60c3SAndreas Jaekel return (DDI_SUCCESS);
289372a60c3SAndreas Jaekel default:
290372a60c3SAndreas Jaekel return (DDI_FAILURE);
291372a60c3SAndreas Jaekel }
292372a60c3SAndreas Jaekel }
293372a60c3SAndreas Jaekel
294372a60c3SAndreas Jaekel /* ARGSUSED */
295372a60c3SAndreas Jaekel static int
gg_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** resultp)296372a60c3SAndreas Jaekel gg_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **resultp)
297372a60c3SAndreas Jaekel {
298372a60c3SAndreas Jaekel int instance;
299372a60c3SAndreas Jaekel gg_state_t *sp;
300372a60c3SAndreas Jaekel switch (infocmd) {
301372a60c3SAndreas Jaekel case DDI_INFO_DEVT2DEVINFO:
302372a60c3SAndreas Jaekel /* arg is dev_t */
303372a60c3SAndreas Jaekel instance = getminor((dev_t)arg);
304372a60c3SAndreas Jaekel if ((sp = ddi_get_soft_state(statep, instance)) != NULL) {
305372a60c3SAndreas Jaekel mutex_enter(&sp->mutex);
306372a60c3SAndreas Jaekel *resultp = sp->dip;
307372a60c3SAndreas Jaekel mutex_exit(&sp->mutex);
308372a60c3SAndreas Jaekel return (DDI_SUCCESS);
309372a60c3SAndreas Jaekel }
310372a60c3SAndreas Jaekel *resultp = NULL;
311372a60c3SAndreas Jaekel return (DDI_FAILURE);
312372a60c3SAndreas Jaekel case DDI_INFO_DEVT2INSTANCE:
313372a60c3SAndreas Jaekel /* arg is dev_t */
314372a60c3SAndreas Jaekel instance = getminor((dev_t)arg);
315372a60c3SAndreas Jaekel *resultp = (void *)(uintptr_t)instance;
316372a60c3SAndreas Jaekel return (DDI_FAILURE);
317372a60c3SAndreas Jaekel }
318372a60c3SAndreas Jaekel return (DDI_FAILURE);
319372a60c3SAndreas Jaekel }
320372a60c3SAndreas Jaekel
321372a60c3SAndreas Jaekel static struct dev_ops gg_dev_ops = {
322372a60c3SAndreas Jaekel DEVO_REV, /* driver build revision */
323372a60c3SAndreas Jaekel 0, /* driver reference count */
324372a60c3SAndreas Jaekel gg_getinfo, /* getinfo */
325372a60c3SAndreas Jaekel nulldev, /* identify (obsolete) */
326372a60c3SAndreas Jaekel nulldev, /* probe (search for devices) */
327372a60c3SAndreas Jaekel gg_attach, /* attach */
328372a60c3SAndreas Jaekel gg_detach, /* detach */
329372a60c3SAndreas Jaekel nodev, /* reset (obsolete, use quiesce) */
330372a60c3SAndreas Jaekel &gg_cb_ops, /* character and block device ops */
331372a60c3SAndreas Jaekel NULL, /* bus driver ops */
332372a60c3SAndreas Jaekel NULL, /* power management, not needed */
333372a60c3SAndreas Jaekel ddi_quiesce_not_needed, /* quiesce */
334372a60c3SAndreas Jaekel };
335372a60c3SAndreas Jaekel
336372a60c3SAndreas Jaekel static struct modldrv gg_modldrv = {
337372a60c3SAndreas Jaekel &mod_driverops, /* all loadable modules use this */
338*03d38ed9SDavid Hanisch "getgen - znode info, v1.1", /* driver name and version info */
339372a60c3SAndreas Jaekel &gg_dev_ops /* ops method pointers */
340372a60c3SAndreas Jaekel };
341372a60c3SAndreas Jaekel
342372a60c3SAndreas Jaekel static struct modlinkage gg_modlinkage = {
343372a60c3SAndreas Jaekel MODREV_1, /* fixed value */
344372a60c3SAndreas Jaekel {
345372a60c3SAndreas Jaekel &gg_modldrv, /* driver linkage structure */
346372a60c3SAndreas Jaekel NULL /* list terminator */
347372a60c3SAndreas Jaekel }
348372a60c3SAndreas Jaekel };
349372a60c3SAndreas Jaekel
350372a60c3SAndreas Jaekel int
_init(void)351372a60c3SAndreas Jaekel _init(void)
352372a60c3SAndreas Jaekel {
353372a60c3SAndreas Jaekel int error;
354372a60c3SAndreas Jaekel
355372a60c3SAndreas Jaekel if ((error = ddi_soft_state_init(&statep, sizeof(gg_state_t), 1)) != 0)
356372a60c3SAndreas Jaekel return (error);
357372a60c3SAndreas Jaekel gg_instances = 0;
358372a60c3SAndreas Jaekel
359372a60c3SAndreas Jaekel mutex_init(&gg_mutex, NULL, MUTEX_DRIVER, NULL);
360372a60c3SAndreas Jaekel
361372a60c3SAndreas Jaekel if ((error = mod_install(&gg_modlinkage)) != 0) {
362372a60c3SAndreas Jaekel cmn_err(CE_WARN, "getgen: could not install module");
363372a60c3SAndreas Jaekel mutex_destroy(&gg_mutex);
364372a60c3SAndreas Jaekel ddi_soft_state_fini(&statep);
365372a60c3SAndreas Jaekel return (error);
366372a60c3SAndreas Jaekel }
367372a60c3SAndreas Jaekel return (0);
368372a60c3SAndreas Jaekel }
369372a60c3SAndreas Jaekel
370372a60c3SAndreas Jaekel int
_info(struct modinfo * modinfop)371372a60c3SAndreas Jaekel _info(struct modinfo *modinfop)
372372a60c3SAndreas Jaekel {
373372a60c3SAndreas Jaekel return (mod_info(&gg_modlinkage, modinfop));
374372a60c3SAndreas Jaekel }
375372a60c3SAndreas Jaekel
376372a60c3SAndreas Jaekel int
_fini(void)377372a60c3SAndreas Jaekel _fini(void)
378372a60c3SAndreas Jaekel {
379372a60c3SAndreas Jaekel int error = 0;
380372a60c3SAndreas Jaekel
381372a60c3SAndreas Jaekel mutex_enter(&gg_mutex);
382372a60c3SAndreas Jaekel if (gg_instances > 0) {
383372a60c3SAndreas Jaekel mutex_exit(&gg_mutex);
384372a60c3SAndreas Jaekel return (SET_ERROR(EBUSY));
385372a60c3SAndreas Jaekel }
386372a60c3SAndreas Jaekel mutex_exit(&gg_mutex);
387372a60c3SAndreas Jaekel
388372a60c3SAndreas Jaekel if ((error = mod_remove(&gg_modlinkage)) != 0) {
389372a60c3SAndreas Jaekel cmn_err(CE_WARN, "mod_remove failed: %d", error);
390372a60c3SAndreas Jaekel return (error);
391372a60c3SAndreas Jaekel }
392372a60c3SAndreas Jaekel
393372a60c3SAndreas Jaekel /* free resources */
394372a60c3SAndreas Jaekel ddi_soft_state_fini(&statep);
395372a60c3SAndreas Jaekel mutex_destroy(&gg_mutex);
396372a60c3SAndreas Jaekel
397372a60c3SAndreas Jaekel return (0);
398372a60c3SAndreas Jaekel }
399372a60c3SAndreas Jaekel
400