Tizen 2.0 Release
[platform/kernel/u-boot.git] / fs / ext4 / alloc.c
1 /*
2  * alloc.c --- allocate new inodes, blocks for ext2fs
3  *
4  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Library
8  * General Public License, version 2.
9  * %End-Header%
10  */
11
12 #include "ext2_fs.h"
13 #include "ext2fs.h"
14
15 /*
16  * Check for uninit block bitmaps and deal with them appropriately
17  */
18 static void check_block_uninit(ext2_filsys fs, ext2fs_block_bitmap map,
19                           dgrp_t group)
20 {
21         blk_t           i;
22         blk_t           blk, super_blk, old_desc_blk, new_desc_blk;
23         int             old_desc_blocks;
24
25         if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
26                                          EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) ||
27             !(fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT))
28                 return;
29
30         blk = (group * fs->super->s_blocks_per_group) +
31                 fs->super->s_first_data_block;
32
33         ext2fs_super_and_bgd_loc(fs, group, &super_blk,
34                                  &old_desc_blk, &new_desc_blk, 0);
35
36         if (fs->super->s_feature_incompat &
37             EXT2_FEATURE_INCOMPAT_META_BG)
38                 old_desc_blocks = fs->super->s_first_meta_bg;
39         else
40                 old_desc_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
41
42         for (i=0; i < fs->super->s_blocks_per_group; i++, blk++) {
43                 if ((blk == super_blk) ||
44                     (old_desc_blk && old_desc_blocks &&
45                      (blk >= old_desc_blk) &&
46                      (blk < old_desc_blk + old_desc_blocks)) ||
47                     (new_desc_blk && (blk == new_desc_blk)) ||
48                     (blk == fs->group_desc[group].bg_block_bitmap) ||
49                     (blk == fs->group_desc[group].bg_inode_bitmap) ||
50                     (blk >= fs->group_desc[group].bg_inode_table &&
51                      (blk < fs->group_desc[group].bg_inode_table
52                       + fs->inode_blocks_per_group)))
53                         ext2fs_fast_mark_block_bitmap(map, blk);
54                 else
55                         ext2fs_fast_unmark_block_bitmap(map, blk);
56         }
57         fs->group_desc[group].bg_flags &= ~EXT2_BG_BLOCK_UNINIT;
58         ext2fs_group_desc_csum_set(fs, group);
59 }
60
61 /*
62  * Check for uninit inode bitmaps and deal with them appropriately
63  */
64 static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map,
65                           dgrp_t group)
66 {
67         ext2_ino_t      i, ino;
68
69         if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
70                                          EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) ||
71             !(fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT))
72                 return;
73
74         ino = (group * fs->super->s_inodes_per_group) + 1;
75         for (i=0; i < fs->super->s_inodes_per_group; i++, ino++)
76                 ext2fs_fast_unmark_inode_bitmap(map, ino);
77
78         fs->group_desc[group].bg_flags &= ~EXT2_BG_INODE_UNINIT;
79         check_block_uninit(fs, fs->block_map, group);
80 }
81
82 /*
83  * Right now, just search forward from the parent directory's block
84  * group to find the next free inode.
85  *
86  * Should have a special policy for directories.
87  */
88 errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
89                            int mode EXT2FS_ATTR((unused)),
90                            ext2fs_inode_bitmap map, ext2_ino_t *ret)
91 {
92         ext2_ino_t      dir_group = 0;
93         ext2_ino_t      i;
94         ext2_ino_t      start_inode;
95
96         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
97
98         if (!map)
99                 map = fs->inode_map;
100         if (!map)
101                 return EXT2_ET_NO_INODE_BITMAP;
102
103         if (dir > 0)
104                 dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
105
106         start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
107         if (start_inode < EXT2_FIRST_INODE(fs->super))
108                 start_inode = EXT2_FIRST_INODE(fs->super);
109         if (start_inode > fs->super->s_inodes_count)
110                 return EXT2_ET_INODE_ALLOC_FAIL;
111         i = start_inode;
112
113         do {
114                 if (((i - 1) % EXT2_INODES_PER_GROUP(fs->super)) == 0)
115                         check_inode_uninit(fs, map, (i - 1) /
116                                            EXT2_INODES_PER_GROUP(fs->super));
117
118                 if (!ext2fs_fast_test_inode_bitmap(map, i))
119                         break;
120                 i++;
121                 if (i > fs->super->s_inodes_count)
122                         i = EXT2_FIRST_INODE(fs->super);
123         } while (i != start_inode);
124
125         if (ext2fs_test_inode_bitmap(map, i))
126                 return EXT2_ET_INODE_ALLOC_FAIL;
127         *ret = i;
128         return 0;
129 }
130
131 /*
132  * Stupid algorithm --- we now just search forward starting from the
133  * goal.  Should put in a smarter one someday....
134  */
135 errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
136                            ext2fs_block_bitmap map, blk_t *ret)
137 {
138         blk_t   i;
139
140         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
141
142         if (!map)
143                 map = fs->block_map;
144         if (!map)
145                 return EXT2_ET_NO_BLOCK_BITMAP;
146         if (!goal || (goal >= fs->super->s_blocks_count))
147                 goal = fs->super->s_first_data_block;
148         i = goal;
149         check_block_uninit(fs, map,
150                            (i - fs->super->s_first_data_block) /
151                            EXT2_BLOCKS_PER_GROUP(fs->super));
152         do {
153                 if (((i - fs->super->s_first_data_block) %
154                      EXT2_BLOCKS_PER_GROUP(fs->super)) == 0)
155                         check_block_uninit(fs, map,
156                                            (i - fs->super->s_first_data_block) /
157                                            EXT2_BLOCKS_PER_GROUP(fs->super));
158
159                 if (!ext2fs_fast_test_block_bitmap(map, i)) {
160                         *ret = i;
161                         return 0;
162                 }
163                 i++;
164                 if (i >= fs->super->s_blocks_count)
165                         i = fs->super->s_first_data_block;
166         } while (i != goal);
167         return EXT2_ET_BLOCK_ALLOC_FAIL;
168 }
169
170 /*
171  * This function zeros out the allocated block, and updates all of the
172  * appropriate filesystem records.
173  */
174 errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
175                              char *block_buf, blk_t *ret)
176 {
177         errcode_t       retval;
178         blk_t           block;
179         char            *buf = 0;
180
181         if (!block_buf) {
182                 retval = ext2fs_get_mem(fs->blocksize, &buf);
183                 if (retval)
184                         return retval;
185                 block_buf = buf;
186         }
187         memset(block_buf, 0, fs->blocksize);
188
189         if (fs->get_alloc_block) {
190                 blk64_t new;
191
192                 retval = (fs->get_alloc_block)(fs, (blk64_t) goal, &new);
193                 if (retval)
194                         goto fail;
195                 block = (blk_t) new;
196         } else {
197                 if (!fs->block_map) {
198                         retval = ext2fs_read_block_bitmap(fs);
199                         if (retval)
200                                 goto fail;
201                 }
202
203                 retval = ext2fs_new_block(fs, goal, 0, &block);
204                 if (retval)
205                         goto fail;
206         }
207
208 #if 0
209 //uma
210         retval = io_channel_write_blk(fs->io, block, 1, block_buf);
211 #endif
212                 put_ext4(dev_desc, (uint64_t)(block * fs->blocksize),block_buf,(uint32_t)(fs->blocksize));
213                 retval=0;
214
215         if (retval)
216                 goto fail;
217
218         ext2fs_block_alloc_stats(fs, block, +1);
219         *ret = block;
220
221 fail:
222         if (buf)
223                 ext2fs_free_mem(&buf);
224         return retval;
225 }
226
227 errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
228                                  int num, ext2fs_block_bitmap map, blk_t *ret)
229 {
230         blk_t   b = start;
231
232         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
233
234         if (!map)
235                 map = fs->block_map;
236         if (!map)
237                 return EXT2_ET_NO_BLOCK_BITMAP;
238         if (!b)
239                 b = fs->super->s_first_data_block;
240         if (!finish)
241                 finish = start;
242         if (!num)
243                 num = 1;
244         do {
245                 if (b+num-1 > fs->super->s_blocks_count)
246                         b = fs->super->s_first_data_block;
247                 if (ext2fs_fast_test_block_bitmap_range(map, b, num)) {
248                         *ret = b;
249                         return 0;
250                 }
251                 b++;
252         } while (b != finish);
253         return EXT2_ET_BLOCK_ALLOC_FAIL;
254 }
255
256 void ext2fs_set_alloc_block_callback(ext2_filsys fs,
257                                      errcode_t (*func)(ext2_filsys fs,
258                                                        blk64_t goal,
259                                                        blk64_t *ret),
260                                      errcode_t (**old)(ext2_filsys fs,
261                                                        blk64_t goal,
262                                                        blk64_t *ret))
263 {
264         if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
265                 return;
266
267         if (old)
268                 *old = fs->get_alloc_block;
269
270         fs->get_alloc_block = func;
271 }