]>
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_read_inode(fs
, ino
, &inode
);
134 if (EXT2_I_SIZE(&inode
)) {
135 err
= ext2fs_truncate_orphan_file(fs
);
140 err
= ext2fs_new_inode(fs
, EXT2_ROOT_INO
, LINUX_S_IFREG
| 0600,
144 ext2fs_inode_alloc_stats2(fs
, ino
, +1, 0);
147 memset(&inode
, 0, sizeof(struct ext2_inode
));
148 if (ext2fs_has_feature_extents(fs
->super
)) {
149 inode
.i_flags
|= EXT4_EXTENTS_FL
;
150 err
= ext2fs_write_inode(fs
, ino
, &inode
);
155 err
= ext2fs_get_mem(fs
->blocksize
, &buf
);
158 err
= ext2fs_get_mem(fs
->blocksize
, &zerobuf
);
161 memset(buf
, 0, fs
->blocksize
);
162 memset(zerobuf
, 0, fs
->blocksize
);
163 ob_tail
= ext2fs_orphan_block_tail(fs
, buf
);
164 ob_tail
->ob_magic
= ext2fs_cpu_to_le32(EXT4_ORPHAN_BLOCK_MAGIC
);
165 oi
.num_blocks
= num_blocks
;
168 oi
.generation
= inode
.i_generation
;
171 oi
.zerobuf
= zerobuf
;
173 err
= ext2fs_block_iterate3(fs
, ino
, BLOCK_FLAG_APPEND
,
174 0, mkorphan_proc
, &oi
);
182 /* Reread inode after blocks were allocated */
183 err
= ext2fs_read_inode(fs
, ino
, &inode
);
186 ext2fs_iblk_set(fs
, &inode
, 0);
187 inode
.i_atime
= inode
.i_mtime
=
188 inode
.i_ctime
= fs
->now
? fs
->now
: time(0);
189 inode
.i_links_count
= 1;
190 inode
.i_mode
= LINUX_S_IFREG
| 0600;
191 ext2fs_iblk_add_blocks(fs
, &inode
, oi
.alloc_blocks
);
192 err
= ext2fs_inode_size_set(fs
, &inode
,
193 (unsigned long long)fs
->blocksize
* num_blocks
);
196 err
= ext2fs_write_new_inode(fs
, ino
, &inode
);
200 fs
->super
->s_orphan_file_inum
= ino
;
201 ext2fs_set_feature_orphan_file(fs
->super
);
202 ext2fs_mark_super_dirty(fs
);
203 /* Need to update group descriptors as well */
204 fs
->flags
&= ~EXT2_FLAG_SUPER_ONLY
;
207 ext2fs_free_mem(&buf
);
209 ext2fs_free_mem(&zerobuf
);
214 * Find reasonable size for orphan file. We choose orphan file size to be
215 * between 32 and 512 filesystem blocks and not more than 1/4096 of the
216 * filesystem unless it is really small.
218 e2_blkcnt_t
ext2fs_default_orphan_file_blocks(ext2_filsys fs
)
220 __u64 num_blocks
= ext2fs_blocks_count(fs
->super
);
221 e2_blkcnt_t blks
= 512;
223 if (num_blocks
< 128 * 1024)
225 else if (num_blocks
< 2 * 1024 * 1024)
226 blks
= num_blocks
/ 4096;
227 return (blks
+ EXT2FS_CLUSTER_MASK(fs
)) & ~EXT2FS_CLUSTER_MASK(fs
);
230 static errcode_t
ext2fs_orphan_file_block_csum(ext2_filsys fs
, ext2_ino_t ino
,
231 blk64_t blk
, char *buf
,
234 struct ext2_inode inode
;
237 retval
= ext2fs_read_inode(fs
, ino
, &inode
);
240 *crcp
= ext2fs_do_orphan_file_block_csum(fs
, ino
, inode
.i_generation
,
245 errcode_t
ext2fs_orphan_file_block_csum_set(ext2_filsys fs
, ext2_ino_t ino
,
246 blk64_t blk
, char *buf
)
248 struct ext4_orphan_block_tail
*tail
;
250 if (!ext2fs_has_feature_metadata_csum(fs
->super
))
253 tail
= ext2fs_orphan_block_tail(fs
, buf
);
254 return ext2fs_orphan_file_block_csum(fs
, ino
, blk
, buf
,
258 int ext2fs_orphan_file_block_csum_verify(ext2_filsys fs
, ext2_ino_t ino
,
259 blk64_t blk
, char *buf
)
261 struct ext4_orphan_block_tail
*tail
;
265 if (!ext2fs_has_feature_metadata_csum(fs
->super
))
267 retval
= ext2fs_orphan_file_block_csum(fs
, ino
, blk
, buf
, &crc
);
270 tail
= ext2fs_orphan_block_tail(fs
, buf
);
271 return ext2fs_le32_to_cpu(tail
->ob_checksum
) == crc
;