mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 19:19:32 +03:00
Use spa as key besides objsetid for snapentry
objsetid is not unique across pool, so using it solely as key would cause panic when automounting two snapshot on different pools with the same objsetid. We fix this by adding spa pointer as additional key. Signed-off-by: Chunwei Chen <david.chen@osnexus.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Richard Yao <ryao@gentoo.org> Issue #3948 Issue #3786 Issue #3887
This commit is contained in:
parent
b58986eebf
commit
24ef51f660
@ -77,7 +77,8 @@ extern int zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
|
|||||||
extern void zfsctl_snapdir_inactive(struct inode *ip);
|
extern void zfsctl_snapdir_inactive(struct inode *ip);
|
||||||
extern int zfsctl_snapshot_mount(struct path *path, int flags);
|
extern int zfsctl_snapshot_mount(struct path *path, int flags);
|
||||||
extern int zfsctl_snapshot_unmount(char *snapname, int flags);
|
extern int zfsctl_snapshot_unmount(char *snapname, int flags);
|
||||||
extern int zfsctl_snapshot_unmount_delay(uint64_t objsetid, int delay);
|
extern int zfsctl_snapshot_unmount_delay(spa_t *spa, uint64_t objsetid,
|
||||||
|
int delay);
|
||||||
extern int zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid,
|
extern int zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid,
|
||||||
zfs_sb_t **zsb);
|
zfs_sb_t **zsb);
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
#include <sys/zfs_vnops.h>
|
#include <sys/zfs_vnops.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/dmu.h>
|
#include <sys/dmu.h>
|
||||||
|
#include <sys/dmu_objset.h>
|
||||||
#include <sys/dsl_destroy.h>
|
#include <sys/dsl_destroy.h>
|
||||||
#include <sys/dsl_deleg.h>
|
#include <sys/dsl_deleg.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
@ -117,6 +118,7 @@ static taskq_t *zfs_expire_taskq;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
char *se_name; /* full snapshot name */
|
char *se_name; /* full snapshot name */
|
||||||
char *se_path; /* full mount path */
|
char *se_path; /* full mount path */
|
||||||
|
spa_t *se_spa; /* pool spa */
|
||||||
uint64_t se_objsetid; /* snapshot objset id */
|
uint64_t se_objsetid; /* snapshot objset id */
|
||||||
struct dentry *se_root_dentry; /* snapshot root dentry */
|
struct dentry *se_root_dentry; /* snapshot root dentry */
|
||||||
taskqid_t se_taskqid; /* scheduled unmount taskqid */
|
taskqid_t se_taskqid; /* scheduled unmount taskqid */
|
||||||
@ -132,8 +134,8 @@ static void zfsctl_snapshot_unmount_delay_impl(zfs_snapentry_t *se, int delay);
|
|||||||
* the snapshot name and provided mount point. No reference is taken.
|
* the snapshot name and provided mount point. No reference is taken.
|
||||||
*/
|
*/
|
||||||
static zfs_snapentry_t *
|
static zfs_snapentry_t *
|
||||||
zfsctl_snapshot_alloc(char *full_name, char *full_path, uint64_t objsetid,
|
zfsctl_snapshot_alloc(char *full_name, char *full_path, spa_t *spa,
|
||||||
struct dentry *root_dentry)
|
uint64_t objsetid, struct dentry *root_dentry)
|
||||||
{
|
{
|
||||||
zfs_snapentry_t *se;
|
zfs_snapentry_t *se;
|
||||||
|
|
||||||
@ -141,6 +143,7 @@ zfsctl_snapshot_alloc(char *full_name, char *full_path, uint64_t objsetid,
|
|||||||
|
|
||||||
se->se_name = strdup(full_name);
|
se->se_name = strdup(full_name);
|
||||||
se->se_path = strdup(full_path);
|
se->se_path = strdup(full_path);
|
||||||
|
se->se_spa = spa;
|
||||||
se->se_objsetid = objsetid;
|
se->se_objsetid = objsetid;
|
||||||
se->se_root_dentry = root_dentry;
|
se->se_root_dentry = root_dentry;
|
||||||
se->se_taskqid = -1;
|
se->se_taskqid = -1;
|
||||||
@ -242,6 +245,9 @@ snapentry_compare_by_objsetid(const void *a, const void *b)
|
|||||||
const zfs_snapentry_t *se_a = a;
|
const zfs_snapentry_t *se_a = a;
|
||||||
const zfs_snapentry_t *se_b = b;
|
const zfs_snapentry_t *se_b = b;
|
||||||
|
|
||||||
|
if (se_a->se_spa != se_b->se_spa)
|
||||||
|
return ((ulong_t)se_a->se_spa < (ulong_t)se_b->se_spa ? -1 : 1);
|
||||||
|
|
||||||
if (se_a->se_objsetid < se_b->se_objsetid)
|
if (se_a->se_objsetid < se_b->se_objsetid)
|
||||||
return (-1);
|
return (-1);
|
||||||
else if (se_a->se_objsetid > se_b->se_objsetid)
|
else if (se_a->se_objsetid > se_b->se_objsetid)
|
||||||
@ -278,12 +284,13 @@ zfsctl_snapshot_find_by_name(char *snapname)
|
|||||||
* as zfsctl_snapshot_find_by_name().
|
* as zfsctl_snapshot_find_by_name().
|
||||||
*/
|
*/
|
||||||
static zfs_snapentry_t *
|
static zfs_snapentry_t *
|
||||||
zfsctl_snapshot_find_by_objsetid(uint64_t objsetid)
|
zfsctl_snapshot_find_by_objsetid(spa_t *spa, uint64_t objsetid)
|
||||||
{
|
{
|
||||||
zfs_snapentry_t *se, search;
|
zfs_snapentry_t *se, search;
|
||||||
|
|
||||||
ASSERT(MUTEX_HELD(&zfs_snapshot_lock));
|
ASSERT(MUTEX_HELD(&zfs_snapshot_lock));
|
||||||
|
|
||||||
|
search.se_spa = spa;
|
||||||
search.se_objsetid = objsetid;
|
search.se_objsetid = objsetid;
|
||||||
se = avl_find(&zfs_snapshots_by_objsetid, &search, NULL);
|
se = avl_find(&zfs_snapshots_by_objsetid, &search, NULL);
|
||||||
if (se)
|
if (se)
|
||||||
@ -323,6 +330,7 @@ static void
|
|||||||
snapentry_expire(void *data)
|
snapentry_expire(void *data)
|
||||||
{
|
{
|
||||||
zfs_snapentry_t *se = (zfs_snapentry_t *)data;
|
zfs_snapentry_t *se = (zfs_snapentry_t *)data;
|
||||||
|
spa_t *spa = se->se_spa;
|
||||||
uint64_t objsetid = se->se_objsetid;
|
uint64_t objsetid = se->se_objsetid;
|
||||||
|
|
||||||
se->se_taskqid = -1;
|
se->se_taskqid = -1;
|
||||||
@ -334,7 +342,7 @@ snapentry_expire(void *data)
|
|||||||
* This can occur when the snapshot is busy.
|
* This can occur when the snapshot is busy.
|
||||||
*/
|
*/
|
||||||
mutex_enter(&zfs_snapshot_lock);
|
mutex_enter(&zfs_snapshot_lock);
|
||||||
if ((se = zfsctl_snapshot_find_by_objsetid(objsetid)) != NULL) {
|
if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
|
||||||
zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
|
zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
|
||||||
zfsctl_snapshot_rele(se);
|
zfsctl_snapshot_rele(se);
|
||||||
}
|
}
|
||||||
@ -377,13 +385,13 @@ zfsctl_snapshot_unmount_delay_impl(zfs_snapentry_t *se, int delay)
|
|||||||
* and held until the outstanding task is handled or cancelled.
|
* and held until the outstanding task is handled or cancelled.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zfsctl_snapshot_unmount_delay(uint64_t objsetid, int delay)
|
zfsctl_snapshot_unmount_delay(spa_t *spa, uint64_t objsetid, int delay)
|
||||||
{
|
{
|
||||||
zfs_snapentry_t *se;
|
zfs_snapentry_t *se;
|
||||||
int error = ENOENT;
|
int error = ENOENT;
|
||||||
|
|
||||||
mutex_enter(&zfs_snapshot_lock);
|
mutex_enter(&zfs_snapshot_lock);
|
||||||
if ((se = zfsctl_snapshot_find_by_objsetid(objsetid)) != NULL) {
|
if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
|
||||||
zfsctl_snapshot_unmount_cancel(se);
|
zfsctl_snapshot_unmount_cancel(se);
|
||||||
zfsctl_snapshot_unmount_delay_impl(se, delay);
|
zfsctl_snapshot_unmount_delay_impl(se, delay);
|
||||||
zfsctl_snapshot_rele(se);
|
zfsctl_snapshot_rele(se);
|
||||||
@ -560,10 +568,12 @@ zfsctl_destroy(zfs_sb_t *zsb)
|
|||||||
{
|
{
|
||||||
if (zsb->z_issnap) {
|
if (zsb->z_issnap) {
|
||||||
zfs_snapentry_t *se;
|
zfs_snapentry_t *se;
|
||||||
|
spa_t *spa = zsb->z_os->os_spa;
|
||||||
uint64_t objsetid = dmu_objset_id(zsb->z_os);
|
uint64_t objsetid = dmu_objset_id(zsb->z_os);
|
||||||
|
|
||||||
mutex_enter(&zfs_snapshot_lock);
|
mutex_enter(&zfs_snapshot_lock);
|
||||||
if ((se = zfsctl_snapshot_find_by_objsetid(objsetid)) != NULL) {
|
if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid))
|
||||||
|
!= NULL) {
|
||||||
zfsctl_snapshot_unmount_cancel(se);
|
zfsctl_snapshot_unmount_cancel(se);
|
||||||
zfsctl_snapshot_remove(se);
|
zfsctl_snapshot_remove(se);
|
||||||
zfsctl_snapshot_rele(se);
|
zfsctl_snapshot_rele(se);
|
||||||
@ -1129,7 +1139,8 @@ zfsctl_snapshot_mount(struct path *path, int flags)
|
|||||||
|
|
||||||
mutex_enter(&zfs_snapshot_lock);
|
mutex_enter(&zfs_snapshot_lock);
|
||||||
se = zfsctl_snapshot_alloc(full_name, full_path,
|
se = zfsctl_snapshot_alloc(full_name, full_path,
|
||||||
dmu_objset_id(snap_zsb->z_os), dentry);
|
snap_zsb->z_os->os_spa, dmu_objset_id(snap_zsb->z_os),
|
||||||
|
dentry);
|
||||||
zfsctl_snapshot_add(se);
|
zfsctl_snapshot_add(se);
|
||||||
zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
|
zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
|
||||||
mutex_exit(&zfs_snapshot_lock);
|
mutex_exit(&zfs_snapshot_lock);
|
||||||
@ -1152,6 +1163,7 @@ zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid, zfs_sb_t **zsbp)
|
|||||||
{
|
{
|
||||||
zfs_snapentry_t *se;
|
zfs_snapentry_t *se;
|
||||||
int error;
|
int error;
|
||||||
|
spa_t *spa = ((zfs_sb_t *)(sb->s_fs_info))->z_os->os_spa;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify that the snapshot is mounted then lookup the mounted root
|
* Verify that the snapshot is mounted then lookup the mounted root
|
||||||
@ -1161,7 +1173,7 @@ zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid, zfs_sb_t **zsbp)
|
|||||||
* because we hold the zfs_snapshot_lock to prevent the race.
|
* because we hold the zfs_snapshot_lock to prevent the race.
|
||||||
*/
|
*/
|
||||||
mutex_enter(&zfs_snapshot_lock);
|
mutex_enter(&zfs_snapshot_lock);
|
||||||
if ((se = zfsctl_snapshot_find_by_objsetid(objsetid)) != NULL) {
|
if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
|
||||||
zfs_sb_t *zsb;
|
zfs_sb_t *zsb;
|
||||||
|
|
||||||
zsb = ITOZSB(se->se_root_dentry->d_inode);
|
zsb = ITOZSB(se->se_root_dentry->d_inode);
|
||||||
@ -1170,7 +1182,7 @@ zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid, zfs_sb_t **zsbp)
|
|||||||
if (time_after(jiffies, zsb->z_snap_defer_time +
|
if (time_after(jiffies, zsb->z_snap_defer_time +
|
||||||
MAX(zfs_expire_snapshot * HZ / 2, HZ))) {
|
MAX(zfs_expire_snapshot * HZ / 2, HZ))) {
|
||||||
zsb->z_snap_defer_time = jiffies;
|
zsb->z_snap_defer_time = jiffies;
|
||||||
zfsctl_snapshot_unmount_delay(objsetid,
|
zfsctl_snapshot_unmount_delay(spa, objsetid,
|
||||||
zfs_expire_snapshot);
|
zfs_expire_snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <sys/zfs_vfsops.h>
|
#include <sys/zfs_vfsops.h>
|
||||||
#include <sys/zfs_vnops.h>
|
#include <sys/zfs_vnops.h>
|
||||||
#include <sys/zfs_znode.h>
|
#include <sys/zfs_znode.h>
|
||||||
|
#include <sys/dmu_objset.h>
|
||||||
#include <sys/vfs.h>
|
#include <sys/vfs.h>
|
||||||
#include <sys/zpl.h>
|
#include <sys/zpl.h>
|
||||||
|
|
||||||
@ -500,7 +501,7 @@ zpl_revalidate(struct dentry *dentry, unsigned int flags)
|
|||||||
if (time_after(jiffies, zsb->z_snap_defer_time +
|
if (time_after(jiffies, zsb->z_snap_defer_time +
|
||||||
MAX(zfs_expire_snapshot * HZ / 2, HZ))) {
|
MAX(zfs_expire_snapshot * HZ / 2, HZ))) {
|
||||||
zsb->z_snap_defer_time = jiffies;
|
zsb->z_snap_defer_time = jiffies;
|
||||||
zfsctl_snapshot_unmount_delay(
|
zfsctl_snapshot_unmount_delay(zsb->z_os->os_spa,
|
||||||
dmu_objset_id(zsb->z_os), zfs_expire_snapshot);
|
dmu_objset_id(zsb->z_os), zfs_expire_snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user