Skip to contentSkip to conversation

f2fs: avoid needless lock for node pages when fsyncing a file

PATCH In review Jaegeuk Kim 3 participants 11 messages Apr 26, 2016 – Apr 27, 2016

Subsystems (2)
lore
Share & tools
lore

Jaegeuk Kim

author maintainer
#0 lore raw

PATCH 1/7 f2fs: avoid needless lock for node pages when fsyncing a file

When fsync is called, sync_node_pages finds a proper direct node pages to flush. But, it locks unrelated direct node pages together unnecessarily.

---
 fs/f2fs/node.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
fs/f2fs/node.c +7 -3
index 095fc2c..cccee50 100644
@@ -1272,10 +1272,14 @@ next_step:
 			 * we should not skip writing node pages.
 			 */
 lock_node:
-			if (ino && ino_of_node(page) == ino)
-				lock_page(page);
-			else if (!trylock_page(page))
+			if (ino) {
+				if (ino_of_node(page) == ino)
+					lock_page(page);
+				else
+					continue;
+			} else if (!trylock_page(page)) {
 				continue;
+			}
 
 			if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
 continue_unlock:
Signature · 1 line
2.6.3
author maintainer
#1 lore raw

PATCH 2/7 f2fs: avoid writing 0'th page in volatile writes

The first page of volatile writes usually contains a sort of header information which will be used for recovery.
(e.g., journal header of sqlite)

If this is written without other journal data, user needs to handle the stale journal information.

---
 fs/f2fs/data.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
fs/f2fs/data.c +4 -2
index c29bcf4..e54489b 100644
@@ -1177,8 +1177,10 @@ write:
 		goto redirty_out;
 	if (f2fs_is_drop_cache(inode))
 		goto out;
-	if (f2fs_is_volatile_file(inode) && !wbc->for_reclaim &&
-			available_free_memory(sbi, BASE_CHECK))
+	/* we should not write 0'th page having journal header */
+	if (f2fs_is_volatile_file(inode) && (!page->index ||
+			(!wbc->for_reclaim &&
+			available_free_memory(sbi, BASE_CHECK))))
 		goto redirty_out;
 
 	/* Dentry blocks are controlled by checkpoint */
Signature · 1 line
2.6.3
author maintainer
#2 lore raw

PATCH 3/7 f2fs: split sync_node_pages with fsync_node_pages

In reply to Jaegeuk Kim

This patch splits the existing sync_node_pages into (f)sync_node_pages. The fsync_node_pages is used for f2fs_sync_file only.

---
 fs/f2fs/checkpoint.c |   2 +-
 fs/f2fs/f2fs.h       |   3 +-
 fs/f2fs/file.c       |   2 +-
 fs/f2fs/gc.c         |   2 +-
 fs/f2fs/node.c       | 108 +++++++++++++++++++++++++++++++++++++--------------
 5 files changed, 84 insertions(+), 33 deletions(-)
fs/f2fs/checkpoint.c +1 -1
index b92782f..bf040b5 100644
@@ -892,7 +892,7 @@ retry_flush_nodes:
 
 	if (get_pages(sbi, F2FS_DIRTY_NODES)) {
 		up_write(&sbi->node_write);
-		err = sync_node_pages(sbi, 0, &wbc);
+		err = sync_node_pages(sbi, &wbc);
 		if (err) {
 			f2fs_unlock_all(sbi);
 			goto out;
fs/f2fs/f2fs.h +2 -1
index 3f15513..269abe5 100644
@@ -1784,7 +1784,8 @@ void ra_node_page(struct f2fs_sb_info *, nid_t);
 struct page *get_node_page(struct f2fs_sb_info *, pgoff_t);
 struct page *get_node_page_ra(struct page *, int);
 void sync_inode_page(struct dnode_of_data *);
-int sync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *);
+int fsync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *);
+int sync_node_pages(struct f2fs_sb_info *, struct writeback_control *);
 bool alloc_nid(struct f2fs_sb_info *, nid_t *);
 void alloc_nid_done(struct f2fs_sb_info *, nid_t);
 void alloc_nid_failed(struct f2fs_sb_info *, nid_t);
