diff options
-rw-r--r-- | fs/udf/inode.c | 86 | ||||
-rw-r--r-- | fs/udf/super.c | 2 | ||||
-rw-r--r-- | fs/udf/udf_i.h | 16 | ||||
-rw-r--r-- | fs/udf/udfdecl.h | 5 |
4 files changed, 98 insertions, 11 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index cbae1ed0b7c1..7a12e48ad819 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -67,6 +67,74 @@ static void udf_update_extents(struct inode *, | |||
67 | struct extent_position *); | 67 | struct extent_position *); |
68 | static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); | 68 | static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); |
69 | 69 | ||
70 | static void __udf_clear_extent_cache(struct inode *inode) | ||
71 | { | ||
72 | struct udf_inode_info *iinfo = UDF_I(inode); | ||
73 | |||
74 | if (iinfo->cached_extent.lstart != -1) { | ||
75 | brelse(iinfo->cached_extent.epos.bh); | ||
76 | iinfo->cached_extent.lstart = -1; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* Invalidate extent cache */ | ||
81 | static void udf_clear_extent_cache(struct inode *inode) | ||
82 | { | ||
83 | struct udf_inode_info *iinfo = UDF_I(inode); | ||
84 | |||
85 | spin_lock(&iinfo->i_extent_cache_lock); | ||
86 | __udf_clear_extent_cache(inode); | ||
87 | spin_unlock(&iinfo->i_extent_cache_lock); | ||
88 | } | ||
89 | |||
90 | /* Return contents of extent cache */ | ||
91 | static int udf_read_extent_cache(struct inode *inode, loff_t bcount, | ||
92 | loff_t *lbcount, struct extent_position *pos) | ||
93 | { | ||
94 | struct udf_inode_info *iinfo = UDF_I(inode); | ||
95 | int ret = 0; | ||
96 | |||
97 | spin_lock(&iinfo->i_extent_cache_lock); | ||
98 | if ((iinfo->cached_extent.lstart <= bcount) && | ||
99 | (iinfo->cached_extent.lstart != -1)) { | ||
100 | /* Cache hit */ | ||
101 | *lbcount = iinfo->cached_extent.lstart; | ||
102 | memcpy(pos, &iinfo->cached_extent.epos, | ||
103 | sizeof(struct extent_position)); | ||
104 | if (pos->bh) | ||
105 | get_bh(pos->bh); | ||
106 | ret = 1; | ||
107 | } | ||
108 | spin_unlock(&iinfo->i_extent_cache_lock); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | /* Add extent to extent cache */ | ||
113 | static void udf_update_extent_cache(struct inode *inode, loff_t estart, | ||
114 | struct extent_position *pos, int next_epos) | ||
115 | { | ||
116 | struct udf_inode_info *iinfo = UDF_I(inode); | ||
117 | |||
118 | spin_lock(&iinfo->i_extent_cache_lock); | ||
119 | /* Invalidate previously cached extent */ | ||
120 | __udf_clear_extent_cache(inode); | ||
121 | if (pos->bh) | ||
122 | get_bh(pos->bh); | ||
123 | memcpy(&iinfo->cached_extent.epos, pos, | ||
124 | sizeof(struct extent_position)); | ||
125 | iinfo->cached_extent.lstart = estart; | ||
126 | if (next_epos) | ||
127 | switch (iinfo->i_alloc_type) { | ||
128 | case ICBTAG_FLAG_AD_SHORT: | ||
129 | iinfo->cached_extent.epos.offset -= | ||
130 | sizeof(struct short_ad); | ||
131 | break; | ||
132 | case ICBTAG_FLAG_AD_LONG: | ||
133 | iinfo->cached_extent.epos.offset -= | ||
134 | sizeof(struct long_ad); | ||
135 | } | ||
136 | spin_unlock(&iinfo->i_extent_cache_lock); | ||
137 | } | ||
70 | 138 | ||
71 | void udf_evict_inode(struct inode *inode) | 139 | void udf_evict_inode(struct inode *inode) |
72 | { | 140 | { |
@@ -90,6 +158,7 @@ void udf_evict_inode(struct inode *inode) | |||
90 | } | 158 | } |
91 | kfree(iinfo->i_ext.i_data); | 159 | kfree(iinfo->i_ext.i_data); |
92 | iinfo->i_ext.i_data = NULL; | 160 | iinfo->i_ext.i_data = NULL; |
161 | udf_clear_extent_cache(inode); | ||
93 | if (want_delete) { | 162 | if (want_delete) { |
94 | udf_free_inode(inode); | 163 | udf_free_inode(inode); |
95 | } | 164 | } |
@@ -105,6 +174,7 @@ static void udf_write_failed(struct address_space *mapping, loff_t to) | |||
105 | truncate_pagecache(inode, to, isize); | 174 | truncate_pagecache(inode, to, isize); |
106 | if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { | 175 | if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { |
107 | down_write(&iinfo->i_data_sem); | 176 | down_write(&iinfo->i_data_sem); |
177 | udf_clear_extent_cache(inode); | ||
108 | udf_truncate_extents(inode); | 178 | udf_truncate_extents(inode); |
109 | up_write(&iinfo->i_data_sem); | 179 | up_write(&iinfo->i_data_sem); |
110 | } | 180 | } |
@@ -372,7 +442,7 @@ static int udf_get_block(struct inode *inode, sector_t block, | |||
372 | iinfo->i_next_alloc_goal++; | 442 | iinfo->i_next_alloc_goal++; |
373 | } | 443 | } |
374 | 444 | ||
375 | 445 | udf_clear_extent_cache(inode); | |
376 | phys = inode_getblk(inode, block, &err, &new); | 446 | phys = inode_getblk(inode, block, &err, &new); |
377 | if (!phys) | 447 | if (!phys) |
378 | goto abort; | 448 | goto abort; |
@@ -1171,6 +1241,7 @@ set_size: | |||
1171 | } else { | 1241 | } else { |
1172 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { | 1242 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
1173 | down_write(&iinfo->i_data_sem); | 1243 | down_write(&iinfo->i_data_sem); |
1244 | udf_clear_extent_cache(inode); | ||
1174 | memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + newsize, | 1245 | memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + newsize, |
1175 | 0x00, bsize - newsize - | 1246 | 0x00, bsize - newsize - |
1176 | udf_file_entry_alloc_offset(inode)); | 1247 | udf_file_entry_alloc_offset(inode)); |
@@ -1184,6 +1255,7 @@ set_size: | |||
1184 | if (err) | 1255 | if (err) |
1185 | return err; | 1256 | return err; |
1186 | down_write(&iinfo->i_data_sem); | 1257 | down_write(&iinfo->i_data_sem); |
1258 | udf_clear_extent_cache(inode); | ||
1187 | truncate_setsize(inode, newsize); | 1259 | truncate_setsize(inode, newsize); |
1188 | udf_truncate_extents(inode); | 1260 | udf_truncate_extents(inode); |
1189 | up_write(&iinfo->i_data_sem); | 1261 | up_write(&iinfo->i_data_sem); |
@@ -2156,11 +2228,12 @@ int8_t inode_bmap(struct inode *inode, sector_t block, | |||
2156 | struct udf_inode_info *iinfo; | 2228 | struct udf_inode_info *iinfo; |
2157 | 2229 | ||
2158 | iinfo = UDF_I(inode); | 2230 | iinfo = UDF_I(inode); |
2159 | pos->offset = 0; | 2231 | if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) { |
2160 | pos->block = iinfo->i_location; | 2232 | pos->offset = 0; |
2161 | pos->bh = NULL; | 2233 | pos->block = iinfo->i_location; |
2234 | pos->bh = NULL; | ||
2235 | } | ||
2162 | *elen = 0; | 2236 | *elen = 0; |
2163 | |||
2164 | do { | 2237 | do { |
2165 | etype = udf_next_aext(inode, pos, eloc, elen, 1); | 2238 | etype = udf_next_aext(inode, pos, eloc, elen, 1); |
2166 | if (etype == -1) { | 2239 | if (etype == -1) { |
@@ -2170,7 +2243,8 @@ int8_t inode_bmap(struct inode *inode, sector_t block, | |||
2170 | } | 2243 | } |
2171 | lbcount += *elen; | 2244 | lbcount += *elen; |
2172 | } while (lbcount <= bcount); | 2245 | } while (lbcount <= bcount); |
2173 | 2246 | /* update extent cache */ | |
2247 | udf_update_extent_cache(inode, lbcount - *elen, pos, 1); | ||
2174 | *offset = (bcount + *elen - lbcount) >> blocksize_bits; | 2248 | *offset = (bcount + *elen - lbcount) >> blocksize_bits; |
2175 | 2249 | ||
2176 | return etype; | 2250 | return etype; |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 186adbf94b20..da8ce9f14387 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -134,6 +134,8 @@ static struct inode *udf_alloc_inode(struct super_block *sb) | |||
134 | ei->i_next_alloc_goal = 0; | 134 | ei->i_next_alloc_goal = 0; |
135 | ei->i_strat4096 = 0; | 135 | ei->i_strat4096 = 0; |
136 | init_rwsem(&ei->i_data_sem); | 136 | init_rwsem(&ei->i_data_sem); |
137 | ei->cached_extent.lstart = -1; | ||
138 | spin_lock_init(&ei->i_extent_cache_lock); | ||
137 | 139 | ||
138 | return &ei->vfs_inode; | 140 | return &ei->vfs_inode; |
139 | } | 141 | } |
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index bb8309dcd5c1..b5cd8ed2aa12 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h | |||
@@ -1,6 +1,19 @@ | |||
1 | #ifndef _UDF_I_H | 1 | #ifndef _UDF_I_H |
2 | #define _UDF_I_H | 2 | #define _UDF_I_H |
3 | 3 | ||
4 | struct extent_position { | ||
5 | struct buffer_head *bh; | ||
6 | uint32_t offset; | ||
7 | struct kernel_lb_addr block; | ||
8 | }; | ||
9 | |||
10 | struct udf_ext_cache { | ||
11 | /* Extent position */ | ||
12 | struct extent_position epos; | ||
13 | /* Start logical offset in bytes */ | ||
14 | loff_t lstart; | ||
15 | }; | ||
16 | |||
4 | /* | 17 | /* |
5 | * The i_data_sem and i_mutex serve for protection of allocation information | 18 | * The i_data_sem and i_mutex serve for protection of allocation information |
6 | * of a regular files and symlinks. This includes all extents belonging to | 19 | * of a regular files and symlinks. This includes all extents belonging to |
@@ -35,6 +48,9 @@ struct udf_inode_info { | |||
35 | __u8 *i_data; | 48 | __u8 *i_data; |
36 | } i_ext; | 49 | } i_ext; |
37 | struct rw_semaphore i_data_sem; | 50 | struct rw_semaphore i_data_sem; |
51 | struct udf_ext_cache cached_extent; | ||
52 | /* Spinlock for protecting extent cache */ | ||
53 | spinlock_t i_extent_cache_lock; | ||
38 | struct inode vfs_inode; | 54 | struct inode vfs_inode; |
39 | }; | 55 | }; |
40 | 56 | ||
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index de038da6f6bd..be7dabbbcb49 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
@@ -113,11 +113,6 @@ struct ustr { | |||
113 | uint8_t u_len; | 113 | uint8_t u_len; |
114 | }; | 114 | }; |
115 | 115 | ||
116 | struct extent_position { | ||
117 | struct buffer_head *bh; | ||
118 | uint32_t offset; | ||
119 | struct kernel_lb_addr block; | ||
120 | }; | ||
121 | 116 | ||
122 | /* super.c */ | 117 | /* super.c */ |
123 | 118 | ||