diff options
Diffstat (limited to 'fs/ext4/migrate.c')
-rw-r--r-- | fs/ext4/migrate.c | 109 |
1 files changed, 40 insertions, 69 deletions
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index b57b98fb44d1..f729377bf043 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
@@ -15,19 +15,18 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include "ext4_jbd2.h" | 17 | #include "ext4_jbd2.h" |
18 | #include "ext4_extents.h" | ||
19 | 18 | ||
20 | /* | 19 | /* |
21 | * The contiguous blocks details which can be | 20 | * The contiguous blocks details which can be |
22 | * represented by a single extent | 21 | * represented by a single extent |
23 | */ | 22 | */ |
24 | struct list_blocks_struct { | 23 | struct migrate_struct { |
25 | ext4_lblk_t first_block, last_block; | 24 | ext4_lblk_t first_block, last_block, curr_block; |
26 | ext4_fsblk_t first_pblock, last_pblock; | 25 | ext4_fsblk_t first_pblock, last_pblock; |
27 | }; | 26 | }; |
28 | 27 | ||
29 | static int finish_range(handle_t *handle, struct inode *inode, | 28 | static int finish_range(handle_t *handle, struct inode *inode, |
30 | struct list_blocks_struct *lb) | 29 | struct migrate_struct *lb) |
31 | 30 | ||
32 | { | 31 | { |
33 | int retval = 0, needed; | 32 | int retval = 0, needed; |
@@ -87,8 +86,7 @@ err_out: | |||
87 | } | 86 | } |
88 | 87 | ||
89 | static int update_extent_range(handle_t *handle, struct inode *inode, | 88 | static int update_extent_range(handle_t *handle, struct inode *inode, |
90 | ext4_fsblk_t pblock, ext4_lblk_t blk_num, | 89 | ext4_fsblk_t pblock, struct migrate_struct *lb) |
91 | struct list_blocks_struct *lb) | ||
92 | { | 90 | { |
93 | int retval; | 91 | int retval; |
94 | /* | 92 | /* |
@@ -96,9 +94,10 @@ static int update_extent_range(handle_t *handle, struct inode *inode, | |||
96 | */ | 94 | */ |
97 | if (lb->first_pblock && | 95 | if (lb->first_pblock && |
98 | (lb->last_pblock+1 == pblock) && | 96 | (lb->last_pblock+1 == pblock) && |
99 | (lb->last_block+1 == blk_num)) { | 97 | (lb->last_block+1 == lb->curr_block)) { |
100 | lb->last_pblock = pblock; | 98 | lb->last_pblock = pblock; |
101 | lb->last_block = blk_num; | 99 | lb->last_block = lb->curr_block; |
100 | lb->curr_block++; | ||
102 | return 0; | 101 | return 0; |
103 | } | 102 | } |
104 | /* | 103 | /* |
@@ -106,64 +105,49 @@ static int update_extent_range(handle_t *handle, struct inode *inode, | |||
106 | */ | 105 | */ |
107 | retval = finish_range(handle, inode, lb); | 106 | retval = finish_range(handle, inode, lb); |
108 | lb->first_pblock = lb->last_pblock = pblock; | 107 | lb->first_pblock = lb->last_pblock = pblock; |
109 | lb->first_block = lb->last_block = blk_num; | 108 | lb->first_block = lb->last_block = lb->curr_block; |
110 | 109 | lb->curr_block++; | |
111 | return retval; | 110 | return retval; |
112 | } | 111 | } |
113 | 112 | ||
114 | static int update_ind_extent_range(handle_t *handle, struct inode *inode, | 113 | static int update_ind_extent_range(handle_t *handle, struct inode *inode, |
115 | ext4_fsblk_t pblock, ext4_lblk_t *blk_nump, | 114 | ext4_fsblk_t pblock, |
116 | struct list_blocks_struct *lb) | 115 | struct migrate_struct *lb) |
117 | { | 116 | { |
118 | struct buffer_head *bh; | 117 | struct buffer_head *bh; |
119 | __le32 *i_data; | 118 | __le32 *i_data; |
120 | int i, retval = 0; | 119 | int i, retval = 0; |
121 | ext4_lblk_t blk_count = *blk_nump; | ||
122 | unsigned long max_entries = inode->i_sb->s_blocksize >> 2; | 120 | unsigned long max_entries = inode->i_sb->s_blocksize >> 2; |
123 | 121 | ||
124 | if (!pblock) { | ||
125 | /* Only update the file block number */ | ||
126 | *blk_nump += max_entries; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | bh = sb_bread(inode->i_sb, pblock); | 122 | bh = sb_bread(inode->i_sb, pblock); |
131 | if (!bh) | 123 | if (!bh) |
132 | return -EIO; | 124 | return -EIO; |
133 | 125 | ||
134 | i_data = (__le32 *)bh->b_data; | 126 | i_data = (__le32 *)bh->b_data; |
135 | for (i = 0; i < max_entries; i++, blk_count++) { | 127 | for (i = 0; i < max_entries; i++) { |
136 | if (i_data[i]) { | 128 | if (i_data[i]) { |
137 | retval = update_extent_range(handle, inode, | 129 | retval = update_extent_range(handle, inode, |
138 | le32_to_cpu(i_data[i]), | 130 | le32_to_cpu(i_data[i]), lb); |
139 | blk_count, lb); | ||
140 | if (retval) | 131 | if (retval) |
141 | break; | 132 | break; |
133 | } else { | ||
134 | lb->curr_block++; | ||
142 | } | 135 | } |
143 | } | 136 | } |
144 | |||
145 | /* Update the file block number */ | ||
146 | *blk_nump = blk_count; | ||
147 | put_bh(bh); | 137 | put_bh(bh); |
148 | return retval; | 138 | return retval; |
149 | 139 | ||
150 | } | 140 | } |
151 | 141 | ||
152 | static int update_dind_extent_range(handle_t *handle, struct inode *inode, | 142 | static int update_dind_extent_range(handle_t *handle, struct inode *inode, |
153 | ext4_fsblk_t pblock, ext4_lblk_t *blk_nump, | 143 | ext4_fsblk_t pblock, |
154 | struct list_blocks_struct *lb) | 144 | struct migrate_struct *lb) |
155 | { | 145 | { |
156 | struct buffer_head *bh; | 146 | struct buffer_head *bh; |
157 | __le32 *i_data; | 147 | __le32 *i_data; |
158 | int i, retval = 0; | 148 | int i, retval = 0; |
159 | ext4_lblk_t blk_count = *blk_nump; | ||
160 | unsigned long max_entries = inode->i_sb->s_blocksize >> 2; | 149 | unsigned long max_entries = inode->i_sb->s_blocksize >> 2; |
161 | 150 | ||
162 | if (!pblock) { | ||
163 | /* Only update the file block number */ | ||
164 | *blk_nump += max_entries * max_entries; | ||
165 | return 0; | ||
166 | } | ||
167 | bh = sb_bread(inode->i_sb, pblock); | 151 | bh = sb_bread(inode->i_sb, pblock); |
168 | if (!bh) | 152 | if (!bh) |
169 | return -EIO; | 153 | return -EIO; |
@@ -172,38 +156,28 @@ static int update_dind_extent_range(handle_t *handle, struct inode *inode, | |||
172 | for (i = 0; i < max_entries; i++) { | 156 | for (i = 0; i < max_entries; i++) { |
173 | if (i_data[i]) { | 157 | if (i_data[i]) { |
174 | retval = update_ind_extent_range(handle, inode, | 158 | retval = update_ind_extent_range(handle, inode, |
175 | le32_to_cpu(i_data[i]), | 159 | le32_to_cpu(i_data[i]), lb); |
176 | &blk_count, lb); | ||
177 | if (retval) | 160 | if (retval) |
178 | break; | 161 | break; |
179 | } else { | 162 | } else { |
180 | /* Only update the file block number */ | 163 | /* Only update the file block number */ |
181 | blk_count += max_entries; | 164 | lb->curr_block += max_entries; |
182 | } | 165 | } |
183 | } | 166 | } |
184 | |||
185 | /* Update the file block number */ | ||
186 | *blk_nump = blk_count; | ||
187 | put_bh(bh); | 167 | put_bh(bh); |
188 | return retval; | 168 | return retval; |
189 | 169 | ||
190 | } | 170 | } |
191 | 171 | ||
192 | static int update_tind_extent_range(handle_t *handle, struct inode *inode, | 172 | static int update_tind_extent_range(handle_t *handle, struct inode *inode, |
193 | ext4_fsblk_t pblock, ext4_lblk_t *blk_nump, | 173 | ext4_fsblk_t pblock, |
194 | struct list_blocks_struct *lb) | 174 | struct migrate_struct *lb) |
195 | { | 175 | { |
196 | struct buffer_head *bh; | 176 | struct buffer_head *bh; |
197 | __le32 *i_data; | 177 | __le32 *i_data; |
198 | int i, retval = 0; | 178 | int i, retval = 0; |
199 | ext4_lblk_t blk_count = *blk_nump; | ||
200 | unsigned long max_entries = inode->i_sb->s_blocksize >> 2; | 179 | unsigned long max_entries = inode->i_sb->s_blocksize >> 2; |
201 | 180 | ||
202 | if (!pblock) { | ||
203 | /* Only update the file block number */ | ||
204 | *blk_nump += max_entries * max_entries * max_entries; | ||
205 | return 0; | ||
206 | } | ||
207 | bh = sb_bread(inode->i_sb, pblock); | 181 | bh = sb_bread(inode->i_sb, pblock); |
208 | if (!bh) | 182 | if (!bh) |
209 | return -EIO; | 183 | return -EIO; |
@@ -212,16 +186,14 @@ static int update_tind_extent_range(handle_t *handle, struct inode *inode, | |||
212 | for (i = 0; i < max_entries; i++) { | 186 | for (i = 0; i < max_entries; i++) { |
213 | if (i_data[i]) { | 187 | if (i_data[i]) { |
214 | retval = update_dind_extent_range(handle, inode, | 188 | retval = update_dind_extent_range(handle, inode, |
215 | le32_to_cpu(i_data[i]), | 189 | le32_to_cpu(i_data[i]), lb); |
216 | &blk_count, lb); | ||
217 | if (retval) | 190 | if (retval) |
218 | break; | 191 | break; |
219 | } else | 192 | } else { |
220 | /* Only update the file block number */ | 193 | /* Only update the file block number */ |
221 | blk_count += max_entries * max_entries; | 194 | lb->curr_block += max_entries * max_entries; |
195 | } | ||
222 | } | 196 | } |
223 | /* Update the file block number */ | ||
224 | *blk_nump = blk_count; | ||
225 | put_bh(bh); | 197 | put_bh(bh); |
226 | return retval; | 198 | return retval; |
227 | 199 | ||
@@ -462,12 +434,12 @@ int ext4_ext_migrate(struct inode *inode) | |||
462 | handle_t *handle; | 434 | handle_t *handle; |
463 | int retval = 0, i; | 435 | int retval = 0, i; |
464 | __le32 *i_data; | 436 | __le32 *i_data; |
465 | ext4_lblk_t blk_count = 0; | ||
466 | struct ext4_inode_info *ei; | 437 | struct ext4_inode_info *ei; |
467 | struct inode *tmp_inode = NULL; | 438 | struct inode *tmp_inode = NULL; |
468 | struct list_blocks_struct lb; | 439 | struct migrate_struct lb; |
469 | unsigned long max_entries; | 440 | unsigned long max_entries; |
470 | __u32 goal; | 441 | __u32 goal; |
442 | uid_t owner[2]; | ||
471 | 443 | ||
472 | /* | 444 | /* |
473 | * If the filesystem does not support extents, or the inode | 445 | * If the filesystem does not support extents, or the inode |
@@ -495,10 +467,12 @@ int ext4_ext_migrate(struct inode *inode) | |||
495 | } | 467 | } |
496 | goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) * | 468 | goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) * |
497 | EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; | 469 | EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; |
470 | owner[0] = inode->i_uid; | ||
471 | owner[1] = inode->i_gid; | ||
498 | tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, | 472 | tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, |
499 | S_IFREG, NULL, goal); | 473 | S_IFREG, NULL, goal, owner); |
500 | if (IS_ERR(tmp_inode)) { | 474 | if (IS_ERR(tmp_inode)) { |
501 | retval = -ENOMEM; | 475 | retval = PTR_ERR(inode); |
502 | ext4_journal_stop(handle); | 476 | ext4_journal_stop(handle); |
503 | return retval; | 477 | return retval; |
504 | } | 478 | } |
@@ -551,35 +525,32 @@ int ext4_ext_migrate(struct inode *inode) | |||
551 | 525 | ||
552 | /* 32 bit block address 4 bytes */ | 526 | /* 32 bit block address 4 bytes */ |
553 | max_entries = inode->i_sb->s_blocksize >> 2; | 527 | max_entries = inode->i_sb->s_blocksize >> 2; |
554 | for (i = 0; i < EXT4_NDIR_BLOCKS; i++, blk_count++) { | 528 | for (i = 0; i < EXT4_NDIR_BLOCKS; i++) { |
555 | if (i_data[i]) { | 529 | if (i_data[i]) { |
556 | retval = update_extent_range(handle, tmp_inode, | 530 | retval = update_extent_range(handle, tmp_inode, |
557 | le32_to_cpu(i_data[i]), | 531 | le32_to_cpu(i_data[i]), &lb); |
558 | blk_count, &lb); | ||
559 | if (retval) | 532 | if (retval) |
560 | goto err_out; | 533 | goto err_out; |
561 | } | 534 | } else |
535 | lb.curr_block++; | ||
562 | } | 536 | } |
563 | if (i_data[EXT4_IND_BLOCK]) { | 537 | if (i_data[EXT4_IND_BLOCK]) { |
564 | retval = update_ind_extent_range(handle, tmp_inode, | 538 | retval = update_ind_extent_range(handle, tmp_inode, |
565 | le32_to_cpu(i_data[EXT4_IND_BLOCK]), | 539 | le32_to_cpu(i_data[EXT4_IND_BLOCK]), &lb); |
566 | &blk_count, &lb); | ||
567 | if (retval) | 540 | if (retval) |
568 | goto err_out; | 541 | goto err_out; |
569 | } else | 542 | } else |
570 | blk_count += max_entries; | 543 | lb.curr_block += max_entries; |
571 | if (i_data[EXT4_DIND_BLOCK]) { | 544 | if (i_data[EXT4_DIND_BLOCK]) { |
572 | retval = update_dind_extent_range(handle, tmp_inode, | 545 | retval = update_dind_extent_range(handle, tmp_inode, |
573 | le32_to_cpu(i_data[EXT4_DIND_BLOCK]), | 546 | le32_to_cpu(i_data[EXT4_DIND_BLOCK]), &lb); |
574 | &blk_count, &lb); | ||
575 | if (retval) | 547 | if (retval) |
576 | goto err_out; | 548 | goto err_out; |
577 | } else | 549 | } else |
578 | blk_count += max_entries * max_entries; | 550 | lb.curr_block += max_entries * max_entries; |
579 | if (i_data[EXT4_TIND_BLOCK]) { | 551 | if (i_data[EXT4_TIND_BLOCK]) { |
580 | retval = update_tind_extent_range(handle, tmp_inode, | 552 | retval = update_tind_extent_range(handle, tmp_inode, |
581 | le32_to_cpu(i_data[EXT4_TIND_BLOCK]), | 553 | le32_to_cpu(i_data[EXT4_TIND_BLOCK]), &lb); |
582 | &blk_count, &lb); | ||
583 | if (retval) | 554 | if (retval) |
584 | goto err_out; | 555 | goto err_out; |
585 | } | 556 | } |