fs/f2fs/file.c +1 -1
index 7de90e6..3d53ee0 100644
@@ -256,7 +256,7 @@ go_write:
 		goto out;
 	}
 sync_nodes:
-	sync_node_pages(sbi, ino, &wbc);
+	fsync_node_pages(sbi, ino, &wbc);
 
 	/* if cp_error was enabled, we should avoid infinite loop */
 	if (unlikely(f2fs_cp_error(sbi))) {
fs/f2fs/gc.c +1 -1
index b0051a9..e820465 100644
@@ -841,7 +841,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
 				.nr_to_write = LONG_MAX,
 				.for_reclaim = 0,
 			};
-			sync_node_pages(sbi, 0, &wbc);
+			sync_node_pages(sbi, &wbc);
 		} else {
 			f2fs_submit_merged_bio(sbi, DATA, WRITE);
 		}
fs/f2fs/node.c +79 -29

150 lines not on this page · raw message

Signature · 1 line
2.6.3
author maintainer
#3 lore raw

PATCH 4/7 f2fs: report unwritten status in fsync_node_pages

In reply to Jaegeuk Kim

The fsync_node_pages should return pass or failure so that user could know fsync is completed or not.

---
 fs/f2fs/file.c |  4 +++-
 fs/f2fs/node.c | 13 ++++++-------
 2 files changed, 9 insertions(+), 8 deletions(-)
fs/f2fs/file.c +3 -1
index 3d53ee0..60fd64c 100644
@@ -256,7 +256,9 @@ go_write:
 		goto out;
 	}
 sync_nodes:
-	fsync_node_pages(sbi, ino, &wbc);
+	ret = fsync_node_pages(sbi, ino, &wbc);
+	if (ret)
+		goto out;
 
 	/* if cp_error was enabled, we should avoid infinite loop */
 	if (unlikely(f2fs_cp_error(sbi))) {
fs/f2fs/node.c +6 -7
index 675b730..8a1e211 100644
@@ -1227,7 +1227,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
 {
 	pgoff_t index, end;
 	struct pagevec pvec;
-	int nwritten = 0;
+	int ret = 0;
 
 	pagevec_init(&pvec, 0);
 	index = 0;
@@ -1278,21 +1278,20 @@ continue_unlock:
 			if (IS_INODE(page))
 				set_dentry_mark(page,
 						need_dentry_mark(sbi, ino));
-			nwritten++;
 
-			if (NODE_MAPPING(sbi)->a_ops->writepage(page, wbc))
+			ret = NODE_MAPPING(sbi)->a_ops->writepage(page, wbc);
+			if (ret) {
 				unlock_page(page);
-
-			if (--wbc->nr_to_write == 0)
 				break;
+			}
 		}
 		pagevec_release(&pvec);
 		cond_resched();
 
-		if (wbc->nr_to_write == 0)
+		if (ret)
 			break;
 	}
-	return nwritten;
+	return ret ? -EIO: 0;
 }
 
 int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc)
Signature · 1 line
2.6.3
author maintainer
#4 lore raw

PATCH 5/7 f2fs: set fsync mark only for the last dnode

In reply to Jaegeuk Kim

In order to give atomic writes, we should consider power failure during sync_node_pages in fsync.
So, this patch marks fsync flag only in the last dnode block.

---
 fs/f2fs/f2fs.h     |   4 +-
 fs/f2fs/file.c     |  14 +++++--
 fs/f2fs/node.c     | 106 +++++++++++++++++++++++++++++++++++++++++++++++++----
 fs/f2fs/recovery.c |   9 ++---
 4 files changed, 113 insertions(+), 20 deletions(-)
