[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] F2FS support
From: |
Jaegeuk Kim |
Subject: |
Re: [PATCH] F2FS support |
Date: |
Fri, 3 Apr 2015 15:48:22 -0700 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
Hi Andrei,
On Sat, Mar 28, 2015 at 10:31:55AM +0300, Andrei Borzenkov wrote:
> В Tue, 24 Mar 2015 01:19:00 -0700
> Jaegeuk Kim <address@hidden> пишет:
>
...
> > +/* byte-size offset */
> > +#define F2FS_SUPER_OFFSET 1024
> > +
> > +/* 12 bits for 4096 bytes */
> > +#define F2FS_MAX_LOG_SECTOR_SIZE 12
> > +
> > +/* 9 bits for 512 bytes */
> > +#define F2FS_MIN_LOG_SECTOR_SIZE 9
> > +
> > +/* support only 4KB block */
> > +#define F2FS_BLKSIZE 4096
>
> (2 << F2FS_BLK_BITS)?
>
> > +#define F2FS_BLK_BITS 12
> > +#define F2FS_BLK_SEC_BITS (3)
>
>
> It is confusing to have some defines parenthesized and some not. Could
> it be unified somehow?
>
> Also this can be computed from F2FS_BLK_BITS and GRUB_DISK_SECTOR_BITS
> - one magic number less.
Fixed.
>
> ...
> > +struct grub_f2fs_inline_dentry
> > +{
> > + grub_uint8_t dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE];
>
> This is cast to grub_uint32_t everywhere. Can it be non-multiple of 4
> bytes? If not, may be just define as such?
I remained this, since this can be non-multiple of 4 bytes.
>
> > + grub_uint8_t reserved[INLINE_RESERVED_SIZE];
> > + struct grub_f2fs_dir_entry dentry[NR_INLINE_DENTRY];
> > + grub_uint8_t filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN];
> > +} GRUB_PACKED;
> > +
...
> > +
> > +#define ver_after (a, b) (typecheck (unsigned long long, a) && \
> > + typecheck (unsigned long long, b) && \
> > + ((long long)((a) - (b)) > 0))
> > +
>
> Where typecheck definition comes from?
Removed this.
>
> ...
> > +
> > +static inline int
> > +__test_bit (int nr, grub_uint32_t *addr)
> > +{
> > + return 1UL & (addr[nr / 32] >> (nr & (31)));
> Extra parenthesis (31)
Fixed.
>
> > +}
> > +
>
> It is used for dentry_bitmap which is kept in LE format and not
> converted as far as I can tell. This needs fixing for BE systems. Linux
> kernel is explicitly using test_bit_le here. This will also work for
> inode flags (just skip explicit conversion).
>
> There are two functions with more or less identical names. May be make
> them
>
> grub_f2fs_test_bit_le32
> grub_f2fs_test_bit
>
> As a general comment - marking non-modified arguments as const
> everywhere would be good.
I added:
grub_f2fs_general_test_bit
grub_f2fs_test_bit
Both of them keep bit streams without endian conversion, and the difference is
beyond handling the order of bit stream indices.
>
> > +static inline char *
> > +__inline_addr (struct grub_f2fs_inode *inode)
> > +{
> > + return (char *)&(inode->i_addr[1]);
> Redundant parens around inode->
Fixed.
>
> > +}
> > +
> > +static inline grub_uint64_t
> > +__i_size (struct grub_f2fs_inode *inode)
>
> Could we make it grub_f2fs_file_size or similar? i_size really does not
> tell much outside of linux kernel.
Changed to grub_f2fs_file_size.
>
> > +{
> > + return grub_le_to_cpu64 (inode->i_size);
> > +}
> > +
> > +static inline grub_uint32_t
> > +__start_cp_addr (struct grub_f2fs_data *data)
> > +{
> > + struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
> > + grub_uint64_t ckpt_version = grub_le_to_cpu64 (ckpt->checkpoint_ver);
> > + grub_uint32_t start_addr = data->cp_blkaddr;
> > +
> > + if (!(ckpt_version & 1))
> > + return start_addr + data->blocks_per_seg;
> > + return start_addr;
> > +}
> > +
> > +static inline grub_uint32_t
> > +__start_sum_block (struct grub_f2fs_data *data)
> > +{
> > + struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
> > +
> > + return __start_cp_addr (data) + grub_le_to_cpu32
> > (ckpt->cp_pack_start_sum);
> > +}
> > +
> > +static inline grub_uint32_t
> > +__sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
> > +{
> > + struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
> > +
> > + return __start_cp_addr (data) +
> > + grub_le_to_cpu32 (ckpt->cp_pack_total_block_count)
> > + - (base + 1) + type;
> > +}
> > +
> > +static inline int
> > +__ckpt_flag_set (struct grub_f2fs_checkpoint *ckpt, unsigned int f)
> > +{
> > + grub_uint32_t ckpt_flags = grub_le_to_cpu32 (ckpt->ckpt_flags);
> > + return ckpt_flags & f;
>
> All flags are constant so you can simply do
>
> ckpt->ckpt_flags & grub_cpu_to_le32_compile_time (FLAG)
>
> in place to avoid extra calls. This makes function redundant.
Fixed.
>
> > +}
> > +
> > +static inline int
> > +__inode_flag_set (struct grub_f2fs_inode *inode, int flag)
Fixed to refer i_inline. This was a bug.
...
> > + * CRC32
> > + */
> > +#define CRCPOLY_LE 0xedb88320
> > +
> > +static inline grub_uint32_t
> > +grub_f2fs_cal_crc32 (grub_uint32_t crc, void *buf, int len)
>
> Why crc is parameter here? This function is used exactly once with
> fixed value for initial crc.
Fixed.
>
> > +{
> > + int i;
> > + unsigned char *p = (unsigned char *)buf;
> > +
> > + while (len--)
> > + {
> > + crc ^= *p++;
> > + for (i = 0; i < 8; i++)
> > + crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
> > + }
> > + return crc;
> > +}
> > +
> > +static inline int
> > +grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, int len)
> > +{
> > + grub_uint32_t cal_crc = 0;
> > +
> > + cal_crc = grub_f2fs_cal_crc32 (F2FS_SUPER_MAGIC, buf, len);
> > +
> > + return (cal_crc == blk_crc) ? 1 : 0;
> > +}
> > +
> > +static inline int
> > +grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
> > +{
> > + int mask;
> > + char *addr = (char *)p;
>
> Why cast? We are not going to modify it, right?
Right.
>
> > +
> > + addr += (nr >> 3);
> > + mask = 1 << (7 - (nr & 0x07));
> > + return (mask & *addr) != 0;
> > +}
> > +
> > +static int
> > +grub_f2fs_sanity_check_sb (struct grub_f2fs_superblock *sb)
> > +{
> > + unsigned int blocksize;
> > +
> > + if (F2FS_SUPER_MAGIC != grub_le_to_cpu32 (sb->magic))
>
> sb->magic != grub_cpu_to_le32_compile_time (F2FS_SUPER_MAGIC)
Fixed.
>
> > + return -1;
> > +
> > + blocksize = 1 << grub_le_to_cpu32 (sb->log_blocksize);
> > + if (blocksize != F2FS_BLKSIZE)
>
> sb->log_blksize != grub_cpu_to_le32_compile_time (F2FS_BLK_BITS)
Fixed.
>
> > + return -1;
> > +
> > + if (grub_le_to_cpu32 (sb->log_sectorsize) > F2FS_MAX_LOG_SECTOR_SIZE)
> > + return -1;
> > +
> > + if (grub_le_to_cpu32 (sb->log_sectorsize) < F2FS_MIN_LOG_SECTOR_SIZE)
> > + return -1;
> > +
> > + if (grub_le_to_cpu32 (sb->log_sectors_per_block) +
> > + grub_le_to_cpu32 (sb->log_sectorsize) != F2FS_MAX_LOG_SECTOR_SIZE)
>
> Should not it be F2FS_BLKSIZE? At least it sounds logical. Also please
> convert log_sectorsize just once.
Fixed.
>
> > + return -1;
> > +
> > + return 0;
> > +}
> > +
> > +static grub_err_t
> > +grub_f2fs_read_sb (struct grub_f2fs_data *data, int block)
> > +{
> > + grub_disk_t disk = data->disk;
> > + grub_uint64_t offset;
> > + grub_err_t err;
> > +
> > + if (block == 0)
> > + offset = F2FS_SUPER_OFFSET;
> > + else
> > + offset = F2FS_BLKSIZE + F2FS_SUPER_OFFSET;
> > +
>
> Please name it "secondary" or similar instead of "block" to avoid
> confusion. You do not really want to read arbitrary block, right?
>
> offset = F2FS_SUPER_OFFEST;
> if (secondary)
> offset += F2FS_BLKSIZE;
Fixed as your latest comment.
>
> > + /* Read first super block. */
> > + err = grub_disk_read (disk, offset >> GRUB_DISK_SECTOR_BITS, 0,
> > + sizeof (data->sblock), &data->sblock);
> > + if (err)
> > + return err;
> > +
> > + if (grub_f2fs_sanity_check_sb (&data->sblock))
> > + err = GRUB_ERR_BAD_FS;
> > +
> > + return err;
> > +}
> > +
> > +static void *
> > +validate_checkpoint (struct grub_f2fs_data *data, grub_uint32_t cp_addr,
> > + grub_uint64_t *version)
> > +{
> > + void *cp_page_1, *cp_page_2;
> > + struct grub_f2fs_checkpoint *cp_block;
> > + grub_uint64_t cur_version = 0, pre_version = 0;
> > + grub_uint32_t crc = 0;
> > + grub_uint32_t crc_offset;
> > + grub_err_t err;
> > +
> > + /* Read the 1st cp block in this CP pack */
> > + cp_page_1 = grub_malloc (F2FS_BLKSIZE);
> > + if (!cp_page_1)
> > + return NULL;
> > +
> > + err = grub_f2fs_block_read (data, cp_addr, cp_page_1);
> > + if (err)
> > + goto invalid_cp1;
> > +
> > + cp_block = (struct grub_f2fs_checkpoint *)cp_page_1;
> > + crc_offset = grub_le_to_cpu32 (cp_block->checksum_offset);
> > + if (crc_offset >= F2FS_BLKSIZE)
> > + goto invalid_cp1;
> > +
> > + crc = *(grub_uint32_t *)((char *)cp_block + crc_offset);
>
> Is unaligned access possible here? If yes, it probably should be
> grub_get_unaligned32.
No. It was hard-coded as 4092 from mkfs.
>
> > + if (!grub_f2fs_crc_valid (crc, cp_block, crc_offset))
> > + goto invalid_cp1;
> > +
>
> Should not CRC be converted from LE?
Fixed.
>
> > + pre_version = grub_le_to_cpu64 (cp_block->checkpoint_ver);
> > +
> > + /* Read the 2nd cp block in this CP pack */
> > + cp_page_2 = grub_malloc (F2FS_BLKSIZE);
> > + if (!cp_page_2)
> > + goto invalid_cp1;
> > +
> > + cp_addr += grub_le_to_cpu32 (cp_block->cp_pack_total_block_count) - 1;
> > +
> > + err = grub_f2fs_block_read (data, cp_addr, cp_page_2);
> > + if (err)
> > + goto invalid_cp2;
> > +
> > + cp_block = (struct grub_f2fs_checkpoint *)cp_page_2;
> > + crc_offset = grub_le_to_cpu32 (cp_block->checksum_offset);
> > + if (crc_offset >= F2FS_BLKSIZE)
> > + goto invalid_cp2;
> > +
> > + crc = *(grub_uint32_t *)((char *)cp_block + crc_offset);
>
> Ditto alignment.
>
> > + if (!grub_f2fs_crc_valid (crc, cp_block, crc_offset))
> Ditto endianness.
>
> > + goto invalid_cp2;
> > +
> > + cur_version = grub_le_to_cpu64 (cp_block->checkpoint_ver);
> > + if (cur_version == pre_version)
> > + {
> > + *version = cur_version;
> > + grub_free (cp_page_2);
> > + return cp_page_1;
> > + }
> > +
> > +invalid_cp2:
> > + grub_free (cp_page_2);
> > +invalid_cp1:
> > + grub_free (cp_page_1);
> > + return NULL;
> > +}
> > +
> > +static grub_err_t
> > +grub_f2fs_read_cp (struct grub_f2fs_data *data)
> > +{
> > + void *cp1, *cp2, *cur_page;
> > + grub_uint64_t cp1_version = 0, cp2_version = 0;
> > + grub_uint64_t cp_start_blk_no;
> > +
> > + /*
> > + * Finding out valid cp block involves read both
> > + * sets (cp pack1 and cp pack 2)
> > + */
> > + cp_start_blk_no = data->cp_blkaddr;
> > + cp1 = validate_checkpoint (data, cp_start_blk_no, &cp1_version);
> > + if (!cp1 && grub_errno)
> > + return grub_errno;
> > +
> > + /* The second checkpoint pack should start at the next segment */
> > + cp_start_blk_no += data->blocks_per_seg;
> > + cp2 = validate_checkpoint (data, cp_start_blk_no, &cp2_version);
> > + if (!cp2 && grub_errno)
> > + {
> > + grub_free (cp1);
> > + return grub_errno;
> > + }
> > +
> > + if (cp1 && cp2)
> > + cur_page = (cp2_version > cp1_version) ? cp2 : cp1;
> > + else if (cp1)
> > + cur_page = cp1;
> > + else if (cp2)
> > + cur_page = cp2;
> > + else
> > + return grub_error (GRUB_ERR_BAD_FS, "no checkpoints\n");
> > +
> > + grub_memcpy (&data->ckpt, cur_page, F2FS_BLKSIZE);
> > +
> > + grub_free (cp1);
> > + grub_free (cp2);
> > + return 0;
> > +}
> > +
> > +static int
>
> static grub_error_t
Fixed.
>
> > +get_nat_journal (struct grub_f2fs_data *data)
> > +{
> > + grub_uint32_t block;
> > + char *buf;
> > + grub_err_t err;
> > +
> > + buf = grub_malloc (F2FS_BLKSIZE);
> > + if (!buf)
> > + return grub_errno;
> > +
> > + if (__ckpt_flag_set (&data->ckpt, CP_COMPACT_SUM_FLAG))
> > + block = __start_sum_block (data);
> > + else if (__ckpt_flag_set (&data->ckpt, CP_UMOUNT_FLAG))
>
> As mentioned, use grub_cpu_to_leXX_compile_time to avoid run time
> conversion.
Fixed.
>
> > + block = __sum_blk_addr (data, NR_CURSEG_TYPE, CURSEG_HOT_DATA);
> > + else
> > + block = __sum_blk_addr (data, NR_CURSEG_DATA_TYPE, CURSEG_HOT_DATA);
> > +
> > + err = grub_f2fs_block_read (data, block, buf);
> > + if (err)
> > + goto fail;
> > +
> > + if (__ckpt_flag_set (&data->ckpt, CP_COMPACT_SUM_FLAG))
> > + grub_memcpy (&data->nat_j, buf, SUM_JOURNAL_SIZE);
> > + else
> > + grub_memcpy (&data->nat_j, buf + SUM_ENTRIES_SIZE, SUM_JOURNAL_SIZE);
> > +
> > +fail:
> > + grub_free (buf);
> > + return err;
> > +}
> > +
> ...
> > +static int
> > +grub_get_node_path (struct grub_f2fs_inode *inode, grub_uint32_t block,
> > + grub_uint32_t offset[4], grub_uint32_t noffset[4])
> > +{
> > + grub_uint32_t direct_blks = ADDRS_PER_BLOCK;
> > + grub_uint32_t dptrs_per_blk = NIDS_PER_BLOCK;
> > + grub_uint32_t indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
> > + grub_uint32_t dindirect_blks = indirect_blks * NIDS_PER_BLOCK;
> > + grub_uint32_t direct_index = DEF_ADDRS_PER_INODE;
> > + int n = 0;
> > + int level = 0;
> > +
> > + if (__inode_flag_set (inode, FI_INLINE_XATTR))
> > + direct_index -= F2FS_INLINE_XATTR_ADDRS;
> > +
> > + noffset[0] = 0;
> > +
> > + if (block < direct_index)
> > + {
> > + offset[n] = block;
> > + goto got;
> > + }
> > +
> > + block -= direct_index;
> > + if (block < direct_blks)
> > + {
> > + offset[n++] = NODE_DIR1_BLOCK;
> > + noffset[n] = 1;
> > + offset[n] = block;
> > + level = 1;
> > + goto got;
> > + }
> > +
> > + block -= direct_blks;
> > + if (block < direct_blks)
> > + {
> > + offset[n++] = NODE_DIR2_BLOCK;
> > + noffset[n] = 2;
> > + offset[n] = block;
> > + level = 1;
> > + goto got;
> > + }
> > +
> > + block -= direct_blks;
> > + if (block < indirect_blks)
> > + {
> > + offset[n++] = NODE_IND1_BLOCK;
> > + noffset[n] = 3;
> > + offset[n++] = block / direct_blks;
> > + noffset[n] = 4 + offset[n - 1];
>
> That does not fit. You declared offset and noffset as arrays of four
> elements and pass arrays of four elements; here is out of bound
> access already.
It is not out of bound access, since it decreases *block* at every condition
checks.
This function should hit only one of if {} conditions.
>
> > + offset[n] = block % direct_blks;
> > + level = 2;
> > + goto got;
> > + }
> > +
> > + block -= indirect_blks;
> > + if (block < indirect_blks)
> > + {
> > + offset[n++] = NODE_IND2_BLOCK;
> > + noffset[n] = 4 + dptrs_per_blk;
> > + offset[n++] = block / direct_blks;
> > + noffset[n] = 5 + dptrs_per_blk + offset[n - 1];
> > + offset[n] = block % direct_blks;
> > + level = 2;
> > + goto got;
> > + }
> > +
> > + block -= indirect_blks;
> > + if (block < dindirect_blks)
> > + {
> > + offset[n++] = NODE_DIND_BLOCK;
> > + noffset[n] = 5 + (dptrs_per_blk * 2);
> > + offset[n++] = block / indirect_blks;
> > + noffset[n] = 6 + (dptrs_per_blk * 2) +
> > + offset[n - 1] * (dptrs_per_blk + 1);
> > + offset[n++] = (block / direct_blks) % dptrs_per_blk;
> > + noffset[n] = 7 + (dptrs_per_blk * 2) +
> > + offset[n - 2] * (dptrs_per_blk + 1) +
> > + offset[n - 1];
> > + offset[n] = block % direct_blks;
> > + level = 3;
> > + goto got;
> > + }
> > +got:
> > + return level;
> > +}
> > +
> > +
> > +static grub_err_t
> > +load_nat_info (struct grub_f2fs_data *data)
> > +{
> > + void *version_bitmap;
> > + grub_err_t err;
> > +
> > + data->nat_bitmap = grub_malloc (__nat_bitmap_size (data));
> > + if (!data->nat_bitmap)
> > + return grub_errno;
> > +
> > + version_bitmap = __nat_bitmap_ptr (data);
> > +
> > + /* copy version bitmap */
> > + grub_memcpy (data->nat_bitmap, version_bitmap, __nat_bitmap_size (data));
> > +
>
> Any reason to actually copy it? Why is it not possible to just set
> pointer to source, which is available all the time anyway?
Fixed not to allocate and copying this.
>
> > + err = get_nat_journal (data);
> > + if (err)
> > + grub_free (data->nat_bitmap);
> > +
> > + return err;
> > +}
> > +
> > +static grub_err_t
> > +grub_f2fs_read_node (struct grub_f2fs_data *data,
> > + grub_uint32_t nid, struct grub_f2fs_node *np)
> > +{
> > + grub_uint32_t blkaddr;
> > +
> > + blkaddr = get_node_blkaddr (data, nid);
> > + if (!blkaddr)
> > + return grub_errno;
> > +
> > + return grub_f2fs_block_read (data, blkaddr, np);
>
> Is struct grub_f2fs_node guaranteed to always have the same size as F2FS
> block? Then adding char [F2FS_BLKSIZE] to union to make it obvious is
> better and ensures that it will always be at least this size.
Fixed.
>
> > +}
> > +
> > +static struct grub_f2fs_data *
> > +grub_f2fs_mount (grub_disk_t disk)
> > +{
> > + struct grub_f2fs_data *data;
> > + grub_err_t err;
> > +
> > + data = grub_zalloc (sizeof (*data));
> > + if (!data)
> > + return NULL;
> > +
> > + data->disk = disk;
> > +
> > + err = grub_f2fs_read_sb (data, 0);
> > + if (err)
> > + {
> > + err = grub_f2fs_read_sb (data, 1);
> > + if (err)
> > + {
> > + grub_error (GRUB_ERR_BAD_FS, "not a F2FS filesystem");
>
> May be mentioning that superblock could not be read? In another place
> you already tell that checkpoints could not be found. It helps to
> troubleshoot issues.
Fixed.
>
> > + goto fail;
> > + }
> > + }
> > +
> > + data->root_ino = grub_le_to_cpu32 (data->sblock.root_ino);
> > + data->cp_blkaddr = grub_le_to_cpu32 (data->sblock.cp_blkaddr);
> > + data->nat_blkaddr = grub_le_to_cpu32 (data->sblock.nat_blkaddr);
> > + data->blocks_per_seg = 1 <<
> > + grub_le_to_cpu32 (data->sblock.log_blocks_per_seg);
> > +
> > + err = grub_f2fs_read_cp (data);
> > + if (err)
> > + goto fail;
> > +
> > + err = load_nat_info (data);
> > + if (err)
> > + goto fail;
> > +
> > + data->diropen.data = data;
> > + data->diropen.ino = data->root_ino;
> > + data->diropen.inode_read = 1;
> > + data->inode = &data->diropen.inode;
> > +
> > + err = grub_f2fs_read_node (data, data->root_ino, data->inode);
> > + if (err)
> > + goto fail;
> > +
> > + return data;
> > +
> > +fail:
> > + if (data)
> > + grub_free (data->nat_bitmap);
>
> Double free after load_nat_info failure. Assuming that we do need to
> allocate anything at all (see above).
Removed all grub_frees.
>
> > + grub_free (data);
> > + return NULL;
> > +}
> > +
> > +/* guarantee inline_data was handled by caller */
> > +static grub_disk_addr_t
> > +grub_f2fs_read_block (grub_fshelp_node_t node, grub_disk_addr_t block_ofs)
>
> You have grub_f2fs_read_block and grub_f2fs_block_read. Could we make
> them more different and self-explaining? In particular, this one does
> not read anything, it returns disk address. grub_f2fs_map_file_block?
Good suggestion.
Changed to grub_f2fs_get_block.
>
> > +{
> > + struct grub_f2fs_data *data = node->data;
> > + struct grub_f2fs_inode *inode = &node->inode.i;
> > + grub_uint32_t offset[4], noffset[4], nids[4];
>
> See above about overflow in grub_get_inode_path.
No error.
>
> > + struct grub_f2fs_node *node_block;
> > + grub_uint32_t block_addr = -1;
> > + int level, i;
> > +
> > + level = grub_get_node_path (inode, block_ofs, offset, noffset);
> > + if (level == 0)
> > + return grub_le_to_cpu32 (inode->i_addr[offset[0]]);
> > +
> > + node_block = grub_malloc (F2FS_BLKSIZE);
> > + if (!node_block)
> > + return -1;
> > +
> > + nids[1] = __get_node_id (&node->inode, offset[0], 1);
> > +
> > + /* get indirect or direct nodes */
> > + for (i = 1; i <= level; i++)
> > + {
> > + grub_f2fs_read_node (data, nids[i], node_block);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + if (i < level)
> > + nids[i + 1] = __get_node_id (node_block, offset[i], 0);
> > + }
> > +
> > + block_addr = grub_le_to_cpu32 (node_block->dn.addr[offset[level]]);
> > +fail:
> > + grub_free (node_block);
> > + return block_addr;
> > +}
> > +
> ...
> > +
> > +static char *
> > +grub_f2fs_read_symlink (grub_fshelp_node_t node)
> > +{
> > + char *symlink;
> > + struct grub_fshelp_node *diro = node;
> > +
> > + if (!diro->inode_read)
> > + {
> > + grub_f2fs_read_node (diro->data, diro->ino, &diro->inode);
> > + if (grub_errno)
> > + return 0;
> > + }
> > +
> > + symlink = grub_malloc (__i_size (&diro->inode.i) + 1);
> > + if (!symlink)
> > + return 0;
> > +
> > + grub_f2fs_read_file (diro, 0, 0, 0, __i_size (&diro->inode.i), symlink);
> > + if (grub_errno)
> > + {
> > + grub_free (symlink);
> > + return 0;
> > + }
> > +
>
> What about short read? Is this an error or not?
What is short read?
When I refer the other filesystem, it seems that it doesn't need to return
errors.
>
> > + symlink[__i_size (&diro->inode.i)] = '\0';
> > + return symlink;
> > +}
> > +
> > +static int
> > +grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
> > +{
> > + struct grub_fshelp_node *fdiro;
> > + int i;
> > +
> > + for (i = 0; i < ctx->max;)
> > + {
> > + char filename[F2FS_NAME_LEN + 1];
>
> Could we avoid large stack allocations?
Fixed to allocate dynamically.
>
> > + enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
> > + enum FILE_TYPE ftype;
> > + int name_len;
> > +
> > + if (__test_bit (i, ctx->bitmap) == 0)
>
> grub_f2fs_test_bit_le32?
>
> > + {
> > + i++;
> > + continue;
> > + }
> > +
> > + ftype = ctx->dentry[i].file_type;
> > + name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len);
> > + grub_memcpy (filename, ctx->filename[i], name_len);
> > + filename[name_len] = '\0';
> > +
> > + fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
> > + if (!fdiro)
> > + return 0;
> > +
> > + if (ftype == F2FS_FT_DIR)
> > + type = GRUB_FSHELP_DIR;
> > + else if (ftype == F2FS_FT_SYMLINK)
> > + type = GRUB_FSHELP_SYMLINK;
> > + else if (ftype == F2FS_FT_REG_FILE)
> > + type = GRUB_FSHELP_REG;
> > +
> > + fdiro->data = ctx->data;
> > + fdiro->ino = grub_le_to_cpu32 (ctx->dentry[i].ino);
> > + fdiro->inode_read = 0;
> > +
> > + if (ctx->hook (filename, type, fdiro, ctx->hook_data))
> > + return 1;
> > +
> > + i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
> > + }
> > + return 0;
> > +}
> > +
> ...
> > +
> > +static int
> > +grub_f2fs_iterate_dir (grub_fshelp_node_t dir,
> > + grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
> > +{
> > + struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
> > + struct grub_f2fs_inode *inode;
> > + struct grub_f2fs_dir_iter_ctx ctx = {
> > + .data = diro->data,
> > + .hook = hook,
> > + .hook_data = hook_data
> > + };
> > + grub_off_t fpos = 0;
> > +
> > + if (!diro->inode_read)
> > + {
> > + grub_f2fs_read_node (diro->data, diro->ino, &diro->inode);
> > + if (grub_errno)
> > + return 0;
> > + }
> > +
> > + inode = &diro->inode.i;
> > +
> > + if (__inode_flag_set (inode, FI_INLINE_DENTRY))
> > + return grub_f2fs_iterate_inline_dir (inode, &ctx);
> > +
> > + while (fpos < __i_size (inode))
> > + {
> > + struct grub_f2fs_dentry_block *de_blk;
> > + char *buf;
> > +
> > + buf = grub_zalloc (F2FS_BLKSIZE);
> > + if (!buf)
> > + return 0;
> > +
> > + grub_f2fs_read_file (diro, 0, 0, fpos, F2FS_BLKSIZE, buf);
> > + if (grub_errno)
> > + {
> > + grub_free (buf);
> > + return 0;
> > + }
> > +
> > + de_blk = (struct grub_f2fs_dentry_block *) buf;
> > +
> > + ctx.bitmap = (grub_uint32_t *) de_blk->dentry_bitmap;
> > + ctx.dentry = de_blk->dentry;
> > + ctx.filename = de_blk->filename;
> > + ctx.max = NR_DENTRY_IN_BLOCK;
> > +
> > + if (grub_f2fs_check_dentries (&ctx))
> > + return 1;
>
> memory leak
Fixed.
>
> > +
> > + grub_free (buf);
> > +
> > + fpos += F2FS_BLKSIZE;
> > + }
> > + return 0;
> > +}
> > +
> ...
> > +static grub_err_t
> > +grub_f2fs_dir (grub_device_t device, const char *path,
> > + grub_fs_dir_hook_t hook, void *hook_data)
> > +{
> > + struct grub_f2fs_dir_ctx ctx = {
> > + .hook = hook,
> > + .hook_data = hook_data
> > + };
> > + struct grub_fshelp_node *fdiro = 0;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + ctx.data = grub_f2fs_mount (device->disk);
> > + if (!ctx.data)
> > + goto fail;
> > +
> > + grub_fshelp_find_file (path, &ctx.data->diropen, &fdiro,
> > + grub_f2fs_iterate_dir, grub_f2fs_read_symlink,
> > + GRUB_FSHELP_DIR);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + grub_f2fs_iterate_dir (fdiro, grub_f2fs_dir_iter, &ctx);
> > +
> > +fail:
> > + if (fdiro != &ctx.data->diropen)
> > + grub_free (fdiro);
> > + if (ctx.data)
> > + grub_free (ctx.data->nat_bitmap);
>
> Triple free :)
Removed nat_bitmap entirely. :)
>
> > + grub_free (ctx.data);
> > + grub_dl_unref (my_mod);
> > + return grub_errno;
> > +}
> > +
> > +
> > +/* Open a file named NAME and initialize FILE. */
> > +static grub_err_t
> > +grub_f2fs_open (struct grub_file *file, const char *name)
> > +{
> > + struct grub_f2fs_data *data = NULL;
> > + struct grub_fshelp_node *fdiro = 0;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_f2fs_mount (file->device->disk);
> > + if (!data)
> > + goto fail;
> > +
> > + grub_fshelp_find_file (name, &data->diropen, &fdiro,
> > + grub_f2fs_iterate_dir, grub_f2fs_read_symlink,
> > + GRUB_FSHELP_REG);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + if (!fdiro->inode_read)
> > + {
> > + grub_f2fs_read_node (data, fdiro->ino, &fdiro->inode);
> > + if (grub_errno)
> > + goto fail;
> > + }
> > +
> > + grub_memcpy (data->inode, &fdiro->inode, F2FS_BLKSIZE);
> sizeof (*data->inode)? Or they can be different?
Not a big deal. Fixed.
>
> > + grub_free (fdiro);
> > +
> > + file->size = __i_size (&(data->inode->i));
> > + file->data = data;
> > + file->offset = 0;
> > +
> > + return 0;
> > +
> > +fail:
> > + if (fdiro != &data->diropen)
> > + grub_free (fdiro);
> > + if (data)
> > + grub_free (data->nat_bitmap);
>
> Again.
>
> > + grub_free (data);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + return grub_errno;
> > +}
> > +
> > +static grub_ssize_t
> > +grub_f2fs_read (grub_file_t file, char *buf, grub_size_t len)
> > +{
> > + struct grub_f2fs_data *data = (struct grub_f2fs_data *) file->data;
> > +
> > + return grub_f2fs_read_file (&data->diropen,
> > + file->read_hook, file->read_hook_data,
> > + file->offset, len, buf);
> > +}
> > +
> > +static grub_err_t
> > +grub_f2fs_close (grub_file_t file)
> > +{
> > + struct grub_f2fs_data *data = (struct grub_f2fs_data *) file->data;
> > +
> > + if (data)
> > + grub_free (data->nat_bitmap);
>
> Again.
>
> > + grub_free (data);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +static grub_err_t
> > +grub_f2fs_label (grub_device_t device, char **label)
> > +{
> > + struct grub_f2fs_data *data;
> > + grub_disk_t disk = device->disk;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_f2fs_mount (disk);
> > + if (data)
> > + {
> > + *label = grub_zalloc (sizeof (data->sblock.volume_name));
> > + grub_utf16_to_utf8 ((grub_uint8_t *) (*label),
>
> malloc failure check?
Fxied.
>
> > + data->sblock.volume_name, 512);
>
> Where 512 comes from? Should it not be sizeof
> (data->sblock.volume_name) as well?
Fixed regarding to mkfs.f2fs handling.
>
> > + }
> > + else
> > + *label = NULL;
> > +
> > + if (data)
> > + grub_free (data->nat_bitmap);
>
> Again.
>
> > + grub_free (data);
> > + grub_dl_unref (my_mod);
> > + return grub_errno;
> > +}
> > +
> ...
> > diff --git a/tests/util/grub-fs-tester.in b/tests/util/grub-fs-tester.in
> > index e9e85c2..acc35cc 100644
> > --- a/tests/util/grub-fs-tester.in
> > +++ b/tests/util/grub-fs-tester.in
> > @@ -36,7 +36,7 @@ case x"$fs" in
> > MINLOGSECSIZE=8
> > # OS LIMITATION: It could go up to 32768 but Linux rejects sector
> > sizes > 4096
> > MAXLOGSECSIZE=12;;
> > - xxfs)
> > + xxfs|xf2fs)
> > MINLOGSECSIZE=9
> > # OS LIMITATION: GNU/Linux doesn't accept > 4096
> > MAXLOGSECSIZE=12;;
> > @@ -135,6 +135,10 @@ for
> > ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
> > fi
> > MAXBLKSIZE=4096
> > ;;
> > + xf2fs)
> > + MINBLKSIZE=$SECSIZE
> > + # OS Limitation: GNU/Linux doesn't accept > 4096
> > + MAXBLKSIZE=4096;;
> > xsquash*)
> > MINBLKSIZE=4096
> > MAXBLKSIZE=1048576;;
> > @@ -256,7 +260,9 @@ for
> > ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
> > # FS LIMITATION: btrfs label is at most 255 UTF-8 chars
> > x"btrfs"*)
> > FSLABEL="grub_;/testé莭莽😁киритi
> > urewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire
> > nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoif";;
> > -
> > + # FS LIMITATION: btrfs label is at most 512 UTF-16 chars
>
> F2FS, not btrfs
>
> > + x"f2fs")
> > + FSLABEL="grub_;/testjaegeuk kim
>
> Could you leave initial part in place? This includes some funny UNICODE
> characters for a reason, actually. Unless this is not possible with
> f2fs?
I found that mkfs.f2fs doesn't handle utf conversion correctly.
So, for now, I'd like to add just few characters.
Please, v2 patch.
Thanks,
>
> f2fsaskdfjkasdlfajskdfjaksdjfkjaskjkjkzjkjckzjvkcjkjkjekqjkwejkqwrlkasdfjksadjflaskdhzxhvjzxchvjzkxchvjkhakjsdhfjkhqjkwehrjkhasjkdfhjkashdfjkhjzkxhcjkvzhxcjkvhzxjchvkzhxckjvhjzkxchvjkhzjkxchvjkzhxckjvhzkxjchvkjzxhckjvzxcjkvhjzxkchkvjhzxkjcvhjkhjkahsjkdhkjqhwekrjhakjsdfhkjashdkjzhxcvjkhzxcvzxcvggggggggggf";;
> > # FS LIMITATION: exfat is at most 15 UTF-16 chars
> > x"exfat")
> > FSLABEL="géт ;/莭莽😁кир";;
> > @@ -466,7 +472,7 @@ for
> > ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
> > # FIXME: Not sure about BtrFS, NTFS, JFS, AFS, UDF and SFS. Check
> > it.
> > # FS LIMITATION: as far as I know those FS don't store their last
> > modification date.
> > x"jfs_caseins" | x"jfs" | x"xfs"| x"btrfs"* | x"reiserfs_old" |
> > x"reiserfs" \
> > - | x"bfs" | x"afs" \
> > + | x"bfs" | x"afs" | x"f2fs" \
> > | x"tarfs" | x"cpio_"* | x"minix" | x"minix2" \
> > | x"minix3" | x"ntfs"* | x"udf" | x"sfs"*)
> > NOFSTIME=y;;
> > @@ -745,6 +751,8 @@ for
> > ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
> > MOUNTDEVICE="/dev/mapper/grub_test-testvol"
> > MOUNTFS=ext2
> > "mkfs.ext2" -L "$FSLABEL" -q "${MOUNTDEVICE}" ;;
> > + xf2fs)
> > + "mkfs.f2fs" -l "$FSLABEL" -q "${LODEVICES[0]}" ;;
> > xnilfs2)
> > "mkfs.nilfs2" -L "$FSLABEL" -b $BLKSIZE -q
> > "${LODEVICES[0]}" ;;
> > xext2_old)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [PATCH] F2FS support,
Jaegeuk Kim <=