mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 02:49:02 -04:00
Use the st_dev field to ensure to use different disks.
This commit is contained in:
parent
83f89f4f0e
commit
e80d0ccdcf
16 changed files with 222 additions and 50 deletions
2
HISTORY
2
HISTORY
|
|
@ -10,6 +10,8 @@ SnapRAID HISTORY
|
||||||
from the sync process.
|
from the sync process.
|
||||||
* Increased by one the minimum number of content files. Before it was only
|
* Increased by one the minimum number of content files. Before it was only
|
||||||
a suggestion, but now it's a requirement in case you put them in data disks.
|
a suggestion, but now it's a requirement in case you put them in data disks.
|
||||||
|
* Added checks to ensure that data and parity disks are diffent, and to
|
||||||
|
correctly count the number of copies of "content" files in different disks.
|
||||||
|
|
||||||
1.6 2011/9 - THIS UPDATE IS HIGHLY RECOMMENDED!
|
1.6 2011/9 - THIS UPDATE IS HIGHLY RECOMMENDED!
|
||||||
===============================================
|
===============================================
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ maintainer-clean-local:
|
||||||
|
|
||||||
# Automatic testing
|
# Automatic testing
|
||||||
|
|
||||||
CHECKFLAGS =
|
CHECKFLAGS = --test-skip-device
|
||||||
CHECKCOUNT = 2000
|
CHECKCOUNT = 2000
|
||||||
CHECKSIZE = 4000
|
CHECKSIZE = 4000
|
||||||
|
|
||||||
|
|
|
||||||
5
TODO
5
TODO
|
|
@ -5,9 +5,6 @@ This is the list of TODO items for SnapRAID.
|
||||||
|
|
||||||
- v1.7
|
- v1.7
|
||||||
|
|
||||||
* Use st_dev to effectively check if data/parity disks are different and
|
|
||||||
content files are in different disks.
|
|
||||||
|
|
||||||
* Put the content files in the data disks in the default configuration file.
|
* Put the content files in the data disks in the default configuration file.
|
||||||
|
|
||||||
* Remove the dependency of the 'disk' order specification in the conf file.
|
* Remove the dependency of the 'disk' order specification in the conf file.
|
||||||
|
|
@ -36,6 +33,8 @@ in Unix files starting with '.'.
|
||||||
|
|
||||||
- v2.x
|
- v2.x
|
||||||
|
|
||||||
|
* Remove the old MD5 support.
|
||||||
|
|
||||||
* Implement an "undelete" command to recover missing files, without the
|
* Implement an "undelete" command to recover missing files, without the
|
||||||
integrity check of the existing ones.
|
integrity check of the existing ones.
|
||||||
It should restore only missing files, without recovering modified ones
|
It should restore only missing files, without recovering modified ones
|
||||||
|
|
|
||||||
6
elem.c
6
elem.c
|
|
@ -23,12 +23,13 @@
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* snapraid */
|
/* snapraid */
|
||||||
|
|
||||||
struct snapraid_content* content_alloc(const char* path)
|
struct snapraid_content* content_alloc(const char* path, uint64_t dev)
|
||||||
{
|
{
|
||||||
struct snapraid_content* content;
|
struct snapraid_content* content;
|
||||||
|
|
||||||
content = malloc_nofail(sizeof(struct snapraid_content));
|
content = malloc_nofail(sizeof(struct snapraid_content));
|
||||||
pathcpy(content->content, sizeof(content->content), path);
|
pathcpy(content->content, sizeof(content->content), path);
|
||||||
|
content->device = dev;
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
@ -320,7 +321,7 @@ int link_name_compare(const void* void_arg, const void* void_data)
|
||||||
return strcmp(arg, link->sub);
|
return strcmp(arg, link->sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct snapraid_disk* disk_alloc(const char* name, const char* dir)
|
struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev)
|
||||||
{
|
{
|
||||||
struct snapraid_disk* disk;
|
struct snapraid_disk* disk;
|
||||||
|
|
||||||
|
|
@ -331,6 +332,7 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir)
|
||||||
/* ensure that the dir terminate with "/" if it isn't empty */
|
/* ensure that the dir terminate with "/" if it isn't empty */
|
||||||
pathslash(disk->dir, sizeof(disk->dir));
|
pathslash(disk->dir, sizeof(disk->dir));
|
||||||
|
|
||||||
|
disk->device = dev;
|
||||||
disk->first_free_block = 0;
|
disk->first_free_block = 0;
|
||||||
tommy_list_init(&disk->filelist);
|
tommy_list_init(&disk->filelist);
|
||||||
tommy_hashdyn_init(&disk->inodeset);
|
tommy_hashdyn_init(&disk->inodeset);
|
||||||
|
|
|
||||||
6
elem.h
6
elem.h
|
|
@ -49,6 +49,7 @@ typedef int64_t data_off_t;
|
||||||
*/
|
*/
|
||||||
struct snapraid_content {
|
struct snapraid_content {
|
||||||
char content[PATH_MAX]; /**< Path of the content file. */
|
char content[PATH_MAX]; /**< Path of the content file. */
|
||||||
|
uint64_t device; /**< Device identifier. */
|
||||||
tommy_node node; /**< Next node in the list. */
|
tommy_node node; /**< Next node in the list. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -120,6 +121,7 @@ struct snapraid_link {
|
||||||
struct snapraid_disk {
|
struct snapraid_disk {
|
||||||
char name[PATH_MAX]; /**< Name of the disk. */
|
char name[PATH_MAX]; /**< Name of the disk. */
|
||||||
char dir[PATH_MAX]; /**< Mount point of the disk. It always terminates with /. */
|
char dir[PATH_MAX]; /**< Mount point of the disk. It always terminates with /. */
|
||||||
|
uint64_t device; /**< Device identifier. */
|
||||||
block_off_t first_free_block; /**< First free searching block. */
|
block_off_t first_free_block; /**< First free searching block. */
|
||||||
tommy_list filelist; /**< List of all the files. */
|
tommy_list filelist; /**< List of all the files. */
|
||||||
tommy_hashdyn inodeset; /**< Hashtable by inode of all the files. */
|
tommy_hashdyn inodeset; /**< Hashtable by inode of all the files. */
|
||||||
|
|
@ -131,7 +133,7 @@ struct snapraid_disk {
|
||||||
/**
|
/**
|
||||||
* Allocates a content.
|
* Allocates a content.
|
||||||
*/
|
*/
|
||||||
struct snapraid_content* content_alloc(const char* path);
|
struct snapraid_content* content_alloc(const char* path, uint64_t dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deallocates a content.
|
* Deallocates a content.
|
||||||
|
|
@ -299,7 +301,7 @@ static inline tommy_uint32_t link_name_hash(const char* name)
|
||||||
/**
|
/**
|
||||||
* Allocates a disk.
|
* Allocates a disk.
|
||||||
*/
|
*/
|
||||||
struct snapraid_disk* disk_alloc(const char* name, const char* dir);
|
struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deallocates a disk.
|
* Deallocates a disk.
|
||||||
|
|
|
||||||
40
mingw.c
40
mingw.c
|
|
@ -121,6 +121,8 @@ static void windows_info2stat(const BY_HANDLE_FILE_INFORMATION* info, struct win
|
||||||
st->st_ino |= info->nFileIndexLow;
|
st->st_ino |= info->nFileIndexLow;
|
||||||
|
|
||||||
st->st_nlink = info->nNumberOfLinks;
|
st->st_nlink = info->nNumberOfLinks;
|
||||||
|
|
||||||
|
st->st_dev = info->dwVolumeSerialNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -167,6 +169,9 @@ static void windows_finddata2stat(const WIN32_FIND_DATAW* info, struct windows_s
|
||||||
|
|
||||||
/* No link information available */
|
/* No link information available */
|
||||||
st->st_nlink = 0;
|
st->st_nlink = 0;
|
||||||
|
|
||||||
|
/* No device information available */
|
||||||
|
st->st_dev = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void windows_finddata2dirent(const WIN32_FIND_DATAW* info, struct windows_dirent* dirent)
|
static void windows_finddata2dirent(const WIN32_FIND_DATAW* info, struct windows_dirent* dirent)
|
||||||
|
|
@ -259,7 +264,7 @@ int windows_mkdir(const char* file)
|
||||||
return _wmkdir(u8tou16(file));
|
return _wmkdir(u8tou16(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
int lstat_inode(const char* file, struct windows_stat* st)
|
int lstat_ex(const char* file, struct windows_stat* st)
|
||||||
{
|
{
|
||||||
BY_HANDLE_FILE_INFORMATION info;
|
BY_HANDLE_FILE_INFORMATION info;
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
|
|
@ -293,6 +298,39 @@ int lstat_inode(const char* file, struct windows_stat* st)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int windows_stat(const char* file, struct windows_stat* st)
|
||||||
|
{
|
||||||
|
BY_HANDLE_FILE_INFORMATION info;
|
||||||
|
HANDLE h;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open the handle of the file.
|
||||||
|
*
|
||||||
|
* Use FILE_FLAG_BACKUP_SEMANTICS to open directories and to override the file security checks.
|
||||||
|
*/
|
||||||
|
h = CreateFileW(u8tou16(file), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||||
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
|
windows_errno(GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetFileInformationByHandle(h, &info)) {
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
CloseHandle(h);
|
||||||
|
windows_errno(error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CloseHandle(h)) {
|
||||||
|
windows_errno(GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
windows_info2stat(&info, st);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int windows_ftruncate(int fd, off64_t off)
|
int windows_ftruncate(int fd, off64_t off)
|
||||||
{
|
{
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
|
|
|
||||||
16
mingw.h
16
mingw.h
|
|
@ -64,18 +64,24 @@ struct windows_stat {
|
||||||
int64_t st_mtime;
|
int64_t st_mtime;
|
||||||
uint32_t st_mode;
|
uint32_t st_mode;
|
||||||
uint32_t st_nlink;
|
uint32_t st_nlink;
|
||||||
|
uint32_t st_dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like the C fstat() including the inode information.
|
* Like the C fstat() including the inode/device information.
|
||||||
*/
|
*/
|
||||||
int windows_fstat(int fd, struct windows_stat* st);
|
int windows_fstat(int fd, struct windows_stat* st);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like the C stat() but without the inode information.
|
* Like the C lstat() but without the inode information.
|
||||||
*/
|
*/
|
||||||
int windows_lstat(const char* file, struct windows_stat* st);
|
int windows_lstat(const char* file, struct windows_stat* st);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like the C stat() including the inode/device information.
|
||||||
|
*/
|
||||||
|
int windows_stat(const char* file, struct windows_stat* st);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like the C access().
|
* Like the C access().
|
||||||
*/
|
*/
|
||||||
|
|
@ -87,12 +93,12 @@ int windows_access(const char* file, int mode);
|
||||||
int windows_mkdir(const char* file);
|
int windows_mkdir(const char* file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like the C lstat() including the inode information.
|
* Like the C lstat() including the inode/device information.
|
||||||
* It doesn't work for all kind of files and directories. For example "\System Volume Information" cannot be opened.
|
* It doesn't work for all kind of files and directories. For example "\System Volume Information" cannot be opened.
|
||||||
* Note that instead lstat() works for all the files.
|
* Note that instead lstat() works for all the files.
|
||||||
*/
|
*/
|
||||||
#define HAVE_LSTAT_INODE 1
|
#define HAVE_LSTAT_EX 1
|
||||||
int lstat_inode(const char* file, struct windows_stat* st);
|
int lstat_ex(const char* file, struct windows_stat* st);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like the C ftruncate().
|
* Like the C ftruncate().
|
||||||
|
|
|
||||||
4
scan.c
4
scan.c
|
|
@ -385,9 +385,9 @@ static void scan_dir(struct snapraid_scan* scan, struct snapraid_state* state, i
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_LSTAT_INODE
|
#if HAVE_LSTAT_EX
|
||||||
/* get inode info about the file, Windows needs an additional step */
|
/* get inode info about the file, Windows needs an additional step */
|
||||||
if (lstat_inode(path_next, &st) != 0) {
|
if (lstat_ex(path_next, &st) != 0) {
|
||||||
fprintf(stderr, "Error in stat_inode file '%s'. %s.\n", path_next, strerror(errno));
|
fprintf(stderr, "Error in stat_inode file '%s'. %s.\n", path_next, strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -403,7 +403,8 @@ This option is optional and it can be used only one time.
|
||||||
Defines the file to use to store the list and checksums of all the
|
Defines the file to use to store the list and checksums of all the
|
||||||
files present in your disk array.
|
files present in your disk array.
|
||||||
.PP
|
.PP
|
||||||
It can be placed in the disk used to store data or the parity.
|
It can be placed in the disk used to store data, parity, or
|
||||||
|
any other disk available.
|
||||||
If you use a data disk, this file is automatically excluded
|
If you use a data disk, this file is automatically excluded
|
||||||
from the \(a"sync\(a" process.
|
from the \(a"sync\(a" process.
|
||||||
.PP
|
.PP
|
||||||
|
|
|
||||||
17
snapraid.c
17
snapraid.c
|
|
@ -68,6 +68,7 @@ void usage(void)
|
||||||
#define OPT_TEST_KILL_AFTER_SYNC 257
|
#define OPT_TEST_KILL_AFTER_SYNC 257
|
||||||
#define OPT_TEST_EXPECT_UNRECOVERABLE 258
|
#define OPT_TEST_EXPECT_UNRECOVERABLE 258
|
||||||
#define OPT_TEST_EXPECT_RECOVERABLE 259
|
#define OPT_TEST_EXPECT_RECOVERABLE 259
|
||||||
|
#define OPT_TEST_SKIP_DEVICE 260
|
||||||
|
|
||||||
#if HAVE_GETOPT_LONG
|
#if HAVE_GETOPT_LONG
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
|
|
@ -83,10 +84,11 @@ struct option long_options[] = {
|
||||||
{ "help", 0, 0, 'h' },
|
{ "help", 0, 0, 'h' },
|
||||||
{ "version", 0, 0, 'V' },
|
{ "version", 0, 0, 'V' },
|
||||||
/* test specific options, DO NOT USE! */
|
/* test specific options, DO NOT USE! */
|
||||||
{ "test-skip-self", 0, 0, OPT_TEST_SKIP_SELF },
|
|
||||||
{ "test-kill-after-sync", 0, 0, OPT_TEST_KILL_AFTER_SYNC },
|
{ "test-kill-after-sync", 0, 0, OPT_TEST_KILL_AFTER_SYNC },
|
||||||
{ "test-expect-unrecoverable", 0, 0, OPT_TEST_EXPECT_UNRECOVERABLE },
|
{ "test-expect-unrecoverable", 0, 0, OPT_TEST_EXPECT_UNRECOVERABLE },
|
||||||
{ "test-expect-recoverable", 0, 0, OPT_TEST_EXPECT_RECOVERABLE },
|
{ "test-expect-recoverable", 0, 0, OPT_TEST_EXPECT_RECOVERABLE },
|
||||||
|
{ "test-skip-self", 0, 0, OPT_TEST_SKIP_SELF },
|
||||||
|
{ "test-skip-device", 0, 0, OPT_TEST_SKIP_DEVICE },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -121,6 +123,7 @@ int main(int argc, char* argv[])
|
||||||
int test_expect_recoverable;
|
int test_expect_recoverable;
|
||||||
int test_kill_after_sync;
|
int test_kill_after_sync;
|
||||||
int test_skip_self;
|
int test_skip_self;
|
||||||
|
int test_skip_device;
|
||||||
const char* conf;
|
const char* conf;
|
||||||
struct snapraid_state state;
|
struct snapraid_state state;
|
||||||
int operation;
|
int operation;
|
||||||
|
|
@ -140,6 +143,7 @@ int main(int argc, char* argv[])
|
||||||
test_expect_recoverable = 0;
|
test_expect_recoverable = 0;
|
||||||
test_kill_after_sync = 0;
|
test_kill_after_sync = 0;
|
||||||
test_skip_self = 0;
|
test_skip_self = 0;
|
||||||
|
test_skip_device = 0;
|
||||||
blockstart = 0;
|
blockstart = 0;
|
||||||
blockcount = 0;
|
blockcount = 0;
|
||||||
tommy_list_init(&filterlist);
|
tommy_list_init(&filterlist);
|
||||||
|
|
@ -199,9 +203,6 @@ int main(int argc, char* argv[])
|
||||||
case 'T' :
|
case 'T' :
|
||||||
speed();
|
speed();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
case OPT_TEST_SKIP_SELF :
|
|
||||||
test_skip_self = 1;
|
|
||||||
break;
|
|
||||||
case OPT_TEST_KILL_AFTER_SYNC :
|
case OPT_TEST_KILL_AFTER_SYNC :
|
||||||
test_kill_after_sync = 1;
|
test_kill_after_sync = 1;
|
||||||
break;
|
break;
|
||||||
|
|
@ -211,6 +212,12 @@ int main(int argc, char* argv[])
|
||||||
case OPT_TEST_EXPECT_RECOVERABLE :
|
case OPT_TEST_EXPECT_RECOVERABLE :
|
||||||
test_expect_recoverable = 1;
|
test_expect_recoverable = 1;
|
||||||
break;
|
break;
|
||||||
|
case OPT_TEST_SKIP_SELF :
|
||||||
|
test_skip_self = 1;
|
||||||
|
break;
|
||||||
|
case OPT_TEST_SKIP_DEVICE :
|
||||||
|
test_skip_device = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Unknown option '%c'\n", (char)c);
|
fprintf(stderr, "Unknown option '%c'\n", (char)c);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
@ -244,7 +251,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
state_init(&state);
|
state_init(&state);
|
||||||
|
|
||||||
state_config(&state, conf, verbose, gui, force_zero, force_empty, test_expect_unrecoverable, test_expect_recoverable);
|
state_config(&state, conf, verbose, gui, force_zero, force_empty, test_expect_unrecoverable, test_expect_recoverable, test_skip_device);
|
||||||
|
|
||||||
if (operation == OPERATION_DIFF) {
|
if (operation == OPERATION_DIFF) {
|
||||||
state_read(&state);
|
state_read(&state);
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ parity /mnt/diskpar/parity
|
||||||
# Format: "q-parity FILE_PATH"
|
# Format: "q-parity FILE_PATH"
|
||||||
#q-parity /mnt/diskqar/q-parity
|
#q-parity /mnt/diskqar/q-parity
|
||||||
|
|
||||||
# Defines the file to use as content list
|
# Defines the files to use as content list
|
||||||
# You can use multiple specification to store more copies of the file
|
# You can use multiple specification to store more copies
|
||||||
# You must have least one copy for each parity file plus one. Some more don't hurt
|
# You must have least one copy for each parity file plus one. Some more don't hurt
|
||||||
# They can be in the disks used for data, parity or boot,
|
# They can be in the disks used for data, parity or boot,
|
||||||
# but each file must be in a different disk
|
# but each file must be in a different disk
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ parity E:\par\parity
|
||||||
# Format: "q-parity FILE_PATH"
|
# Format: "q-parity FILE_PATH"
|
||||||
#q-parity F:\qar\q-parity
|
#q-parity F:\qar\q-parity
|
||||||
|
|
||||||
# Defines the file to use as content list
|
# Defines the files to use as content list
|
||||||
# You can use multiple specification to store more copies of the file
|
# You can use multiple specification to store more copies
|
||||||
# You must have least one copy for each parity file plus one. Some more don't hurt
|
# You must have least one copy for each parity file plus one. Some more don't hurt
|
||||||
# They can be in the disks used for data, parity or boot,
|
# They can be in the disks used for data, parity or boot,
|
||||||
# but each file must be in a different disk
|
# but each file must be in a different disk
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,8 @@ Configuration
|
||||||
Defines the file to use to store the list and checksums of all the
|
Defines the file to use to store the list and checksums of all the
|
||||||
files present in your disk array.
|
files present in your disk array.
|
||||||
|
|
||||||
It can be placed in the disk used to store data or the parity.
|
It can be placed in the disk used to store data, parity, or
|
||||||
|
any other disk available.
|
||||||
If you use a data disk, this file is automatically excluded
|
If you use a data disk, this file is automatically excluded
|
||||||
from the "sync" process.
|
from the "sync" process.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -336,7 +336,8 @@ This option is optional and it can be used only one time.
|
||||||
Defines the file to use to store the list and checksums of all the
|
Defines the file to use to store the list and checksums of all the
|
||||||
files present in your disk array.
|
files present in your disk array.
|
||||||
|
|
||||||
It can be placed in the disk used to store data or the parity.
|
It can be placed in the disk used to store data, parity, or
|
||||||
|
any other disk available.
|
||||||
If you use a data disk, this file is automatically excluded
|
If you use a data disk, this file is automatically excluded
|
||||||
from the "sync" process.
|
from the "sync" process.
|
||||||
|
|
||||||
|
|
|
||||||
153
state.c
153
state.c
|
|
@ -32,7 +32,9 @@ void state_init(struct snapraid_state* state)
|
||||||
state->need_write = 0;
|
state->need_write = 0;
|
||||||
state->block_size = 256 * 1024; /* default 256 KiB */
|
state->block_size = 256 * 1024; /* default 256 KiB */
|
||||||
state->parity[0] = 0;
|
state->parity[0] = 0;
|
||||||
|
state->parity_device = 0;
|
||||||
state->qarity[0] = 0;
|
state->qarity[0] = 0;
|
||||||
|
state->qarity_device = 0;
|
||||||
state->level = 1; /* default is the lowest protection */
|
state->level = 1; /* default is the lowest protection */
|
||||||
state->hash = HASH_MURMUR3; /* default is the fastest */
|
state->hash = HASH_MURMUR3; /* default is the fastest */
|
||||||
tommy_array_init(&state->diskarr);
|
tommy_array_init(&state->diskarr);
|
||||||
|
|
@ -51,13 +53,10 @@ void state_done(struct snapraid_state* state)
|
||||||
tommy_list_foreach(&state->filterlist, (tommy_foreach_func*)filter_free);
|
tommy_list_foreach(&state->filterlist, (tommy_foreach_func*)filter_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int expect_unrecoverable, int expect_recoverable)
|
void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int expect_unrecoverable, int expect_recoverable, int skip_device)
|
||||||
{
|
{
|
||||||
STREAM* f;
|
STREAM* f;
|
||||||
unsigned line;
|
unsigned line;
|
||||||
unsigned content_count;
|
|
||||||
unsigned content_required;
|
|
||||||
tommy_node* i;
|
|
||||||
|
|
||||||
state->verbose = verbose;
|
state->verbose = verbose;
|
||||||
state->gui = gui;
|
state->gui = gui;
|
||||||
|
|
@ -125,6 +124,10 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
|
||||||
}
|
}
|
||||||
state->block_size *= 1024;
|
state->block_size *= 1024;
|
||||||
} else if (strcmp(tag, "parity") == 0) {
|
} else if (strcmp(tag, "parity") == 0) {
|
||||||
|
char device[PATH_MAX];
|
||||||
|
char* slash;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
if (*state->parity) {
|
if (*state->parity) {
|
||||||
fprintf(stderr, "Multiple 'parity' specification in '%s' at line %u\n", path, line);
|
fprintf(stderr, "Multiple 'parity' specification in '%s' at line %u\n", path, line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
@ -136,8 +139,26 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pathcpy(state->parity, sizeof(state->parity), buffer);
|
pathimport(state->parity, sizeof(state->parity), buffer);
|
||||||
|
|
||||||
|
/* get the device of the directory containing the content file */
|
||||||
|
pathimport(device, sizeof(device), buffer);
|
||||||
|
slash = strrchr(device, '/');
|
||||||
|
if (slash)
|
||||||
|
*slash = 0;
|
||||||
|
else
|
||||||
|
pathcpy(device, sizeof(device), ".");
|
||||||
|
if (stat(device, &st) != 0) {
|
||||||
|
fprintf(stderr, "Error accessing 'parity' dir '%s' specification in '%s' at line %u\n", device, path, line);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->parity_device = st.st_dev;
|
||||||
} else if (strcmp(tag, "q-parity") == 0) {
|
} else if (strcmp(tag, "q-parity") == 0) {
|
||||||
|
char device[PATH_MAX];
|
||||||
|
char* slash;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
if (*state->qarity) {
|
if (*state->qarity) {
|
||||||
fprintf(stderr, "Multiple 'q-parity' specification in '%s' at line %u\n", path, line);
|
fprintf(stderr, "Multiple 'q-parity' specification in '%s' at line %u\n", path, line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
@ -149,10 +170,29 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pathcpy(state->qarity, sizeof(state->qarity), buffer);
|
pathimport(state->qarity, sizeof(state->qarity), buffer);
|
||||||
|
|
||||||
|
/* get the device of the directory containing the content file */
|
||||||
|
pathimport(device, sizeof(device), buffer);
|
||||||
|
slash = strrchr(device, '/');
|
||||||
|
if (slash)
|
||||||
|
*slash = 0;
|
||||||
|
else
|
||||||
|
pathcpy(device, sizeof(device), ".");
|
||||||
|
if (stat(device, &st) != 0) {
|
||||||
|
fprintf(stderr, "Error accessing 'qarity' dir '%s' specification in '%s' at line %u\n", device, path, line);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->qarity_device = st.st_dev;
|
||||||
|
|
||||||
|
/* we have two level of parity */
|
||||||
state->level = 2;
|
state->level = 2;
|
||||||
} else if (strcmp(tag, "content") == 0) {
|
} else if (strcmp(tag, "content") == 0) {
|
||||||
struct snapraid_content* content;
|
struct snapraid_content* content;
|
||||||
|
char device[PATH_MAX];
|
||||||
|
char* slash;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
ret = sgetlasttok(f, buffer, sizeof(buffer));
|
ret = sgetlasttok(f, buffer, sizeof(buffer));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
@ -160,11 +200,25 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
content = content_alloc(buffer);
|
/* get the device of the directory containing the content file */
|
||||||
|
pathimport(device, sizeof(device), buffer);
|
||||||
|
slash = strrchr(device, '/');
|
||||||
|
if (slash)
|
||||||
|
*slash = 0;
|
||||||
|
else
|
||||||
|
pathcpy(device, sizeof(device), ".");
|
||||||
|
if (stat(device, &st) != 0) {
|
||||||
|
fprintf(stderr, "Error accessing 'content' dir '%s' specification in '%s' at line %u\n", device, path, line);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
content = content_alloc(buffer, st.st_dev);
|
||||||
|
|
||||||
tommy_list_insert_tail(&state->contentlist, &content->node, content);
|
tommy_list_insert_tail(&state->contentlist, &content->node, content);
|
||||||
} else if (strcmp(tag, "disk") == 0) {
|
} else if (strcmp(tag, "disk") == 0) {
|
||||||
char dir[PATH_MAX];
|
char dir[PATH_MAX];
|
||||||
|
char device[PATH_MAX];
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
ret = sgettok(f, buffer, sizeof(buffer));
|
ret = sgettok(f, buffer, sizeof(buffer));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
@ -180,7 +234,14 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
tommy_array_insert(&state->diskarr, disk_alloc(buffer, dir));
|
/* get the device of the dir */
|
||||||
|
pathimport(device, sizeof(device), dir);
|
||||||
|
if (stat(device, &st) != 0) {
|
||||||
|
fprintf(stderr, "Error accessing 'disk' '%s' specification in '%s' at line %u\n", dir, device, line);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
tommy_array_insert(&state->diskarr, disk_alloc(buffer, dir, st.st_dev));
|
||||||
} else if (strcmp(tag, "exclude") == 0) {
|
} else if (strcmp(tag, "exclude") == 0) {
|
||||||
struct snapraid_filter* filter;
|
struct snapraid_filter* filter;
|
||||||
|
|
||||||
|
|
@ -251,23 +312,73 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count the content files */
|
if (tommy_list_empty(&state->contentlist)) {
|
||||||
content_count = 0;
|
|
||||||
for(i=state->contentlist;i!=0;i=i->next) {
|
|
||||||
++content_count;
|
|
||||||
}
|
|
||||||
if (content_count == 0) {
|
|
||||||
fprintf(stderr, "No 'content' specification in '%s'\n", path);
|
fprintf(stderr, "No 'content' specification in '%s'\n", path);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (state->qarity[0] != 0) {
|
|
||||||
content_required = 3;
|
/* count the content files */
|
||||||
} else {
|
if (!skip_device) {
|
||||||
content_required = 2;
|
unsigned content_count;
|
||||||
|
tommy_node* i;
|
||||||
|
|
||||||
|
content_count = 0;
|
||||||
|
for(i=state->contentlist;i!=0;i=i->next) {
|
||||||
|
tommy_node* j;
|
||||||
|
struct snapraid_content* content = i->data;
|
||||||
|
|
||||||
|
/* check if there are others in the same disk */
|
||||||
|
for(j=i->next;j!=0;j=j->next) {
|
||||||
|
struct snapraid_content* other = j->data;
|
||||||
|
if (content->device == other->device) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j != 0) {
|
||||||
|
/* skip it */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++content_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content_count < state->level+1) {
|
||||||
|
fprintf(stderr, "You must have at least %d 'content' files in different disks.\n", state->level+1);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (content_count < content_required) {
|
|
||||||
fprintf(stderr, "You must have at least %d 'content' files. One for each parity disk plus one.\n", content_required);
|
/* check if all the data and parity disks are different */
|
||||||
exit(EXIT_FAILURE);
|
if (!skip_device) {
|
||||||
|
unsigned j;
|
||||||
|
unsigned diskmax;
|
||||||
|
diskmax = tommy_array_size(&state->diskarr);
|
||||||
|
for(j=0;j<diskmax;++j) {
|
||||||
|
unsigned k;
|
||||||
|
struct snapraid_disk* disk = tommy_array_get(&state->diskarr, j);
|
||||||
|
|
||||||
|
for(k=j+1;k<diskmax;++k) {
|
||||||
|
struct snapraid_disk* other = tommy_array_get(&state->diskarr, k);
|
||||||
|
if (disk->device == other->device) {
|
||||||
|
fprintf(stderr, "Disks '%s' and '%s' are on the same device.\n", disk->dir, other->dir);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disk->device == state->parity_device) {
|
||||||
|
fprintf(stderr, "Disk '%s' and parity '%s' are on the same device.\n", disk->dir, state->parity);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disk->device == state->qarity_device) {
|
||||||
|
fprintf(stderr, "Disk '%s' and parity '%s' are on the same device.\n", disk->dir, state->qarity);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state->parity_device == state->qarity_device) {
|
||||||
|
fprintf(stderr, "Parity '%s' and '%s' are on the same device.\n", state->parity, state->qarity);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->gui) {
|
if (state->gui) {
|
||||||
|
|
|
||||||
4
state.h
4
state.h
|
|
@ -39,7 +39,9 @@ struct snapraid_state {
|
||||||
int need_write; /**< If the state is changed. */
|
int need_write; /**< If the state is changed. */
|
||||||
uint32_t block_size; /**< Block size in bytes. */
|
uint32_t block_size; /**< Block size in bytes. */
|
||||||
char parity[PATH_MAX]; /**< Path of the parity file. */
|
char parity[PATH_MAX]; /**< Path of the parity file. */
|
||||||
|
uint64_t parity_device; /**< Device identifier of the parity. */
|
||||||
char qarity[PATH_MAX]; /**< Path of the qarity file. */
|
char qarity[PATH_MAX]; /**< Path of the qarity file. */
|
||||||
|
uint64_t qarity_device; /**< Device identifier of the qarity. */
|
||||||
unsigned level; /**< Number of parity levels. 1 for RAID5, 2 for RAID6. */
|
unsigned level; /**< Number of parity levels. 1 for RAID5, 2 for RAID6. */
|
||||||
unsigned hash; /**< Hash kind used. */
|
unsigned hash; /**< Hash kind used. */
|
||||||
tommy_list contentlist; /**< List of content files. */
|
tommy_list contentlist; /**< List of content files. */
|
||||||
|
|
@ -62,7 +64,7 @@ void state_done(struct snapraid_state* state);
|
||||||
/**
|
/**
|
||||||
* Read the configuration file.
|
* Read the configuration file.
|
||||||
*/
|
*/
|
||||||
void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int expect_unrecoverable, int expect_recoverable);
|
void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int expect_unrecoverable, int expect_recoverable, int skip_device);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the state.
|
* Read the state.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue