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