Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1416521 > unrolled thread
| Started by | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| First post | 2016-06-07 21:30 +0200 |
| Last post | 2016-06-07 21:30 +0200 |
| Articles | 3 — 1 participant |
Back to article view | Back to linux.kernel
[RESEND PATCH v7 0/4] vfs: Use per-cpu list for SB's s_inodes list Waiman Long <Waiman.Long@hpe.com> - 2016-06-07 21:30 +0200
[RESEND PATCH v7 3/4] vfs: Remove unnecessary list_for_each_entry_safe() variants Waiman Long <Waiman.Long@hpe.com> - 2016-06-07 21:30 +0200
[RESEND PATCH v7 2/4] fsnotify: Simplify inode iteration on umount Waiman Long <Waiman.Long@hpe.com> - 2016-06-07 21:30 +0200
| From | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| Date | 2016-06-07 21:30 +0200 |
| Subject | [RESEND PATCH v7 0/4] vfs: Use per-cpu list for SB's s_inodes list |
| Message-ID | <rHuRj-6J6-3@gated-at.bofh.it> |
v6->v7: - Fix the race condition in __pcpu_list_next_cpu() as reported by Jan Kara. - No changes in patches 2-4. v5->v6: - Remove patch 5 which can increase the kernel testing matrix. - Disable preemption in pcpu_list_add() as it was complained by the 0-day test even though it is not technically necessary. - Add a PERCPU_LIST_WARN_ON() macro to simplify code. - No changes in patches 2-4. v4->v5: - Fix the UP panic problem reported by 0day test by unifying the SMP and UP code. - Add patch 5 to add a new kernel config parameter to allow disabling per-cpu list for small systems that won't benefit much from this feature. v3->v4: - Fix some racing conditions in the code. - Add another patch from Jan to replace list_for_each_entry_safe() by list_for_each_entry(). - Add lockdep annotation. v2->v3: - Directly replace list_for_each_entry() and list_for_each_entry_safe() by pcpu_list_iterate() and pcpu_list_iterate_safe() respectively instead. Those 2 functions provide a stateful per-cpu list iteration interface. - Include Jan Kara's patch to clean up the fsnotify_unmount_inodes() function. v1->v2: - Use separate structures for list head and nodes & provide a cleaner interface. - Use existing list_for_each_entry() or list_for_each_entry_safe() macros for each of the sb's s_inodes iteration functions instead of using list_for_each_entry_safe() for all of them which may not be safe in some cases. - Use an iterator interface to access all the nodes of a group of per-cpu lists. This approach is cleaner than the previous double-for macro which is kind of hacky. However, it does require more lines of code changes. - Add a preparatory patch 2 to extract out the per-inode codes from the superblock s_inodes list iteration functions to minimize code changes needed in the patch 3. This patch is a replacement of my previous list batching patch - https://lwn.net/Articles/674105/. Compared with the previous patch, this one provides better performance and fairness. However, it also requires a bit more changes in the VFS layer. This patchset is a derivative of Andi Kleen's patch on "Initial per cpu list for the per sb inode list" https://git.kernel.org/cgit/linux/kernel/git/ak/linux-misc.git/commit/?h=hle315/ combined&id=f1cf9e715a40f44086662ae3b29f123cf059cbf4 Patch 1 introduces the per-cpu list. Patch 2 cleans up the fsnotify_unmount_inodes() function by making the code simpler and more standard. Patch 3 replaces the use of list_for_each_entry_safe() in evict_inodes() and invalidate_inodes() by list_for_each_entry(). Patch 4 modifies the superblock and inode structures to use the per-cpu list. The corresponding functions that reference those structures are modified. Jan Kara (2): fsnotify: Simplify inode iteration on umount vfs: Remove unnecessary list_for_each_entry_safe() variants Waiman Long (2): lib/percpu-list: Per-cpu list with associated per-cpu locks vfs: Use per-cpu list for superblock's inode list fs/block_dev.c | 13 ++- fs/drop_caches.c | 10 +- fs/fs-writeback.c | 13 ++- fs/inode.c | 40 +++----- fs/notify/inode_mark.c | 53 +++-------- fs/quota/dquot.c | 16 ++-- fs/super.c | 7 +- include/linux/fs.h | 8 +- include/linux/percpu-list.h | 231 +++++++++++++++++++++++++++++++++++++++++++ lib/Makefile | 2 +- lib/percpu-list.c | 100 +++++++++++++++++++ 11 files changed, 397 insertions(+), 96 deletions(-) create mode 100644 include/linux/percpu-list.h create mode 100644 lib/percpu-list.c
[toc] | [next] | [standalone]
| From | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| Date | 2016-06-07 21:30 +0200 |
| Subject | [RESEND PATCH v7 3/4] vfs: Remove unnecessary list_for_each_entry_safe() variants |
| Message-ID | <rHuRj-6J6-21@gated-at.bofh.it> |
| In reply to | #1416521 |
From: Jan Kara <jack@suse.cz>
evict_inodes() and invalidate_inodes() use list_for_each_entry_safe()
to iterate sb->s_inodes list. However, since we use i_lru list entry for
our local temporary list of inodes to destroy, the inode is guaranteed
to stay in sb->s_inodes list while we hold sb->s_inode_list_lock. So
there is no real need for safe iteration variant and we can use
list_for_each_entry() just fine.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Waiman Long <Waiman.Long@hpe.com>
---
fs/inode.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index 69b8b52..c9cbea8 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -596,12 +596,12 @@ static void dispose_list(struct list_head *head)
*/
void evict_inodes(struct super_block *sb)
{
- struct inode *inode, *next;
+ struct inode *inode;
LIST_HEAD(dispose);
again:
spin_lock(&sb->s_inode_list_lock);
- list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
+ list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (atomic_read(&inode->i_count))
continue;
@@ -646,11 +646,11 @@ again:
int invalidate_inodes(struct super_block *sb, bool kill_dirty)
{
int busy = 0;
- struct inode *inode, *next;
+ struct inode *inode;
LIST_HEAD(dispose);
spin_lock(&sb->s_inode_list_lock);
- list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
+ list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
spin_lock(&inode->i_lock);
if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
spin_unlock(&inode->i_lock);
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| Date | 2016-06-07 21:30 +0200 |
| Subject | [RESEND PATCH v7 2/4] fsnotify: Simplify inode iteration on umount |
| Message-ID | <rHuRj-6J6-27@gated-at.bofh.it> |
| In reply to | #1416521 |
From: Jan Kara <jack@suse.cz>
fsnotify_unmount_inodes() played complex tricks to pin next inode in the
sb->s_inodes list when iterating over all inodes. If we switch to
keeping current inode pinned somewhat longer, we can make the code much
simpler and standard.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Waiman Long <Waiman.Long@hpe.com>
---
fs/notify/inode_mark.c | 45 +++++++++------------------------------------
1 files changed, 9 insertions(+), 36 deletions(-)
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index 741077d..a364524 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -150,12 +150,10 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
*/
void fsnotify_unmount_inodes(struct super_block *sb)
{
- struct inode *inode, *next_i, *need_iput = NULL;
+ struct inode *inode, *iput_inode = NULL;
spin_lock(&sb->s_inode_list_lock);
- list_for_each_entry_safe(inode, next_i, &sb->s_inodes, i_sb_list) {
- struct inode *need_iput_tmp;
-
+ list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
/*
* We cannot __iget() an inode in state I_FREEING,
* I_WILL_FREE, or I_NEW which is fine because by that point
@@ -178,49 +176,24 @@ void fsnotify_unmount_inodes(struct super_block *sb)
continue;
}
- need_iput_tmp = need_iput;
- need_iput = NULL;
-
- /* In case fsnotify_inode_delete() drops a reference. */
- if (inode != need_iput_tmp)
- __iget(inode);
- else
- need_iput_tmp = NULL;
+ __iget(inode);
spin_unlock(&inode->i_lock);
-
- /* In case the dropping of a reference would nuke next_i. */
- while (&next_i->i_sb_list != &sb->s_inodes) {
- spin_lock(&next_i->i_lock);
- if (!(next_i->i_state & (I_FREEING | I_WILL_FREE)) &&
- atomic_read(&next_i->i_count)) {
- __iget(next_i);
- need_iput = next_i;
- spin_unlock(&next_i->i_lock);
- break;
- }
- spin_unlock(&next_i->i_lock);
- next_i = list_next_entry(next_i, i_sb_list);
- }
-
- /*
- * We can safely drop s_inode_list_lock here because either
- * we actually hold references on both inode and next_i or
- * end of list. Also no new inodes will be added since the
- * umount has begun.
- */
spin_unlock(&sb->s_inode_list_lock);
- if (need_iput_tmp)
- iput(need_iput_tmp);
+ if (iput_inode)
+ iput(iput_inode);
/* for each watch, send FS_UNMOUNT and then remove it */
fsnotify(inode, FS_UNMOUNT, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
fsnotify_inode_delete(inode);
- iput(inode);
+ iput_inode = inode;
spin_lock(&sb->s_inode_list_lock);
}
spin_unlock(&sb->s_inode_list_lock);
+
+ if (iput_inode)
+ iput(iput_inode);
}
--
1.7.1
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web