}
-void make_dentry_ptr(struct f2fs_dentry_ptr *d, void *src, int type)
+void make_dentry_ptr(struct f2fs_dentry_ptr *d, struct f2fs_node *node_blk,
+ void *src, int type)
{
if (type == 1) {
struct f2fs_dentry_block *t = (struct f2fs_dentry_block *)src;
d->dentry = t->dentry;
d->filename = t->filename;
} else {
- struct f2fs_inline_dentry *t = (struct f2fs_inline_dentry *)src;
- d->max = NR_INLINE_DENTRY;
- d->nr_bitmap = INLINE_DENTRY_BITMAP_SIZE;
- d->bitmap = t->dentry_bitmap;
- d->dentry = t->dentry;
- d->filename = t->filename;
+ int entry_cnt = NR_INLINE_DENTRY(node_blk);
+ int bitmap_size = INLINE_DENTRY_BITMAP_SIZE(node_blk);
+ int reserved_size = INLINE_RESERVED_SIZE(node_blk);
+
+ d->max = entry_cnt;
+ d->nr_bitmap = bitmap_size;
+ d->bitmap = src;
+ d->dentry = src + bitmap_size + reserved_size;
+ d->filename = src + bitmap_size + reserved_size +
+ SIZE_OF_DIR_ENTRY * entry_cnt;
}
}
{
struct f2fs_dentry_ptr d;
- make_dentry_ptr(&d, block, 1);
+ make_dentry_ptr(&d, NULL, block, 1);
return find_target_dentry(name, len, namehash, max_slots, &d);
}
goto start;
add_dentry:
- make_dentry_ptr(&d, (void *)dentry_blk, 1);
+ make_dentry_ptr(&d, NULL, (void *)dentry_blk, 1);
f2fs_update_dentry(ino, file_type, &d, name, name_len, dentry_hash, bit_pos);
ret = dev_write_block(dentry_blk, dn.data_blkaddr);
ret = dev_write_block(dent_blk, blkaddr);
ASSERT(ret >= 0);
- inode->i.i_addr[0] = cpu_to_le32(blkaddr);
+ inode->i.i_addr[get_extra_isize(inode)] = cpu_to_le32(blkaddr);
free(dent_blk);
}
get_node_info(sbi, ino, &ni);
/* store into inline_data */
- if (symlen + 1 <= MAX_INLINE_DATA) {
+ if (symlen + 1 <= MAX_INLINE_DATA(inode)) {
inode->i.i_inline |= F2FS_INLINE_DATA;
inode->i.i_inline |= F2FS_DATA_EXIST;
- memcpy(&inode->i.i_addr[1], symname, symlen);
+ memcpy(inline_data_addr(inode), symname, symlen);
return;
}
ret = dev_write_block(data_blk, blkaddr);
ASSERT(ret >= 0);
- inode->i.i_addr[0] = cpu_to_le32(blkaddr);
+ inode->i.i_addr[get_extra_isize(inode)] = cpu_to_le32(blkaddr);
free(data_blk);
}
ASSERT(de->link);
mode |= S_IFLNK;
size = strlen(de->link);
- if (size + 1 > MAX_INLINE_DATA)
+ if (size + 1 > MAX_INLINE_DATA(node_blk))
blocks++;
} else {
ASSERT(0);
memcpy(node_blk->i.i_name, de->name, de->len);
node_blk->i.i_name[de->len] = 0;
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
+ node_blk->i.i_inline |= F2FS_EXTRA_ATTR;
+ node_blk->i.i_extra_isize =
+ cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE);
+ }
+
node_blk->footer.ino = cpu_to_le32(de->ino);
node_blk->footer.nid = cpu_to_le32(de->ino);
node_blk->footer.flag = 0;
struct f2fs_inode *inode = &(node->i);
unsigned int dir_level = node->i.i_dir_level;
nid_t ino = le32_to_cpu(node->footer.ino);
- char inline_data[MAX_INLINE_DATA];
+ char inline_data[MAX_INLINE_DATA(node)];
struct dnode_of_data dn = {0};
struct f2fs_dentry_ptr d;
unsigned long bit_pos = 0;
if (!(inode->i_inline & F2FS_INLINE_DENTRY))
return 0;
- memcpy(inline_data, inline_data_addr(node), MAX_INLINE_DATA);
- memset(inline_data_addr(node), 0, MAX_INLINE_DATA);
+ memcpy(inline_data, inline_data_addr(node), MAX_INLINE_DATA(node));
+ memset(inline_data_addr(node), 0, MAX_INLINE_DATA(node));
inode->i_inline &= ~F2FS_INLINE_DENTRY;
ret = dev_write_block(node, p_blkaddr);
if (dn.data_blkaddr == NULL_ADDR)
new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA);
- make_dentry_ptr(&src, (void *)inline_data, 2);
- make_dentry_ptr(&dst, (void *)dentry_blk, 1);
+ make_dentry_ptr(&src, node, (void *)inline_data, 2);
+ make_dentry_ptr(&dst, NULL, (void *)dentry_blk, 1);
/* copy data from inline dentry block to new dentry block */
memcpy(dst.bitmap, src.bitmap, src.nr_bitmap);
}
make_empty_dir(sbi, node);
- make_dentry_ptr(&d, (void *)inline_data, 2);
+ make_dentry_ptr(&d, node, (void *)inline_data, 2);
while (bit_pos < d.max) {
struct f2fs_dir_entry *de;
DBG(3, "ino[0x%x] has inline data!\n", nid);
/* recover from inline data */
dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
- 0, MAX_INLINE_DATA);
+ 0, MAX_INLINE_DATA(node_blk));
return;
}
/* check data blocks in inode */
for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
- dump_data_blk(sbi, ofs * F2FS_BLKSIZE,
- le32_to_cpu(node_blk->i.i_addr[i]));
+ dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
+ node_blk->i.i_addr[get_extra_isize(node_blk) + i]));
/* check node blocks in inode */
for (i = 0; i < 5; i++) {
static inline void *inline_data_addr(struct f2fs_node *node_blk)
{
- return (void *)&(node_blk->i.i_addr[1]);
+ int ofs = get_extra_isize(node_blk) + DEF_INLINE_RESERVED_SIZE;
+
+ return (void *)&(node_blk->i.i_addr[ofs]);
}
static inline unsigned int ofs_of_node(struct f2fs_node *node_blk)
goto out;
/* check its block address */
- if (node_blk->footer.nid == node_blk->footer.ino)
- target_blk_addr = node_blk->i.i_addr[ofs_in_node];
- else
+ if (node_blk->footer.nid == node_blk->footer.ino) {
+ int ofs = get_extra_isize(node_blk);
+
+ target_blk_addr = node_blk->i.i_addr[ofs + ofs_in_node];
+ } else {
target_blk_addr = node_blk->dn.addr[ofs_in_node];
+ }
if (blk_addr == le32_to_cpu(target_blk_addr))
ret = 1;
goto check;
if((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
- if (le32_to_cpu(node_blk->i.i_addr[0]) != 0) {
+ int ofs = get_extra_isize(node_blk);
+
+ if (le32_to_cpu(node_blk->i.i_addr[ofs]) != 0) {
/* should fix this bug all the time */
FIX_MSG("inline_data has wrong 0'th block = %x",
- le32_to_cpu(node_blk->i.i_addr[0]));
- node_blk->i.i_addr[0] = 0;
+ le32_to_cpu(node_blk->i.i_addr[ofs]));
+ node_blk->i.i_addr[ofs] = 0;
node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
need_fix = 1;
}
if (!(node_blk->i.i_inline & F2FS_DATA_EXIST)) {
- char buf[MAX_INLINE_DATA];
- memset(buf, 0, MAX_INLINE_DATA);
+ char buf[MAX_INLINE_DATA(node_blk)];
+ memset(buf, 0, MAX_INLINE_DATA(node_blk));
- if (memcmp(buf, &node_blk->i.i_addr[1],
- MAX_INLINE_DATA)) {
+ if (memcmp(buf, inline_data_addr(node_blk),
+ MAX_INLINE_DATA(node_blk))) {
FIX_MSG("inline_data has DATA_EXIST");
node_blk->i.i_inline |= F2FS_DATA_EXIST;
need_fix = 1;
/* check data blocks in inode */
for (idx = 0; idx < ADDRS_PER_INODE(&node_blk->i);
idx++, child.pgofs++) {
- block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[idx]);
+ int ofs = get_extra_isize(node_blk);
+ block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[ofs + idx]);
/* check extent info */
check_extent_info(&child, blkaddr, 0);
if (!ret) {
*blk_cnt = *blk_cnt + 1;
} else if (c.fix_on) {
- node_blk->i.i_addr[idx] = 0;
+ node_blk->i.i_addr[ofs + idx] = 0;
need_fix = 1;
- FIX_MSG("[0x%x] i_addr[%d] = 0", nid, idx);
+ FIX_MSG("[0x%x] i_addr[%d] = 0",
+ nid, ofs + idx);
}
}
}
inline_dentry = inline_data_addr(node_blk);
ASSERT(inline_dentry != NULL);
- make_dentry_ptr(&d, inline_dentry, 2);
+ make_dentry_ptr(&d, node_blk, inline_dentry, 2);
fsck->dentry_depth++;
dentries = __chk_dentries(sbi, child,
struct dnode_of_data *, unsigned int);
void get_dnode_of_data(struct f2fs_sb_info *, struct dnode_of_data *,
pgoff_t, int);
-void make_dentry_ptr(struct f2fs_dentry_ptr *, void *, int);
+void make_dentry_ptr(struct f2fs_dentry_ptr *, struct f2fs_node *, void *, int);
int f2fs_create(struct f2fs_sb_info *, struct dentry *);
int f2fs_mkdir(struct f2fs_sb_info *, struct dentry *);
int f2fs_symlink(struct f2fs_sb_info *, struct dentry *);
unsigned int i = 0;
int namelen = le32_to_cpu(inode->i_namelen);
int enc_name = file_enc_name(inode);
+ int ofs = __get_extra_isize(inode);
namelen = convert_encrypted_name(inode->i_name, namelen, en, enc_name);
en[namelen] = '\0';
le32_to_cpu(inode->i_ext.blk_addr),
le32_to_cpu(inode->i_ext.len));
- DISP_u32(inode, i_addr[0]); /* Pointers to data blocks */
- DISP_u32(inode, i_addr[1]); /* Pointers to data blocks */
- DISP_u32(inode, i_addr[2]); /* Pointers to data blocks */
- DISP_u32(inode, i_addr[3]); /* Pointers to data blocks */
+ DISP_u16(inode, i_extra_isize);
+ DISP_u16(inode, i_padding);
- for (i = 4; i < ADDRS_PER_INODE(inode); i++) {
+ DISP_u32(inode, i_addr[ofs]); /* Pointers to data blocks */
+ DISP_u32(inode, i_addr[ofs + 1]); /* Pointers to data blocks */
+ DISP_u32(inode, i_addr[ofs + 2]); /* Pointers to data blocks */
+ DISP_u32(inode, i_addr[ofs + 3]); /* Pointers to data blocks */
+
+ for (i = ofs + 4; i < ADDRS_PER_INODE(inode); i++) {
if (inode->i_addr[i] != 0x0) {
printf("i_addr[0x%x] points data block\r\t\t[0x%4x]\n",
i, le32_to_cpu(inode->i_addr[i]));
if (f & cpu_to_le32(F2FS_FEATURE_BLKZONED)) {
MSG(0, "%s", " zoned block device");
}
+ if (f & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
+ MSG(0, "%s", " extra attribute");
+ }
MSG(0, "\n");
MSG(0, "Info: superblock encrypt level = %d, salt = ",
sb->encryption_level);
/* check its block address */
if (node_blk->footer.nid == node_blk->footer.ino) {
- oldaddr = le32_to_cpu(node_blk->i.i_addr[ofs_in_node]);
- node_blk->i.i_addr[ofs_in_node] = cpu_to_le32(newaddr);
+ int ofs = get_extra_isize(node_blk);
+
+ oldaddr = le32_to_cpu(node_blk->i.i_addr[ofs + ofs_in_node]);
+ node_blk->i.i_addr[ofs + ofs_in_node] = cpu_to_le32(newaddr);
} else {
oldaddr = le32_to_cpu(node_blk->dn.addr[ofs_in_node]);
node_blk->dn.addr[ofs_in_node] = cpu_to_le32(newaddr);
*
* By default, it sets inline_xattr and inline_data
*/
-static int get_node_path(unsigned long block,
+static int get_node_path(struct f2fs_node *node, unsigned long block,
int offset[4], unsigned int noffset[4])
{
- const long direct_index = DEF_ADDRS_PER_INODE_INLINE_XATTR;
+ const long direct_index = ADDRS_PER_INODE(&node->i);
const long direct_blks = ADDRS_PER_BLOCK;
const long dptrs_per_blk = NIDS_PER_BLOCK;
const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
int level, i;
int ret;
- level = get_node_path(index, offset, noffset);
+ level = get_node_path(dn->inode_blk, index, offset, noffset);
nids[0] = dn->nid;
parent = dn->inode_blk;
return ((node)->footer.nid == (node)->footer.ino);
}
+static inline __le32 *blkaddr_in_inode(struct f2fs_node *node)
+{
+ return node->i.i_addr + get_extra_isize(node);
+}
+
static inline __le32 *blkaddr_in_node(struct f2fs_node *node)
{
- return IS_INODE(node) ? node->i.i_addr : node->dn.addr;
+ return IS_INODE(node) ? blkaddr_in_inode(node) : node->dn.addr;
}
static inline block_t datablock_addr(struct f2fs_node *node_page,
}
/* inline_data support */
- if (de->size <= MAX_INLINE_DATA) {
+ if (de->size <= DEF_MAX_INLINE_DATA) {
struct node_info ni;
struct f2fs_node *node_blk;
int ret;
node_blk->i.i_inline |= F2FS_INLINE_DATA;
node_blk->i.i_inline |= F2FS_DATA_EXIST;
+
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
+ node_blk->i.i_inline |= F2FS_EXTRA_ATTR;
+ node_blk->i.i_extra_isize =
+ cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE);
+ }
n = read(fd, buffer, BLOCK_SZ);
ASSERT(n == de->size);
- memcpy(&node_blk->i.i_addr[1], buffer, de->size);
+ memcpy(inline_data_addr(node_blk), buffer, de->size);
node_blk->i.i_size = cpu_to_le64(de->size);
printf("%-30s" fmt, #member, ((ptr)->member)); \
} while (0)
+#define DISP_u16(ptr, member) \
+ do { \
+ assert(sizeof((ptr)->member) == 2); \
+ printf("%-30s" "\t\t[0x%8x : %u]\n", \
+ #member, le16_to_cpu(((ptr)->member)), \
+ le16_to_cpu(((ptr)->member))); \
+ } while (0)
+
#define DISP_u32(ptr, member) \
do { \
assert(sizeof((ptr)->member) <= 4); \
#define F2FS_FEATURE_ENCRYPT 0x0001
#define F2FS_FEATURE_BLKZONED 0x0002
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
+#define F2FS_FEATURE_EXTRA_ATTR 0x0008
#define MAX_VOLUME_NAME 512
#define F2FS_NAME_LEN 255
#define F2FS_INLINE_XATTR_ADDRS 50 /* 200 bytes for inline xattrs */
#define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */
+#define CUR_ADDRS_PER_INODE(inode) (DEF_ADDRS_PER_INODE - \
+ __get_extra_isize(inode))
#define ADDRS_PER_INODE(i) addrs_per_inode(i)
#define DEF_ADDRS_PER_INODE_INLINE_XATTR \
(DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS)
#define F2FS_INLINE_DENTRY 0x04 /* file inline dentry flag */
#define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */
#define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */
+#define F2FS_EXTRA_ATTR 0x20 /* file having extra attribute */
-#define MAX_INLINE_DATA (sizeof(__le32) * \
- (DEF_ADDRS_PER_INODE_INLINE_XATTR - 1))
+#if !defined(offsetof)
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+#define F2FS_TOTAL_EXTRA_ATTR_SIZE \
+ (offsetof(struct f2fs_inode, i_extra_end) - \
+ offsetof(struct f2fs_inode, i_extra_isize)) \
+
+#define MAX_INLINE_DATA(node) (sizeof(__le32) * \
+ (DEF_ADDRS_PER_INODE_INLINE_XATTR - \
+ get_extra_isize(node) - \
+ DEF_INLINE_RESERVED_SIZE))
+#define DEF_MAX_INLINE_DATA (sizeof(__le32) * \
+ (DEF_ADDRS_PER_INODE_INLINE_XATTR - \
+ F2FS_TOTAL_EXTRA_ATTR_SIZE - \
+ DEF_INLINE_RESERVED_SIZE))
#define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer) \
- - sizeof(__le32)*(DEF_ADDRS_PER_INODE + 5 - 1))
+ - sizeof(__le32)*(DEF_ADDRS_PER_INODE + 5 - \
+ DEF_INLINE_RESERVED_SIZE))
#define DEF_DIR_LEVEL 0
struct f2fs_extent i_ext; /* caching a largest extent */
- __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
-
+ union {
+ struct {
+ __le16 i_extra_isize; /* extra inode attribute size */
+ __le16 i_padding; /* padding */
+ __le32 i_extra_end[0]; /* for attribute size calculation */
+ };
+ __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
+ };
__le32 i_nid[5]; /* direct(2), indirect(2),
double_indirect(1) node id */
} __attribute__((packed));
__u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN];
} __attribute__((packed));
+/* for inline stuff */
+#define DEF_INLINE_RESERVED_SIZE 1
+
/* for inline dir */
-#define NR_INLINE_DENTRY (MAX_INLINE_DATA * BITS_PER_BYTE / \
+#define NR_INLINE_DENTRY(node) (MAX_INLINE_DATA(node) * BITS_PER_BYTE / \
((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
BITS_PER_BYTE + 1))
-#define INLINE_DENTRY_BITMAP_SIZE ((NR_INLINE_DENTRY + \
+#define INLINE_DENTRY_BITMAP_SIZE(node) ((NR_INLINE_DENTRY(node) + \
BITS_PER_BYTE - 1) / BITS_PER_BYTE)
-#define INLINE_RESERVED_SIZE (MAX_INLINE_DATA - \
+#define INLINE_RESERVED_SIZE(node) (MAX_INLINE_DATA(node) - \
((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
- NR_INLINE_DENTRY + INLINE_DENTRY_BITMAP_SIZE))
-
-/* inline directory entry structure */
-struct f2fs_inline_dentry {
- __u8 dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE];
- __u8 reserved[INLINE_RESERVED_SIZE];
- struct f2fs_dir_entry dentry[NR_INLINE_DENTRY];
- __u8 filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN];
-} __attribute__((packed));
+ NR_INLINE_DENTRY(node) + \
+ INLINE_DENTRY_BITMAP_SIZE(node)))
/* file types used in inode_info->flags */
enum FILE_TYPE {
extern void get_kernel_version(__u8 *);
f2fs_hash_t f2fs_dentry_hash(const unsigned char *, int);
+static inline bool f2fs_has_extra_isize(struct f2fs_inode *inode)
+{
+ return (inode->i_inline & F2FS_EXTRA_ATTR);
+}
+
+static inline int __get_extra_isize(struct f2fs_inode *inode)
+{
+ if (f2fs_has_extra_isize(inode))
+ return le16_to_cpu(inode->i_extra_isize) / sizeof(__le32);
+ return 0;
+}
+
+#define get_extra_isize(node) __get_extra_isize(&node->i)
+
#define F2FS_ZONED_NONE 0
#define F2FS_ZONED_HA 1
#define F2FS_ZONED_HM 2
unsigned int addrs_per_inode(struct f2fs_inode *i)
{
if (i->i_inline & F2FS_INLINE_XATTR)
- return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
- return DEF_ADDRS_PER_INODE;
+ return CUR_ADDRS_PER_INODE(i) - F2FS_INLINE_XATTR_ADDRS;
+ return CUR_ADDRS_PER_INODE(i);
}
/*
raw_node->i.i_current_depth = cpu_to_le32(1);
raw_node->i.i_dir_level = DEF_DIR_LEVEL;
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
+ raw_node->i.i_inline = F2FS_EXTRA_ATTR;
+ raw_node->i.i_extra_isize =
+ cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE);
+ }
+
data_blk_nor = get_sb(main_blkaddr) +
c.cur_seg[CURSEG_HOT_DATA] * c.blks_per_seg;
- raw_node->i.i_addr[0] = cpu_to_le32(data_blk_nor);
+ raw_node->i.i_addr[get_extra_isize(raw_node)] = cpu_to_le32(data_blk_nor);
raw_node->i.i_ext.fofs = 0;
raw_node->i.i_ext.blk_addr = 0;
features++;
if (!strcmp(features, "encrypt")) {
c.feature |= cpu_to_le32(F2FS_FEATURE_ENCRYPT);
+ } else if (!strcmp(features, "extra_attr")) {
+ c.feature |= cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR);
} else {
MSG(0, "Error: Wrong features\n");
mkfs_usage();