diff options
author | Mark Fasheh <mfasheh@suse.com> | 2009-12-07 16:10:48 -0500 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2010-05-05 21:17:30 -0400 |
commit | d02f00cc057809d96c044cc72d5b9809d59f7d49 (patch) | |
tree | 44a6d81ecf9fb4b5aa91c0501a8da2ee36890a38 /fs/ocfs2/super.c | |
parent | ec20cec7a351584ca6c70ead012e73d61f9a8e04 (diff) |
ocfs2: allocation reservations
This patch improves Ocfs2 allocation policy by allowing an inode to
reserve a portion of the local alloc bitmap for itself. The reserved
portion (allocation window) is advisory in that other allocation
windows might steal it if the local alloc bitmap becomes
full. Otherwise, the reservations are honored and guaranteed to be
free. When the local alloc window is moved to a different portion of
the bitmap, existing reservations are discarded.
Reservation windows are represented internally by a red-black
tree. Within that tree, each node represents the reservation window of
one inode. An LRU of active reservations is also maintained. When new
data is written, we allocate it from the inodes window. When all bits
in a window are exhausted, we allocate a new one as close to the
previous one as possible. Should we not find free space, an existing
reservation is pulled off the LRU and cannibalized.
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/super.c')
-rw-r--r-- | fs/ocfs2/super.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index dee03197a494..cfe672e72b27 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -95,6 +95,7 @@ struct mount_options | |||
95 | unsigned int atime_quantum; | 95 | unsigned int atime_quantum; |
96 | signed short slot; | 96 | signed short slot; |
97 | unsigned int localalloc_opt; | 97 | unsigned int localalloc_opt; |
98 | unsigned int resv_level; | ||
98 | char cluster_stack[OCFS2_STACK_LABEL_LEN + 1]; | 99 | char cluster_stack[OCFS2_STACK_LABEL_LEN + 1]; |
99 | }; | 100 | }; |
100 | 101 | ||
@@ -176,6 +177,7 @@ enum { | |||
176 | Opt_noacl, | 177 | Opt_noacl, |
177 | Opt_usrquota, | 178 | Opt_usrquota, |
178 | Opt_grpquota, | 179 | Opt_grpquota, |
180 | Opt_resv_level, | ||
179 | Opt_err, | 181 | Opt_err, |
180 | }; | 182 | }; |
181 | 183 | ||
@@ -202,6 +204,7 @@ static const match_table_t tokens = { | |||
202 | {Opt_noacl, "noacl"}, | 204 | {Opt_noacl, "noacl"}, |
203 | {Opt_usrquota, "usrquota"}, | 205 | {Opt_usrquota, "usrquota"}, |
204 | {Opt_grpquota, "grpquota"}, | 206 | {Opt_grpquota, "grpquota"}, |
207 | {Opt_resv_level, "resv_level=%u"}, | ||
205 | {Opt_err, NULL} | 208 | {Opt_err, NULL} |
206 | }; | 209 | }; |
207 | 210 | ||
@@ -1030,6 +1033,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
1030 | osb->osb_commit_interval = parsed_options.commit_interval; | 1033 | osb->osb_commit_interval = parsed_options.commit_interval; |
1031 | osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); | 1034 | osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); |
1032 | osb->local_alloc_bits = osb->local_alloc_default_bits; | 1035 | osb->local_alloc_bits = osb->local_alloc_default_bits; |
1036 | osb->osb_resv_level = parsed_options.resv_level; | ||
1033 | 1037 | ||
1034 | status = ocfs2_verify_userspace_stack(osb, &parsed_options); | 1038 | status = ocfs2_verify_userspace_stack(osb, &parsed_options); |
1035 | if (status) | 1039 | if (status) |
@@ -1290,6 +1294,7 @@ static int ocfs2_parse_options(struct super_block *sb, | |||
1290 | mopt->slot = OCFS2_INVALID_SLOT; | 1294 | mopt->slot = OCFS2_INVALID_SLOT; |
1291 | mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE; | 1295 | mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE; |
1292 | mopt->cluster_stack[0] = '\0'; | 1296 | mopt->cluster_stack[0] = '\0'; |
1297 | mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL; | ||
1293 | 1298 | ||
1294 | if (!options) { | 1299 | if (!options) { |
1295 | status = 1; | 1300 | status = 1; |
@@ -1433,6 +1438,17 @@ static int ocfs2_parse_options(struct super_block *sb, | |||
1433 | mopt->mount_opt |= OCFS2_MOUNT_NO_POSIX_ACL; | 1438 | mopt->mount_opt |= OCFS2_MOUNT_NO_POSIX_ACL; |
1434 | mopt->mount_opt &= ~OCFS2_MOUNT_POSIX_ACL; | 1439 | mopt->mount_opt &= ~OCFS2_MOUNT_POSIX_ACL; |
1435 | break; | 1440 | break; |
1441 | case Opt_resv_level: | ||
1442 | if (is_remount) | ||
1443 | break; | ||
1444 | if (match_int(&args[0], &option)) { | ||
1445 | status = 0; | ||
1446 | goto bail; | ||
1447 | } | ||
1448 | if (option >= OCFS2_MIN_RESV_LEVEL && | ||
1449 | option < OCFS2_MAX_RESV_LEVEL) | ||
1450 | mopt->resv_level = option; | ||
1451 | break; | ||
1436 | default: | 1452 | default: |
1437 | mlog(ML_ERROR, | 1453 | mlog(ML_ERROR, |
1438 | "Unrecognized mount option \"%s\" " | 1454 | "Unrecognized mount option \"%s\" " |
@@ -1514,6 +1530,9 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1514 | else | 1530 | else |
1515 | seq_printf(s, ",noacl"); | 1531 | seq_printf(s, ",noacl"); |
1516 | 1532 | ||
1533 | if (osb->osb_resv_level != OCFS2_DEFAULT_RESV_LEVEL) | ||
1534 | seq_printf(s, ",resv_level=%d", osb->osb_resv_level); | ||
1535 | |||
1517 | return 0; | 1536 | return 0; |
1518 | } | 1537 | } |
1519 | 1538 | ||
@@ -2042,6 +2061,12 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
2042 | 2061 | ||
2043 | init_waitqueue_head(&osb->osb_mount_event); | 2062 | init_waitqueue_head(&osb->osb_mount_event); |
2044 | 2063 | ||
2064 | status = ocfs2_resmap_init(osb, &osb->osb_la_resmap); | ||
2065 | if (status) { | ||
2066 | mlog_errno(status); | ||
2067 | goto bail; | ||
2068 | } | ||
2069 | |||
2045 | osb->vol_label = kmalloc(OCFS2_MAX_VOL_LABEL_LEN, GFP_KERNEL); | 2070 | osb->vol_label = kmalloc(OCFS2_MAX_VOL_LABEL_LEN, GFP_KERNEL); |
2046 | if (!osb->vol_label) { | 2071 | if (!osb->vol_label) { |
2047 | mlog(ML_ERROR, "unable to alloc vol label\n"); | 2072 | mlog(ML_ERROR, "unable to alloc vol label\n"); |