/* * Safely mark an inode dirty. Inodes which are part of a read-only * file system or snapshot may not be dirtied. */ void zfs_mark_inode_dirty(struct inode *ip) { zfs_sb_t *zsb = ITOZSB(ip); if (zfs_is_readonly(zsb) || dmu_objset_is_snapshot(zsb->z_os)) return; mark_inode_dirty(ip); }
/* * Return a znode for the extended attribute directory for zp. * ** If the directory does not already exist, it is created ** * * IN: zp - znode to obtain attribute directory from * cr - credentials of caller * flags - flags from the VOP_LOOKUP call * * OUT: xipp - pointer to extended attribute znode * * RETURN: 0 on success * error number on failure */ int zfs_get_xattrdir(znode_t *zp, struct inode **xipp, cred_t *cr, int flags) { zfsvfs_t *zfsvfs = ZTOZSB(zp); znode_t *xzp; zfs_dirlock_t *dl; vattr_t va; int error; top: error = zfs_dirent_lock(&dl, zp, "", &xzp, ZXATTR, NULL, NULL); if (error) return (error); if (xzp != NULL) { *xipp = ZTOI(xzp); zfs_dirent_unlock(dl); return (0); } if (!(flags & CREATE_XATTR_DIR)) { zfs_dirent_unlock(dl); return (SET_ERROR(ENOENT)); } if (zfs_is_readonly(zfsvfs)) { zfs_dirent_unlock(dl); return (SET_ERROR(EROFS)); } /* * The ability to 'create' files in an attribute * directory comes from the write_xattr permission on the base file. * * The ability to 'search' an attribute directory requires * read_xattr permission on the base file. * * Once in a directory the ability to read/write attributes * is controlled by the permissions on the attribute file. */ va.va_mask = ATTR_MODE | ATTR_UID | ATTR_GID; va.va_mode = S_IFDIR | S_ISVTX | 0777; zfs_fuid_map_ids(zp, cr, &va.va_uid, &va.va_gid); va.va_dentry = NULL; error = zfs_make_xattrdir(zp, &va, xipp, cr); zfs_dirent_unlock(dl); if (error == ERESTART) { /* NB: we already did dmu_tx_wait() if necessary */ goto top; } return (error); }
int zfs_sb_setup(zfs_sb_t *zsb, boolean_t mounting) { int error; error = zfs_register_callbacks(zsb); if (error) return (error); /* * Set the objset user_ptr to track its zsb. */ mutex_enter(&zsb->z_os->os_user_ptr_lock); dmu_objset_set_user(zsb->z_os, zsb); mutex_exit(&zsb->z_os->os_user_ptr_lock); zsb->z_log = zil_open(zsb->z_os, zfs_get_data); /* * If we are not mounting (ie: online recv), then we don't * have to worry about replaying the log as we blocked all * operations out since we closed the ZIL. */ if (mounting) { boolean_t readonly; /* * During replay we remove the read only flag to * allow replays to succeed. */ readonly = zfs_is_readonly(zsb); if (readonly != 0) readonly_changed_cb(zsb, B_FALSE); else zfs_unlinked_drain(zsb); /* * Parse and replay the intent log. * * Because of ziltest, this must be done after * zfs_unlinked_drain(). (Further note: ziltest * doesn't use readonly mounts, where * zfs_unlinked_drain() isn't called.) This is because * ziltest causes spa_sync() to think it's committed, * but actually it is not, so the intent log contains * many txg's worth of changes. * * In particular, if object N is in the unlinked set in * the last txg to actually sync, then it could be * actually freed in a later txg and then reallocated * in a yet later txg. This would write a "create * object N" record to the intent log. Normally, this * would be fine because the spa_sync() would have * written out the fact that object N is free, before * we could write the "create object N" intent log * record. * * But when we are in ziltest mode, we advance the "open * txg" without actually spa_sync()-ing the changes to * disk. So we would see that object N is still * allocated and in the unlinked set, and there is an * intent log record saying to allocate it. */ if (spa_writeable(dmu_objset_spa(zsb->z_os))) { if (zil_replay_disable) { zil_destroy(zsb->z_log, B_FALSE); } else { zsb->z_replay = B_TRUE; zil_replay(zsb->z_os, zsb, zfs_replay_vector); zsb->z_replay = B_FALSE; } } /* restore readonly bit */ if (readonly != 0) readonly_changed_cb(zsb, B_TRUE); } return (0); }
int zfs_register_callbacks(zfs_sb_t *zsb) { struct dsl_dataset *ds = NULL; objset_t *os = zsb->z_os; zfs_mntopts_t *zmo = zsb->z_mntopts; int error = 0; ASSERT(zsb); ASSERT(zmo); /* * The act of registering our callbacks will destroy any mount * options we may have. In order to enable temporary overrides * of mount options, we stash away the current values and * restore them after we register the callbacks. */ if (zfs_is_readonly(zsb) || !spa_writeable(dmu_objset_spa(os))) { zmo->z_do_readonly = B_TRUE; zmo->z_readonly = B_TRUE; } /* * Register property callbacks. * * It would probably be fine to just check for i/o error from * the first prop_register(), but I guess I like to go * overboard... */ ds = dmu_objset_ds(os); dsl_pool_config_enter(dmu_objset_pool(os), FTAG); error = dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_RELATIME), relatime_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE), blksz_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_READONLY), readonly_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_DEVICES), devices_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_SETUID), setuid_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_EXEC), exec_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_SNAPDIR), snapdir_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_ACLTYPE), acltype_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_VSCAN), vscan_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_NBMAND), nbmand_changed_cb, zsb); dsl_pool_config_exit(dmu_objset_pool(os), FTAG); if (error) goto unregister; /* * Invoke our callbacks to restore temporary mount options. */ if (zmo->z_do_readonly) readonly_changed_cb(zsb, zmo->z_readonly); if (zmo->z_do_setuid) setuid_changed_cb(zsb, zmo->z_setuid); if (zmo->z_do_exec) exec_changed_cb(zsb, zmo->z_exec); if (zmo->z_do_devices) devices_changed_cb(zsb, zmo->z_devices); if (zmo->z_do_xattr) xattr_changed_cb(zsb, zmo->z_xattr); if (zmo->z_do_atime) atime_changed_cb(zsb, zmo->z_atime); if (zmo->z_do_relatime) relatime_changed_cb(zsb, zmo->z_relatime); if (zmo->z_do_nbmand) nbmand_changed_cb(zsb, zmo->z_nbmand); return (0); unregister: /* * We may attempt to unregister some callbacks that are not * registered, but this is OK; it will simply return ENOMSG, * which we will ignore. */ (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RELATIME), relatime_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE), blksz_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_READONLY), readonly_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_DEVICES), devices_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SETUID), setuid_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_EXEC), exec_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SNAPDIR), snapdir_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLTYPE), acltype_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_VSCAN), vscan_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_NBMAND), nbmand_changed_cb, zsb); return (error); }
/* * Teardown the zfs_sb_t. * * Note, if 'unmounting' if FALSE, we return with the 'z_teardown_lock' * and 'z_teardown_inactive_lock' held. */ int zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting) { znode_t *zp; /* * If someone has not already unmounted this file system, * drain the iput_taskq to ensure all active references to the * zfs_sb_t have been handled only then can it be safely destroyed. */ if (zsb->z_os) { /* * If we're unmounting we have to wait for the list to * drain completely. * * If we're not unmounting there's no guarantee the list * will drain completely, but iputs run from the taskq * may add the parents of dir-based xattrs to the taskq * so we want to wait for these. * * We can safely read z_nr_znodes without locking because the * VFS has already blocked operations which add to the * z_all_znodes list and thus increment z_nr_znodes. */ int round = 0; while (zsb->z_nr_znodes > 0) { taskq_wait_outstanding(dsl_pool_iput_taskq( dmu_objset_pool(zsb->z_os)), 0); if (++round > 1 && !unmounting) break; } } rrm_enter(&zsb->z_teardown_lock, RW_WRITER, FTAG); if (!unmounting) { /* * We purge the parent filesystem's super block as the * parent filesystem and all of its snapshots have their * inode's super block set to the parent's filesystem's * super block. Note, 'z_parent' is self referential * for non-snapshots. */ shrink_dcache_sb(zsb->z_parent->z_sb); } /* * Close the zil. NB: Can't close the zil while zfs_inactive * threads are blocked as zil_close can call zfs_inactive. */ if (zsb->z_log) { zil_close(zsb->z_log); zsb->z_log = NULL; } rw_enter(&zsb->z_teardown_inactive_lock, RW_WRITER); /* * If we are not unmounting (ie: online recv) and someone already * unmounted this file system while we were doing the switcheroo, * or a reopen of z_os failed then just bail out now. */ if (!unmounting && (zsb->z_unmounted || zsb->z_os == NULL)) { rw_exit(&zsb->z_teardown_inactive_lock); rrm_exit(&zsb->z_teardown_lock, FTAG); return (SET_ERROR(EIO)); } /* * At this point there are no VFS ops active, and any new VFS ops * will fail with EIO since we have z_teardown_lock for writer (only * relevant for forced unmount). * * Release all holds on dbufs. */ if (!unmounting) { mutex_enter(&zsb->z_znodes_lock); for (zp = list_head(&zsb->z_all_znodes); zp != NULL; zp = list_next(&zsb->z_all_znodes, zp)) { if (zp->z_sa_hdl) zfs_znode_dmu_fini(zp); } mutex_exit(&zsb->z_znodes_lock); } /* * If we are unmounting, set the unmounted flag and let new VFS ops * unblock. zfs_inactive will have the unmounted behavior, and all * other VFS ops will fail with EIO. */ if (unmounting) { zsb->z_unmounted = B_TRUE; rrm_exit(&zsb->z_teardown_lock, FTAG); rw_exit(&zsb->z_teardown_inactive_lock); } /* * z_os will be NULL if there was an error in attempting to reopen * zsb, so just return as the properties had already been * * unregistered and cached data had been evicted before. */ if (zsb->z_os == NULL) return (0); /* * Unregister properties. */ zfs_unregister_callbacks(zsb); /* * Evict cached data */ if (dsl_dataset_is_dirty(dmu_objset_ds(zsb->z_os)) && !zfs_is_readonly(zsb)) txg_wait_synced(dmu_objset_pool(zsb->z_os), 0); dmu_objset_evict_dbufs(zsb->z_os); return (0); }
int zfs_register_callbacks(zfs_sb_t *zsb) { struct dsl_dataset *ds = NULL; objset_t *os = zsb->z_os; boolean_t do_readonly = B_FALSE; int error = 0; if (zfs_is_readonly(zsb) || !spa_writeable(dmu_objset_spa(os))) do_readonly = B_TRUE; /* * Register property callbacks. * * It would probably be fine to just check for i/o error from * the first prop_register(), but I guess I like to go * overboard... */ ds = dmu_objset_ds(os); dsl_pool_config_enter(dmu_objset_pool(os), FTAG); error = dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE), blksz_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_READONLY), readonly_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_DEVICES), devices_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_SETUID), setuid_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_EXEC), exec_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_SNAPDIR), snapdir_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_VSCAN), vscan_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, zfs_prop_to_name(ZFS_PROP_NBMAND), nbmand_changed_cb, zsb); dsl_pool_config_exit(dmu_objset_pool(os), FTAG); if (error) goto unregister; if (do_readonly) readonly_changed_cb(zsb, B_TRUE); return (0); unregister: /* * We may attempt to unregister some callbacks that are not * registered, but this is OK; it will simply return ENOMSG, * which we will ignore. */ (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ATIME), atime_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_XATTR), xattr_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE), blksz_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_READONLY), readonly_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_DEVICES), devices_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SETUID), setuid_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_EXEC), exec_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SNAPDIR), snapdir_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_VSCAN), vscan_changed_cb, zsb); (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_NBMAND), nbmand_changed_cb, zsb); return (error); }
/* * Teardown the zfs_sb_t. * * Note, if 'unmounting' if FALSE, we return with the 'z_teardown_lock' * and 'z_teardown_inactive_lock' held. */ int zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting) { znode_t *zp; rrw_enter(&zsb->z_teardown_lock, RW_WRITER, FTAG); if (!unmounting) { /* * We purge the parent filesystem's super block as the * parent filesystem and all of its snapshots have their * inode's super block set to the parent's filesystem's * super block. Note, 'z_parent' is self referential * for non-snapshots. */ shrink_dcache_sb(zsb->z_parent->z_sb); } /* * If someone has not already unmounted this file system, * drain the iput_taskq to ensure all active references to the * zfs_sb_t have been handled only then can it be safely destroyed. */ if (zsb->z_os) taskq_wait(dsl_pool_iput_taskq(dmu_objset_pool(zsb->z_os))); /* * Close the zil. NB: Can't close the zil while zfs_inactive * threads are blocked as zil_close can call zfs_inactive. */ if (zsb->z_log) { zil_close(zsb->z_log); zsb->z_log = NULL; } rw_enter(&zsb->z_teardown_inactive_lock, RW_WRITER); /* * If we are not unmounting (ie: online recv) and someone already * unmounted this file system while we were doing the switcheroo, * or a reopen of z_os failed then just bail out now. */ if (!unmounting && (zsb->z_unmounted || zsb->z_os == NULL)) { rw_exit(&zsb->z_teardown_inactive_lock); rrw_exit(&zsb->z_teardown_lock, FTAG); return (EIO); } /* * At this point there are no VFS ops active, and any new VFS ops * will fail with EIO since we have z_teardown_lock for writer (only * relevant for forced unmount). * * Release all holds on dbufs. */ mutex_enter(&zsb->z_znodes_lock); for (zp = list_head(&zsb->z_all_znodes); zp != NULL; zp = list_next(&zsb->z_all_znodes, zp)) { if (zp->z_sa_hdl) { ASSERT(atomic_read(&ZTOI(zp)->i_count) > 0); zfs_znode_dmu_fini(zp); } } mutex_exit(&zsb->z_znodes_lock); /* * If we are unmounting, set the unmounted flag and let new VFS ops * unblock. zfs_inactive will have the unmounted behavior, and all * other VFS ops will fail with EIO. */ if (unmounting) { zsb->z_unmounted = B_TRUE; rrw_exit(&zsb->z_teardown_lock, FTAG); rw_exit(&zsb->z_teardown_inactive_lock); } /* * z_os will be NULL if there was an error in attempting to reopen * zsb, so just return as the properties had already been * * unregistered and cached data had been evicted before. */ if (zsb->z_os == NULL) return (0); /* * Unregister properties. */ zfs_unregister_callbacks(zsb); /* * Evict cached data */ if (dsl_dataset_is_dirty(dmu_objset_ds(zsb->z_os)) && !zfs_is_readonly(zsb)) txg_wait_synced(dmu_objset_pool(zsb->z_os), 0); dmu_objset_evict_dbufs(zsb->z_os); return (0); }
int zfs_register_callbacks(zfs_sb_t *zsb) { struct dsl_dataset *ds = NULL; objset_t *os = zsb->z_os; int error = 0; if (zfs_is_readonly(zsb) || !spa_writeable(dmu_objset_spa(os))) readonly_changed_cb(zsb, B_TRUE); /* * Register property callbacks. * * It would probably be fine to just check for i/o error from * the first prop_register(), but I guess I like to go * overboard... */ ds = dmu_objset_ds(os); error = dsl_prop_register(ds, "atime", atime_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "xattr", xattr_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "recordsize", blksz_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "readonly", readonly_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "devices", devices_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "setuid", setuid_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "exec", exec_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "snapdir", snapdir_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "aclinherit", acl_inherit_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "vscan", vscan_changed_cb, zsb); error = error ? error : dsl_prop_register(ds, "nbmand", nbmand_changed_cb, zsb); if (error) goto unregister; return (0); unregister: /* * We may attempt to unregister some callbacks that are not * registered, but this is OK; it will simply return ENOMSG, * which we will ignore. */ (void) dsl_prop_unregister(ds, "atime", atime_changed_cb, zsb); (void) dsl_prop_unregister(ds, "xattr", xattr_changed_cb, zsb); (void) dsl_prop_unregister(ds, "recordsize", blksz_changed_cb, zsb); (void) dsl_prop_unregister(ds, "readonly", readonly_changed_cb, zsb); (void) dsl_prop_unregister(ds, "devices", devices_changed_cb, zsb); (void) dsl_prop_unregister(ds, "setuid", setuid_changed_cb, zsb); (void) dsl_prop_unregister(ds, "exec", exec_changed_cb, zsb); (void) dsl_prop_unregister(ds, "snapdir", snapdir_changed_cb, zsb); (void) dsl_prop_unregister(ds, "aclinherit", acl_inherit_changed_cb, zsb); (void) dsl_prop_unregister(ds, "vscan", vscan_changed_cb, zsb); (void) dsl_prop_unregister(ds, "nbmand", nbmand_changed_cb, zsb); return (error); }