ocfs2: Add dir_resv_level mount option
The default behavior for directory reservations stays the same, but we add a mount option so people can tweak the size of directory reservations according to their workloads. Signed-off-by: Mark Fasheh <mfasheh@suse.com> Signed-off-by: Joel Becker <joel.becker@oracle.com>
This commit is contained in:
parent
b07f8f24df
commit
83f92318fa
6 changed files with 40 additions and 5 deletions
|
@ -83,3 +83,7 @@ noacl (*) Disables POSIX Access Control Lists support.
|
||||||
resv_level=2 (*) Set how agressive allocation reservations will be.
|
resv_level=2 (*) Set how agressive allocation reservations will be.
|
||||||
Valid values are between 0 (reservations off) to 8
|
Valid values are between 0 (reservations off) to 8
|
||||||
(maximum space for reservations).
|
(maximum space for reservations).
|
||||||
|
dir_resv_level= (*) By default, directory reservations will scale with file
|
||||||
|
reservations - users should rarely need to change this
|
||||||
|
value. If allocation reservations are turned off, this
|
||||||
|
option will have no effect.
|
||||||
|
|
|
@ -2977,7 +2977,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
|
||||||
* if we only get one now, that's enough to continue. The rest
|
* if we only get one now, that's enough to continue. The rest
|
||||||
* will be claimed after the conversion to extents.
|
* will be claimed after the conversion to extents.
|
||||||
*/
|
*/
|
||||||
data_ac->ac_resv = &oi->ip_la_data_resv;
|
if (ocfs2_dir_resv_allowed(osb))
|
||||||
|
data_ac->ac_resv = &oi->ip_la_data_resv;
|
||||||
ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
|
ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
|
@ -3348,7 +3349,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_ac->ac_resv = &OCFS2_I(dir)->ip_la_data_resv;
|
if (ocfs2_dir_resv_allowed(osb))
|
||||||
|
data_ac->ac_resv = &OCFS2_I(dir)->ip_la_data_resv;
|
||||||
|
|
||||||
credits = ocfs2_calc_extend_credits(sb, el, 1);
|
credits = ocfs2_calc_extend_credits(sb, el, 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -356,6 +356,7 @@ struct ocfs2_super
|
||||||
struct ocfs2_reservation_map osb_la_resmap;
|
struct ocfs2_reservation_map osb_la_resmap;
|
||||||
|
|
||||||
unsigned int osb_resv_level;
|
unsigned int osb_resv_level;
|
||||||
|
unsigned int osb_dir_resv_level;
|
||||||
|
|
||||||
/* Next three fields are for local node slot recovery during
|
/* Next three fields are for local node slot recovery during
|
||||||
* mount. */
|
* mount. */
|
||||||
|
|
|
@ -44,7 +44,11 @@ DEFINE_SPINLOCK(resv_lock);
|
||||||
|
|
||||||
#define OCFS2_MIN_RESV_WINDOW_BITS 8
|
#define OCFS2_MIN_RESV_WINDOW_BITS 8
|
||||||
#define OCFS2_MAX_RESV_WINDOW_BITS 1024
|
#define OCFS2_MAX_RESV_WINDOW_BITS 1024
|
||||||
#define OCFS2_RESV_DIR_WINDOW_BITS OCFS2_MIN_RESV_WINDOW_BITS
|
|
||||||
|
int ocfs2_dir_resv_allowed(struct ocfs2_super *osb)
|
||||||
|
{
|
||||||
|
return (osb->osb_resv_level && osb->osb_dir_resv_level);
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int ocfs2_resv_window_bits(struct ocfs2_reservation_map *resmap,
|
static unsigned int ocfs2_resv_window_bits(struct ocfs2_reservation_map *resmap,
|
||||||
struct ocfs2_alloc_reservation *resv)
|
struct ocfs2_alloc_reservation *resv)
|
||||||
|
@ -56,8 +60,7 @@ static unsigned int ocfs2_resv_window_bits(struct ocfs2_reservation_map *resmap,
|
||||||
/* 8, 16, 32, 64, 128, 256, 512, 1024 */
|
/* 8, 16, 32, 64, 128, 256, 512, 1024 */
|
||||||
bits = 4 << osb->osb_resv_level;
|
bits = 4 << osb->osb_resv_level;
|
||||||
} else {
|
} else {
|
||||||
/* For now, treat directories the same as files. */
|
bits = 4 << osb->osb_dir_resv_level;
|
||||||
bits = 4 << osb->osb_resv_level;
|
|
||||||
}
|
}
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ void ocfs2_resv_init_once(struct ocfs2_alloc_reservation *resv);
|
||||||
void ocfs2_resv_set_type(struct ocfs2_alloc_reservation *resv,
|
void ocfs2_resv_set_type(struct ocfs2_alloc_reservation *resv,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
|
||||||
|
int ocfs2_dir_resv_allowed(struct ocfs2_super *osb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ocfs2_resv_discard() - truncate a reservation
|
* ocfs2_resv_discard() - truncate a reservation
|
||||||
* @resmap:
|
* @resmap:
|
||||||
|
|
|
@ -96,6 +96,7 @@ struct mount_options
|
||||||
signed short slot;
|
signed short slot;
|
||||||
int localalloc_opt;
|
int localalloc_opt;
|
||||||
unsigned int resv_level;
|
unsigned int resv_level;
|
||||||
|
int dir_resv_level;
|
||||||
char cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
|
char cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,6 +179,7 @@ enum {
|
||||||
Opt_usrquota,
|
Opt_usrquota,
|
||||||
Opt_grpquota,
|
Opt_grpquota,
|
||||||
Opt_resv_level,
|
Opt_resv_level,
|
||||||
|
Opt_dir_resv_level,
|
||||||
Opt_err,
|
Opt_err,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -205,6 +207,7 @@ static const match_table_t tokens = {
|
||||||
{Opt_usrquota, "usrquota"},
|
{Opt_usrquota, "usrquota"},
|
||||||
{Opt_grpquota, "grpquota"},
|
{Opt_grpquota, "grpquota"},
|
||||||
{Opt_resv_level, "resv_level=%u"},
|
{Opt_resv_level, "resv_level=%u"},
|
||||||
|
{Opt_dir_resv_level, "dir_resv_level=%u"},
|
||||||
{Opt_err, NULL}
|
{Opt_err, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1034,6 +1037,11 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
|
|
||||||
ocfs2_la_set_sizes(osb, parsed_options.localalloc_opt);
|
ocfs2_la_set_sizes(osb, parsed_options.localalloc_opt);
|
||||||
osb->osb_resv_level = parsed_options.resv_level;
|
osb->osb_resv_level = parsed_options.resv_level;
|
||||||
|
osb->osb_dir_resv_level = parsed_options.resv_level;
|
||||||
|
if (parsed_options.dir_resv_level == -1)
|
||||||
|
osb->osb_dir_resv_level = parsed_options.resv_level;
|
||||||
|
else
|
||||||
|
osb->osb_dir_resv_level = parsed_options.dir_resv_level;
|
||||||
|
|
||||||
status = ocfs2_verify_userspace_stack(osb, &parsed_options);
|
status = ocfs2_verify_userspace_stack(osb, &parsed_options);
|
||||||
if (status)
|
if (status)
|
||||||
|
@ -1295,6 +1303,7 @@ static int ocfs2_parse_options(struct super_block *sb,
|
||||||
mopt->localalloc_opt = -1;
|
mopt->localalloc_opt = -1;
|
||||||
mopt->cluster_stack[0] = '\0';
|
mopt->cluster_stack[0] = '\0';
|
||||||
mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
|
mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
|
||||||
|
mopt->dir_resv_level = -1;
|
||||||
|
|
||||||
if (!options) {
|
if (!options) {
|
||||||
status = 1;
|
status = 1;
|
||||||
|
@ -1449,6 +1458,17 @@ static int ocfs2_parse_options(struct super_block *sb,
|
||||||
option < OCFS2_MAX_RESV_LEVEL)
|
option < OCFS2_MAX_RESV_LEVEL)
|
||||||
mopt->resv_level = option;
|
mopt->resv_level = option;
|
||||||
break;
|
break;
|
||||||
|
case Opt_dir_resv_level:
|
||||||
|
if (is_remount)
|
||||||
|
break;
|
||||||
|
if (match_int(&args[0], &option)) {
|
||||||
|
status = 0;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
if (option >= OCFS2_MIN_RESV_LEVEL &&
|
||||||
|
option < OCFS2_MAX_RESV_LEVEL)
|
||||||
|
mopt->dir_resv_level = option;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
mlog(ML_ERROR,
|
mlog(ML_ERROR,
|
||||||
"Unrecognized mount option \"%s\" "
|
"Unrecognized mount option \"%s\" "
|
||||||
|
@ -1533,6 +1553,9 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
|
||||||
if (osb->osb_resv_level != OCFS2_DEFAULT_RESV_LEVEL)
|
if (osb->osb_resv_level != OCFS2_DEFAULT_RESV_LEVEL)
|
||||||
seq_printf(s, ",resv_level=%d", osb->osb_resv_level);
|
seq_printf(s, ",resv_level=%d", osb->osb_resv_level);
|
||||||
|
|
||||||
|
if (osb->osb_dir_resv_level != osb->osb_resv_level)
|
||||||
|
seq_printf(s, ",dir_resv_level=%d", osb->osb_resv_level);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue