/* * If the property is 'mountpoint', go through and unmount filesystems as * necessary. We don't do the same for 'sharenfs', because we can just re-share * with different options without interrupting service. We do handle 'sharesmb' * since there may be old resource names that need to be removed. */ int changelist_prefix(prop_changelist_t *clp) { prop_changenode_t *cn; int ret = 0; if (clp->cl_prop != ZFS_PROP_MOUNTPOINT && clp->cl_prop != ZFS_PROP_SHARESMB) return (0); for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { /* if a previous loop failed, set the remaining to false */ if (ret == -1) { cn->cn_needpost = B_FALSE; continue; } /* * If we are in the global zone, but this dataset is exported * to a local zone, do nothing. */ if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned) continue; if (!ZFS_IS_VOLUME(cn->cn_handle)) { /* * Do the property specific processing. */ switch (clp->cl_prop) { case ZFS_PROP_MOUNTPOINT: if (zfs_unmount(cn->cn_handle, NULL, clp->cl_mflags) != 0) { ret = -1; cn->cn_needpost = B_FALSE; } break; case ZFS_PROP_SHARESMB: (void) zfs_unshare_smb(cn->cn_handle, NULL); break; default: break; } } } if (ret == -1) { #if defined(HAVE_ZPL) (void) changelist_postfix(clp); #else ret = changelist_postfix(clp); #endif } return (ret); }
/* * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or * reshare the filesystems as necessary. In changelist_gather() we recorded * whether the filesystem was previously shared or mounted. The action we take * depends on the previous state, and whether the value was previously 'legacy'. * For non-legacy properties, we only remount/reshare the filesystem if it was * previously mounted/shared. Otherwise, we always remount/reshare the * filesystem. */ int changelist_postfix(prop_changelist_t *clp) { prop_changenode_t *cn; char shareopts[ZFS_MAXPROPLEN]; int errors = 0; libzfs_handle_t *hdl; /* * If we're changing the mountpoint, attempt to destroy the underlying * mountpoint. All other datasets will have inherited from this dataset * (in which case their mountpoints exist in the filesystem in the new * location), or have explicit mountpoints set (in which case they won't * be in the changelist). */ if ((cn = uu_list_last(clp->cl_list)) == NULL) return (0); if (clp->cl_prop == ZFS_PROP_MOUNTPOINT && !(clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)) { remove_mountpoint(cn->cn_handle); } /* * It is possible that the changelist_prefix() used libshare * to unshare some entries. Since libshare caches data, an * attempt to reshare during postfix can fail unless libshare * is uninitialized here so that it will reinitialize later. */ if (cn->cn_handle != NULL) { hdl = cn->cn_handle->zfs_hdl; assert(hdl != NULL); zfs_uninit_libshare(hdl); } /* * We walk the datasets in reverse, because we want to mount any parent * datasets before mounting the children. We walk all datasets even if * there are errors. */ for (cn = uu_list_last(clp->cl_list); cn != NULL; cn = uu_list_prev(clp->cl_list, cn)) { boolean_t sharenfs; boolean_t sharesmb; boolean_t mounted; /* * If we are in the global zone, but this dataset is exported * to a local zone, do nothing. */ if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned) continue; /* Only do post-processing if it's required */ if (!cn->cn_needpost) continue; cn->cn_needpost = B_FALSE; zfs_refresh_properties(cn->cn_handle); if (ZFS_IS_VOLUME(cn->cn_handle)) continue; /* * Remount if previously mounted or mountpoint was legacy, * or sharenfs or sharesmb property is set. */ sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0) && (strcmp(shareopts, "off") != 0)); sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB, shareopts, sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0) && (strcmp(shareopts, "off") != 0)); mounted = (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT) || zfs_is_mounted(cn->cn_handle, NULL); if (!mounted && (cn->cn_mounted || ((sharenfs || sharesmb || clp->cl_waslegacy) && (zfs_prop_get_int(cn->cn_handle, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) { if (zfs_mount(cn->cn_handle, NULL, 0) != 0) errors++; else mounted = TRUE; } /* * If the file system is mounted we always re-share even * if the filesystem is currently shared, so that we can * adopt any new options. */ if (sharenfs && mounted) errors += zfs_share_nfs(cn->cn_handle); else if (cn->cn_shared || clp->cl_waslegacy) errors += zfs_unshare_nfs(cn->cn_handle, NULL); if (sharesmb && mounted) errors += zfs_share_smb(cn->cn_handle); else if (cn->cn_shared || clp->cl_waslegacy) errors += zfs_unshare_smb(cn->cn_handle, NULL); } return (errors ? -1 : 0); }