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