/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#pragma ident "@(#)libzfs_shadow.c 1.2 08/11/18 SMI"
/*
* ZFS shadow data migration
*
* ZFS supports native integration with the 'shadow' mount property used to
* migrate data from one filesystem to another. The kernel implementation of
* this is quite generic, and allows for 'shadow=<path>' to be set on any
* filesystem. To make life easier for ZFS consumers, we integrate this with a
* native 'shadow' property, and support a friendlier way of specifying
* remote filesystems.
*
* The 'shadow' ZFS property does not take a filesystem path, but a URI
* indicating where the filesystem can be found. This URL can take one of
* the following forms:
*
* file:///path
*
* ZFS will then automatically mount this filesystem locally using the
* appropriate protocol, and pass down the path to the shadow filesystem.
* Using this model, the kernel is blissfully unaware that we are copying data
* from a remote filesystem, but the user can specify the location in a
* higher-level form.
*
* This file handles mounting and unmounting this transient mount before it is
* passed to the kernel.
*/
#include <libgen.h>
#include <libintl.h>
#include <libzfs.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <paths.h>
#include "libzfs_impl.h"
static int
{
int len;
*mntopts = "ro";
*protocol = MNTTYPE_LOFS;
shadow += 7;
/*
* For file targets, we need to make sure the directory exists
*/
if (shadow[0] != '/') {
"shadow file path must be absolute"));
}
sizeof (fullpath))) < 0) {
}
/*
* Don't accept a path within our shadow mount directory.
* Also disallow any path that's one of the directories along
* the way to the shadow mount directory.
*/
return (-1);
strlen(ZFS_SHADOW_DIR)) == 0 &&
"path may not include %s"), ZFS_SHADOW_DIR);
}
*checkend = '\0';
"path may not be along the path to %s"),
EZFS_BADSHADOW, errmsg));
}
break;
}
return (-1);
*protocol = MNTTYPE_NFS;
shadow += 6;
/*
* For NFS mounts, we need to convert the first slash into a
*/
"missing host name"));
}
"missing path"));
}
return (-1);
/*
* We never want to hang trying to mount the underlying source,
* so specify no retries.
*/
*mntopts = "ro,retry=0";
shadow += 6;
/*
* For SMB mounts, there is nothing we need to do, though we
* check for obvious mistakes.
*/
"incomplete path"));
}
return (-1);
} else {
"unknown shadow protocol"));
}
return (0);
}
int
{
const char *protocol;
const char *mntopts;
char *path;
return (0);
return (-1);
return (0);
}
int
{
/* strip any 'shadow=standby' from a mount that doesn't need it */
if (noprop) {
return (0);
return (0);
}
/*
* If this is a remount request, then check to see if the shadow
* property is changing. If not, there's nothing left to do.
*/
prevshadow += 7;
return (0);
}
/*
* Each directory is named after the GUID of the underlying filesystem.
*/
guid);
/*
* Make sure the shadow directory exists.
*/
"failed to create shadow directory")));
}
/*
* Attempt to unmount anything that may be there. In general, this
* shouldn't be possible, but we do it just in case we died and left
* the system in a strange state.
*/
/*
* If the user has manually specified a shadow setting (typically only
* allowed with "shadow=standby"), then don't do anything else.
*/
return (0);
/*
* Ideally, we'd just like to call mount(2) here, but the mount(1m)
* command does a significant amount of additional work (particularly
* for smbfs) that we need in order to pass private information to the
* kernel.
*
* We need to exec the following command:
*
* mount -F <mnttype> -O -o ro <arg> <path>
*
* We always specify an overlay mount just in case
* there is a stale mount there, or someone happens to
* be in that current directory. While this shouldn't
* happen, it shouldn't cause us to fail.
*/
return (-1);
argv[0] = "mount";
hdl->libzfs_spawn_data) != 0) {
}
if (mountopts[0] != '\0')
return (0);
}
static void
{
guid);
/*
* Attempt to unmount and remove the directory.
*/
}
int
{
return (0);
return (0);
}
static int
{
return (-1);
return (0);
}
int
{
return (-1);
return (zfs_shadow_clear(zhp));
else
}