fs/f2fs/f2fs.h +2 -2
index 269abe5..ca828b0 100644
@@ -159,7 +159,6 @@ struct fsync_inode_entry {
 	struct inode *inode;	/* vfs inode pointer */
 	block_t blkaddr;	/* block address locating the last fsync */
 	block_t last_dentry;	/* block address locating the last dentry */
-	block_t last_inode;	/* block address locating the last inode */
 };
 
 #define nats_in_cursum(jnl)		(le16_to_cpu(jnl->n_nats))
@@ -1784,7 +1783,8 @@ void ra_node_page(struct f2fs_sb_info *, nid_t);
 struct page *get_node_page(struct f2fs_sb_info *, pgoff_t);
 struct page *get_node_page_ra(struct page *, int);
 void sync_inode_page(struct dnode_of_data *);
-int fsync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *);
+int fsync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *,
+								bool);
 int sync_node_pages(struct f2fs_sb_info *, struct writeback_control *);
 bool alloc_nid(struct f2fs_sb_info *, nid_t *);
 void alloc_nid_done(struct f2fs_sb_info *, nid_t);
fs/f2fs/file.c +10 -4
index 60fd64c..dc47d5c 100644
@@ -182,7 +182,8 @@ static void try_to_fix_pino(struct inode *inode)
 	}
 }
 
-int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
+static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
+						int datasync, bool atomic)
 {
 	struct inode *inode = file->f_mapping->host;
 	struct f2fs_inode_info *fi = F2FS_I(inode);
@@ -256,7 +257,7 @@ go_write:
 		goto out;
 	}
 sync_nodes:
-	ret = fsync_node_pages(sbi, ino, &wbc);
+	ret = fsync_node_pages(sbi, ino, &wbc, atomic);
 	if (ret)
 		goto out;
 
@@ -290,6 +291,11 @@ out:
 	return ret;
 }
 
+int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
+{
+	return f2fs_do_sync_file(file, start, end, datasync, false);
+}
+
 static pgoff_t __get_first_dirty_index(struct address_space *mapping,
 						pgoff_t pgofs, int whence)
 {
@@ -1407,7 +1413,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
 		}
 	}
 
-	ret = f2fs_sync_file(filp, 0, LLONG_MAX, 0);
+	ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
 err_out:
 	mnt_drop_write_file(filp);
 	return ret;
@@ -1465,7 +1471,7 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp)
 		drop_inmem_pages(inode);
 	if (f2fs_is_volatile_file(inode)) {
 		clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
-		ret = f2fs_sync_file(filp, 0, LLONG_MAX, 0);
+		ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
 	}
 
 	mnt_drop_write_file(filp);
fs/f2fs/node.c +98 -8

150 lines not on this page · raw message

fs/f2fs/recovery.c +3 -6
index 2c87c12..a646d3b 100644
@@ -257,11 +257,8 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
 		}
 		entry->blkaddr = blkaddr;
 
-		if (IS_INODE(page)) {
-			entry->last_inode = blkaddr;
-			if (is_dent_dnode(page))
-				entry->last_dentry = blkaddr;
-		}
+		if (IS_INODE(page) && is_dent_dnode(page))
+			entry->last_dentry = blkaddr;
 next:
 		/* check next segment */
 		blkaddr = next_blkaddr_of_node(page);
@@ -521,7 +518,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
 		 * In this case, we can lose the latest inode(x).
 		 * So, call recover_inode for the inode update.
 		 */
-		if (entry->last_inode == blkaddr)
+		if (IS_INODE(page))
 			recover_inode(entry->inode, page);
 		if (entry->last_dentry == blkaddr) {
 			err = recover_dentry(entry->inode, page);
Signature · 1 line
2.6.3
author maintainer
#5 lore raw

PATCH 6/7 f2fs: issue cache flush on direct IO

In reply to Jaegeuk Kim

Under direct IO path with O_(D)SYNC, it needs to set proper APPEND or UPDATE flags, so taht f2fs_sync_file can make its data safe.

---
 fs/f2fs/data.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
fs/f2fs/data.c +9 -2
index e54489b..38ce5d6 100644
@@ -673,6 +673,9 @@ next_block:
 					err = reserve_new_block(&dn);
 			} else {
 				err = __allocate_data_block(&dn);
+				if (!err)
+					set_inode_flag(F2FS_I(inode),
+							FI_APPEND_WRITE);
 			}
 			if (err)
 				goto sync_out;
@@ -1685,8 +1688,12 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
 	trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
 
 	err = blockdev_direct_IO(iocb, inode, iter, offset, get_data_block_dio);
-	if (err < 0 && iov_iter_rw(iter) == WRITE)
-		f2fs_write_failed(mapping, offset + count);
+	if (iov_iter_rw(iter) == WRITE) {
+		if (err > 0)
+			set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE);
+		else if (err < 0)
+			f2fs_write_failed(mapping, offset + count);
+	}
 
 	trace_f2fs_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), err);
 
Signature · 1 line
2.6.3
author maintainer
#6 lore raw

PATCH 7/7 f2fs: should check the remaining dentry bits

In reply to Jaegeuk Kim

Let's consider a race condition between f2fs_add_regular_entry and find_target_dentry.

1.
- f2fs_add_regular_entry updated len: 24 first.

       |
Bits:  0 0 0 1
Lens: 24 0 0 3 (name: foo)
       |->

- find_target_dentry checks the first bit to find "foo", then ++pointer.

2.
- f2fs_add_regular_entry updates bits.

       |>|>|
Bits:  1 1 1 1
Lens: 24 0 0 3 (name: foo)
         |

- find_target_dentry is checking second bit, but it's len is zero, which makes the process being terminated.

In this case, user can add additional dentry named "foo" accordingly. This patch enables to check the remaining bits.

---
 fs/f2fs/dir.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
fs/f2fs/dir.c +3 -3
index e90380d..aed5e6d 100644
@@ -149,9 +149,9 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
 
 		/* remain bug on condition */
 		if (unlikely(!de->name_len))
-			d->max = -1;
-
-		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+			bit_pos++;
+		else
+			bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
 	}
 
 	de = NULL;
Signature · 1 line
2.6.3
author maintainer
#7 lore raw

Re: [PATCH v2 7/7] f2fs: should check the remaining dentry bits

Change log from v1:
o remove wron f2fs_bug_on()

Quoted 1 line

From 545c0c9055b0d8dc5d134d9340b3cd80eeecdafa Mon Sep 17 00:00:00 2001

From: Jaegeuk Kim <[email protected]>
Date: Mon, 25 Apr 2016 14:24:44 -0700
Subject: [PATCH] f2fs: should check the remaining dentry bits

Let's consider a race condition between f2fs_add_regular_entry and find_target_dentry.

1.
- f2fs_add_regular_entry updated len: 24 first.

       |
Bits:  0 0 0 1
Lens: 24 0 0 3 (name: foo)
       |->

- find_target_dentry checks the first bit to find "foo", then ++pointer.

2.
- f2fs_add_regular_entry updates bits.

       |>|>|
Bits:  1 1 1 1
Lens: 24 0 0 3 (name: foo)
         |

- find_target_dentry is checking second bit, but it's len is zero, which makes the process being terminated.

In this case, user can add additional dentry named "foo" accordingly. This patch enables to check the remaining bits.

---
 fs/f2fs/dir.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)
fs/f2fs/dir.c +3 -9
index e90380d..0ad7b9a 100644
@@ -100,12 +100,6 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
 		*res_page = dentry_page;
 	else
 		kunmap(dentry_page);
-
-	/*
-	 * For the most part, it should be a bug when name_len is zero.
-	 * We stop here for figuring out where the bugs has occurred.
-	 */
-	f2fs_bug_on(F2FS_P_SB(dentry_page), d.max < 0);
 	return de;
 }
 
@@ -149,9 +143,9 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
 
 		/* remain bug on condition */
 		if (unlikely(!de->name_len))
-			d->max = -1;
-
-		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+			bit_pos++;
+		else
+			bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
 	}
 
 	de = NULL;
Signature · 1 line
2.6.3
maintainer
#8 lore raw

Re: [f2fs-dev] [PATCH 7/7] f2fs: should check the remaining dentry bits

In reply to Jaegeuk Kim

Hi Jaegeuk, Yunlei,

Quoted 11 lines · Jaegeuk Kim

Let's consider a race condition between f2fs_add_regular_entry and find_target_dentry.

1.
- f2fs_add_regular_entry updated len: 24 first.

       |
Bits:  0 0 0 1
Lens: 24 0 0 3 (name: foo)
       |->

- find_target_dentry checks the first bit to find "foo", then ++pointer.

Quoted 8 lines

2.
- f2fs_add_regular_entry updates bits.

       |>|>|
Bits:  1 1 1 1
Lens: 24 0 0 3 (name: foo)
         |

- find_target_dentry is checking second bit, but it's len is zero, which makes the process being terminated.

As Pengyang reminded, there are no racing condition between find_target_dentry and f2fs_add_regular_entry since i_mutex lock make each of operations being atomical. So seems above condition can not happen.

But still we should handle dirent with zero-sized length correctly, as it may cause deadloop. So how do you think of following patch?

From: Chao Yu <[email protected]>
Subject: [PATCH] f2fs: be aware of invalid filename length

The filename length in dirent of may become zero-sized after random junk data injection, once encounter such dirent, find_target_dentry or f2fs_add_inline_entries will run into an infinite loop. So let f2fs being aware of that to avoid deadloop.

---
 fs/f2fs/dir.c    | 14 +++++---------
 fs/f2fs/inline.c | 14 ++++++--------
 2 files changed, 11 insertions(+), 17 deletions(-)
fs/f2fs/dir.c +0 -0
index e90380d..3b1c14e 100644
@@ -101,11 +101,6 @@ static struct f2fs_dir_entry *find_in_block(struct page

*dentry_page,
else
kunmap(dentry_page);

- /*
- * For the most part, it should be a bug when name_len is zero.
- * We stop here for figuring out where the bugs has occurred.
- */
- f2fs_bug_on(F2FS_P_SB(dentry_page), d.max < 0);
return de;
}

@@ -130,6 +125,11 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,

de = &d->dentry[bit_pos];

+ if (unlikely(!de->name_len)) {
+ bit_pos++;
+ continue;
+ }
+
/* encrypted case */
de_name.name = d->filename[bit_pos]; de_name.len = le16_to_cpu(de->name_len);
@@ -147,10 +147,6 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
*max_slots = max_len;
max_len = 0;

- /* remain bug on condition */
- if (unlikely(!de->name_len))
- d->max = -1;
-
bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
}

fs/f2fs/inline.c +6 -8
index 7720565..e61084c 100644
@@ -303,11 +303,6 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
 	else
 		f2fs_put_page(ipage, 0);
 
-	/*
-	 * For the most part, it should be a bug when name_len is zero.
-	 * We stop here for figuring out where the bugs has occurred.
-	 */
-	f2fs_bug_on(sbi, d.max < 0);
 	return de;
 }
 
@@ -437,6 +432,12 @@ static int f2fs_add_inline_entries(struct inode *dir,
 		}
 
 		de = &d.dentry[bit_pos];
+
+		if (unlikely(!de->name_len)) {
+			bit_pos++;
+			continue;
+		}
+
 		new_name.name = d.filename[bit_pos];
 		new_name.len = de->name_len;
 
@@ -448,9 +449,6 @@ static int f2fs_add_inline_entries(struct inode *dir,
 		if (err)
 			goto punch_dentry_pages;
 
-		if (unlikely(!de->name_len))
-			d.max = -1;
-
 		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
 	}
 	return 0;
Signature · 1 line
2.7.2
author maintainer
#9 lore raw

Re: [f2fs-dev] [PATCH 7/7] f2fs: should check the remaining dentry bits

