Do not stuck forever if something wrong.
This function also used for /proc/pid/smaps.
Signed-off-by: Konstantin Khlebnikov <[email protected]>
---
fs/proc/task_mmu.c | 6 +++++-
fs/proc/task_nommu.c | 6 +++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 01d4eb0e6bd1..2bf210229daf 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -166,7 +166,11 @@ static void *m_start(struct seq_file *m, loff_t *ppos)
if (!mm || !mmget_not_zero(mm))
return NULL;
- down_read(&mm->mmap_sem);
+ if (down_read_killable(&mm->mmap_sem)) {
+ mmput(mm);
+ return ERR_PTR(-EINTR);
+ }
+
hold_task_mempolicy(priv);
priv->tail_vma = get_gate_vma(mm);
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 36bf0f2e102e..7907e6419e57 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -211,7 +211,11 @@ static void *m_start(struct seq_file *m, loff_t *pos)
if (!mm || !mmget_not_zero(mm))
return NULL;
- down_read(&mm->mmap_sem);
+ if (down_read_killable(&mm->mmap_sem)) {
+ mmput(mm);
+ return ERR_PTR(-EINTR);
+ }
+
/* start from the Nth VMA */
for (p = rb_first(&mm->mm_rb); p; p = rb_next(p))
if (n-- == 0)
Ditto.
Signed-off-by: Konstantin Khlebnikov <[email protected]>
---
fs/proc/task_mmu.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 2bf210229daf..781879a91e3b 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -832,7 +832,10 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
memset(&mss, 0, sizeof(mss));
- down_read(&mm->mmap_sem);
+ ret = down_read_killable(&mm->mmap_sem);
+ if (ret)
+ goto out_put_mm;
+
hold_task_mempolicy(priv);
for (vma = priv->mm->mmap; vma; vma = vma->vm_next) {
@@ -849,8 +852,9 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
release_task_mempolicy(priv);
up_read(&mm->mmap_sem);
- mmput(mm);
+out_put_mm:
+ mmput(mm);
out_put_task:
put_task_struct(priv->task);
priv->task = NULL;
Replace the only unkillable mmap_sem lock in clear_refs_write.
Signed-off-by: Konstantin Khlebnikov <[email protected]>
---
fs/proc/task_mmu.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 78bed6adc62d..7f84d1477b5b 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1140,7 +1140,10 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
goto out_mm;
}
- down_read(&mm->mmap_sem);
+ if (down_read_killable(&mm->mmap_sem)) {
+ count = -EINTR;
+ goto out_mm;
+ }
tlb_gather_mmu(&tlb, mm, 0, -1);
if (type == CLEAR_REFS_SOFT_DIRTY) {
for (vma = mm->mmap; vma; vma = vma->vm_next) {
Ditto.
Signed-off-by: Konstantin Khlebnikov <[email protected]>
---
fs/proc/task_mmu.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 781879a91e3b..78bed6adc62d 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1547,7 +1547,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
/* overflow ? */
if (end < start_vaddr || end > end_vaddr)
end = end_vaddr;
- down_read(&mm->mmap_sem);
+ ret = down_read_killable(&mm->mmap_sem);
+ if (ret)
+ goto out_free;
ret = walk_page_range(start_vaddr, end, &pagemap_walk);
up_read(&mm->mmap_sem);
start_vaddr = end;
It seems ->d_revalidate() could return any error (except ECHILD) to
abort validation and pass error as result of lookup sequence.
Signed-off-by: Konstantin Khlebnikov <[email protected]>
---
fs/proc/base.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 9c8ca6cd3ce4..515ab29c2adf 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1962,9 +1962,12 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
goto out;
if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) {
- down_read(&mm->mmap_sem);
- exact_vma_exists = !!find_exact_vma(mm, vm_start, vm_end);
- up_read(&mm->mmap_sem);
+ status = down_read_killable(&mm->mmap_sem);
+ if (!status) {
+ exact_vma_exists = !!find_exact_vma(mm, vm_start,
+ vm_end);
+ up_read(&mm->mmap_sem);
+ }
}
mmput(mm);
@@ -2010,8 +2013,11 @@ static int map_files_get_link(struct dentry *dentry, struct path *path)
if (rc)
goto out_mmput;
+ rc = down_read_killable(&mm->mmap_sem);
+ if (rc)
+ goto out_mmput;
+
rc = -ENOENT;
- down_read(&mm->mmap_sem);
vma = find_exact_vma(mm, vm_start, vm_end);
if (vma && vma->vm_file) {
*path = vma->vm_file->f_path;
@@ -2107,7 +2113,10 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
if (!mm)
goto out_put_task;
- down_read(&mm->mmap_sem);
+ result = ERR_PTR(-EINTR);
+ if (down_read_killable(&mm->mmap_sem))
+ goto out_put_mm;
+
vma = find_exact_vma(mm, vm_start, vm_end);
if (!vma)
goto out_no_vma;
@@ -2118,6 +2127,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
out_no_vma:
up_read(&mm->mmap_sem);
+out_put_mm:
mmput(mm);
out_put_task:
put_task_struct(task);
@@ -2160,7 +2170,12 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
mm = get_task_mm(task);
if (!mm)
goto out_put_task;
- down_read(&mm->mmap_sem);
+
+ ret = down_read_killable(&mm->mmap_sem);
+ if (ret) {
+ mmput(mm);
+ goto out_put_task;
+ }
nr_files = 0;
On Wed, May 15, 2019 at 11:41:12AM +0300, Konstantin Khlebnikov wrote:
> Do not stuck forever if something wrong.
> This function also used for /proc/pid/smaps.
>
> Signed-off-by: Konstantin Khlebnikov <[email protected]>
All patches in series look ok to me (actually I thought if there
is a scenario where might_sleep may trigger a warning, and didn't
find one, so should be safe).
Reviewed-by: Cyrill Gorcunov <[email protected]>
On 15.05.2019 11:41, Konstantin Khlebnikov wrote:
> Do not stuck forever if something wrong.
> This function also used for /proc/pid/smaps.
>
> Signed-off-by: Konstantin Khlebnikov <[email protected]>
For the series:
Reviewed-by: Kirill Tkhai <[email protected]>
> ---
> fs/proc/task_mmu.c | 6 +++++-
> fs/proc/task_nommu.c | 6 +++++-
> 2 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index 01d4eb0e6bd1..2bf210229daf 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -166,7 +166,11 @@ static void *m_start(struct seq_file *m, loff_t *ppos)
> if (!mm || !mmget_not_zero(mm))
> return NULL;
>
> - down_read(&mm->mmap_sem);
> + if (down_read_killable(&mm->mmap_sem)) {
> + mmput(mm);
> + return ERR_PTR(-EINTR);
> + }
> +
> hold_task_mempolicy(priv);
> priv->tail_vma = get_gate_vma(mm);
>
> diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
> index 36bf0f2e102e..7907e6419e57 100644
> --- a/fs/proc/task_nommu.c
> +++ b/fs/proc/task_nommu.c
> @@ -211,7 +211,11 @@ static void *m_start(struct seq_file *m, loff_t *pos)
> if (!mm || !mmget_not_zero(mm))
> return NULL;
>
> - down_read(&mm->mmap_sem);
> + if (down_read_killable(&mm->mmap_sem)) {
> + mmput(mm);
> + return ERR_PTR(-EINTR);
> + }
> +
> /* start from the Nth VMA */
> for (p = rb_first(&mm->mm_rb); p; p = rb_next(p))
> if (n-- == 0)
On Wed, May 15, 2019 at 11:41:23AM +0300, Konstantin Khlebnikov wrote:
> It seems ->d_revalidate() could return any error (except ECHILD) to
> abort validation and pass error as result of lookup sequence.
>
> Signed-off-by: Konstantin Khlebnikov <[email protected]>
> ---
> fs/proc/base.c | 27 +++++++++++++++++++++------
> 1 file changed, 21 insertions(+), 6 deletions(-)
Hi!
The series looks good to me!
Reviewed-by: Roman Gushchin <[email protected]>
for all patches in the set.
The only thing, you need to add a bit more detailed commit messages
to patches 2 and 3.
Thanks!
On Wed 15-05-19 11:41:14, Konstantin Khlebnikov wrote:
> Ditto.
Proper changelog or simply squash those patches into a single patch if
you do not feel like copy&paste is fun
>
> Signed-off-by: Konstantin Khlebnikov <[email protected]>
> ---
> fs/proc/task_mmu.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index 2bf210229daf..781879a91e3b 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -832,7 +832,10 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
>
> memset(&mss, 0, sizeof(mss));
>
> - down_read(&mm->mmap_sem);
> + ret = down_read_killable(&mm->mmap_sem);
> + if (ret)
> + goto out_put_mm;
Why not ret = -EINTR. The seq_file code seems to be handling all errors
AFAICS.
> +
> hold_task_mempolicy(priv);
>
> for (vma = priv->mm->mmap; vma; vma = vma->vm_next) {
> @@ -849,8 +852,9 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
>
> release_task_mempolicy(priv);
> up_read(&mm->mmap_sem);
> - mmput(mm);
>
> +out_put_mm:
> + mmput(mm);
> out_put_task:
> put_task_struct(priv->task);
> priv->task = NULL;
--
Michal Hocko
SUSE Labs
On Wed 15-05-19 11:41:12, Konstantin Khlebnikov wrote:
> Do not stuck forever if something wrong.
> This function also used for /proc/pid/smaps.
I do agree that the killable variant is better but I do not understand
the changelog. What would keep the lock blocked for ever? I do not think
we have writer lock held for unbound amount of time anywhere, do we?
> Signed-off-by: Konstantin Khlebnikov <[email protected]>
Other than that
Acked-by: Michal Hocko <[email protected]>
> ---
> fs/proc/task_mmu.c | 6 +++++-
> fs/proc/task_nommu.c | 6 +++++-
> 2 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index 01d4eb0e6bd1..2bf210229daf 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -166,7 +166,11 @@ static void *m_start(struct seq_file *m, loff_t *ppos)
> if (!mm || !mmget_not_zero(mm))
> return NULL;
>
> - down_read(&mm->mmap_sem);
> + if (down_read_killable(&mm->mmap_sem)) {
> + mmput(mm);
> + return ERR_PTR(-EINTR);
> + }
> +
> hold_task_mempolicy(priv);
> priv->tail_vma = get_gate_vma(mm);
>
> diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
> index 36bf0f2e102e..7907e6419e57 100644
> --- a/fs/proc/task_nommu.c
> +++ b/fs/proc/task_nommu.c
> @@ -211,7 +211,11 @@ static void *m_start(struct seq_file *m, loff_t *pos)
> if (!mm || !mmget_not_zero(mm))
> return NULL;
>
> - down_read(&mm->mmap_sem);
> + if (down_read_killable(&mm->mmap_sem)) {
> + mmput(mm);
> + return ERR_PTR(-EINTR);
> + }
> +
> /* start from the Nth VMA */
> for (p = rb_first(&mm->mm_rb); p; p = rb_next(p))
> if (n-- == 0)
--
Michal Hocko
SUSE Labs
On Wed 15-05-19 11:41:21, Konstantin Khlebnikov wrote:
> Replace the only unkillable mmap_sem lock in clear_refs_write.
Poor changelog again.
The change itself looks ok to me.
> Signed-off-by: Konstantin Khlebnikov <[email protected]>
> ---
> fs/proc/task_mmu.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index 78bed6adc62d..7f84d1477b5b 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -1140,7 +1140,10 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
> goto out_mm;
> }
>
> - down_read(&mm->mmap_sem);
> + if (down_read_killable(&mm->mmap_sem)) {
> + count = -EINTR;
> + goto out_mm;
> + }
> tlb_gather_mmu(&tlb, mm, 0, -1);
> if (type == CLEAR_REFS_SOFT_DIRTY) {
> for (vma = mm->mmap; vma; vma = vma->vm_next) {
--
Michal Hocko
SUSE Labs
On Wed 15-05-19 11:41:19, Konstantin Khlebnikov wrote:
> Ditto.
ditto to the previous patch, including -EINTR.
>
> Signed-off-by: Konstantin Khlebnikov <[email protected]>
> ---
> fs/proc/task_mmu.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index 781879a91e3b..78bed6adc62d 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -1547,7 +1547,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
> /* overflow ? */
> if (end < start_vaddr || end > end_vaddr)
> end = end_vaddr;
> - down_read(&mm->mmap_sem);
> + ret = down_read_killable(&mm->mmap_sem);
> + if (ret)
> + goto out_free;
> ret = walk_page_range(start_vaddr, end, &pagemap_walk);
> up_read(&mm->mmap_sem);
> start_vaddr = end;
--
Michal Hocko
SUSE Labs
On 17.05.2019 15:45, Michal Hocko wrote:
> On Wed 15-05-19 11:41:14, Konstantin Khlebnikov wrote:
>> Ditto.
>
> Proper changelog or simply squash those patches into a single patch if
> you do not feel like copy&paste is fun
>
>>
>> Signed-off-by: Konstantin Khlebnikov <[email protected]>
>> ---
>> fs/proc/task_mmu.c | 8 ++++++--
>> 1 file changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
>> index 2bf210229daf..781879a91e3b 100644
>> --- a/fs/proc/task_mmu.c
>> +++ b/fs/proc/task_mmu.c
>> @@ -832,7 +832,10 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
>>
>> memset(&mss, 0, sizeof(mss));
>>
>> - down_read(&mm->mmap_sem);
>> + ret = down_read_killable(&mm->mmap_sem);
>> + if (ret)
>> + goto out_put_mm;
>
> Why not ret = -EINTR. The seq_file code seems to be handling all errors
> AFAICS.
>
I've missed your comment. Sorry.
down_read_killable returns 0 for success and exactly -EINTR for failure.
>> +
>> hold_task_mempolicy(priv);
>>
>> for (vma = priv->mm->mmap; vma; vma = vma->vm_next) {
>> @@ -849,8 +852,9 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
>>
>> release_task_mempolicy(priv);
>> up_read(&mm->mmap_sem);
>> - mmput(mm);
>>
>> +out_put_mm:
>> + mmput(mm);
>> out_put_task:
>> put_task_struct(priv->task);
>> priv->task = NULL;
>
On Sun 09-06-19 12:07:36, Konstantin Khlebnikov wrote:
[...]
> > > diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> > > index 2bf210229daf..781879a91e3b 100644
> > > --- a/fs/proc/task_mmu.c
> > > +++ b/fs/proc/task_mmu.c
> > > @@ -832,7 +832,10 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
> > > memset(&mss, 0, sizeof(mss));
> > > - down_read(&mm->mmap_sem);
> > > + ret = down_read_killable(&mm->mmap_sem);
> > > + if (ret)
> > > + goto out_put_mm;
> >
> > Why not ret = -EINTR. The seq_file code seems to be handling all errors
> > AFAICS.
> >
>
> I've missed your comment. Sorry.
>
> down_read_killable returns 0 for success and exactly -EINTR for failure.
You are right of course. I must have misread the code at the time. Sorry
about that.
--
Michal Hocko
SUSE Labs