diff options
author | Mark Fasheh <mfasheh@suse.com> | 2008-07-28 21:02:53 -0400 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-10-13 16:57:57 -0400 |
commit | 9c7af40b210e87f8fddd97b0badc0a352862234a (patch) | |
tree | deb248e5295439b96ad9bd1789e8512f93803142 /fs/ocfs2/suballoc.c | |
parent | ebcee4b5c9136096f64ee6f691a013d7c0a4bc34 (diff) |
ocfs2: throttle back local alloc when low on disk space
Ocfs2's local allocator disables itself for the duration of a mount point
when it has trouble allocating a large enough area from the primary bitmap.
That can cause performance problems, especially for disks which were only
temporarily full or fragmented. This patch allows for the allocator to
shrink it's window first, before being disabled. Later, it can also be
re-enabled so that any performance drop is minimized.
To do this, we allow the value of osb->local_alloc_bits to be shrunk when
needed. The default value is recorded in a mostly read-only variable so that
we can re-initialize when required.
Locking had to be updated so that we could protect changes to
local_alloc_bits. Mostly this involves protecting various local alloc values
with the osb spinlock. A new state is also added, OCFS2_LA_THROTTLED, which
is used when the local allocator is has shrunk, but is not disabled. If the
available space dips below 1 megabyte, the local alloc file is disabled. In
either case, local alloc is re-enabled 30 seconds after the event, or when
an appropriate amount of bits is seen in the primary bitmap.
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/suballoc.c')
-rw-r--r-- | fs/ocfs2/suballoc.c | 31 |
1 files changed, 17 insertions, 14 deletions
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index d2d278fb981..de7b93d76d1 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -111,7 +111,7 @@ static inline void ocfs2_block_to_cluster_group(struct inode *inode, | |||
111 | u64 *bg_blkno, | 111 | u64 *bg_blkno, |
112 | u16 *bg_bit_off); | 112 | u16 *bg_bit_off); |
113 | 113 | ||
114 | static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac) | 114 | void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac) |
115 | { | 115 | { |
116 | struct inode *inode = ac->ac_inode; | 116 | struct inode *inode = ac->ac_inode; |
117 | 117 | ||
@@ -686,15 +686,6 @@ int ocfs2_reserve_clusters(struct ocfs2_super *osb, | |||
686 | if ((status < 0) && (status != -ENOSPC)) { | 686 | if ((status < 0) && (status != -ENOSPC)) { |
687 | mlog_errno(status); | 687 | mlog_errno(status); |
688 | goto bail; | 688 | goto bail; |
689 | } else if (status == -ENOSPC) { | ||
690 | /* reserve_local_bits will return enospc with | ||
691 | * the local alloc inode still locked, so we | ||
692 | * can change this safely here. */ | ||
693 | mlog(0, "Disabling local alloc\n"); | ||
694 | /* We set to OCFS2_LA_DISABLED so that umount | ||
695 | * can clean up what's left of the local | ||
696 | * allocation */ | ||
697 | osb->local_alloc_state = OCFS2_LA_DISABLED; | ||
698 | } | 689 | } |
699 | } | 690 | } |
700 | 691 | ||
@@ -1005,6 +996,7 @@ static int ocfs2_cluster_group_search(struct inode *inode, | |||
1005 | int search = -ENOSPC; | 996 | int search = -ENOSPC; |
1006 | int ret; | 997 | int ret; |
1007 | struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data; | 998 | struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data; |
999 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
1008 | u16 tmp_off, tmp_found; | 1000 | u16 tmp_off, tmp_found; |
1009 | unsigned int max_bits, gd_cluster_off; | 1001 | unsigned int max_bits, gd_cluster_off; |
1010 | 1002 | ||
@@ -1045,6 +1037,12 @@ static int ocfs2_cluster_group_search(struct inode *inode, | |||
1045 | *bit_off = tmp_off; | 1037 | *bit_off = tmp_off; |
1046 | *bits_found = tmp_found; | 1038 | *bits_found = tmp_found; |
1047 | search = 0; /* success */ | 1039 | search = 0; /* success */ |
1040 | } else if (tmp_found) { | ||
1041 | /* | ||
1042 | * Don't show bits which we'll be returning | ||
1043 | * for allocation to the local alloc bitmap. | ||
1044 | */ | ||
1045 | ocfs2_local_alloc_seen_free_bits(osb, tmp_found); | ||
1048 | } | 1046 | } |
1049 | } | 1047 | } |
1050 | 1048 | ||
@@ -1203,9 +1201,8 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
1203 | status = -ENOSPC; | 1201 | status = -ENOSPC; |
1204 | /* for now, the chain search is a bit simplistic. We just use | 1202 | /* for now, the chain search is a bit simplistic. We just use |
1205 | * the 1st group with any empty bits. */ | 1203 | * the 1st group with any empty bits. */ |
1206 | while ((status = ac->ac_group_search(alloc_inode, group_bh, | 1204 | while ((status = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, |
1207 | bits_wanted, min_bits, bit_off, | 1205 | min_bits, bit_off, &tmp_bits)) == -ENOSPC) { |
1208 | &tmp_bits)) == -ENOSPC) { | ||
1209 | if (!bg->bg_next_group) | 1206 | if (!bg->bg_next_group) |
1210 | break; | 1207 | break; |
1211 | 1208 | ||
@@ -1838,9 +1835,15 @@ int ocfs2_free_clusters(handle_t *handle, | |||
1838 | status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh, | 1835 | status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh, |
1839 | bg_start_bit, bg_blkno, | 1836 | bg_start_bit, bg_blkno, |
1840 | num_clusters); | 1837 | num_clusters); |
1841 | if (status < 0) | 1838 | if (status < 0) { |
1842 | mlog_errno(status); | 1839 | mlog_errno(status); |
1840 | goto out; | ||
1841 | } | ||
1842 | |||
1843 | ocfs2_local_alloc_seen_free_bits(OCFS2_SB(bitmap_inode->i_sb), | ||
1844 | num_clusters); | ||
1843 | 1845 | ||
1846 | out: | ||
1844 | mlog_exit(status); | 1847 | mlog_exit(status); |
1845 | return status; | 1848 | return status; |
1846 | } | 1849 | } |