Skip to content

Commit

Permalink
Automatic detection of volume mount points
Browse files Browse the repository at this point in the history
Volume Mount Points are now automatically detected.

If we detect a volume mount point, we check wich volume is
mounted there and add it to the snapshotset.

If the volume is not already in the snapshotset, we add it and
check if the new volume also has volume mount points.

The total number of volume mount points and the number of volume mount
point volumes added to the snapshotset is reported, if VMPs exist.

Signed-off-by: Philipp Storz <philipp.storz@bareos.com>
Signed-off-by: Marco van Wieringen <marco.van.wieringen@bareos.com>
  • Loading branch information
Oleg Livshyts authored and Marco van Wieringen committed Dec 3, 2014
1 parent fdbd74c commit 02562b0
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 62 deletions.
27 changes: 15 additions & 12 deletions src/filed/dir_cmd.c
Expand Up @@ -1586,9 +1586,9 @@ static bool backup_cmd(JCR *jcr)
*/
if (jcr->VSS) {
if (g_pVSSClient->InitializeForBackup(jcr)) {
int drive_count, vmp_count;
int drive_count;
char szWinDriveLetters[27];
dlist *szWinVolumeMountpoints = NULL;
bool onefs_disabled;

generate_plugin_event(jcr, bEventVssBackupAddComponents);

Expand All @@ -1603,15 +1603,22 @@ static bool backup_cmd(JCR *jcr)
generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);

drive_count = get_win32_driveletters(jcr->ff->fileset, szWinDriveLetters);
vmp_count = get_win32_virtualmountpoints(jcr->ff->fileset, &szWinVolumeMountpoints);

if (drive_count > 0 || vmp_count > 0) {
Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\" VMP(s)=%d\n"),
g_pVSSClient->GetDriverName(), (drive_count) ? szWinDriveLetters : "None", vmp_count);
if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters, szWinVolumeMountpoints)) {
onefs_disabled = win32_onefs_is_disabled(jcr->ff->fileset);

if (drive_count > 0) {
Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"),
g_pVSSClient->GetDriverName(), (drive_count) ? szWinDriveLetters : "None");

if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters, onefs_disabled)) {
berrno be;
Jmsg(jcr, M_FATAL, 0, _("CreateSGenerate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
} else {
/*
* Inform about VMPs if we have them
*/
g_pVSSClient->ShowVolumeMountPointStats(jcr);

/*
* Tell user if snapshot creation of a specific drive failed
*/
Expand All @@ -1631,12 +1638,8 @@ static bool backup_cmd(JCR *jcr)
}
}

if (szWinVolumeMountpoints) {
szWinVolumeMountpoints->destroy();
free(szWinVolumeMountpoints);
}
} else {
Jmsg(jcr, M_FATAL, 0, _("No drive letters or Volume Mount Points found for generating VSS snapshots.\n"));
Jmsg(jcr, M_FATAL, 0, _("No drive letters found for generating VSS snapshots.\n"));
}
} else {
berrno be;
Expand Down
12 changes: 8 additions & 4 deletions src/findlib/find_one.c
Expand Up @@ -589,10 +589,18 @@ static inline int process_directory(JCR *jcr, FF_PKT *ff_pkt,
ff_pkt->type = FT_DIRBEGIN;
}

bool is_win32_mount_point = false;
#if defined(HAVE_WIN32)
is_win32_mount_point = ff_pkt->statp.st_rdev & FILE_ATTRIBUTE_VOLUME_MOUNT_POINT;

if (ff_pkt->statp.st_rdev & FILE_ATTRIBUTE_REPARSE_POINT) {
ff_pkt->type = FT_REPARSE;
}

/* treat win32 mount points (Volume Mount Points) as directories */
if (is_win32_mount_point) {
ff_pkt->type = FT_DIRBEGIN;
}
#endif

/*
Expand Down Expand Up @@ -637,10 +645,6 @@ static inline int process_directory(JCR *jcr, FF_PKT *ff_pkt,
* to cross, or we may be restricted by a list of permitted
* file systems.
*/
bool is_win32_mount_point = false;
#if defined(HAVE_WIN32)
is_win32_mount_point = ff_pkt->statp.st_rdev & FILE_ATTRIBUTE_VOLUME_MOUNT_POINT;
#endif
if (!top_level && bit_is_set(FO_NO_RECURSION, ff_pkt->flags)) {
ff_pkt->type = FT_NORECURSE;
recurse = false;
Expand Down
1 change: 1 addition & 0 deletions src/findlib/protos.h
Expand Up @@ -107,6 +107,7 @@ void check_include_list_shadowing(JCR *jcr, findFILESET *fileset);

#if defined(HAVE_WIN32)
/* win32.c */
bool win32_onefs_is_disabled(findFILESET *fileset);
int get_win32_driveletters(findFILESET *fileset, char *szDrives);
int get_win32_virtualmountpoints(findFILESET *fileset, dlist **szVmps);
bool expand_win32_fileset(findFILESET *fileset);
Expand Down
162 changes: 136 additions & 26 deletions src/win32/filed/vss_generic.c
Expand Up @@ -105,6 +105,9 @@ class IXMLDOMDocument;
#include "Win2003/vsbackup.h"
#endif

#define VSS_ERROR_OBJECT_ALREADY_EXISTS 0x8004230D


/* In VSSAPI.DLL */
typedef HRESULT (STDAPICALLTYPE* t_CreateVssBackupComponents)(OUT IVssBackupComponents **);
typedef void (APIENTRY* t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
Expand Down Expand Up @@ -306,6 +309,68 @@ static inline wstring GetUniqueVolumeNameForPath(wstring path)
return volumeUniqueName;
}

static inline POOLMEM *GetMountedVolumeForMountPointPath(POOLMEM *volumepath, POOLMEM *mountpoint)
{
POOLMEM *fullPath, *buf, *vol;
int len;

/*
* GetUniqueVolumeNameForPath() should be used here
*/
len = strlen(volumepath) + 1;
fullPath = get_pool_memory(PM_FNAME);
pm_strcpy(fullPath, volumepath);
pm_strcat(fullPath, mountpoint);

buf = get_pool_memory(PM_FNAME);
GetVolumeNameForVolumeMountPoint(fullPath, buf, len);

Dmsg3(200, "%s%s mounts volume %s\n", volumepath, mountpoint, buf);

vol = get_pool_memory(PM_FNAME);
UTF8_2_wchar(&vol, buf);

free_pool_memory(fullPath);
free_pool_memory(buf);

return vol;
}

static inline bool HandleVolumeMountPoint(VSSClientGeneric *pVssClient,
IVssBackupComponents *pVssObj,
POOLMEM *volumepath,
POOLMEM *mountpoint)
{
bool retval = false;
HRESULT hr;
POOLMEM *vol = NULL;
POOLMEM *pvol;
VSS_ID pid;

vol = GetMountedVolumeForMountPointPath(volumepath, mountpoint);
hr = pVssObj->AddToSnapshotSet((LPWSTR)vol, GUID_NULL, &pid);

pvol = get_pool_memory(PM_FNAME);
wchar_2_UTF8(&pvol, (wchar_t *)vol);

if (SUCCEEDED(hr)) {
pVssClient->AddVolumeMountPointSnapshots(pVssObj, (wchar_t *)vol);
Dmsg1(200, "%s added to snapshotset \n", pvol);
retval = true;
} else if((unsigned)hr == VSS_ERROR_OBJECT_ALREADY_EXISTS) {
Dmsg1(200, "%s already in snapshotset, skipping.\n" ,pvol);
} else {
Dmsg3(200, "%s with vmp %s could not be added to snapshotset, COM ERROR: 0x%X\n", vol, mountpoint, hr);
}

free_pool_memory(pvol);
if (vol) {
free_pool_memory(vol);
}

return retval;
}

/*
* Helper macro for quick treatment of case statements for error codes
*/
Expand Down Expand Up @@ -375,10 +440,12 @@ VSSClientGeneric::~VSSClientGeneric()
*/
bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore)
{
VMPs = 0;
VMP_snapshots = 0;
HRESULT hr;
CComPtr<IVssAsync> pAsync1;
VSS_BACKUP_TYPE backup_type;
IVssBackupComponents* pVssObj = (IVssBackupComponents*)m_pVssObject;
IVssBackupComponents *pVssObj = (IVssBackupComponents *)m_pVssObject;

if (!(p_CreateVssBackupComponents && p_VssFreeSnapshotProperties)) {
Dmsg2(0, "VSSClientGeneric::Initialize: p_CreateVssBackupComponents=0x%08X, p_VssFreeSnapshotProperties=0x%08X\n", p_CreateVssBackupComponents, p_VssFreeSnapshotProperties);
Expand Down Expand Up @@ -447,7 +514,7 @@ bool VSSClientGeneric::Initialize(DWORD dwContext, bool bDuringRestore)
/*
* Define shorthand VssObject with time
*/
pVssObj = (IVssBackupComponents*)m_pVssObject;
pVssObj = (IVssBackupComponents *)m_pVssObject;


if (!bDuringRestore) {
Expand Down Expand Up @@ -580,7 +647,7 @@ bool VSSClientGeneric::WaitAndCheckForAsyncOperation(IVssAsync* pAsync)
/*
* Add all drive letters that need to be snapshotted.
*/
void VSSClientGeneric::AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters)
void VSSClientGeneric::AddDriveSnapshots(IVssBackupComponents *pVssObj, char *szDriveLetters, bool onefs_disabled)
{
wstring volume;
wchar_t szDrive[3];
Expand All @@ -600,43 +667,89 @@ void VSSClientGeneric::AddDriveSnapshots(IVssBackupComponents *pVssObj, char *sz
/*
* Store uniquevolumname.
*/

if (SUCCEEDED(pVssObj->AddToSnapshotSet((LPWSTR)volume.c_str(), GUID_NULL, &pid))) {
if (debug_level >= 200) {

POOLMEM *szBuf = get_pool_memory(PM_FNAME);

wchar_2_UTF8(&szBuf, volume.c_str());
Dmsg1(200, "VSSClientGeneric::AddDriveSnapshots added snapshot for drive with volumename %s\n", szBuf);

Dmsg2(200, "%s added to snapshotset (Drive %s:\\)\n", szBuf, szDrive);
free_pool_memory(szBuf);
}
wcsncpy(m_wszUniqueVolumeName[szDriveLetters[i]-'A'], (LPWSTR)volume.c_str(), MAX_PATH);
} else {
szDriveLetters[i] = tolower(szDriveLetters[i]);
}
if (onefs_disabled) {
AddVolumeMountPointSnapshots(pVssObj, (LPWSTR)volume.c_str());
} else {
Jmsg(m_jcr, M_INFO, 0, "VolumeMountpoints are not processed as onefs = yes.\n");
}
}
}

/*
* Add all volume mountpoints that need to be snapshotted.
* Volumes can be mounted multiple times, but can only be added to the snapshotset once.
* So we skip adding a volume if it is already in snapshotset.
* We count the total number of vmps and the number of volumes we added to the snapshotset.
*/
void VSSClientGeneric::AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, dlist *szVmps)
void VSSClientGeneric::AddVolumeMountPointSnapshots(IVssBackupComponents *pVssObj, LPWSTR volume)
{
dlistString *vmp;
POOLMEM *volume;
VSS_ID pid;
BOOL b;
int len;
HANDLE hMount;
POOLMEM *mp, *path;

if (szVmps) {
volume = get_pool_memory(PM_FNAME);
foreach_dlist(vmp, szVmps) {
Dmsg1(200, "VSSClientGeneric::AddVolumeMountPointSnapshots added snapshot for volume mountpoint with volumename %s\n", vmp->c_str());
UTF8_2_wchar(&volume, vmp->c_str());
pVssObj->AddToSnapshotSet((LPWSTR)volume, GUID_NULL, &pid);
mp = get_pool_memory(PM_FNAME);
path = get_pool_memory(PM_FNAME);

wchar_2_UTF8(&path, volume);

len = wcslen(volume) + 1;

hMount = FindFirstVolumeMountPoint(path, mp, len);
if (hMount != INVALID_HANDLE_VALUE) {
/*
* Count number of vmps.
*/
VMPs += 1;
if (HandleVolumeMountPoint(this, pVssObj, path, mp)) {
/*
* Count vmps that were snapshotted
*/
VMP_snapshots += 1;
}

while ((b = FindNextVolumeMountPoint(hMount, mp, len))) {
/*
* Count number of vmps.
*/
VMPs += 1;
if (HandleVolumeMountPoint(this, pVssObj, path, mp)) {
/*
* Count vmps that were snapshotted
*/
VMP_snapshots += 1;
}
}
free_pool_memory(volume);
}

FindVolumeMountPointClose(hMount);

free_pool_memory(path);
free_pool_memory(mp);
}

bool VSSClientGeneric::CreateSnapshots(char *szDriveLetters, dlist *szVmps)
void VSSClientGeneric::ShowVolumeMountPointStats(JCR *jcr)
{
if (VMPs) {
Jmsg(jcr, M_INFO, 0, _("Volume Mount Points found: %d, added to snapshotset: %d\n"), VMPs, VMP_snapshots);
}
}

bool VSSClientGeneric::CreateSnapshots(char *szDriveLetters, bool onefs_disabled)
{
IVssBackupComponents *pVssObj;
CComPtr<IVssAsync> pAsync1;
Expand Down Expand Up @@ -670,10 +783,7 @@ bool VSSClientGeneric::CreateSnapshots(char *szDriveLetters, dlist *szVmps)
* AddToSnapshotSet
*/
if (szDriveLetters) {
AddDriveSnapshots(pVssObj, szDriveLetters);
}
if (szVmps) {
AddVolumeMountPointSnapshots(pVssObj, szVmps);
AddDriveSnapshots(pVssObj, szDriveLetters, onefs_disabled);
}

/*
Expand Down Expand Up @@ -860,10 +970,10 @@ void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
* Get list all shadow copies.
*/
CComPtr<IVssEnumObject> pIEnumSnapshots;
HRESULT hr = pVssObj->Query( GUID_NULL,
VSS_OBJECT_NONE,
VSS_OBJECT_SNAPSHOT,
(IVssEnumObject**)(&pIEnumSnapshots) );
HRESULT hr = pVssObj->Query(GUID_NULL,
VSS_OBJECT_NONE,
VSS_OBJECT_SNAPSHOT,
(IVssEnumObject**)(&pIEnumSnapshots));

/*
* If there are no shadow copies, just return
Expand All @@ -885,7 +995,7 @@ void VSSClientGeneric::QuerySnapshotSet(GUID snapshotSetID)
* Get the next element
*/
ULONG ulFetched;
hr = (pIEnumSnapshots.p)->Next( 1, &Prop, &ulFetched );
hr = (pIEnumSnapshots.p)->Next(1, &Prop, &ulFetched);

/*
* We reached the end of list
Expand Down
24 changes: 24 additions & 0 deletions src/win32/findlib/win32.c
Expand Up @@ -29,6 +29,30 @@
#include "find.h"
#include "lib/cbuf.h"

/*
* We need to analyze if a fileset contains onefs=no as option, because only then
* we need to snapshot submounted vmps
*/
bool win32_onefs_is_disabled(findFILESET *fileset)
{
findINCEXE *incexe;

for (int i = 0; i < fileset->include_list.size(); i++) {
incexe = (findINCEXE *)fileset->include_list.get(i);
/*
* Look through all files and check
*/
for (int j = 0; j < incexe->opts_list.size(); j++) {
findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
if (bit_is_set(FO_MULTIFS, fo->flags)) {
return true;
}
}
}

return false;
}

/*
* For VSS we need to know which windows drives are used, because we create a snapshot
* of all used drives. This function returns the number of used drives and fills
Expand Down

0 comments on commit 02562b0

Please sign in to comment.