Hello,
attached is a patch which implements necessary support for
mkfs so that quota files can be created.
Honza
--
Jan Kara <[EMAIL PROTECTED]>
SUSE Labs, CR
>From c5de88cee9136605dc64f943aa31d2ebdd9bd8c7 Mon Sep 17 00:00:00 2001
From: Jan Kara <[EMAIL PROTECTED]>
Date: Tue, 14 Oct 2008 15:44:31 +0200
Subject: [PATCH] Implement quota support to mkfs and add a few auxiliary functions for quotas
into libocfs2.
Signed-off-by: Jan Kara <[EMAIL PROTECTED]>
---
Preamble.make | 3 +-
include/ocfs2-kernel/ocfs2_fs.h | 114 +++++++++++++++++++++++++++++++-
include/ocfs2/ocfs2.h | 25 +++++++
libocfs2/Makefile | 1 +
libocfs2/feature_string.c | 22 ++++++-
mkfs.ocfs2/mkfs.c | 140 ++++++++++++++++++++++++++++++++++++++-
mkfs.ocfs2/mkfs.h | 1 +
o2image/Makefile | 2 +-
8 files changed, 302 insertions(+), 6 deletions(-)
diff --git a/include/ocfs2-kernel/ocfs2_fs.h b/include/ocfs2-kernel/ocfs2_fs.h
index e454099..d27b098 100644
--- a/include/ocfs2-kernel/ocfs2_fs.h
+++ b/include/ocfs2-kernel/ocfs2_fs.h
@@ -92,7 +92,9 @@
| OCFS2_FEATURE_INCOMPAT_INLINE_DATA \
| OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \
| OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK)
-#define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
+#define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
+ | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
+ | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
/*
* Heartbeat-only devices are missing journals and other files. The
@@ -159,6 +161,12 @@
*/
#define OCFS2_FEATURE_RO_COMPAT_UNWRITTEN 0x0001
+/*
+ * Maintain quota information for this filesystem
+ */
+#define OCFS2_FEATURE_RO_COMPAT_USRQUOTA 0x0002
+#define OCFS2_FEATURE_RO_COMPAT_GRPQUOTA 0x0004
+
/* The byte offset of the first backup block will be 1G.
* The following will be 4G, 16G, 64G, 256G and 1T.
*/
@@ -188,6 +196,7 @@
#define OCFS2_HEARTBEAT_FL (0x00000200) /* Heartbeat area */
#define OCFS2_CHAIN_FL (0x00000400) /* Chain allocator */
#define OCFS2_DEALLOC_FL (0x00000800) /* Truncate log */
+#define OCFS2_QUOTA_FL (0x00001000) /* Quota file */
/*
* Flags on ocfs2_dinode.i_dyn_features
@@ -311,6 +320,8 @@ enum {
#define OCFS2_FIRST_ONLINE_SYSTEM_INODE SLOT_MAP_SYSTEM_INODE
HEARTBEAT_SYSTEM_INODE,
GLOBAL_BITMAP_SYSTEM_INODE,
+ USER_QUOTA_SYSTEM_INODE,
+ GROUP_QUOTA_SYSTEM_INODE,
#define OCFS2_LAST_GLOBAL_SYSTEM_INODE GLOBAL_BITMAP_SYSTEM_INODE
ORPHAN_DIR_SYSTEM_INODE,
EXTENT_ALLOC_SYSTEM_INODE,
@@ -318,6 +329,8 @@ enum {
JOURNAL_SYSTEM_INODE,
LOCAL_ALLOC_SYSTEM_INODE,
TRUNCATE_LOG_SYSTEM_INODE,
+ LOCAL_USER_QUOTA_SYSTEM_INODE,
+ LOCAL_GROUP_QUOTA_SYSTEM_INODE,
NUM_SYSTEM_INODES
};
@@ -331,6 +344,8 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
[SLOT_MAP_SYSTEM_INODE] = { "slot_map", 0, S_IFREG | 0644 },
[HEARTBEAT_SYSTEM_INODE] = { "heartbeat", OCFS2_HEARTBEAT_FL, S_IFREG | 0644 },
[GLOBAL_BITMAP_SYSTEM_INODE] = { "global_bitmap", 0, S_IFREG | 0644 },
+ [USER_QUOTA_SYSTEM_INODE] = { "aquota.user", OCFS2_QUOTA_FL, S_IFREG | 0644 },
+ [GROUP_QUOTA_SYSTEM_INODE] = { "aquota.group", OCFS2_QUOTA_FL, S_IFREG | 0644 },
/* Slot-specific system inodes (one copy per slot) */
[ORPHAN_DIR_SYSTEM_INODE] = { "orphan_dir:%04d", 0, S_IFDIR | 0755 },
@@ -338,7 +353,9 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
[INODE_ALLOC_SYSTEM_INODE] = { "inode_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_CHAIN_FL, S_IFREG | 0644 },
[JOURNAL_SYSTEM_INODE] = { "journal:%04d", OCFS2_JOURNAL_FL, S_IFREG | 0644 },
[LOCAL_ALLOC_SYSTEM_INODE] = { "local_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_LOCAL_ALLOC_FL, S_IFREG | 0644 },
- [TRUNCATE_LOG_SYSTEM_INODE] = { "truncate_log:%04d", OCFS2_DEALLOC_FL, S_IFREG | 0644 }
+ [TRUNCATE_LOG_SYSTEM_INODE] = { "truncate_log:%04d", OCFS2_DEALLOC_FL, S_IFREG | 0644 },
+ [LOCAL_USER_QUOTA_SYSTEM_INODE] = { "aquota%04d.user", OCFS2_QUOTA_FL, S_IFREG | 0644 },
+ [LOCAL_GROUP_QUOTA_SYSTEM_INODE] = { "aquota%04d.group", OCFS2_QUOTA_FL, S_IFREG | 0644 },
};
/* Parameter passed from mount.ocfs2 to module */
@@ -713,6 +730,99 @@ struct ocfs2_group_desc
/*40*/ __u8 bg_bitmap[0];
};
+/* Magic numbers and known versions for local quota files */
+#define OCFS2_LOCAL_QMAGICS {\
+ 0x0cf524c0, /* USRQUOTA */ \
+ 0x0cf524c1 /* GRPQUOTA */ \
+}
+
+#define OCFS2_LOCAL_QVERSIONS {\
+ 0, \
+ 0, \
+}
+
+/* Magic numbers and known versions for global quota files */
+#define OCFS2_GLOBAL_QMAGICS {\
+ 0x0cf52470, /* USRQUOTA */ \
+ 0x0cf52471 /* GRPQUOTA */ \
+}
+
+#define OCFS2_GLOBAL_QVERSIONS {\
+ 0, \
+ 0, \
+}
+
+/* How many bytes to we reserve in each quota file block for our internal
+ * purposes? E.g. checksums... */
+#define OCFS2_QBLK_RESERVED_SPACE 8
+
+/* Generic header of all quota files */
+struct ocfs2_disk_dqheader {
+ __le32 dqh_magic; /* Magic number identifying file */
+ __le32 dqh_version; /* Quota format version */
+};
+
+/* Quota flags in dqinfo header */
+#define OLQF_CLEAN 0x0001 /* Quota file is empty (this should be after\
+ * quota has been cleanly turned off) */
+
+#define OCFS2_LOCAL_INFO_OFF (sizeof(struct ocfs2_disk_dqheader))
+
+/* Information header of local quota file (immediately follows the generic
+ * header) */
+struct ocfs2_local_disk_dqinfo {
+ __le32 dqi_flags; /* Flags for quota file */
+ __le32 dqi_chunks; /* Number of chunks of quota structures
+ * with a bitmap */
+ __le32 dqi_blocks; /* Number of blocks allocated for quota file */
+};
+
+/* Header of one chunk of a quota file */
+struct ocfs2_local_disk_chunk {
+ __le32 dqc_free; /* Number of free entries in the bitmap */
+ uint8_t dqc_bitmap[0]; /* Bitmap of entries in the corresponding
+ * chunk of quota file */
+};
+
+#define OCFS2_GLOBAL_INFO_OFF (sizeof(struct ocfs2_disk_dqheader))
+
+/* Information header of global quota file (immediately follows the generic
+ * header) */
+struct ocfs2_global_disk_dqinfo {
+ __le32 dqi_bgrace;
+ __le32 dqi_igrace;
+ __le32 dqi_syncms;
+ __le32 dqi_blocks;
+ __le32 dqi_free_blk;
+ __le32 dqi_free_entry;
+};
+
+/* Header of leaf tree block */
+struct ocfs2_disk_dqdbheader {
+ __le32 dqdh_next_free; /* Number of next block with free entry */
+ __le32 dqdh_prev_free; /* Number of previous block with free entry */
+ __le16 dqdh_entries; /* Number of valid entries in block */
+ __le16 dqdh_pad1;
+ __le32 dqdh_pad2;
+};
+
+/* Structure with global user / group information. We reserve some space
+ * for future use. */
+struct ocfs2_global_disk_dqblk {
+ __le32 dqb_id; /* ID the structure belongs to */
+ __le32 dqb_use_count; /* Number of nodes having reference to this structure */
+ __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */
+ __le64 dqb_isoftlimit; /* preferred inode limit */
+ __le64 dqb_curinodes; /* current # allocated inodes */
+ __le64 dqb_bhardlimit; /* absolute limit on disk space */
+ __le64 dqb_bsoftlimit; /* preferred limit on disk space */
+ __le64 dqb_curspace; /* current space occupied */
+ __le64 dqb_btime; /* time limit for excessive disk use */
+ __le64 dqb_itime; /* time limit for excessive inode use */
+ __le64 dqb_pad1;
+ __le64 dqb_pad2;
+};
+
#ifdef __KERNEL__
static inline int ocfs2_fast_symlink_chars(struct super_block *sb)
{
diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index 68ba4f5..cabae04 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -134,6 +134,16 @@ typedef struct _ocfs2_dir_scan ocfs2_dir_scan;
typedef struct _ocfs2_bitmap ocfs2_bitmap;
typedef struct _ocfs2_devices ocfs2_devices;
+#define MAXQUOTAS 2
+
+struct _ocfs2_quota_info {
+ uint32_t dqi_bgrace;
+ uint32_t dqi_igrace;
+ uint32_t dqi_syncms;
+};
+
+typedef struct _ocfs2_quota_info ocfs2_quota_info;
+
struct _ocfs2_filesys {
char *fs_devname;
uint32_t fs_flags;
@@ -160,6 +170,8 @@ struct _ocfs2_filesys {
struct o2dlm_ctxt *fs_dlm_ctxt;
struct ocfs2_image_state *ost;
+ ocfs2_quota_info qinfo[MAXQUOTAS];
+
/* Reserved for the use of the calling application. */
void *fs_private;
};
@@ -557,6 +569,19 @@ errcode_t ocfs2_meta_lock(ocfs2_filesys *fs, ocfs2_cached_inode *inode,
errcode_t ocfs2_meta_unlock(ocfs2_filesys *fs, ocfs2_cached_inode *ci);
+/* Quota operations */
+void ocfs2_swap_quota_header(struct ocfs2_disk_dqheader *header);
+void ocfs2_swap_quota_local_info(struct ocfs2_local_disk_dqinfo *info);
+void ocfs2_swap_quota_chunk_header(struct ocfs2_local_disk_chunk *chunk);
+void ocfs2_swap_quota_global_info(struct ocfs2_global_disk_dqinfo *info);
+void ocfs2_swap_quota_global_dqblk(struct ocfs2_global_disk_dqblk *dqblk);
+void ocfs2_swap_quota_leaf_block_header(struct ocfs2_disk_dqdbheader *bheader);
+errcode_t ocfs2_create_local_quota_file(ocfs2_filesys *fs, int type,
+ uint64_t blkno);
+int ocfs2_qtree_depth(int blocksize);
+errcode_t ocfs2_create_global_quota_file(ocfs2_filesys *fs, int type,
+ uint64_t blkno);
+
/* Low level */
void ocfs2_swap_slot_map(struct ocfs2_slot_map *sm, int num_slots);
void ocfs2_swap_slot_map_extended(struct ocfs2_slot_map_extended *se,
diff --git a/libocfs2/Makefile b/libocfs2/Makefile
index 446c8b4..18cf2ee 100644
--- a/libocfs2/Makefile
+++ b/libocfs2/Makefile
@@ -72,6 +72,7 @@ CFILES = \
lockid.c \
backup_super.c \
feature_string.c\
+ quota.c \
image.c
HFILES = \
diff --git a/libocfs2/feature_string.c b/libocfs2/feature_string.c
index 7b1f93e..00c4f26 100644
--- a/libocfs2/feature_string.c
+++ b/libocfs2/feature_string.c
@@ -73,7 +73,9 @@ static ocfs2_fs_options feature_level_defaults[] = {
OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC |
OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP |
OCFS2_FEATURE_INCOMPAT_INLINE_DATA,
- OCFS2_FEATURE_RO_COMPAT_UNWRITTEN}, /* OCFS2_FEATURE_LEVEL_MAX_FEATURES */
+ OCFS2_FEATURE_RO_COMPAT_UNWRITTEN |
+ OCFS2_FEATURE_RO_COMPAT_USRQUOTA |
+ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA }, /* OCFS2_FEATURE_LEVEL_MAX_FEATURES */
};
/* These are the features we support in mkfs/tunefs via --fs-features */
@@ -110,6 +112,16 @@ static struct fs_feature_flags ocfs2_supported_features[] = {
{0, OCFS2_FEATURE_INCOMPAT_INLINE_DATA, 0},
},
{
+ "usrquota",
+ {0, 0, OCFS2_FEATURE_RO_COMPAT_USRQUOTA},
+ {0, 0, OCFS2_FEATURE_RO_COMPAT_USRQUOTA},
+ },
+ {
+ "grpquota",
+ {0, 0, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA},
+ {0, 0, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA},
+ },
+ {
NULL,
{0, 0, 0},
{0, 0, 0}
@@ -161,6 +173,14 @@ static struct feature_name ocfs2_feature_names[] = {
.fn_flag = {0, 0, OCFS2_FEATURE_RO_COMPAT_UNWRITTEN},
},
{
+ .fn_name = "UserQuota",
+ .fn_flag = {0, 0, OCFS2_FEATURE_RO_COMPAT_USRQUOTA},
+ },
+ {
+ .fn_name = "GroupQuota",
+ .fn_flag = {0, 0, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA},
+ },
+ {
.fn_name = "InlineData",
.fn_flag = {0, OCFS2_FEATURE_INCOMPAT_INLINE_DATA, 0},
},
diff --git a/mkfs.ocfs2/mkfs.c b/mkfs.ocfs2/mkfs.c
index aad166b..9fe2ac2 100644
--- a/mkfs.ocfs2/mkfs.c
+++ b/mkfs.ocfs2/mkfs.c
@@ -96,12 +96,16 @@ static SystemFileInfo system_files[] = {
{ "slot_map", SFI_OTHER, 1, S_IFREG | 0644 },
{ "heartbeat", SFI_HEARTBEAT, 1, S_IFREG | 0644 },
{ "global_bitmap", SFI_CLUSTER, 1, S_IFREG | 0644 },
+ { "aquota.user", SFI_QUOTA, 1, S_IFREG | 0644 },
+ { "aquota.group", SFI_QUOTA, 1, S_IFREG | 0644 },
{ "orphan_dir:%04d", SFI_OTHER, 0, S_IFDIR | 0755 },
{ "extent_alloc:%04d", SFI_CHAIN, 0, S_IFREG | 0644 },
{ "inode_alloc:%04d", SFI_CHAIN, 0, S_IFREG | 0644 },
{ "journal:%04d", SFI_JOURNAL, 0, S_IFREG | 0644 },
{ "local_alloc:%04d", SFI_LOCAL_ALLOC, 0, S_IFREG | 0644 },
- { "truncate_log:%04d", SFI_TRUNCATE_LOG, 0, S_IFREG | 0644 }
+ { "truncate_log:%04d", SFI_TRUNCATE_LOG, 0, S_IFREG | 0644 },
+ { "aquota%04d.user", SFI_QUOTA, 0, S_IFREG | 0644 },
+ { "aquota%04d.group", SFI_QUOTA, 0, S_IFREG | 0644 },
};
struct fs_type_translation {
@@ -184,6 +188,23 @@ static int hb_dev_skip(State *s, int system_inode)
return ret;
}
+/* Should we skip this inode because of features enabled / disabled? */
+static int feature_skip(State *s, int system_inode)
+{
+ switch (system_inode) {
+ case USER_QUOTA_SYSTEM_INODE:
+ case LOCAL_USER_QUOTA_SYSTEM_INODE:
+ return !(s->feature_flags.opt_ro_compat &
+ OCFS2_FEATURE_RO_COMPAT_USRQUOTA);
+ case GROUP_QUOTA_SYSTEM_INODE:
+ case LOCAL_GROUP_QUOTA_SYSTEM_INODE:
+ return !(s->feature_flags.opt_ro_compat &
+ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA);
+ default:
+ return 0;
+ }
+}
+
static inline uint32_t system_dir_bytes_needed(State *s)
{
int each = OCFS2_DIR_REC_LEN(SYSTEM_FILE_NAME_MAX);
@@ -191,6 +212,108 @@ static inline uint32_t system_dir_bytes_needed(State *s)
return each * sys_blocks_needed(s->initial_slots);
}
+static void format_quota_files(State *s)
+{
+ errcode_t ret;
+ ocfs2_filesys *fs = NULL;
+ char fname[SYSTEM_FILE_NAME_MAX];
+ uint64_t blkno;
+ int i;
+
+ ret = ocfs2_open(s->device_name, OCFS2_FLAG_RW, 0, 0, &fs);
+ if (ret) {
+ com_err(s->progname, ret, "while opening new file system");
+ exit(1);
+ }
+
+ /* Write correct data into quota files */
+ if (!feature_skip(s, USER_QUOTA_SYSTEM_INODE)) {
+ fs->qinfo[0].dqi_syncms = 10000;
+ fs->qinfo[0].dqi_bgrace = 604800; /* 1 week */
+ fs->qinfo[0].dqi_igrace = 604800; /* 1 week */
+ snprintf(fname, sizeof(fname),
+ ocfs2_system_inodes[USER_QUOTA_SYSTEM_INODE].si_name);
+ ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname,
+ strlen(fname), NULL, &blkno);
+ if (ret) {
+ com_err(s->progname, ret,
+ "while looking up quota filename \"%.*s\"",
+ (int)strlen(fname), fname);
+ goto error;
+ }
+ ret = ocfs2_create_global_quota_file(fs, 0, blkno);
+ if (ret) {
+ com_err(s->progname, ret, "while creating global user "
+ "quota file");
+ goto error;
+ }
+ for (i = 0; i < s->initial_slots; ++i) {
+ snprintf(fname, sizeof(fname),
+ ocfs2_system_inodes[
+ LOCAL_USER_QUOTA_SYSTEM_INODE].si_name, i);
+ ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname,
+ strlen(fname), NULL, &blkno);
+ if (ret) {
+ com_err(s->progname, ret,
+ "while looking up quota filename "
+ "\"%.*s\"", (int)strlen(fname), fname);
+ goto error;
+ }
+ ret = ocfs2_create_local_quota_file(fs, 0, blkno);
+ if (ret) {
+ com_err(s->progname, ret, "while creating "
+ "local user quota file");
+ goto error;
+ }
+ }
+ }
+ if (!feature_skip(s, GROUP_QUOTA_SYSTEM_INODE)) {
+ fs->qinfo[1].dqi_syncms = 10000;
+ fs->qinfo[1].dqi_bgrace = 604800; /* 1 week */
+ fs->qinfo[1].dqi_igrace = 604800; /* 1 week */
+ snprintf(fname, sizeof(fname),
+ ocfs2_system_inodes[GROUP_QUOTA_SYSTEM_INODE].si_name);
+ ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname,
+ strlen(fname), NULL, &blkno);
+ if (ret) {
+ com_err(s->progname, ret,
+ "while looking up quota filename \"%.*s\"",
+ (int)strlen(fname), fname);
+ goto error;
+ }
+ ret = ocfs2_create_global_quota_file(fs, 1, blkno);
+ if (ret) {
+ com_err(s->progname, ret, "while creating global group "
+ "quota file");
+ goto error;
+ }
+ for (i = 0; i < s->initial_slots; ++i) {
+ snprintf(fname, sizeof(fname),
+ ocfs2_system_inodes[
+ LOCAL_GROUP_QUOTA_SYSTEM_INODE].si_name, i);
+ ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname,
+ strlen(fname), NULL, &blkno);
+ if (ret) {
+ com_err(s->progname, ret,
+ "while looking up quota filename "
+ "\"%.*s\"", (int)strlen(fname), fname);
+ goto error;
+ }
+ ret = ocfs2_create_local_quota_file(fs, 1, blkno);
+ if (ret) {
+ com_err(s->progname, ret, "while creating "
+ "local group quota file");
+ goto error;
+ }
+ }
+ }
+ ocfs2_close(fs);
+ return;
+error:
+ clear_both_ends(s);
+ exit(1);
+}
+
int
main(int argc, char **argv)
{
@@ -355,6 +478,8 @@ main(int argc, char **argv)
for (i = 0; i < NUM_SYSTEM_INODES; i++) {
if (hb_dev_skip(s, i))
continue;
+ if (feature_skip(s, i))
+ continue;
num = (system_files[i].global) ? 1 : s->initial_slots;
for (j = 0; j < num; j++) {
@@ -413,6 +538,8 @@ main(int argc, char **argv)
for (i = 0; i < NUM_SYSTEM_INODES; i++) {
if (hb_dev_skip(s, i))
continue;
+ if (feature_skip(s, i))
+ continue;
num = system_files[i].global ? 1 : s->initial_slots;
for (j = 0; j < num; j++) {
@@ -496,6 +623,14 @@ main(int argc, char **argv)
if (!s->quiet)
printf("done\n");
+
+ if (!s->quiet)
+ printf("Formatting quota files: ");
+
+ format_quota_files(s);
+
+ if (!s->quiet)
+ printf("done\n");
}
close_device(s);
@@ -2304,6 +2439,9 @@ init_record(State *s, SystemFileDiskRecord *rec, int type, int mode)
case SFI_TRUNCATE_LOG:
rec->flags |= OCFS2_DEALLOC_FL;
break;
+ case SFI_QUOTA:
+ rec->flags |= OCFS2_QUOTA_FL;
+ break;
case SFI_OTHER:
break;
}
diff --git a/mkfs.ocfs2/mkfs.h b/mkfs.ocfs2/mkfs.h
index bd8ac45..969e4df 100644
--- a/mkfs.ocfs2/mkfs.h
+++ b/mkfs.ocfs2/mkfs.h
@@ -96,6 +96,7 @@ enum {
SFI_HEARTBEAT,
SFI_CHAIN,
SFI_TRUNCATE_LOG,
+ SFI_QUOTA,
SFI_OTHER
};
--
1.5.2.4
_______________________________________________
Ocfs2-devel mailing list
[email protected]
http://oss.oracle.com/mailman/listinfo/ocfs2-devel