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 return (0); 146 } 147 148 /* gg_close() is called when the final fd/reference is removed. */ 149 /* ARGSUSED */ 150 static int 151 gg_close(dev_t dev, int flag, int otyp, cred_t *crepd) 152 { 153 gg_state_t *sp; 154 int instance; 155 156 instance = getminor(dev); 157 if ((sp = ddi_get_soft_state(statep, instance)) == NULL) 158 return (ENXIO); 159 if (otyp != OTYP_CHR) 160 return (EINVAL); 161 mutex_enter(&sp->mutex); 162 if (sp->busy != B_TRUE) { 163 mutex_exit(&sp->mutex); 164 return (EINVAL); 165 } 166 sp->busy = B_FALSE; 167 mutex_exit(&sp->mutex); 168 return (0); 169 } 170 171 /* gg_open() is called every time the device is opened/mounted/duped. */ 172 /* ARGSUSED */ 173 static int 174 gg_open(dev_t *devp, int flag, int otyp, cred_t *credp) 175 { 176 gg_state_t *sp; 177 int instance; 178 179 instance = getminor(*devp); 180 if ((sp = ddi_get_soft_state(statep, instance)) == NULL) 181 return (ENXIO); 182 if (otyp != OTYP_CHR) 183 return (EINVAL); 184 if (drv_priv(credp) != 0) 185 return (EPERM); 186 mutex_enter(&sp->mutex); 187 if ((flag & FEXCL) && (sp->busy == B_TRUE)) { 188 mutex_exit(&sp->mutex); 189 return (EBUSY); 190 } 191 sp->busy = B_TRUE; 192 mutex_exit(&sp->mutex); 193 return (0); 194 } 195 196 static struct cb_ops gg_cb_ops = { 197 gg_open, /* open */ 198 gg_close, /* close */ 199 nodev, /* strategy */ 200 nodev, /* print */ 201 nodev, /* dump */ 202 nodev, /* read */ 203 nodev, /* write */ 204 gg_ioctl, /* ioctl */ 205 nodev, /* devmap */ 206 nodev, /* mmap */ 207 nodev, /* segmap */ 208 nochpoll, /* chpoll */ 209 ddi_prop_op, /* prop_op */ 210 NULL, /* streamtab */ 211 D_MP | D_64BIT, /* cb_flag */ 212 CB_REV, /* cb_rev */ 213 nodev, /* aread */ 214 nodev, /* awrite */ 215 }; 216 217 static int 218 gg_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 219 { 220 int instance; 221 gg_state_t *sp; 222 /* called once per instance with DDI_DETACH, 223 may be called to suspend */ 224 switch (cmd) { 225 case DDI_DETACH: 226 /* instance busy? */ 227 instance = ddi_get_instance(dip); 228 if ((sp = ddi_get_soft_state(statep, instance)) == NULL) 229 return (DDI_FAILURE); 230 mutex_enter(&sp->mutex); 231 if (sp->busy == B_TRUE) { 232 mutex_exit(&sp->mutex); 233 return (DDI_FAILURE); 234 } 235 mutex_exit(&sp->mutex); 236 /* free resources allocated for this instance */ 237 mutex_destroy(&sp->mutex); 238 ddi_remove_minor_node(dip, NULL); 239 ddi_soft_state_free(statep, instance); 240 mutex_enter(&gg_mutex); 241 gg_instances--; 242 mutex_exit(&gg_mutex); 243 return (DDI_SUCCESS); 244 case DDI_SUSPEND: 245 return (DDI_FAILURE); 246 default: 247 return (DDI_FAILURE); 248 } 249 } 250 251 static int 252 gg_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 253 { 254 /* called once per instance with DDI_ATTACH, 255 may be called to resume */ 256 int instance; 257 gg_state_t *sp; 258 switch (cmd) { 259 case DDI_ATTACH: 260 instance = ddi_get_instance(dip); 261 if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS) { 262 return (DDI_FAILURE); 263 } 264 sp = ddi_get_soft_state(statep, instance); 265 ddi_set_driver_private(dip, sp); 266 sp->dip = dip; 267 sp->busy = B_FALSE; 268 if (ddi_create_minor_node(dip, ddi_get_name(dip), 269 S_IFCHR, instance, DDI_PSEUDO, 0) == DDI_FAILURE) { 270 ddi_soft_state_free(statep, instance); 271 return (DDI_FAILURE); 272 } 273 mutex_init(&sp->mutex, NULL, MUTEX_DRIVER, NULL); 274 ddi_report_dev(dip); 275 mutex_enter(&gg_mutex); 276 gg_instances++; 277 mutex_exit(&gg_mutex); 278 return (DDI_SUCCESS); 279 case DDI_RESUME: 280 return (DDI_SUCCESS); 281 default: 282 return (DDI_FAILURE); 283 } 284 } 285 286 /* ARGSUSED */ 287 static int 288 gg_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **resultp) 289 { 290 int instance; 291 gg_state_t *sp; 292 switch (infocmd) { 293 case DDI_INFO_DEVT2DEVINFO: 294 /* arg is dev_t */ 295 instance = getminor((dev_t)arg); 296 if ((sp = ddi_get_soft_state(statep, instance)) != NULL) { 297 mutex_enter(&sp->mutex); 298 *resultp = sp->dip; 299 mutex_exit(&sp->mutex); 300 return (DDI_SUCCESS); 301 } 302 *resultp = NULL; 303 return (DDI_FAILURE); 304 case DDI_INFO_DEVT2INSTANCE: 305 /* arg is dev_t */ 306 instance = getminor((dev_t)arg); 307 *resultp = (void *)(uintptr_t)instance; 308 return (DDI_FAILURE); 309 } 310 return (DDI_FAILURE); 311 } 312 313 static struct dev_ops gg_dev_ops = { 314 DEVO_REV, /* driver build revision */ 315 0, /* driver reference count */ 316 gg_getinfo, /* getinfo */ 317 nulldev, /* identify (obsolete) */ 318 nulldev, /* probe (search for devices) */ 319 gg_attach, /* attach */ 320 gg_detach, /* detach */ 321 nodev, /* reset (obsolete, use quiesce) */ 322 &gg_cb_ops, /* character and block device ops */ 323 NULL, /* bus driver ops */ 324 NULL, /* power management, not needed */ 325 ddi_quiesce_not_needed, /* quiesce */ 326 }; 327 328 static struct modldrv gg_modldrv = { 329 &mod_driverops, /* all loadable modules use this */ 330 "getgen - znode info, v1.0", /* driver name and version info */ 331 &gg_dev_ops /* ops method pointers */ 332 }; 333 334 static struct modlinkage gg_modlinkage = { 335 MODREV_1, /* fixed value */ 336 { 337 &gg_modldrv, /* driver linkage structure */ 338 NULL /* list terminator */ 339 } 340 }; 341 342 int 343 _init(void) 344 { 345 int error; 346 347 if ((error = ddi_soft_state_init(&statep, sizeof(gg_state_t), 1)) != 0) 348 return (error); 349 gg_instances = 0; 350 351 mutex_init(&gg_mutex, NULL, MUTEX_DRIVER, NULL); 352 353 if ((error = mod_install(&gg_modlinkage)) != 0) { 354 cmn_err(CE_WARN, "getgen: could not install module"); 355 mutex_destroy(&gg_mutex); 356 ddi_soft_state_fini(&statep); 357 return (error); 358 } 359 return (0); 360 } 361 362 int 363 _info(struct modinfo *modinfop) 364 { 365 return (mod_info(&gg_modlinkage, modinfop)); 366 } 367 368 int 369 _fini(void) 370 { 371 int error = 0; 372 373 mutex_enter(&gg_mutex); 374 if (gg_instances > 0) { 375 mutex_exit(&gg_mutex); 376 return (SET_ERROR(EBUSY)); 377 } 378 mutex_exit(&gg_mutex); 379 380 if ((error = mod_remove(&gg_modlinkage)) != 0) { 381 cmn_err(CE_WARN, "mod_remove failed: %d", error); 382 return (error); 383 } 384 385 /* free resources */ 386 ddi_soft_state_fini(&statep); 387 mutex_destroy(&gg_mutex); 388 389 return (0); 390 } 391 392