staticint ext4_orphan_file_add(handle_t *handle, struct inode *inode)
{ int i, j, start; struct ext4_orphan_info *oi = &EXT4_SB(inode->i_sb)->s_orphan_info; int ret = 0; bool found = false;
__le32 *bdata; int inodes_per_ob = ext4_inodes_per_orphan_block(inode->i_sb); int looped = 0;
/* *Findblockwithfreeorphanentry.UseCPUnumberforanaivehash *forasearchstartintheorphanfile
*/
start = raw_smp_processor_id()*13 % oi->of_blocks;
i = start; do { if (atomic_dec_if_positive(&oi->of_binfo[i].ob_free_entries)
>= 0) {
found = true; break;
} if (++i >= oi->of_blocks)
i = 0;
} while (i != start);
ext4_debug("superblock will point to %lu\n", inode->i_ino);
ext4_debug("orphan inode %lu will point to %d\n",
inode->i_ino, NEXT_ORPHAN(inode));
out:
ext4_std_error(sb, err); return err;
}
staticint ext4_orphan_file_del(handle_t *handle, struct inode *inode)
{ struct ext4_orphan_info *oi = &EXT4_SB(inode->i_sb)->s_orphan_info;
__le32 *bdata; int blk, off; int inodes_per_ob = ext4_inodes_per_orphan_block(inode->i_sb); int ret = 0;
if (!handle) goto out;
blk = EXT4_I(inode)->i_orphan_idx / inodes_per_ob;
off = EXT4_I(inode)->i_orphan_idx % inodes_per_ob; if (WARN_ON_ONCE(blk >= oi->of_blocks)) goto out;
ret = ext4_journal_get_write_access(handle, inode->i_sb,
oi->of_binfo[blk].ob_bh, EXT4_JTR_ORPHAN_FILE); if (ret) goto out;
/* If we're on an error path, we may not have a valid *transactionhandlewithwhichtoupdatetheorphanliston *disk,butwestillneedtoremovetheinodefromthelinked
* list in memory. */ if (!handle || err) {
mutex_unlock(&sbi->s_orphan_lock); goto out_err;
}
/* Check if feature set would not allow a r/w mount */ if (!ext4_feature_set_ok(sb, 0)) {
ext4_msg(sb, KERN_INFO, "Skipping orphan cleanup due to " "unknown ROCOMPAT features"); return;
}
if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { /* don't clear list on RO mount w/ errors */ if (es->s_last_orphan && !(s_flags & SB_RDONLY)) {
ext4_msg(sb, KERN_INFO, "Errors on filesystem, " "clearing orphan list.");
es->s_last_orphan = 0;
}
ext4_debug("Skipping orphan recovery on fs with errors.\n"); return;
}
if (s_flags & SB_RDONLY) {
ext4_msg(sb, KERN_INFO, "orphan cleanup on readonly fs");
sb->s_flags &= ~SB_RDONLY;
} #ifdef CONFIG_QUOTA /* *Turnonquotaswhichwerenotenabledforread-onlymountsif *filesystemhasquotafeature,sothattheyareupdatedcorrectly.
*/ if (ext4_has_feature_quota(sb) && (s_flags & SB_RDONLY)) { int ret = ext4_enable_quotas(sb);
if (!ret)
quota_update = 1; else
ext4_msg(sb, KERN_ERR, "Cannot turn on quotas: error %d", ret);
}
/* Turn on journaled quotas used for old sytle */ for (i = 0; i < EXT4_MAXQUOTAS; i++) { if (EXT4_SB(sb)->s_qf_names[i]) { int ret = ext4_quota_on_mount(sb, i);
if (!ret)
quota_update = 1; else
ext4_msg(sb, KERN_ERR, "Cannot turn on journaled " "quota: type %d: error %d", i, ret);
}
} #endif
while (es->s_last_orphan) { /* *Wemayhaveencounteredanerrorduringcleanup;if *so,skiptherest.
*/ if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
ext4_debug("Skipping orphan recovery on fs with errors.\n");
es->s_last_orphan = 0; break;
}
for (i = 0; i < oi->of_blocks; i++) {
bdata = (__le32 *)(oi->of_binfo[i].ob_bh->b_data); for (j = 0; j < inodes_per_ob; j++) { if (!bdata[j]) continue;
inode = ext4_orphan_get(sb, le32_to_cpu(bdata[j])); if (IS_ERR(inode)) continue;
ext4_set_inode_state(inode, EXT4_STATE_ORPHAN_FILE);
EXT4_I(inode)->i_orphan_idx = i * inodes_per_ob + j;
ext4_process_orphan(inode, &nr_truncates, &nr_orphans);
}
}
#define PLURAL(x) (x), ((x) == 1) ? "" : "s"
if (nr_orphans)
ext4_msg(sb, KERN_INFO, "%d orphan inode%s deleted",
PLURAL(nr_orphans)); if (nr_truncates)
ext4_msg(sb, KERN_INFO, "%d truncate%s cleaned up",
PLURAL(nr_truncates)); #ifdef CONFIG_QUOTA /* Turn off quotas if they were enabled for orphan cleanup */ if (quota_update) { for (i = 0; i < EXT4_MAXQUOTAS; i++) { if (sb_dqopt(sb)->files[i])
dquot_quota_off(sb, i);
}
} #endif
sb->s_flags = s_flags; /* Restore SB_RDONLY status */
}
int ext4_init_orphan_info(struct super_block *sb)
{ struct ext4_orphan_info *oi = &EXT4_SB(sb)->s_orphan_info; struct inode *inode; int i, j; int ret; int free;
__le32 *bdata; int inodes_per_ob = ext4_inodes_per_orphan_block(sb); struct ext4_orphan_block_tail *ot;
ino_t orphan_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_orphan_file_inum);
if (!ext4_has_feature_orphan_file(sb)) return0;
inode = ext4_iget(sb, orphan_ino, EXT4_IGET_SPECIAL); if (IS_ERR(inode)) {
ext4_msg(sb, KERN_ERR, "get orphan inode failed"); return PTR_ERR(inode);
} /* *Thisisjustanartificiallimittopreventcorruptedfsfrom *consumingabsurdamountsofmemorywhenpinningblocksoforphan *fileinmemory.
*/ if (inode->i_size > 8 << 20) {
ext4_msg(sb, KERN_ERR, "orphan file too big: %llu",
(unsignedlonglong)inode->i_size);
ret = -EFSCORRUPTED; goto out_put;
}
oi->of_blocks = inode->i_size >> sb->s_blocksize_bits;
oi->of_csum_seed = EXT4_I(inode)->i_csum_seed;
oi->of_binfo = kvmalloc_array(oi->of_blocks, sizeof(struct ext4_orphan_block),
GFP_KERNEL); if (!oi->of_binfo) {
ret = -ENOMEM; goto out_put;
} for (i = 0; i < oi->of_blocks; i++) {
oi->of_binfo[i].ob_bh = ext4_bread(NULL, inode, i, 0); if (IS_ERR(oi->of_binfo[i].ob_bh)) {
ret = PTR_ERR(oi->of_binfo[i].ob_bh); goto out_free;
} if (!oi->of_binfo[i].ob_bh) {
ret = -EIO; goto out_free;
}
ot = ext4_orphan_block_tail(sb, oi->of_binfo[i].ob_bh); if (le32_to_cpu(ot->ob_magic) != EXT4_ORPHAN_BLOCK_MAGIC) {
ext4_error(sb, "orphan file block %d: bad magic", i);
ret = -EIO; goto out_free;
} if (!ext4_orphan_file_block_csum_verify(sb,
oi->of_binfo[i].ob_bh)) {
ext4_error(sb, "orphan file block %d: bad checksum", i);
ret = -EIO; goto out_free;
}
bdata = (__le32 *)(oi->of_binfo[i].ob_bh->b_data);
free = 0; for (j = 0; j < inodes_per_ob; j++) if (bdata[j] == 0)
free++;
atomic_set(&oi->of_binfo[i].ob_free_entries, free);
}
iput(inode); return0;
out_free: for (i--; i >= 0; i--)
brelse(oi->of_binfo[i].ob_bh);
kvfree(oi->of_binfo);
out_put:
iput(inode); return ret;
}
int ext4_orphan_file_empty(struct super_block *sb)
{ struct ext4_orphan_info *oi = &EXT4_SB(sb)->s_orphan_info; int i; int inodes_per_ob = ext4_inodes_per_orphan_block(sb);
if (!ext4_has_feature_orphan_file(sb)) return1; for (i = 0; i < oi->of_blocks; i++) if (atomic_read(&oi->of_binfo[i].ob_free_entries) !=
inodes_per_ob) return0; return1;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.