Commit 2fbe8d1e authored by Sunil Mushran's avatar Sunil Mushran Committed by Mark Fasheh

ocfs2: Local alloc window size changeable via mount option

Local alloc is a performance optimization in ocfs2 in which a node
takes a window of bits from the global bitmap and then uses that for
all small local allocations. This window size is fixed to 8MB currently.
This patch allows users to specify the window size in MB including
disabling it by passing in 0. If the number specified is too large,
the fs will use the default value of 8MB.

mount -o localalloc=X /dev/sdX /mntpoint
Signed-off-by: default avatarSunil Mushran <sunil.mushran@oracle.com>
Signed-off-by: default avatarMark Fasheh <mark.fasheh@oracle.com>
parent d147b3d6
...@@ -72,3 +72,6 @@ commit=nrsec (*) Ocfs2 can be told to sync all its data and metadata ...@@ -72,3 +72,6 @@ commit=nrsec (*) Ocfs2 can be told to sync all its data and metadata
it at the default (5 seconds). it at the default (5 seconds).
Setting it to very large values will improve Setting it to very large values will improve
performance. performance.
localalloc=8(*) Allows custom localalloc size in MB. If the value is too
large, the fs will silently revert it to the default.
Localalloc is not enabled for local mounts.
...@@ -75,18 +75,12 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, ...@@ -75,18 +75,12 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
struct inode *local_alloc_inode); struct inode *local_alloc_inode);
/*
* Determine how large our local alloc window should be, in bits.
*
* These values (and the behavior in ocfs2_alloc_should_use_local) have
* been chosen so that most allocations, including new block groups go
* through local alloc.
*/
static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb) static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
{ {
BUG_ON(osb->s_clustersize_bits < 12); BUG_ON(osb->s_clustersize_bits > 20);
return 2048 >> (osb->s_clustersize_bits - 12); /* Size local alloc windows by the megabyte */
return osb->local_alloc_size << (20 - osb->s_clustersize_bits);
} }
/* /*
...@@ -96,18 +90,23 @@ static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb) ...@@ -96,18 +90,23 @@ static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits) int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
{ {
int la_bits = ocfs2_local_alloc_window_bits(osb); int la_bits = ocfs2_local_alloc_window_bits(osb);
int ret = 0;
if (osb->local_alloc_state != OCFS2_LA_ENABLED) if (osb->local_alloc_state != OCFS2_LA_ENABLED)
return 0; goto bail;
/* la_bits should be at least twice the size (in clusters) of /* la_bits should be at least twice the size (in clusters) of
* a new block group. We want to be sure block group * a new block group. We want to be sure block group
* allocations go through the local alloc, so allow an * allocations go through the local alloc, so allow an
* allocation to take up to half the bitmap. */ * allocation to take up to half the bitmap. */
if (bits > (la_bits / 2)) if (bits > (la_bits / 2))
return 0; goto bail;
return 1; ret = 1;
bail:
mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
return ret;
} }
int ocfs2_load_local_alloc(struct ocfs2_super *osb) int ocfs2_load_local_alloc(struct ocfs2_super *osb)
...@@ -121,6 +120,19 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) ...@@ -121,6 +120,19 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
mlog_entry_void(); mlog_entry_void();
if (ocfs2_mount_local(osb))
goto bail;
if (osb->local_alloc_size == 0)
goto bail;
if (ocfs2_local_alloc_window_bits(osb) >= osb->bitmap_cpg) {
mlog(ML_NOTICE, "Requested local alloc window %d is larger "
"than max possible %u. Using defaults.\n",
ocfs2_local_alloc_window_bits(osb), (osb->bitmap_cpg - 1));
osb->local_alloc_size = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
}
/* read the alloc off disk */ /* read the alloc off disk */
inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE, inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE,
osb->slot_num); osb->slot_num);
...@@ -181,6 +193,9 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) ...@@ -181,6 +193,9 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
if (inode) if (inode)
iput(inode); iput(inode);
mlog(0, "Local alloc window bits = %d\n",
ocfs2_local_alloc_window_bits(osb));
mlog_exit(status); mlog_exit(status);
return status; return status;
} }
...@@ -521,6 +536,9 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb, ...@@ -521,6 +536,9 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
iput(local_alloc_inode); iput(local_alloc_inode);
} }
mlog(0, "bits=%d, slot=%d, ret=%d\n", bits_wanted, osb->slot_num,
status);
mlog_exit(status); mlog_exit(status);
return status; return status;
} }
......
...@@ -231,6 +231,7 @@ struct ocfs2_super ...@@ -231,6 +231,7 @@ struct ocfs2_super
struct ocfs2_journal *journal; struct ocfs2_journal *journal;
unsigned long osb_commit_interval; unsigned long osb_commit_interval;
int local_alloc_size;
enum ocfs2_local_alloc_state local_alloc_state; enum ocfs2_local_alloc_state local_alloc_state;
struct buffer_head *local_alloc_bh; struct buffer_head *local_alloc_bh;
u64 la_last_gd; u64 la_last_gd;
......
...@@ -270,6 +270,14 @@ struct ocfs2_new_group_input { ...@@ -270,6 +270,14 @@ struct ocfs2_new_group_input {
/* Journal limits (in bytes) */ /* Journal limits (in bytes) */
#define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024) #define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024)
/*
* Default local alloc size (in megabytes)
*
* The value chosen should be such that most allocations, including new
* block groups, use local alloc.
*/
#define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE 8
struct ocfs2_system_inode_info { struct ocfs2_system_inode_info {
char *si_name; char *si_name;
int si_iflags; int si_iflags;
......
...@@ -1516,8 +1516,9 @@ int __ocfs2_claim_clusters(struct ocfs2_super *osb, ...@@ -1516,8 +1516,9 @@ int __ocfs2_claim_clusters(struct ocfs2_super *osb,
if (min_clusters > (osb->bitmap_cpg - 1)) { if (min_clusters > (osb->bitmap_cpg - 1)) {
/* The only paths asking for contiguousness /* The only paths asking for contiguousness
* should know about this already. */ * should know about this already. */
mlog(ML_ERROR, "minimum allocation requested exceeds " mlog(ML_ERROR, "minimum allocation requested %u exceeds "
"group bitmap size!"); "group bitmap size %u!\n", min_clusters,
osb->bitmap_cpg);
status = -ENOSPC; status = -ENOSPC;
goto bail; goto bail;
} }
......
...@@ -87,6 +87,7 @@ struct mount_options ...@@ -87,6 +87,7 @@ struct mount_options
unsigned long mount_opt; unsigned long mount_opt;
unsigned int atime_quantum; unsigned int atime_quantum;
signed short slot; signed short slot;
unsigned int localalloc_opt;
}; };
static int ocfs2_parse_options(struct super_block *sb, char *options, static int ocfs2_parse_options(struct super_block *sb, char *options,
...@@ -151,6 +152,7 @@ enum { ...@@ -151,6 +152,7 @@ enum {
Opt_atime_quantum, Opt_atime_quantum,
Opt_slot, Opt_slot,
Opt_commit, Opt_commit,
Opt_localalloc,
Opt_err, Opt_err,
}; };
...@@ -167,6 +169,7 @@ static match_table_t tokens = { ...@@ -167,6 +169,7 @@ static match_table_t tokens = {
{Opt_atime_quantum, "atime_quantum=%u"}, {Opt_atime_quantum, "atime_quantum=%u"},
{Opt_slot, "preferred_slot=%u"}, {Opt_slot, "preferred_slot=%u"},
{Opt_commit, "commit=%u"}, {Opt_commit, "commit=%u"},
{Opt_localalloc, "localalloc=%d"},
{Opt_err, NULL} {Opt_err, NULL}
}; };
...@@ -602,6 +605,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -602,6 +605,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
osb->s_atime_quantum = parsed_options.atime_quantum; osb->s_atime_quantum = parsed_options.atime_quantum;
osb->preferred_slot = parsed_options.slot; osb->preferred_slot = parsed_options.slot;
osb->osb_commit_interval = parsed_options.commit_interval; osb->osb_commit_interval = parsed_options.commit_interval;
osb->local_alloc_size = parsed_options.localalloc_opt;
sb->s_magic = OCFS2_SUPER_MAGIC; sb->s_magic = OCFS2_SUPER_MAGIC;
...@@ -756,6 +760,7 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -756,6 +760,7 @@ static int ocfs2_parse_options(struct super_block *sb,
mopt->mount_opt = 0; mopt->mount_opt = 0;
mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM; mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
mopt->slot = OCFS2_INVALID_SLOT; mopt->slot = OCFS2_INVALID_SLOT;
mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
if (!options) { if (!options) {
status = 1; status = 1;
...@@ -834,6 +839,15 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -834,6 +839,15 @@ static int ocfs2_parse_options(struct super_block *sb,
option = JBD_DEFAULT_MAX_COMMIT_AGE; option = JBD_DEFAULT_MAX_COMMIT_AGE;
mopt->commit_interval = HZ * option; mopt->commit_interval = HZ * option;
break; break;
case Opt_localalloc:
option = 0;
if (match_int(&args[0], &option)) {
status = 0;
goto bail;
}
if (option >= 0 && (option <= ocfs2_local_alloc_size(sb) * 8))
mopt->localalloc_opt = option;
break;
default: default:
mlog(ML_ERROR, mlog(ML_ERROR,
"Unrecognized mount option \"%s\" " "Unrecognized mount option \"%s\" "
...@@ -886,6 +900,9 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) ...@@ -886,6 +900,9 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
seq_printf(s, ",commit=%u", seq_printf(s, ",commit=%u",
(unsigned) (osb->osb_commit_interval / HZ)); (unsigned) (osb->osb_commit_interval / HZ));
if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
seq_printf(s, ",localalloc=%d", osb->local_alloc_size);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment