2015-12-10 00:18:44 +00:00
|
|
|
/**
|
|
|
|
* segment.c
|
|
|
|
*
|
|
|
|
* Many parts of codes are copied from Linux kernel/fs/f2fs.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015 Huawei Ltd.
|
|
|
|
* Witten by:
|
|
|
|
* Hou Pengyang <houpengyang@huawei.com>
|
|
|
|
* Liu Shuoran <liushuoran@huawei.com>
|
|
|
|
* Jaegeuk Kim <jaegeuk@kernel.org>
|
2020-12-08 08:15:54 +00:00
|
|
|
* Copyright (c) 2020 Google Inc.
|
|
|
|
* Robin Hsu <robinhsu@google.com>
|
|
|
|
* : add sload compression support
|
2015-12-10 00:18:44 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
#include "fsck.h"
|
|
|
|
#include "node.h"
|
2020-02-05 07:41:57 +00:00
|
|
|
#include "quotaio.h"
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2019-04-15 09:14:38 +00:00
|
|
|
int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
|
2019-08-05 09:44:06 +00:00
|
|
|
struct f2fs_summary *sum, int type, bool is_inode)
|
2015-12-10 00:18:44 +00:00
|
|
|
{
|
2017-10-30 23:21:09 +00:00
|
|
|
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
|
2015-12-10 00:18:44 +00:00
|
|
|
struct seg_entry *se;
|
2017-10-30 23:21:09 +00:00
|
|
|
u64 blkaddr, offset;
|
|
|
|
u64 old_blkaddr = *to;
|
2019-08-05 09:44:06 +00:00
|
|
|
bool is_node = IS_NODESEG(type);
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2019-04-15 09:14:38 +00:00
|
|
|
if (old_blkaddr == NULL_ADDR) {
|
|
|
|
if (c.func == FSCK) {
|
|
|
|
if (fsck->chk.valid_blk_cnt >= sbi->user_block_count) {
|
2019-08-09 10:53:02 +00:00
|
|
|
ERR_MSG("Not enough space\n");
|
2019-04-15 09:14:38 +00:00
|
|
|
return -ENOSPC;
|
|
|
|
}
|
2019-08-05 09:44:06 +00:00
|
|
|
if (is_node && fsck->chk.valid_node_cnt >=
|
|
|
|
sbi->total_valid_node_count) {
|
2019-08-09 10:53:02 +00:00
|
|
|
ERR_MSG("Not enough space for node block\n");
|
2019-08-05 09:44:06 +00:00
|
|
|
return -ENOSPC;
|
|
|
|
}
|
2019-04-15 09:14:38 +00:00
|
|
|
} else {
|
|
|
|
if (sbi->total_valid_block_count >=
|
|
|
|
sbi->user_block_count) {
|
2019-08-09 10:53:02 +00:00
|
|
|
ERR_MSG("Not enough space\n");
|
2019-04-15 09:14:38 +00:00
|
|
|
return -ENOSPC;
|
|
|
|
}
|
2019-08-05 09:44:06 +00:00
|
|
|
if (is_node && sbi->total_valid_node_count >=
|
|
|
|
sbi->total_node_count) {
|
2019-08-09 10:53:02 +00:00
|
|
|
ERR_MSG("Not enough space for node block\n");
|
2019-08-05 09:44:06 +00:00
|
|
|
return -ENOSPC;
|
|
|
|
}
|
2019-04-15 09:14:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-10 00:18:44 +00:00
|
|
|
blkaddr = SM_I(sbi)->main_blkaddr;
|
|
|
|
|
2019-11-28 07:59:26 +00:00
|
|
|
if (find_next_free_block(sbi, &blkaddr, 0, type, false)) {
|
2019-04-15 09:14:38 +00:00
|
|
|
ERR_MSG("Can't find free block");
|
2015-12-10 00:18:44 +00:00
|
|
|
ASSERT(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
|
|
|
|
offset = OFFSET_IN_SEG(sbi, blkaddr);
|
|
|
|
se->type = type;
|
|
|
|
se->valid_blocks++;
|
|
|
|
f2fs_set_bit(offset, (char *)se->cur_valid_map);
|
2019-11-28 07:59:28 +00:00
|
|
|
if (need_fsync_data_record(sbi)) {
|
f2fs-tools: fix to skip block allocation for fsynced data
Previously, we don't allow block allocation on unclean umounted image,
result in failing to repair quota system file.
In this patch, we port most recovery codes from kernel to userspace
tools, so that on unclean image, during fsck initialization, we will
record all data/node block address we may recover in kernel, and
then during allocation of quota file repair, we can skip those blocks
to avoid block use conflict.
Eventually, if free space is enough, we can repair the quota system
file on an unclean umounted image.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
[Jaegeuk Kim: remove unnecessary parameter]
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-08-14 08:48:55 +00:00
|
|
|
se->ckpt_type = type;
|
|
|
|
se->ckpt_valid_blocks++;
|
|
|
|
f2fs_set_bit(offset, (char *)se->ckpt_valid_map);
|
|
|
|
}
|
2017-10-30 23:21:09 +00:00
|
|
|
if (c.func == FSCK) {
|
|
|
|
f2fs_set_main_bitmap(sbi, blkaddr, type);
|
|
|
|
f2fs_set_sit_bitmap(sbi, blkaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old_blkaddr == NULL_ADDR) {
|
|
|
|
sbi->total_valid_block_count++;
|
2019-08-05 09:44:06 +00:00
|
|
|
if (is_node) {
|
|
|
|
sbi->total_valid_node_count++;
|
|
|
|
if (is_inode)
|
|
|
|
sbi->total_valid_inode_count++;
|
|
|
|
}
|
2019-08-05 07:26:21 +00:00
|
|
|
if (c.func == FSCK) {
|
2017-10-30 23:21:09 +00:00
|
|
|
fsck->chk.valid_blk_cnt++;
|
2019-08-05 09:44:06 +00:00
|
|
|
if (is_node) {
|
2019-08-05 07:26:21 +00:00
|
|
|
fsck->chk.valid_node_cnt++;
|
2019-08-05 09:44:06 +00:00
|
|
|
if (is_inode)
|
|
|
|
fsck->chk.valid_inode_cnt++;
|
|
|
|
}
|
2019-08-05 07:26:21 +00:00
|
|
|
}
|
2017-10-30 23:21:09 +00:00
|
|
|
}
|
2015-12-10 00:18:44 +00:00
|
|
|
se->dirty = 1;
|
|
|
|
|
|
|
|
/* read/write SSA */
|
|
|
|
*to = (block_t)blkaddr;
|
|
|
|
update_sum_entry(sbi, *to, sum);
|
2019-04-15 09:14:38 +00:00
|
|
|
|
|
|
|
return 0;
|
2015-12-10 00:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-10-01 01:16:38 +00:00
|
|
|
int new_data_block(struct f2fs_sb_info *sbi, void *block,
|
2015-12-10 00:18:44 +00:00
|
|
|
struct dnode_of_data *dn, int type)
|
|
|
|
{
|
2020-06-30 21:03:51 +00:00
|
|
|
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
|
2015-12-10 00:18:44 +00:00
|
|
|
struct f2fs_summary sum;
|
|
|
|
struct node_info ni;
|
2017-11-02 17:41:16 +00:00
|
|
|
unsigned int blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node);
|
2019-04-15 09:14:38 +00:00
|
|
|
int ret;
|
2018-10-01 01:16:38 +00:00
|
|
|
|
2020-06-30 21:03:51 +00:00
|
|
|
if ((get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) &&
|
|
|
|
type != CURSEG_HOT_DATA)
|
|
|
|
type = CURSEG_HOT_DATA;
|
|
|
|
|
2015-12-10 00:18:44 +00:00
|
|
|
ASSERT(dn->node_blk);
|
|
|
|
memset(block, 0, BLOCK_SZ);
|
|
|
|
|
|
|
|
get_node_info(sbi, dn->nid, &ni);
|
|
|
|
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
|
2020-12-08 08:15:54 +00:00
|
|
|
|
|
|
|
dn->data_blkaddr = blkaddr;
|
2019-08-05 09:44:06 +00:00
|
|
|
ret = reserve_new_block(sbi, &dn->data_blkaddr, &sum, type, 0);
|
2019-04-15 09:14:38 +00:00
|
|
|
if (ret) {
|
|
|
|
c.alloc_failed = 1;
|
|
|
|
return ret;
|
|
|
|
}
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 23:21:09 +00:00
|
|
|
if (blkaddr == NULL_ADDR)
|
|
|
|
inc_inode_blocks(dn);
|
|
|
|
else if (blkaddr == NEW_ADDR)
|
|
|
|
dn->idirty = 1;
|
2015-12-10 00:18:44 +00:00
|
|
|
set_data_blkaddr(dn);
|
2018-10-01 01:16:38 +00:00
|
|
|
return 0;
|
2015-12-10 00:18:44 +00:00
|
|
|
}
|
|
|
|
|
2020-02-05 07:41:57 +00:00
|
|
|
u64 f2fs_quota_size(struct quota_file *qf)
|
|
|
|
{
|
|
|
|
struct node_info ni;
|
|
|
|
struct f2fs_node *inode;
|
|
|
|
u64 filesize;
|
|
|
|
|
|
|
|
inode = (struct f2fs_node *) calloc(BLOCK_SZ, 1);
|
|
|
|
ASSERT(inode);
|
|
|
|
|
|
|
|
/* Read inode */
|
|
|
|
get_node_info(qf->sbi, qf->ino, &ni);
|
|
|
|
ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
|
|
|
|
ASSERT(S_ISREG(le16_to_cpu(inode->i.i_mode)));
|
|
|
|
|
|
|
|
filesize = le64_to_cpu(inode->i.i_size);
|
|
|
|
free(inode);
|
|
|
|
return filesize;
|
|
|
|
}
|
|
|
|
|
2017-11-02 17:41:16 +00:00
|
|
|
u64 f2fs_read(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
|
2015-12-10 00:18:44 +00:00
|
|
|
u64 count, pgoff_t offset)
|
|
|
|
{
|
2017-10-30 21:26:30 +00:00
|
|
|
struct dnode_of_data dn;
|
2015-12-10 00:18:44 +00:00
|
|
|
struct node_info ni;
|
|
|
|
struct f2fs_node *inode;
|
2017-10-30 21:26:30 +00:00
|
|
|
char *blk_buffer;
|
|
|
|
u64 filesize;
|
|
|
|
u64 off_in_blk;
|
|
|
|
u64 len_in_blk;
|
|
|
|
u64 read_count;
|
|
|
|
u64 remained_blkentries;
|
|
|
|
block_t blkaddr;
|
|
|
|
void *index_node = NULL;
|
|
|
|
|
|
|
|
memset(&dn, 0, sizeof(dn));
|
|
|
|
|
|
|
|
/* Memory allocation for block buffer and inode. */
|
|
|
|
blk_buffer = calloc(BLOCK_SZ, 2);
|
|
|
|
ASSERT(blk_buffer);
|
|
|
|
inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
|
|
|
|
|
|
|
|
/* Read inode */
|
2015-12-10 00:18:44 +00:00
|
|
|
get_node_info(sbi, ino, &ni);
|
2017-10-30 21:26:30 +00:00
|
|
|
ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
|
|
|
|
ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
|
|
|
|
ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
|
|
|
|
|
|
|
|
/* Adjust count with file length. */
|
|
|
|
filesize = le64_to_cpu(inode->i.i_size);
|
|
|
|
if (offset > filesize)
|
|
|
|
count = 0;
|
|
|
|
else if (count + offset > filesize)
|
|
|
|
count = filesize - offset;
|
|
|
|
|
|
|
|
/* Main loop for file blocks */
|
|
|
|
read_count = remained_blkentries = 0;
|
|
|
|
while (count > 0) {
|
|
|
|
if (remained_blkentries == 0) {
|
|
|
|
set_new_dnode(&dn, inode, NULL, ino);
|
|
|
|
get_dnode_of_data(sbi, &dn, F2FS_BYTES_TO_BLK(offset),
|
|
|
|
LOOKUP_NODE);
|
|
|
|
if (index_node)
|
|
|
|
free(index_node);
|
|
|
|
index_node = (dn.node_blk == dn.inode_blk) ?
|
|
|
|
NULL : dn.node_blk;
|
2019-03-25 13:19:35 +00:00
|
|
|
remained_blkentries = ADDRS_PER_PAGE(sbi,
|
|
|
|
dn.node_blk, dn.inode_blk);
|
2017-10-30 21:26:30 +00:00
|
|
|
}
|
|
|
|
ASSERT(remained_blkentries > 0);
|
|
|
|
|
|
|
|
blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
|
|
|
|
if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR)
|
|
|
|
break;
|
|
|
|
|
|
|
|
off_in_blk = offset % BLOCK_SZ;
|
|
|
|
len_in_blk = BLOCK_SZ - off_in_blk;
|
|
|
|
if (len_in_blk > count)
|
|
|
|
len_in_blk = count;
|
|
|
|
|
|
|
|
/* Read data from single block. */
|
|
|
|
if (len_in_blk < BLOCK_SZ) {
|
|
|
|
ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
|
|
|
|
memcpy(buffer, blk_buffer + off_in_blk, len_in_blk);
|
|
|
|
} else {
|
|
|
|
/* Direct read */
|
|
|
|
ASSERT(dev_read_block(buffer, blkaddr) >= 0);
|
|
|
|
}
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
offset += len_in_blk;
|
|
|
|
count -= len_in_blk;
|
|
|
|
buffer += len_in_blk;
|
|
|
|
read_count += len_in_blk;
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
dn.ofs_in_node++;
|
|
|
|
remained_blkentries--;
|
|
|
|
}
|
|
|
|
if (index_node)
|
|
|
|
free(index_node);
|
|
|
|
free(blk_buffer);
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
return read_count;
|
|
|
|
}
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2020-12-08 08:15:54 +00:00
|
|
|
/*
|
|
|
|
* Do not call this function directly. Instead, call one of the following:
|
|
|
|
* u64 f2fs_write();
|
|
|
|
* u64 f2fs_write_compress_data();
|
|
|
|
* u64 f2fs_write_addrtag();
|
|
|
|
*/
|
|
|
|
static u64 f2fs_write_ex(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
|
|
|
|
u64 count, pgoff_t offset, enum wr_addr_type addr_type)
|
2017-10-30 21:26:30 +00:00
|
|
|
{
|
|
|
|
struct dnode_of_data dn;
|
|
|
|
struct node_info ni;
|
|
|
|
struct f2fs_node *inode;
|
|
|
|
char *blk_buffer;
|
|
|
|
u64 off_in_blk;
|
|
|
|
u64 len_in_blk;
|
|
|
|
u64 written_count;
|
|
|
|
u64 remained_blkentries;
|
|
|
|
block_t blkaddr;
|
|
|
|
void* index_node = NULL;
|
|
|
|
int idirty = 0;
|
2018-10-01 01:16:38 +00:00
|
|
|
int err;
|
2020-12-08 08:15:54 +00:00
|
|
|
bool has_data = (addr_type == WR_NORMAL
|
|
|
|
|| addr_type == WR_COMPRESS_DATA);
|
|
|
|
|
|
|
|
if (count == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Enforce calling from f2fs_write(), f2fs_write_compress_data(),
|
|
|
|
* and f2fs_write_addrtag(). Beside, check if is properly called.
|
|
|
|
*/
|
|
|
|
ASSERT((!has_data && buffer == NULL) || (has_data && buffer != NULL));
|
|
|
|
if (addr_type != WR_NORMAL)
|
|
|
|
ASSERT(offset % F2FS_BLKSIZE == 0); /* block boundary only */
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
/* Memory allocation for block buffer and inode. */
|
|
|
|
blk_buffer = calloc(BLOCK_SZ, 2);
|
|
|
|
ASSERT(blk_buffer);
|
|
|
|
inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
/* Read inode */
|
|
|
|
get_node_info(sbi, ino, &ni);
|
|
|
|
ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
|
|
|
|
ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
|
|
|
|
ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
|
|
|
|
|
|
|
|
/* Main loop for file blocks */
|
|
|
|
written_count = remained_blkentries = 0;
|
|
|
|
while (count > 0) {
|
|
|
|
if (remained_blkentries == 0) {
|
|
|
|
set_new_dnode(&dn, inode, NULL, ino);
|
2018-10-01 01:16:38 +00:00
|
|
|
err = get_dnode_of_data(sbi, &dn,
|
|
|
|
F2FS_BYTES_TO_BLK(offset), ALLOC_NODE);
|
|
|
|
if (err)
|
|
|
|
break;
|
2017-10-30 21:26:30 +00:00
|
|
|
idirty |= dn.idirty;
|
2020-12-08 08:15:54 +00:00
|
|
|
free(index_node);
|
2017-10-30 21:26:30 +00:00
|
|
|
index_node = (dn.node_blk == dn.inode_blk) ?
|
2020-12-08 08:15:54 +00:00
|
|
|
NULL : dn.node_blk;
|
2019-03-25 13:19:35 +00:00
|
|
|
remained_blkentries = ADDRS_PER_PAGE(sbi,
|
2020-12-08 08:15:54 +00:00
|
|
|
dn.node_blk, dn.inode_blk) -
|
|
|
|
dn.ofs_in_node;
|
2017-10-30 21:26:30 +00:00
|
|
|
}
|
|
|
|
ASSERT(remained_blkentries > 0);
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2020-12-08 08:15:54 +00:00
|
|
|
if (!has_data) {
|
|
|
|
dn.data_blkaddr = addr_type;
|
|
|
|
set_data_blkaddr(&dn);
|
|
|
|
idirty |= dn.idirty;
|
|
|
|
if (dn.ndirty)
|
|
|
|
ASSERT(dev_write_block(dn.node_blk,
|
|
|
|
dn.node_blkaddr) >= 0);
|
|
|
|
written_count = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
|
|
|
|
if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
|
2018-10-01 01:16:38 +00:00
|
|
|
err = new_data_block(sbi, blk_buffer,
|
|
|
|
&dn, CURSEG_WARM_DATA);
|
|
|
|
if (err)
|
|
|
|
break;
|
2017-10-30 21:26:30 +00:00
|
|
|
blkaddr = dn.data_blkaddr;
|
2020-12-08 08:15:54 +00:00
|
|
|
idirty |= dn.idirty;
|
2017-10-30 21:26:30 +00:00
|
|
|
}
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
off_in_blk = offset % BLOCK_SZ;
|
|
|
|
len_in_blk = BLOCK_SZ - off_in_blk;
|
|
|
|
if (len_in_blk > count)
|
|
|
|
len_in_blk = count;
|
|
|
|
|
|
|
|
/* Write data to single block. */
|
|
|
|
if (len_in_blk < BLOCK_SZ) {
|
|
|
|
ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
|
|
|
|
memcpy(blk_buffer + off_in_blk, buffer, len_in_blk);
|
|
|
|
ASSERT(dev_write_block(blk_buffer, blkaddr) >= 0);
|
|
|
|
} else {
|
|
|
|
/* Direct write */
|
|
|
|
ASSERT(dev_write_block(buffer, blkaddr) >= 0);
|
|
|
|
}
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
offset += len_in_blk;
|
|
|
|
count -= len_in_blk;
|
|
|
|
buffer += len_in_blk;
|
|
|
|
written_count += len_in_blk;
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
dn.ofs_in_node++;
|
|
|
|
if ((--remained_blkentries == 0 || count == 0) && (dn.ndirty))
|
2020-12-08 08:15:54 +00:00
|
|
|
ASSERT(dev_write_block(dn.node_blk, dn.node_blkaddr)
|
|
|
|
>= 0);
|
2015-12-10 00:18:44 +00:00
|
|
|
}
|
2020-12-08 08:15:54 +00:00
|
|
|
if (addr_type == WR_NORMAL && offset > le64_to_cpu(inode->i.i_size)) {
|
2017-10-30 21:26:30 +00:00
|
|
|
inode->i.i_size = cpu_to_le64(offset);
|
2017-10-30 19:12:39 +00:00
|
|
|
idirty = 1;
|
2015-12-10 00:18:44 +00:00
|
|
|
}
|
2017-10-30 19:12:39 +00:00
|
|
|
if (idirty) {
|
2015-12-10 00:18:44 +00:00
|
|
|
ASSERT(inode == dn.inode_blk);
|
2019-05-24 07:28:11 +00:00
|
|
|
ASSERT(write_inode(inode, ni.blk_addr) >= 0);
|
2015-12-10 00:18:44 +00:00
|
|
|
}
|
2020-12-08 08:15:54 +00:00
|
|
|
|
|
|
|
free(index_node);
|
2017-10-30 21:26:30 +00:00
|
|
|
free(blk_buffer);
|
|
|
|
|
|
|
|
return written_count;
|
|
|
|
}
|
|
|
|
|
2020-12-08 08:15:54 +00:00
|
|
|
u64 f2fs_write(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
|
|
|
|
u64 count, pgoff_t offset)
|
|
|
|
{
|
|
|
|
return f2fs_write_ex(sbi, ino, buffer, count, offset, WR_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 f2fs_write_compress_data(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
|
|
|
|
u64 count, pgoff_t offset)
|
|
|
|
{
|
|
|
|
return f2fs_write_ex(sbi, ino, buffer, count, offset, WR_COMPRESS_DATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 f2fs_write_addrtag(struct f2fs_sb_info *sbi, nid_t ino, pgoff_t offset,
|
|
|
|
unsigned int addrtag)
|
|
|
|
{
|
|
|
|
ASSERT(addrtag == COMPRESS_ADDR || addrtag == NEW_ADDR
|
|
|
|
|| addrtag == NULL_ADDR);
|
|
|
|
return f2fs_write_ex(sbi, ino, NULL, F2FS_BLKSIZE, offset, addrtag);
|
|
|
|
}
|
|
|
|
|
2017-10-30 21:26:30 +00:00
|
|
|
/* This function updates only inode->i.i_size */
|
|
|
|
void f2fs_filesize_update(struct f2fs_sb_info *sbi, nid_t ino, u64 filesize)
|
|
|
|
{
|
|
|
|
struct node_info ni;
|
|
|
|
struct f2fs_node *inode;
|
|
|
|
|
|
|
|
inode = calloc(BLOCK_SZ, 1);
|
|
|
|
ASSERT(inode);
|
|
|
|
get_node_info(sbi, ino, &ni);
|
|
|
|
|
|
|
|
ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
|
|
|
|
ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
|
|
|
|
ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
|
|
|
|
|
|
|
|
inode->i.i_size = cpu_to_le64(filesize);
|
2015-12-10 00:18:44 +00:00
|
|
|
|
2019-05-24 07:28:11 +00:00
|
|
|
ASSERT(write_inode(inode, ni.blk_addr) >= 0);
|
2015-12-10 00:18:44 +00:00
|
|
|
free(inode);
|
|
|
|
}
|
|
|
|
|
2020-12-08 08:15:54 +00:00
|
|
|
#define MAX_BULKR_RETRY 5
|
|
|
|
int bulkread(int fd, void *rbuf, size_t rsize, bool *eof)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
int retry = MAX_BULKR_RETRY;
|
|
|
|
int cur;
|
|
|
|
|
|
|
|
if (!rsize)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (eof != NULL)
|
|
|
|
*eof = false;
|
|
|
|
while (rsize && (cur = read(fd, rbuf, rsize)) != 0) {
|
|
|
|
if (cur == -1) {
|
|
|
|
if (errno == EINTR && retry--)
|
|
|
|
continue;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
retry = MAX_BULKR_RETRY;
|
|
|
|
|
|
|
|
rsize -= cur;
|
|
|
|
n += cur;
|
|
|
|
}
|
|
|
|
if (eof != NULL)
|
|
|
|
*eof = (cur == 0);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 f2fs_fix_mutable(struct f2fs_sb_info *sbi, nid_t ino, pgoff_t offset,
|
|
|
|
unsigned int compressed)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
u64 wlen;
|
|
|
|
|
|
|
|
if (c.compress.readonly)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < compressed - 1; i++) {
|
|
|
|
wlen = f2fs_write_addrtag(sbi, ino,
|
|
|
|
offset + (i << F2FS_BLKSIZE_BITS), NEW_ADDR);
|
|
|
|
if (wlen)
|
|
|
|
return wlen;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-15 18:44:49 +00:00
|
|
|
static inline int is_consecutive(u32 prev_addr, u32 cur_addr)
|
|
|
|
{
|
|
|
|
if (is_valid_data_blkaddr(cur_addr) && (cur_addr == prev_addr + 1))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void copy_extent_info(struct extent_info *t_ext,
|
|
|
|
struct extent_info *s_ext)
|
|
|
|
{
|
|
|
|
t_ext->fofs = s_ext->fofs;
|
|
|
|
t_ext->blk = s_ext->blk;
|
|
|
|
t_ext->len = s_ext->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void update_extent_info(struct f2fs_node *inode,
|
|
|
|
struct extent_info *ext)
|
|
|
|
{
|
|
|
|
inode->i.i_ext.fofs = cpu_to_le32(ext->fofs);
|
|
|
|
inode->i.i_ext.blk_addr = cpu_to_le32(ext->blk);
|
|
|
|
inode->i.i_ext.len = cpu_to_le32(ext->len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_largest_extent(struct f2fs_sb_info *sbi, nid_t ino)
|
|
|
|
{
|
|
|
|
struct dnode_of_data dn;
|
|
|
|
struct node_info ni;
|
|
|
|
struct f2fs_node *inode;
|
|
|
|
u32 blkaddr, prev_blkaddr, cur_blk = 0, end_blk;
|
|
|
|
struct extent_info largest_ext, cur_ext;
|
|
|
|
u64 remained_blkentries = 0;
|
|
|
|
u32 cluster_size;
|
|
|
|
int count;
|
|
|
|
void *index_node = NULL;
|
|
|
|
|
|
|
|
memset(&dn, 0, sizeof(dn));
|
|
|
|
largest_ext.len = cur_ext.len = 0;
|
|
|
|
|
|
|
|
inode = (struct f2fs_node *) calloc(BLOCK_SZ, 1);
|
|
|
|
ASSERT(inode);
|
|
|
|
|
|
|
|
/* Read inode info */
|
|
|
|
get_node_info(sbi, ino, &ni);
|
|
|
|
ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
|
|
|
|
cluster_size = 1 << inode->i.i_log_cluster_size;
|
|
|
|
|
|
|
|
if (inode->i.i_inline & F2FS_INLINE_DATA)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
end_blk = f2fs_max_file_offset(&inode->i) >> F2FS_BLKSIZE_BITS;
|
|
|
|
|
|
|
|
while (cur_blk <= end_blk) {
|
|
|
|
if (remained_blkentries == 0) {
|
|
|
|
set_new_dnode(&dn, inode, NULL, ino);
|
|
|
|
get_dnode_of_data(sbi, &dn, cur_blk, LOOKUP_NODE);
|
|
|
|
if (index_node)
|
|
|
|
free(index_node);
|
|
|
|
index_node = (dn.node_blk == dn.inode_blk) ?
|
|
|
|
NULL : dn.node_blk;
|
|
|
|
remained_blkentries = ADDRS_PER_PAGE(sbi,
|
|
|
|
dn.node_blk, dn.inode_blk);
|
|
|
|
}
|
|
|
|
ASSERT(remained_blkentries > 0);
|
|
|
|
|
|
|
|
blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
|
|
|
|
if (cur_ext.len > 0) {
|
|
|
|
if (is_consecutive(prev_blkaddr, blkaddr))
|
|
|
|
cur_ext.len++;
|
|
|
|
else {
|
|
|
|
if (cur_ext.len > largest_ext.len)
|
|
|
|
copy_extent_info(&largest_ext,
|
|
|
|
&cur_ext);
|
|
|
|
cur_ext.len = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur_ext.len == 0 && is_valid_data_blkaddr(blkaddr)) {
|
|
|
|
cur_ext.fofs = cur_blk;
|
|
|
|
cur_ext.len = 1;
|
|
|
|
cur_ext.blk = blkaddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev_blkaddr = blkaddr;
|
|
|
|
count = blkaddr == COMPRESS_ADDR ? cluster_size : 1;
|
|
|
|
cur_blk += count;
|
|
|
|
dn.ofs_in_node += count;
|
|
|
|
remained_blkentries -= count;
|
|
|
|
ASSERT(remained_blkentries >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
if (cur_ext.len > largest_ext.len)
|
|
|
|
copy_extent_info(&largest_ext, &cur_ext);
|
|
|
|
if (largest_ext.len > 0) {
|
|
|
|
update_extent_info(inode, &largest_ext);
|
|
|
|
ASSERT(write_inode(inode, ni.blk_addr) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index_node)
|
|
|
|
free(index_node);
|
|
|
|
free(inode);
|
|
|
|
}
|
|
|
|
|
2015-12-10 00:18:44 +00:00
|
|
|
int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
|
|
|
|
{
|
|
|
|
int fd, n;
|
|
|
|
pgoff_t off = 0;
|
2017-11-02 17:41:16 +00:00
|
|
|
u8 buffer[BLOCK_SZ];
|
2020-12-08 08:15:54 +00:00
|
|
|
struct node_info ni;
|
|
|
|
struct f2fs_node *node_blk;
|
2015-12-10 00:18:44 +00:00
|
|
|
|
|
|
|
if (de->ino == 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-12-10 15:28:11 +00:00
|
|
|
if (de->from_devino) {
|
|
|
|
struct hardlink_cache_entry *found_hardlink;
|
|
|
|
|
|
|
|
found_hardlink = f2fs_search_hardlink(sbi, de);
|
|
|
|
if (found_hardlink && found_hardlink->to_ino &&
|
|
|
|
found_hardlink->nbuild)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
found_hardlink->nbuild++;
|
|
|
|
}
|
|
|
|
|
2015-12-10 00:18:44 +00:00
|
|
|
fd = open(de->full_path, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
MSG(0, "Skip: Fail to open %s\n", de->full_path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* inline_data support */
|
2017-07-26 14:49:57 +00:00
|
|
|
if (de->size <= DEF_MAX_INLINE_DATA) {
|
2015-12-10 00:18:44 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
get_node_info(sbi, de->ino, &ni);
|
|
|
|
|
|
|
|
node_blk = calloc(BLOCK_SZ, 1);
|
|
|
|
ASSERT(node_blk);
|
|
|
|
|
|
|
|
ret = dev_read_block(node_blk, ni.blk_addr);
|
|
|
|
ASSERT(ret >= 0);
|
|
|
|
|
|
|
|
node_blk->i.i_inline |= F2FS_INLINE_DATA;
|
|
|
|
node_blk->i.i_inline |= F2FS_DATA_EXIST;
|
2017-07-26 14:49:57 +00:00
|
|
|
|
|
|
|
if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
|
|
|
|
node_blk->i.i_inline |= F2FS_EXTRA_ATTR;
|
|
|
|
node_blk->i.i_extra_isize =
|
2019-04-28 09:17:37 +00:00
|
|
|
cpu_to_le16(calc_extra_isize());
|
2017-07-26 14:49:57 +00:00
|
|
|
}
|
2015-12-10 00:18:44 +00:00
|
|
|
n = read(fd, buffer, BLOCK_SZ);
|
2017-11-02 17:41:16 +00:00
|
|
|
ASSERT((unsigned long)n == de->size);
|
2017-07-26 14:49:57 +00:00
|
|
|
memcpy(inline_data_addr(node_blk), buffer, de->size);
|
2015-12-10 00:18:44 +00:00
|
|
|
node_blk->i.i_size = cpu_to_le64(de->size);
|
2019-05-24 07:28:11 +00:00
|
|
|
ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
|
2015-12-10 00:18:44 +00:00
|
|
|
free(node_blk);
|
2020-12-08 08:15:54 +00:00
|
|
|
#ifdef WITH_SLOAD
|
|
|
|
} else if (c.func == SLOAD && c.compress.enabled &&
|
|
|
|
c.compress.filter_ops->filter(de->full_path)) {
|
|
|
|
bool eof = false;
|
|
|
|
u8 *rbuf = c.compress.cc.rbuf;
|
|
|
|
unsigned int cblocks = 0;
|
|
|
|
|
|
|
|
node_blk = calloc(BLOCK_SZ, 1);
|
|
|
|
ASSERT(node_blk);
|
|
|
|
|
|
|
|
/* read inode */
|
|
|
|
get_node_info(sbi, de->ino, &ni);
|
|
|
|
ASSERT(dev_read_block(node_blk, ni.blk_addr) >= 0);
|
|
|
|
/* update inode meta */
|
|
|
|
node_blk->i.i_compress_algrithm = c.compress.alg;
|
|
|
|
node_blk->i.i_log_cluster_size =
|
|
|
|
c.compress.cc.log_cluster_size;
|
2021-05-25 19:00:46 +00:00
|
|
|
node_blk->i.i_flags = cpu_to_le32(F2FS_COMPR_FL);
|
|
|
|
if (c.compress.readonly)
|
|
|
|
node_blk->i.i_inline |= F2FS_COMPRESS_RELEASED;
|
2020-12-08 08:15:54 +00:00
|
|
|
ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
|
|
|
|
|
|
|
|
while (!eof && (n = bulkread(fd, rbuf, c.compress.cc.rlen,
|
|
|
|
&eof)) > 0) {
|
|
|
|
int ret = c.compress.ops->compress(&c.compress.cc);
|
|
|
|
u64 wlen;
|
|
|
|
u32 csize = ALIGN_UP(c.compress.cc.clen +
|
|
|
|
COMPRESS_HEADER_SIZE, BLOCK_SZ);
|
|
|
|
unsigned int cur_cblk;
|
|
|
|
|
|
|
|
if (ret || n < c.compress.cc.rlen ||
|
|
|
|
n < (int)(csize + BLOCK_SZ *
|
|
|
|
c.compress.min_blocks)) {
|
|
|
|
wlen = f2fs_write(sbi, de->ino, rbuf, n, off);
|
|
|
|
ASSERT((int)wlen == n);
|
|
|
|
} else {
|
|
|
|
wlen = f2fs_write_addrtag(sbi, de->ino, off,
|
|
|
|
WR_COMPRESS_ADDR);
|
|
|
|
ASSERT(!wlen);
|
|
|
|
wlen = f2fs_write_compress_data(sbi, de->ino,
|
|
|
|
(u8 *)c.compress.cc.cbuf,
|
|
|
|
csize, off + BLOCK_SZ);
|
|
|
|
ASSERT(wlen == csize);
|
|
|
|
c.compress.ops->reset(&c.compress.cc);
|
|
|
|
cur_cblk = (c.compress.cc.rlen - csize) /
|
|
|
|
BLOCK_SZ;
|
|
|
|
cblocks += cur_cblk;
|
|
|
|
wlen = f2fs_fix_mutable(sbi, de->ino,
|
|
|
|
off + BLOCK_SZ + csize,
|
|
|
|
cur_cblk);
|
|
|
|
ASSERT(!wlen);
|
|
|
|
}
|
|
|
|
off += n;
|
|
|
|
}
|
|
|
|
if (n == -1) {
|
|
|
|
fprintf(stderr, "Load file '%s' failed: ",
|
|
|
|
de->full_path);
|
|
|
|
perror(NULL);
|
|
|
|
}
|
|
|
|
/* read inode */
|
|
|
|
get_node_info(sbi, de->ino, &ni);
|
|
|
|
ASSERT(dev_read_block(node_blk, ni.blk_addr) >= 0);
|
|
|
|
/* update inode meta */
|
|
|
|
node_blk->i.i_size = cpu_to_le64(off);
|
|
|
|
if (!c.compress.readonly) {
|
|
|
|
node_blk->i.i_compr_blocks = cpu_to_le64(cblocks);
|
|
|
|
node_blk->i.i_blocks += cpu_to_le64(cblocks);
|
|
|
|
}
|
|
|
|
ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
|
|
|
|
free(node_blk);
|
|
|
|
|
|
|
|
if (!c.compress.readonly) {
|
|
|
|
sbi->total_valid_block_count += cblocks;
|
|
|
|
if (sbi->total_valid_block_count >=
|
|
|
|
sbi->user_block_count) {
|
|
|
|
ERR_MSG("Not enough space\n");
|
|
|
|
ASSERT(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2015-12-10 00:18:44 +00:00
|
|
|
} else {
|
|
|
|
while ((n = read(fd, buffer, BLOCK_SZ)) > 0) {
|
2017-10-30 21:26:30 +00:00
|
|
|
f2fs_write(sbi, de->ino, buffer, n, off);
|
2015-12-10 00:18:44 +00:00
|
|
|
off += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
if (n < 0)
|
|
|
|
return -1;
|
|
|
|
|
2021-06-15 18:44:49 +00:00
|
|
|
if (!c.compress.enabled || (c.feature & cpu_to_le32(F2FS_FEATURE_RO)))
|
|
|
|
update_largest_extent(sbi, de->ino);
|
2015-12-10 00:18:44 +00:00
|
|
|
update_free_segments(sbi);
|
|
|
|
|
2017-11-30 01:21:12 +00:00
|
|
|
MSG(1, "Info: Create %s -> %s\n"
|
|
|
|
" -- ino=%x, type=%x, mode=%x, uid=%x, "
|
|
|
|
"gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n",
|
|
|
|
de->full_path, de->path,
|
|
|
|
de->ino, de->file_type, de->mode,
|
|
|
|
de->uid, de->gid, de->capabilities, de->size, de->pino);
|
2015-12-10 00:18:44 +00:00
|
|
|
return 0;
|
|
|
|
}
|