summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/ocfs2.txt4
-rw-r--r--fs/ocfs2/dir.c6
-rw-r--r--fs/ocfs2/ocfs2.h1
-rw-r--r--fs/ocfs2/reservations.c9
-rw-r--r--fs/ocfs2/reservations.h2
-rw-r--r--fs/ocfs2/super.c23
6 files changed, 40 insertions, 5 deletions
diff --git a/Documentation/filesystems/ocfs2.txt b/Documentation/filesystems/ocfs2.txt
index 32339e584a9..1f7ae144f6d 100644
--- a/Documentation/filesystems/ocfs2.txt
+++ b/Documentation/filesystems/ocfs2.txt
@@ -83,3 +83,7 @@ noacl (*) Disables POSIX Access Control Lists support.
resv_level=2 (*) Set how agressive allocation reservations will be.
Valid values are between 0 (reservations off) to 8
(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.
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 8563f97c58a..6c9a28a2d3a 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -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
* 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);
if (ret) {
mlog_errno(ret);
@@ -3348,7 +3349,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
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);
} else {
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 09d7aee3dab..a388528f485 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -356,6 +356,7 @@ struct ocfs2_super
struct ocfs2_reservation_map osb_la_resmap;
unsigned int osb_resv_level;
+ unsigned int osb_dir_resv_level;
/* Next three fields are for local node slot recovery during
* mount. */
diff --git a/fs/ocfs2/reservations.c b/fs/ocfs2/reservations.c
index 87fa35791f1..6497bcc00fa 100644
--- a/fs/ocfs2/reservations.c
+++ b/fs/ocfs2/reservations.c
@@ -44,7 +44,11 @@ DEFINE_SPINLOCK(resv_lock);
#define OCFS2_MIN_RESV_WINDOW_BITS 8
#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,
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 */
bits = 4 << osb->osb_resv_level;
} else {
- /* For now, treat directories the same as files. */
- bits = 4 << osb->osb_resv_level;
+ bits = 4 << osb->osb_dir_resv_level;
}
return bits;
}
diff --git a/fs/ocfs2/reservations.h b/fs/ocfs2/reservations.h
index 022aff601e1..25b0c0e31e9 100644
--- a/fs/ocfs2/reservations.h
+++ b/fs/ocfs2/reservations.h
@@ -67,6 +67,8 @@ void ocfs2_resv_init_once(struct ocfs2_alloc_reservation *resv);
void ocfs2_resv_set_type(struct ocfs2_alloc_reservation *resv,
unsigned int flags);
+int ocfs2_dir_resv_allowed(struct ocfs2_super *osb);
+
/**
* ocfs2_resv_discard() - truncate a reservation
* @resmap:
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 5745682eb1c..79d7d4cf45b 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -96,6 +96,7 @@ struct mount_options
signed short slot;
int localalloc_opt;
unsigned int resv_level;
+ int dir_resv_level;
char cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
};
@@ -178,6 +179,7 @@ enum {
Opt_usrquota,
Opt_grpquota,
Opt_resv_level,
+ Opt_dir_resv_level,
Opt_err,
};
@@ -205,6 +207,7 @@ static const match_table_t tokens = {
{Opt_usrquota, "usrquota"},
{Opt_grpquota, "grpquota"},
{Opt_resv_level, "resv_level=%u"},
+ {Opt_dir_resv_level, "dir_resv_level=%u"},
{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);
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);
if (status)
@@ -1295,6 +1303,7 @@ static int ocfs2_parse_options(struct super_block *sb,
mopt->localalloc_opt = -1;
mopt->cluster_stack[0] = '\0';
mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
+ mopt->dir_resv_level = -1;
if (!options) {
status = 1;
@@ -1449,6 +1458,17 @@ static int ocfs2_parse_options(struct super_block *sb,
option < OCFS2_MAX_RESV_LEVEL)
mopt->resv_level = option;
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:
mlog(ML_ERROR,
"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)
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;
}