Looks better.
Merged. :)

Thanks,

Quoted 127 lines · Chao Yu

Hi Jaegeuk, Yunlei,

Quoted 11 lines · Jaegeuk Kim

Let's consider a race condition between f2fs_add_regular_entry and find_target_dentry.

1.
- f2fs_add_regular_entry updated len: 24 first.

       |
Bits:  0 0 0 1
Lens: 24 0 0 3 (name: foo)
       |->

- find_target_dentry checks the first bit to find "foo", then ++pointer.

Quoted 8 lines

2.
- f2fs_add_regular_entry updates bits.

       |>|>|
Bits:  1 1 1 1
Lens: 24 0 0 3 (name: foo)
         |

- find_target_dentry is checking second bit, but it's len is zero, which makes the process being terminated.

As Pengyang reminded, there are no racing condition between find_target_dentry and f2fs_add_regular_entry since i_mutex lock make each of operations being atomical. So seems above condition can not happen.

But still we should handle dirent with zero-sized length correctly, as it may cause deadloop. So how do you think of following patch?

From: Chao Yu <[email protected]>
Subject: [PATCH] f2fs: be aware of invalid filename length

The filename length in dirent of may become zero-sized after random junk data injection, once encounter such dirent, find_target_dentry or f2fs_add_inline_entries will run into an infinite loop. So let f2fs being aware of that to avoid deadloop.

---
 fs/f2fs/dir.c    | 14 +++++---------
 fs/f2fs/inline.c | 14 ++++++--------
 2 files changed, 11 insertions(+), 17 deletions(-)
fs/f2fs/dir.c +5 -5
index e90380d..3b1c14e 100644
@@ -101,11 +101,6 @@ static struct f2fs_dir_entry *find_in_block(struct page
 *dentry_page,
 	else
 		kunmap(dentry_page);
 
-	/*
-	 * For the most part, it should be a bug when name_len is zero.
-	 * We stop here for figuring out where the bugs has occurred.
-	 */
-	f2fs_bug_on(F2FS_P_SB(dentry_page), d.max < 0);
 	return de;
 }
@@ -130,6 +125,11 @@ struct f2fs_dir_entry *find_target_dentry(struct
 fscrypt_name *fname,
 
 		de = &d->dentry[bit_pos];
 
+		if (unlikely(!de->name_len)) {
+			bit_pos++;
+			continue;
+		}
+
 		/* encrypted case */
 		de_name.name = d->filename[bit_pos];
fs/f2fs/dir.c +0 -4
 		de_name.len = le16_to_cpu(de->name_len);
@@ -147,10 +147,6 @@ struct f2fs_dir_entry *find_target_dentry(struct
 fscrypt_name *fname,
 			*max_slots = max_len;
 		max_len = 0;
 
-		/* remain bug on condition */
-		if (unlikely(!de->name_len))
-			d->max = -1;
-
 		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
 	}
fs/f2fs/inline.c +6 -8
index 7720565..e61084c 100644
@@ -303,11 +303,6 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
 	else
 		f2fs_put_page(ipage, 0);
 
-	/*
-	 * For the most part, it should be a bug when name_len is zero.
-	 * We stop here for figuring out where the bugs has occurred.
-	 */
-	f2fs_bug_on(sbi, d.max < 0);
 	return de;
 }
 
@@ -437,6 +432,12 @@ static int f2fs_add_inline_entries(struct inode *dir,
 		}
 
 		de = &d.dentry[bit_pos];
+
+		if (unlikely(!de->name_len)) {
+			bit_pos++;
+			continue;
+		}
+
 		new_name.name = d.filename[bit_pos];
 		new_name.len = de->name_len;
 
@@ -448,9 +449,6 @@ static int f2fs_add_inline_entries(struct inode *dir,
 		if (err)
 			goto punch_dentry_pages;
 
-		if (unlikely(!de->name_len))
-			d.max = -1;
-
 		bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
 	}
 	return 0;
Signature · 1 line
2.7.2