aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@google.com>2023-10-26 15:56:20 -0700
committerJaegeuk Kim <jaegeuk@google.com>2023-10-26 15:56:20 -0700
commita769fcac25ecbbada1aea5a53e6128242bd01554 (patch)
treef8ba5dec384e8bdd694c1053b76c55a8c8fd3d7e
parentb8989769355540ef37b958f915465ec4c53be708 (diff)
parentd860afaebd1e04839047d247fa5d1cfcdeaeefb6 (diff)
downloadf2fs-tools-a769fcac25ecbbada1aea5a53e6128242bd01554.tar.gz
Upgrade f2fs-tools to d860afaebd1e04839047d247fa5d1cfcdeaeefb6
This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update f2fs-tools For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md Test: TreeHugger Change-Id: Id85b5101b7ee5021efe3aee84ebd3b1c498e143e
-rw-r--r--METADATA4
-rw-r--r--fsck/dump.c2
-rw-r--r--fsck/fsck.c206
-rw-r--r--fsck/fsck.h4
-rw-r--r--fsck/mount.c3
-rw-r--r--fsck/segment.c5
-rw-r--r--fsck/xattr.c9
-rw-r--r--include/f2fs_fs.h1
-rw-r--r--lib/libf2fs_io.c45
-rw-r--r--tools/f2fs_io/f2fs_io.c107
10 files changed, 313 insertions, 73 deletions
diff --git a/METADATA b/METADATA
index 932266e..d784a72 100644
--- a/METADATA
+++ b/METADATA
@@ -13,11 +13,11 @@ third_party {
type: GIT
value: "https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git"
}
- version: "efcb92448dd217a332dddfeb5b3637521ed62ef3"
+ version: "d860afaebd1e04839047d247fa5d1cfcdeaeefb6"
license_type: RESTRICTED
last_upgrade_date {
year: 2023
month: 10
- day: 17
+ day: 26
}
}
diff --git a/fsck/dump.c b/fsck/dump.c
index ecadfdd..864a3c3 100644
--- a/fsck/dump.c
+++ b/fsck/dump.c
@@ -359,7 +359,7 @@ static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
char xattr_name[F2FS_NAME_LEN] = {0};
int ret;
- xattr = read_all_xattrs(sbi, node_blk);
+ xattr = read_all_xattrs(sbi, node_blk, true);
if (!xattr)
return;
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 99cface..f1a55db 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -67,6 +67,14 @@ int f2fs_set_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap);
}
+static inline int f2fs_clear_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_clear_bit(BLKOFF_FROM_MAIN(sbi, blk),
+ fsck->sit_area_bitmap);
+}
+
static int add_into_hard_link_list(struct f2fs_sb_info *sbi,
u32 nid, u32 link_cnt)
{
@@ -826,6 +834,61 @@ void fsck_reada_all_direct_node_blocks(struct f2fs_sb_info *sbi,
}
}
+static bool is_zeroed(const u8 *p, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ if (p[i])
+ return false;
+ }
+ return true;
+}
+
+int chk_extended_attributes(struct f2fs_sb_info *sbi, u32 nid,
+ struct f2fs_node *inode)
+{
+ void *xattr;
+ void *last_base_addr;
+ struct f2fs_xattr_entry *ent;
+ __u32 xattr_size = XATTR_SIZE(&inode->i);
+ bool need_fix = false;
+
+ if (xattr_size == 0)
+ return 0;
+
+ xattr = read_all_xattrs(sbi, inode, false);
+ ASSERT(xattr);
+
+ last_base_addr = (void *)xattr + xattr_size;
+
+ list_for_each_xattr(ent, xattr) {
+ if ((void *)(ent) + sizeof(__u32) > last_base_addr ||
+ (void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) {
+ ASSERT_MSG("[0x%x] last xattr entry (offset: %lx) "
+ "crosses the boundary",
+ nid, (long int)((void *)ent - xattr));
+ need_fix = true;
+ break;
+ }
+ }
+ if (!need_fix &&
+ !is_zeroed((u8 *)ent, (u8 *)last_base_addr - (u8 *)ent)) {
+ ASSERT_MSG("[0x%x] nonzero bytes in xattr space after "
+ "end of list", nid);
+ need_fix = true;
+ }
+ if (need_fix && c.fix_on) {
+ memset(ent, 0, (u8 *)last_base_addr - (u8 *)ent);
+ write_all_xattrs(sbi, inode, xattr_size, xattr);
+ FIX_MSG("[0x%x] nullify wrong xattr entries", nid);
+ free(xattr);
+ return 1;
+ }
+ free(xattr);
+ return 0;
+}
+
/* start with valid nid and blkaddr */
void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
enum FILE_TYPE ftype, struct f2fs_node *node_blk,
@@ -1000,6 +1063,9 @@ check_next:
}
}
+ if (chk_extended_attributes(sbi, nid, node_blk))
+ need_fix = 1;
+
if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
unsigned int inline_size = MAX_INLINE_DATA(node_blk);
if (cur_qtype != -1)
@@ -2150,6 +2216,9 @@ int fsck_chk_quota_node(struct f2fs_sb_info *sbi)
return ret;
}
+static void fsck_disconnect_file(struct f2fs_sb_info *sbi, nid_t ino,
+ bool dealloc);
+
int fsck_chk_quota_files(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -2181,6 +2250,8 @@ int fsck_chk_quota_files(struct f2fs_sb_info *sbi)
if (c.fix_on) {
DBG(0, "Fixing Quota file ([%3d] ino [0x%x])\n",
qtype, ino);
+ fsck_disconnect_file(sbi, ino, true);
+ f2fs_rebuild_qf_inode(sbi, qtype);
f2fs_filesize_update(sbi, ino, 0);
ret = quota_write_inode(sbi, qtype);
if (!ret) {
@@ -2874,10 +2945,53 @@ static int fsck_do_reconnect_file(struct f2fs_sb_info *sbi,
return 0;
}
-static void fsck_failed_reconnect_file_dnode(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode, nid_t nid)
+static inline void release_inode_cnt(struct f2fs_sb_info *sbi, bool dealloc)
+{
+ F2FS_FSCK(sbi)->chk.valid_inode_cnt--;
+ if (dealloc)
+ sbi->total_valid_inode_count--;
+}
+
+static inline void release_node_cnt(struct f2fs_sb_info *sbi, bool dealloc)
+{
+ F2FS_FSCK(sbi)->chk.valid_node_cnt--;
+ if (dealloc)
+ sbi->total_valid_node_count--;
+}
+
+static inline void release_block_cnt(struct f2fs_sb_info *sbi, bool dealloc)
+{
+ F2FS_FSCK(sbi)->chk.valid_blk_cnt--;
+ if (dealloc)
+ sbi->total_valid_block_count--;
+}
+
+static inline void release_block(struct f2fs_sb_info *sbi, u64 blkaddr,
+ bool dealloc)
+{
+ f2fs_clear_main_bitmap(sbi, blkaddr);
+ if (dealloc) {
+ struct seg_entry *se;
+ u64 offset;
+
+ se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
+ offset = OFFSET_IN_SEG(sbi, blkaddr);
+ se->valid_blocks--;
+ f2fs_clear_bit(offset, (char *)se->cur_valid_map);
+ se->dirty = 1;
+ f2fs_clear_sit_bitmap(sbi, blkaddr);
+ }
+}
+
+static inline void release_nat_entry(struct f2fs_sb_info *sbi, u32 nid)
+{
+ nullify_nat_entry(sbi, nid);
+ F2FS_FSCK(sbi)->chk.valid_nat_entry_cnt--;
+}
+
+static void fsck_disconnect_file_dnode(struct f2fs_sb_info *sbi,
+ struct f2fs_inode *inode, nid_t nid, bool dealloc)
{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_node *node;
struct node_info ni;
u32 addr;
@@ -2890,27 +3004,29 @@ static void fsck_failed_reconnect_file_dnode(struct f2fs_sb_info *sbi,
err = dev_read_block(node, ni.blk_addr);
ASSERT(err >= 0);
- fsck->chk.valid_node_cnt--;
- fsck->chk.valid_blk_cnt--;
- f2fs_clear_main_bitmap(sbi, ni.blk_addr);
+ release_node_cnt(sbi, dealloc);
+ release_block_cnt(sbi, dealloc);
+ release_block(sbi, ni.blk_addr, dealloc);
for (i = 0; i < ADDRS_PER_BLOCK(inode); i++) {
addr = le32_to_cpu(node->dn.addr[i]);
if (!addr)
continue;
- fsck->chk.valid_blk_cnt--;
+ release_block_cnt(sbi, dealloc);
if (addr == NEW_ADDR || addr == COMPRESS_ADDR)
continue;
- f2fs_clear_main_bitmap(sbi, addr);
+ release_block(sbi, addr, dealloc);
}
+ if (dealloc)
+ release_nat_entry(sbi, nid);
+
free(node);
}
-static void fsck_failed_reconnect_file_idnode(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode, nid_t nid)
+static void fsck_disconnect_file_idnode(struct f2fs_sb_info *sbi,
+ struct f2fs_inode *inode, nid_t nid, bool dealloc)
{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_node *node;
struct node_info ni;
nid_t tmp;
@@ -2923,24 +3039,26 @@ static void fsck_failed_reconnect_file_idnode(struct f2fs_sb_info *sbi,
err = dev_read_block(node, ni.blk_addr);
ASSERT(err >= 0);
- fsck->chk.valid_node_cnt--;
- fsck->chk.valid_blk_cnt--;
- f2fs_clear_main_bitmap(sbi, ni.blk_addr);
+ release_node_cnt(sbi, dealloc);
+ release_block_cnt(sbi, dealloc);
+ release_block(sbi, ni.blk_addr, dealloc);
for (i = 0; i < NIDS_PER_BLOCK; i++) {
tmp = le32_to_cpu(node->in.nid[i]);
if (!tmp)
continue;
- fsck_failed_reconnect_file_dnode(sbi, inode, tmp);
+ fsck_disconnect_file_dnode(sbi, inode, tmp, dealloc);
}
+ if (dealloc)
+ release_nat_entry(sbi, nid);
+
free(node);
}
-static void fsck_failed_reconnect_file_didnode(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode, nid_t nid)
+static void fsck_disconnect_file_didnode(struct f2fs_sb_info *sbi,
+ struct f2fs_inode *inode, nid_t nid, bool dealloc)
{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_node *node;
struct node_info ni;
nid_t tmp;
@@ -2953,28 +3071,26 @@ static void fsck_failed_reconnect_file_didnode(struct f2fs_sb_info *sbi,
err = dev_read_block(node, ni.blk_addr);
ASSERT(err >= 0);
- fsck->chk.valid_node_cnt--;
- fsck->chk.valid_blk_cnt--;
- f2fs_clear_main_bitmap(sbi, ni.blk_addr);
+ release_node_cnt(sbi, dealloc);
+ release_block_cnt(sbi, dealloc);
+ release_block(sbi, ni.blk_addr, dealloc);
for (i = 0; i < NIDS_PER_BLOCK; i++) {
tmp = le32_to_cpu(node->in.nid[i]);
if (!tmp)
continue;
- fsck_failed_reconnect_file_idnode(sbi, inode, tmp);
+ fsck_disconnect_file_idnode(sbi, inode, tmp, dealloc);
}
+ if (dealloc)
+ release_nat_entry(sbi, nid);
+
free(node);
}
-/*
- * Counters and main_area_bitmap are already changed during checking
- * inode block, so clear them. There is no need to clear new blocks
- * allocted to lost+found.
- */
-static void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino)
+static void fsck_disconnect_file(struct f2fs_sb_info *sbi, nid_t ino,
+ bool dealloc)
{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_node *node;
struct node_info ni;
nid_t nid;
@@ -2988,18 +3104,18 @@ static void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino)
ASSERT(err >= 0);
/* clear inode counters */
- fsck->chk.valid_inode_cnt--;
- fsck->chk.valid_node_cnt--;
- fsck->chk.valid_blk_cnt--;
- f2fs_clear_main_bitmap(sbi, ni.blk_addr);
+ release_inode_cnt(sbi, dealloc);
+ release_node_cnt(sbi, dealloc);
+ release_block_cnt(sbi, dealloc);
+ release_block(sbi, ni.blk_addr, dealloc);
/* clear xnid counters */
if (node->i.i_xattr_nid) {
nid = le32_to_cpu(node->i.i_xattr_nid);
- fsck->chk.valid_node_cnt--;
- fsck->chk.valid_blk_cnt--;
+ release_node_cnt(sbi, dealloc);
+ release_block_cnt(sbi, dealloc);
get_node_info(sbi, nid, &ni);
- f2fs_clear_main_bitmap(sbi, ni.blk_addr);
+ release_block(sbi, ni.blk_addr, dealloc);
}
/* clear data counters */
@@ -3009,10 +3125,10 @@ static void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino)
block_t addr = le32_to_cpu(node->i.i_addr[ofs + i]);
if (!addr)
continue;
- fsck->chk.valid_blk_cnt--;
+ release_block_cnt(sbi, dealloc);
if (addr == NEW_ADDR || addr == COMPRESS_ADDR)
continue;
- f2fs_clear_main_bitmap(sbi, addr);
+ release_block(sbi, addr, dealloc);
}
}
@@ -3024,18 +3140,24 @@ static void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino)
switch (i) {
case 0: /* direct node */
case 1:
- fsck_failed_reconnect_file_dnode(sbi, &node->i, nid);
+ fsck_disconnect_file_dnode(sbi, &node->i, nid,
+ dealloc);
break;
case 2: /* indirect node */
case 3:
- fsck_failed_reconnect_file_idnode(sbi, &node->i, nid);
+ fsck_disconnect_file_idnode(sbi, &node->i, nid,
+ dealloc);
break;
case 4: /* double indirect node */
- fsck_failed_reconnect_file_didnode(sbi, &node->i, nid);
+ fsck_disconnect_file_didnode(sbi, &node->i, nid,
+ dealloc);
break;
}
}
+ if (dealloc)
+ release_nat_entry(sbi, ino);
+
free(node);
}
@@ -3121,7 +3243,7 @@ static int fsck_reconnect_file(struct f2fs_sb_info *sbi)
if (fsck_do_reconnect_file(sbi, lpf_node, node)) {
DBG(1, "Failed to reconnect inode [0x%x]\n",
nid);
- fsck_failed_reconnect_file(sbi, nid);
+ fsck_disconnect_file(sbi, nid, false);
continue;
}
diff --git a/fsck/fsck.h b/fsck/fsck.h
index 091b5d8..c25f381 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -330,6 +330,8 @@ struct hardlink_cache_entry *f2fs_search_hardlink(struct f2fs_sb_info *sbi,
struct dentry *de);
/* xattr.c */
-void *read_all_xattrs(struct f2fs_sb_info *, struct f2fs_node *);
+void *read_all_xattrs(struct f2fs_sb_info *, struct f2fs_node *, bool);
+void write_all_xattrs(struct f2fs_sb_info *sbi,
+ struct f2fs_node *inode, __u32 hsize, void *txattr_addr);
#endif /* _FSCK_H_ */
diff --git a/fsck/mount.c b/fsck/mount.c
index 9d786ea..3b02d73 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -370,7 +370,7 @@ void print_inode_info(struct f2fs_sb_info *sbi,
DISP_u32(F2FS_INODE_NIDS(inode), i_nid[3]); /* indirect */
DISP_u32(F2FS_INODE_NIDS(inode), i_nid[4]); /* double indirect */
- xattr_addr = read_all_xattrs(sbi, node);
+ xattr_addr = read_all_xattrs(sbi, node, true);
if (!xattr_addr)
goto out;
@@ -716,6 +716,7 @@ static char *errors_str[] = {
[ERROR_CORRUPTED_VERITY_XATTR] = "corrupted_verity_xattr",
[ERROR_CORRUPTED_XATTR] = "corrupted_xattr",
[ERROR_INVALID_NODE_REFERENCE] = "invalid_node_reference",
+ [ERROR_INCONSISTENT_NAT] = "inconsistent_nat",
};
void print_sb_errors(struct f2fs_super_block *sb)
diff --git a/fsck/segment.c b/fsck/segment.c
index 3a9500f..4b05fd4 100644
--- a/fsck/segment.c
+++ b/fsck/segment.c
@@ -36,7 +36,7 @@ int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
ERR_MSG("Not enough space\n");
return -ENOSPC;
}
- if (is_node && fsck->chk.valid_node_cnt >=
+ if (is_node && fsck->chk.valid_node_cnt >
sbi->total_valid_node_count) {
ERR_MSG("Not enough space for node block\n");
return -ENOSPC;
@@ -76,7 +76,7 @@ int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
offset = OFFSET_IN_SEG(sbi, blkaddr);
- se->type = type;
+ se->type = se->orig_type = type;
if (se->valid_blocks == 0)
SM_I(sbi)->free_segments--;
se->valid_blocks++;
@@ -101,6 +101,7 @@ int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
if (c.func == FSCK) {
fsck->chk.valid_blk_cnt++;
if (is_node) {
+ fsck->chk.valid_nat_entry_cnt++;
fsck->chk.valid_node_cnt++;
if (is_inode)
fsck->chk.valid_inode_cnt++;
diff --git a/fsck/xattr.c b/fsck/xattr.c
index fe28437..9ccf361 100644
--- a/fsck/xattr.c
+++ b/fsck/xattr.c
@@ -17,14 +17,15 @@
#include "node.h"
#include "xattr.h"
-void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode)
+void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode,
+ bool sanity_check)
{
struct f2fs_xattr_header *header;
void *txattr_addr;
u64 inline_size = inline_xattr_size(&inode->i);
nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid);
- if (c.func == FSCK && xnid) {
+ if (c.func == FSCK && xnid && sanity_check) {
if (fsck_sanity_check_nid(sbi, xnid, F2FS_FT_XATTR, TYPE_XATTR))
return NULL;
}
@@ -78,7 +79,7 @@ static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
return entry;
}
-static void write_all_xattrs(struct f2fs_sb_info *sbi,
+void write_all_xattrs(struct f2fs_sb_info *sbi,
struct f2fs_node *inode, __u32 hsize, void *txattr_addr)
{
void *xattr_addr;
@@ -165,7 +166,7 @@ int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *na
ret = dev_read_block(inode, ni.blk_addr);
ASSERT(ret >= 0);
- base_addr = read_all_xattrs(sbi, inode);
+ base_addr = read_all_xattrs(sbi, inode, true);
ASSERT(base_addr);
last_base_addr = (void *)base_addr + XATTR_SIZE(&inode->i);
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 772a6a5..abd5abf 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -741,6 +741,7 @@ enum f2fs_error {
ERROR_CORRUPTED_VERITY_XATTR,
ERROR_CORRUPTED_XATTR,
ERROR_INVALID_NODE_REFERENCE,
+ ERROR_INCONSISTENT_NAT,
ERROR_MAX,
};
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 74e5f3a..39d3777 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -246,7 +246,7 @@ static inline long dcache_relocate(long entry, int n)
dcache_config.num_cache_entry;
}
-static long dcache_find(off_t blk)
+static long dcache_find(__u64 blk)
{
register long n = dcache_config.num_cache_entry;
register unsigned m = dcache_config.max_hash_collision;
@@ -267,8 +267,13 @@ static long dcache_find(off_t blk)
}
/* Physical read into cache */
-static int dcache_io_read(int fd, long entry, off_t offset, off_t blk)
+static int dcache_io_read(long entry, __u64 offset, off_t blk)
{
+ int fd = __get_device_fd(&offset);
+
+ if (fd < 0)
+ return fd;
+
if (lseek(fd, offset, SEEK_SET) < 0) {
MSG(0, "\n lseek fail.\n");
return -1;
@@ -297,12 +302,11 @@ static int dcache_io_read(int fd, long entry, off_t offset, off_t blk)
* 1: cache not available (uninitialized)
* -1: error
*/
-static int dcache_update_rw(int fd, void *buf, off_t offset,
+static int dcache_update_rw(void *buf, __u64 offset,
size_t byte_count, bool is_write)
{
- off_t blk;
+ __u64 blk, start;
int addr_in_blk;
- off_t start;
if (!dcache_initialized)
dcache_init(); /* auto initialize */
@@ -337,7 +341,7 @@ static int dcache_update_rw(int fd, void *buf, off_t offset,
if (dcache_valid[entry])
++dcache_rreplace;
/* read: physical I/O read into cache */
- err = dcache_io_read(fd, entry, start, blk);
+ err = dcache_io_read(entry, start, blk);
if (err)
return err;
}
@@ -366,15 +370,15 @@ static int dcache_update_rw(int fd, void *buf, off_t offset,
* return value: 1: cache not available
* 0: success, -1: I/O error
*/
-int dcache_update_cache(int fd, void *buf, off_t offset, size_t count)
+int dcache_update_cache(void *buf, __u64 offset, size_t count)
{
- return dcache_update_rw(fd, buf, offset, count, true);
+ return dcache_update_rw(buf, offset, count, true);
}
/* handles read into cache + read into buffer */
-int dcache_read(int fd, void *buf, off_t offset, size_t count)
+int dcache_read(void *buf, __u64 offset, size_t count)
{
- return dcache_update_rw(fd, buf, offset, count, false);
+ return dcache_update_rw(buf, offset, count, false);
}
/*
@@ -517,15 +521,15 @@ int dev_read(void *buf, __u64 offset, size_t len)
return sparse_read_blk(offset / F2FS_BLKSIZE,
len / F2FS_BLKSIZE, buf);
- fd = __get_device_fd(&offset);
- if (fd < 0)
- return fd;
-
/* err = 1: cache not available, fall back to non-cache R/W */
/* err = 0: success, err=-1: I/O error */
- err = dcache_read(fd, buf, (off_t)offset, len);
+ err = dcache_read(buf, offset, len);
if (err <= 0)
return err;
+
+ fd = __get_device_fd(&offset);
+ if (fd < 0)
+ return fd;
if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
return -1;
if (read(fd, buf, len) < 0)
@@ -561,16 +565,17 @@ int dev_write(void *buf, __u64 offset, size_t len)
return sparse_write_blk(offset / F2FS_BLKSIZE,
len / F2FS_BLKSIZE, buf);
- fd = __get_device_fd(&offset);
- if (fd < 0)
- return fd;
-
/*
* dcache_update_cache() just update cache, won't do I/O.
* Thus even no error, we need normal non-cache I/O for actual write
*/
- if (dcache_update_cache(fd, buf, (off_t)offset, len) < 0)
+ if (dcache_update_cache(buf, offset, len) < 0)
return -1;
+
+ fd = __get_device_fd(&offset);
+ if (fd < 0)
+ return fd;
+
if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
return -1;
if (write(fd, buf, len) < 0)
diff --git a/tools/f2fs_io/f2fs_io.c b/tools/f2fs_io/f2fs_io.c
index c812aa1..e7d286a 100644
--- a/tools/f2fs_io/f2fs_io.c
+++ b/tools/f2fs_io/f2fs_io.c
@@ -35,6 +35,7 @@
#include <termios.h>
#include <time.h>
#include <unistd.h>
+#include <sys/xattr.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -1526,6 +1527,109 @@ static void do_gc_range(int argc, char **argv, const struct cmd_desc *cmd)
exit(0);
}
+#define listxattr_desc "listxattr"
+#define listxattr_help "f2fs_io listxattr [file_path]\n\n"
+
+static void do_listxattr(int argc, char **argv, const struct cmd_desc *cmd)
+{
+ char *buf, *key, *val;
+ ssize_t buflen, vallen, keylen;
+
+ if (argc != 2) {
+ fputs("Excess arguments\n\n", stderr);
+ fputs(cmd->cmd_help, stderr);
+ exit(1);
+ }
+
+ buflen = listxattr(argv[1], NULL, 0);
+ if (buflen == -1) {
+ perror("listxattr");
+ exit(1);
+ }
+ if (buflen == 0) {
+ printf("%s has no attributes.\n", argv[1]);
+ exit(0);
+ }
+ buf = xmalloc(buflen);
+ buflen = listxattr(argv[1], buf, buflen);
+ if (buflen == -1) {
+ perror("listxattr");
+ exit(1);
+ }
+
+ key = buf;
+ while (buflen > 0) {
+ printf("%s: ", key);
+ vallen = getxattr(argv[1], key, NULL, 0);
+ if (vallen == -1) {
+ perror("getxattr");
+ exit(1);
+ }
+ if (vallen == 0) {
+ printf("<no value>");
+ } else {
+ val = xmalloc(vallen + 1);
+ vallen = getxattr(argv[1], key, val, vallen);
+ if (vallen == -1) {
+ perror("getxattr");
+ exit(1);
+ }
+ val[vallen] = 0;
+ printf("%s", val);
+ free(val);
+ }
+ printf("\n");
+ keylen = strlen(key) + 1;
+ buflen -= keylen;
+ key += keylen;
+ }
+ exit(0);
+}
+
+#define setxattr_desc "setxattr"
+#define setxattr_help "f2fs_io setxattr [name] [value] [file_path]\n\n"
+
+static void do_setxattr(int argc, char **argv, const struct cmd_desc *cmd)
+{
+ int ret;
+
+ if (argc != 4) {
+ fputs("Excess arguments\n\n", stderr);
+ fputs(cmd->cmd_help, stderr);
+ exit(1);
+ }
+
+ ret = setxattr(argv[3], argv[1], argv[2], strlen(argv[2]), XATTR_CREATE);
+ printf("setxattr %s CREATE: name: %s, value: %s: ret=%d\n",
+ argv[3], argv[1], argv[2], ret);
+ if (ret < 0 && errno == EEXIST) {
+ ret = setxattr(argv[3], argv[1], argv[2], strlen(argv[2]), XATTR_REPLACE);
+ printf("setxattr %s REPLACE: name: %s, value: %s: ret=%d\n",
+ argv[3], argv[1], argv[2], ret);
+ }
+ if (ret < 0)
+ perror("setxattr");
+ exit(0);
+}
+
+#define removexattr_desc "removexattr"
+#define removexattr_help "f2fs_io removexattr [name] [file_path]\n\n"
+
+static void do_removexattr(int argc, char **argv, const struct cmd_desc *cmd)
+{
+ int ret;
+
+ if (argc != 3) {
+ fputs("Excess arguments\n\n", stderr);
+ fputs(cmd->cmd_help, stderr);
+ exit(1);
+ }
+
+ ret = removexattr(argv[2], argv[1]);
+ printf("removexattr %s REMOVE: name: %s: ret=%d\n", argv[1], argv[2], ret);
+ exit(0);
+}
+
#define CMD_HIDDEN 0x0001
#define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
#define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
@@ -1564,6 +1668,9 @@ const struct cmd_desc cmd_list[] = {
CMD(precache_extents),
CMD(move_range),
CMD(gc_range),
+ CMD(listxattr),
+ CMD(setxattr),
+ CMD(removexattr),
{ NULL, NULL, NULL, NULL, 0 }
};