]>
git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - lib/ext2fs/orphan.c
2 * orphan.c --- utility function to handle orphan file
4 * Copyright (C) 2015 Jan Kara.
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
18 errcode_t
ext2fs_truncate_orphan_file(ext2_filsys fs
)
20 struct ext2_inode inode
;
22 ext2_ino_t ino
= fs
->super
->s_orphan_file_inum
;
24 err
= ext2fs_read_inode(fs
, ino
, &inode
);
28 err
= ext2fs_punch(fs
, ino
, &inode
, NULL
, 0, ~0ULL);
32 fs
->flags
&= ~EXT2_FLAG_SUPER_ONLY
;
33 memset(&inode
, 0, sizeof(struct ext2_inode
));
34 err
= ext2fs_write_inode(fs
, ino
, &inode
);
36 ext2fs_clear_feature_orphan_file(fs
->super
);
37 ext2fs_clear_feature_orphan_present(fs
->super
);
38 ext2fs_mark_super_dirty(fs
);
39 /* Need to update group descriptors as well */
40 fs
->flags
&= ~EXT2_FLAG_SUPER_ONLY
;
45 __u32
ext2fs_do_orphan_file_block_csum(ext2_filsys fs
, ext2_ino_t ino
,
46 __u32 gen
, blk64_t blk
, char *buf
)
48 int inodes_per_ob
= ext2fs_inodes_per_orphan_block(fs
);
51 ino
= ext2fs_cpu_to_le32(ino
);
52 gen
= ext2fs_cpu_to_le32(gen
);
53 blk
= ext2fs_cpu_to_le64(blk
);
54 crc
= ext2fs_crc32c_le(fs
->csum_seed
, (unsigned char *)&ino
,
56 crc
= ext2fs_crc32c_le(crc
, (unsigned char *)&gen
, sizeof(gen
));
57 crc
= ext2fs_crc32c_le(crc
, (unsigned char *)&blk
, sizeof(blk
));
58 crc
= ext2fs_crc32c_le(crc
, (unsigned char *)buf
,
59 inodes_per_ob
* sizeof(__u32
));
61 return ext2fs_cpu_to_le32(crc
);
64 struct mkorphan_info
{
75 static int mkorphan_proc(ext2_filsys fs
,
78 blk64_t ref_block
EXT2FS_ATTR((unused
)),
79 int ref_offset
EXT2FS_ATTR((unused
)),
82 struct mkorphan_info
*oi
= (struct mkorphan_info
*)priv_data
;
86 /* Can we just continue in currently allocated cluster? */
88 EXT2FS_B2C(fs
, oi
->last_blk
) == EXT2FS_B2C(fs
, oi
->last_blk
+ 1)) {
89 new_blk
= oi
->last_blk
+ 1;
91 err
= ext2fs_new_block2(fs
, oi
->last_blk
, 0, &new_blk
);
96 ext2fs_block_alloc_stats2(fs
, new_blk
, +1);
100 if (ext2fs_has_feature_metadata_csum(fs
->super
)) {
101 struct ext4_orphan_block_tail
*tail
;
103 tail
= ext2fs_orphan_block_tail(fs
, oi
->buf
);
104 tail
->ob_checksum
= ext2fs_do_orphan_file_block_csum(fs
,
105 oi
->ino
, oi
->generation
, new_blk
, oi
->buf
);
107 err
= io_channel_write_blk64(fs
->io
, new_blk
, 1, oi
->buf
);
108 } else /* zerobuf is used to initialize new indirect blocks... */
109 err
= io_channel_write_blk64(fs
->io
, new_blk
, 1, oi
->zerobuf
);
114 oi
->last_blk
= new_blk
;
116 if (blockcnt
>= 0 && --oi
->num_blocks
== 0)
117 return BLOCK_CHANGED
| BLOCK_ABORT
;
118 return BLOCK_CHANGED
;
121 errcode_t
ext2fs_create_orphan_file(ext2_filsys fs
, blk_t num_blocks
)
123 struct ext2_inode inode
;
124 ext2_ino_t ino
= fs
->super
->s_orphan_file_inum
;
126 char *buf
= NULL
, *zerobuf
= NULL
;
127 struct mkorphan_info oi
;
128 struct ext4_orphan_block_tail
*ob_tail
;
131 err
= ext2fs_new_inode(fs
, EXT2_ROOT_INO
, LINUX_S_IFREG
| 0600,
135 ext2fs_inode_alloc_stats2(fs
, ino
, +1, 0);
136 ext2fs_mark_ib_dirty(fs
);
139 err
= ext2fs_read_inode(fs
, ino
, &inode
);
142 if (EXT2_I_SIZE(&inode
)) {
143 err
= ext2fs_truncate_orphan_file(fs
);
148 memset(&inode
, 0, sizeof(struct ext2_inode
));
149 if (ext2fs_has_feature_extents(fs
->super
)) {
150 inode
.i_flags
|= EXT4_EXTENTS_FL
;
151 err
= ext2fs_write_inode(fs
, ino
, &inode
);
156 err
= ext2fs_get_mem(fs
->blocksize
, &buf
);
159 err
= ext2fs_get_mem(fs
->blocksize
, &zerobuf
);
162 memset(buf
, 0, fs
->blocksize
);
163 memset(zerobuf
, 0, fs
->blocksize
);
164 ob_tail
= ext2fs_orphan_block_tail(fs
, buf
);
165 ob_tail
->ob_magic
= ext2fs_cpu_to_le32(EXT4_ORPHAN_BLOCK_MAGIC
);
166 oi
.num_blocks
= num_blocks
;
169 oi
.generation
= inode
.i_generation
;
172 oi
.zerobuf
= zerobuf
;
174 err
= ext2fs_block_iterate3(fs
, ino
, BLOCK_FLAG_APPEND
,
175 0, mkorphan_proc
, &oi
);
183 /* Reread inode after blocks were allocated */
184 err
= ext2fs_read_inode(fs
, ino
, &inode
);
187 ext2fs_iblk_set(fs
, &inode
, 0);
188 inode
.i_atime
= inode
.i_mtime
=
189 inode
.i_ctime
= fs
->now
? fs
->now
: time(0);
190 inode
.i_links_count
= 1;
191 inode
.i_mode
= LINUX_S_IFREG
| 0600;
192 ext2fs_iblk_add_blocks(fs
, &inode
, oi
.alloc_blocks
);
193 err
= ext2fs_inode_size_set(fs
, &inode
,
194 (unsigned long long)fs
->blocksize
* num_blocks
);
197 err
= ext2fs_write_new_inode(fs
, ino
, &inode
);
201 fs
->super
->s_orphan_file_inum
= ino
;
202 ext2fs_set_feature_orphan_file(fs
->super
);
203 ext2fs_mark_super_dirty(fs
);
204 /* Need to update group descriptors as well */
205 fs
->flags
&= ~EXT2_FLAG_SUPER_ONLY
;
208 ext2fs_free_mem(&buf
);
210 ext2fs_free_mem(&zerobuf
);
215 * Find reasonable size for orphan file. We choose orphan file size to be
216 * between 32 and 512 filesystem blocks and not more than 1/4096 of the
217 * filesystem unless it is really small.
219 e2_blkcnt_t
ext2fs_default_orphan_file_blocks(ext2_filsys fs
)
221 __u64 num_blocks
= ext2fs_blocks_count(fs
->super
);
222 e2_blkcnt_t blks
= 512;
224 if (num_blocks
< 128 * 1024)
226 else if (num_blocks
< 2 * 1024 * 1024)
227 blks
= num_blocks
/ 4096;
228 return (blks
+ EXT2FS_CLUSTER_MASK(fs
)) & ~EXT2FS_CLUSTER_MASK(fs
);
231 static errcode_t
ext2fs_orphan_file_block_csum(ext2_filsys fs
, ext2_ino_t ino
,
232 blk64_t blk
, char *buf
,
235 struct ext2_inode inode
;
238 retval
= ext2fs_read_inode(fs
, ino
, &inode
);
241 *crcp
= ext2fs_do_orphan_file_block_csum(fs
, ino
, inode
.i_generation
,
246 errcode_t
ext2fs_orphan_file_block_csum_set(ext2_filsys fs
, ext2_ino_t ino
,
247 blk64_t blk
, char *buf
)
249 struct ext4_orphan_block_tail
*tail
;
251 if (!ext2fs_has_feature_metadata_csum(fs
->super
))
254 tail
= ext2fs_orphan_block_tail(fs
, buf
);
255 return ext2fs_orphan_file_block_csum(fs
, ino
, blk
, buf
,
259 int ext2fs_orphan_file_block_csum_verify(ext2_filsys fs
, ext2_ino_t ino
,
260 blk64_t blk
, char *buf
)
262 struct ext4_orphan_block_tail
*tail
;
266 if (!ext2fs_has_feature_metadata_csum(fs
->super
))
268 retval
= ext2fs_orphan_file_block_csum(fs
, ino
, blk
, buf
, &crc
);
271 tail
= ext2fs_orphan_block_tail(fs
, buf
);
272 return ext2fs_le32_to_cpu(tail
->ob_checksum
) == crc
;