On 06/22, Andy Lutomirski wrote:
>
> On Mon, Jun 22, 2015 at 5:47 PM, Oleg Nesterov <[email protected]> wrote:
> >
> > I never understood why ->mremap() lives in file_operations, not in
> > vm_operations_struct. To me vma->vm_file->f_op in move_vma() just
> > looks strange, vma->vm_ops->mremap(new_vma) looks "obviously better".
> >
> > And afaics more useful. CRIU remaps vdso, but this does not update
> > mm->context.vdso. OK, probably this does not matter currently, CRIU
> > can't c/r the compat tasks, and 64-bit apps do not use context.vdso.
> > Afaics. Still, I think we might want to have special_mapping_remap()
> > and we can't do this because ->vm_file == NULL.
>
> I would like this. Then I could clean up and resubmit my patch to
> keep context.vdso up to date.
Cough... where can I find this patch ? ;)
> Oleg, can you let me know what patch, if any, I should be reviewing?
This one, it looks really trivial. And of course I will appreciate it
if you can review the special_mapping_fault() fixes.
The change in move_vma() textually depends on another patch I sent,
[PATCH 1/4] mremap: don't leak new_vma if f_op->mremap() fails
http://marc.info/?l=linux-kernel&m=143475603713622
Oleg.
vma->vm_ops->mremap() looks more natural and clean in move_vma(),
and this way ->mremap() can have more users. Say, vdso.
Signed-off-by: Oleg Nesterov <[email protected]>
---
fs/aio.c | 25 ++++++++++++++++---------
include/linux/fs.h | 1 -
include/linux/mm.h | 1 +
mm/mremap.c | 4 ++--
4 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/fs/aio.c b/fs/aio.c
index 9bc1335..6fe662a 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -308,15 +308,9 @@ static void aio_free_ring(struct kioctx *ctx)
}
}
-static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
-{
- vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_ops = &generic_file_vm_ops;
- return 0;
-}
-
-static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
+static int aio_ring_remap(struct vm_area_struct *vma)
{
+ struct file *file = vma->vm_file;
struct mm_struct *mm = vma->vm_mm;
struct kioctx_table *table;
int i, res = -EINVAL;
@@ -339,9 +333,22 @@ static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
return res;
}
+static const struct vm_operations_struct aio_ring_vm_ops = {
+ .mremap = aio_ring_remap,
+ .fault = filemap_fault,
+ .map_pages = filemap_map_pages,
+ .page_mkwrite = filemap_page_mkwrite,
+};
+
+static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_ops = &aio_ring_vm_ops;
+ return 0;
+}
+
static const struct file_operations aio_ring_fops = {
.mmap = aio_ring_mmap,
- .mremap = aio_ring_remap,
};
#if IS_ENABLED(CONFIG_MIGRATION)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 35ec87e..42aac09 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1582,7 +1582,6 @@ struct file_operations {
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
- int (*mremap)(struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a0fe3d3..0295b4a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -244,6 +244,7 @@ struct vm_fault {
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
+ int (*mremap)(struct vm_area_struct * area);
int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
void (*map_pages)(struct vm_area_struct *vma, struct vm_fault *vmf);
diff --git a/mm/mremap.c b/mm/mremap.c
index ed1b13a..aeba807 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -276,8 +276,8 @@ static unsigned long move_vma(struct vm_area_struct *vma,
need_rmap_locks);
if (moved_len < old_len) {
err = -ENOMEM;
- } else if (vma->vm_file && vma->vm_file->f_op->mremap) {
- err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma);
+ } else if (vma->vm_ops && vma->vm_ops->mremap) {
+ err = vma->vm_ops->mremap(new_vma);
}
if (unlikely(err)) {
--
1.5.5.1
On Tue, Jun 23, 2015 at 08:02:51PM +0200, Oleg Nesterov wrote:
> vma->vm_ops->mremap() looks more natural and clean in move_vma(),
> and this way ->mremap() can have more users. Say, vdso.
>
> Signed-off-by: Oleg Nesterov <[email protected]>
> ---
> fs/aio.c | 25 ++++++++++++++++---------
> include/linux/fs.h | 1 -
> include/linux/mm.h | 1 +
> mm/mremap.c | 4 ++--
Please, update Documentation/filesystems/Locking.
> 4 files changed, 19 insertions(+), 12 deletions(-)
>
> diff --git a/fs/aio.c b/fs/aio.c
> index 9bc1335..6fe662a 100644
> --- a/fs/aio.c
> +++ b/fs/aio.c
> @@ -308,15 +308,9 @@ static void aio_free_ring(struct kioctx *ctx)
> }
> }
>
> -static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
> -{
> - vma->vm_flags |= VM_DONTEXPAND;
> - vma->vm_ops = &generic_file_vm_ops;
> - return 0;
> -}
> -
> -static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
> +static int aio_ring_remap(struct vm_area_struct *vma)
I guess aio_ring_mremap() would be a better name.
> {
> + struct file *file = vma->vm_file;
> struct mm_struct *mm = vma->vm_mm;
> struct kioctx_table *table;
> int i, res = -EINVAL;
--
Kirill A. Shutemov
On 06/23, Kirill A. Shutemov wrote:
>
> On Tue, Jun 23, 2015 at 08:02:51PM +0200, Oleg Nesterov wrote:
> > vma->vm_ops->mremap() looks more natural and clean in move_vma(),
> > and this way ->mremap() can have more users. Say, vdso.
> >
> > Signed-off-by: Oleg Nesterov <[email protected]>
> > ---
> > fs/aio.c | 25 ++++++++++++++++---------
> > include/linux/fs.h | 1 -
> > include/linux/mm.h | 1 +
> > mm/mremap.c | 4 ++--
>
> Please, update Documentation/filesystems/Locking.
OK, thanks, will do.
> > -static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
> > +static int aio_ring_remap(struct vm_area_struct *vma)
>
> I guess aio_ring_mremap() would be a better name.
Yes, agreed.
OK, I'll wait for other comments then send v2 with these changes.
Oleg.
On Tue, Jun 23, 2015 at 11:02 AM, Oleg Nesterov <[email protected]> wrote:
> On 06/22, Andy Lutomirski wrote:
>>
>> On Mon, Jun 22, 2015 at 5:47 PM, Oleg Nesterov <[email protected]> wrote:
>> >
>> > I never understood why ->mremap() lives in file_operations, not in
>> > vm_operations_struct. To me vma->vm_file->f_op in move_vma() just
>> > looks strange, vma->vm_ops->mremap(new_vma) looks "obviously better".
>> >
>> > And afaics more useful. CRIU remaps vdso, but this does not update
>> > mm->context.vdso. OK, probably this does not matter currently, CRIU
>> > can't c/r the compat tasks, and 64-bit apps do not use context.vdso.
>> > Afaics. Still, I think we might want to have special_mapping_remap()
>> > and we can't do this because ->vm_file == NULL.
>>
>> I would like this. Then I could clean up and resubmit my patch to
>> keep context.vdso up to date.
>
> Cough... where can I find this patch ? ;)
>
https://git.kernel.org/cgit/linux/kernel/git/luto/linux.git/log/?h=vdso/vma_tracking
--Andy
On Tue, Jun 23, 2015 at 11:02 AM, Oleg Nesterov <[email protected]> wrote:
> vma->vm_ops->mremap() looks more natural and clean in move_vma(),
> and this way ->mremap() can have more users. Say, vdso.
>
Looks generally reasonable.
--Andy
On 06/23/2015 09:02 PM, Oleg Nesterov wrote:
> vma->vm_ops->mremap() looks more natural and clean in move_vma(),
> and this way ->mremap() can have more users. Say, vdso.
>
> Signed-off-by: Oleg Nesterov <[email protected]>
Looks-good-to: /me :) Thanks!
On 06/23, Andy Lutomirski wrote:
>
> On Tue, Jun 23, 2015 at 11:02 AM, Oleg Nesterov <[email protected]> wrote:
> > On 06/22, Andy Lutomirski wrote:
> >>
> >> On Mon, Jun 22, 2015 at 5:47 PM, Oleg Nesterov <[email protected]> wrote:
> >> >
> >> > I never understood why ->mremap() lives in file_operations, not in
> >> > vm_operations_struct. To me vma->vm_file->f_op in move_vma() just
> >> > looks strange, vma->vm_ops->mremap(new_vma) looks "obviously better".
> >> >
> >> > And afaics more useful. CRIU remaps vdso, but this does not update
> >> > mm->context.vdso. OK, probably this does not matter currently, CRIU
> >> > can't c/r the compat tasks, and 64-bit apps do not use context.vdso.
> >> > Afaics. Still, I think we might want to have special_mapping_remap()
> >> > and we can't do this because ->vm_file == NULL.
> >>
> >> I would like this. Then I could clean up and resubmit my patch to
> >> keep context.vdso up to date.
> >
> > Cough... where can I find this patch ? ;)
> >
>
> https://git.kernel.org/cgit/linux/kernel/git/luto/linux.git/log/?h=vdso/vma_tracking
Aha, thanks. So yes, looks like your "Add a mechanism to track the current
address of a special mapping" can rely on vm_ops->mremap().
Oleg.
On 06/23, Oleg Nesterov wrote:
>
> On 06/23, Kirill A. Shutemov wrote:
> >
> > On Tue, Jun 23, 2015 at 08:02:51PM +0200, Oleg Nesterov wrote:
> > > vma->vm_ops->mremap() looks more natural and clean in move_vma(),
> > > and this way ->mremap() can have more users. Say, vdso.
> > >
> > > Signed-off-by: Oleg Nesterov <[email protected]>
> > > ---
> > > fs/aio.c | 25 ++++++++++++++++---------
> > > include/linux/fs.h | 1 -
> > > include/linux/mm.h | 1 +
> > > mm/mremap.c | 4 ++--
> >
> > Please, update Documentation/filesystems/Locking.
>
> OK, thanks, will do.
Wait... Documentation/filesystems/Locking doesn't mention
->mremap() at all.
So you actually ask me to add the new documentation? ;)
Oh well... OK, I'll try if you think this is necessary.
I tried to make the minimal change before ->mremap() finds another
user in file_operations. I thinks it needs more arguments, at least
new_addr and new_len, otherwise it is not easy to document it. The
same for f_op->mremap() of course.
Currently this does not matter, the only user is aio.c and
VM_DONTEXPAND means that it is not mergeable, so mremap() always
creates the new vma.
Hmm. Can't we do this change and add the documentation later?
Oleg.
On Wed, Jun 24, 2015 at 05:49:14PM +0200, Oleg Nesterov wrote:
> On 06/23, Oleg Nesterov wrote:
> >
> > On 06/23, Kirill A. Shutemov wrote:
> > >
> > > On Tue, Jun 23, 2015 at 08:02:51PM +0200, Oleg Nesterov wrote:
> > > > vma->vm_ops->mremap() looks more natural and clean in move_vma(),
> > > > and this way ->mremap() can have more users. Say, vdso.
> > > >
> > > > Signed-off-by: Oleg Nesterov <[email protected]>
> > > > ---
> > > > fs/aio.c | 25 ++++++++++++++++---------
> > > > include/linux/fs.h | 1 -
> > > > include/linux/mm.h | 1 +
> > > > mm/mremap.c | 4 ++--
> > >
> > > Please, update Documentation/filesystems/Locking.
> >
> > OK, thanks, will do.
>
> Wait... Documentation/filesystems/Locking doesn't mention
> ->mremap() at all.
>
> So you actually ask me to add the new documentation? ;)
I tried ;)
> Oh well... OK, I'll try if you think this is necessary.
>
> I tried to make the minimal change before ->mremap() finds another
> user in file_operations. I thinks it needs more arguments, at least
> new_addr and new_len, otherwise it is not easy to document it. The
> same for f_op->mremap() of course.
>
> Currently this does not matter, the only user is aio.c and
> VM_DONTEXPAND means that it is not mergeable, so mremap() always
> creates the new vma.
>
> Hmm. Can't we do this change and add the documentation later?
I'm fine with that.
--
Kirill A. Shutemov
On 06/24, Kirill A. Shutemov wrote:
>
> On Wed, Jun 24, 2015 at 05:49:14PM +0200, Oleg Nesterov wrote:
> >
> > Wait... Documentation/filesystems/Locking doesn't mention
> > ->mremap() at all.
> >
> > So you actually ask me to add the new documentation? ;)
>
> I tried ;)
Understand ;) but I failed to do this. Serisouly, I simply don't
know what can I add into this (outadted anyway) section except
"called when move_page_tables() targets this vma".
> > I tried to make the minimal change before ->mremap() finds another
> > user in file_operations. I thinks it needs more arguments, at least
> > new_addr and new_len, otherwise it is not easy to document it. The
> > same for f_op->mremap() of course.
> >
> > Currently this does not matter, the only user is aio.c and
> > VM_DONTEXPAND means that it is not mergeable, so mremap() always
> > creates the new vma.
> >
> > Hmm. Can't we do this change and add the documentation later?
>
> I'm fine with that.
OK, so I am sending v2 with the only change: rename aio_ring_remap
to aio_ring_mremap as you suggested.
Oleg.
vma->vm_ops->mremap() looks more natural and clean in move_vma(),
and this way ->mremap() can have more users. Say, vdso.
While at it, s/aio_ring_remap/aio_ring_mremap/.
Signed-off-by: Oleg Nesterov <[email protected]>
---
fs/aio.c | 25 ++++++++++++++++---------
include/linux/fs.h | 1 -
include/linux/mm.h | 1 +
mm/mremap.c | 4 ++--
4 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/fs/aio.c b/fs/aio.c
index 9bc1335..a632f14 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -308,15 +308,9 @@ static void aio_free_ring(struct kioctx *ctx)
}
}
-static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
-{
- vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_ops = &generic_file_vm_ops;
- return 0;
-}
-
-static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
+static int aio_ring_mremap(struct vm_area_struct *vma)
{
+ struct file *file = vma->vm_file;
struct mm_struct *mm = vma->vm_mm;
struct kioctx_table *table;
int i, res = -EINVAL;
@@ -339,9 +333,22 @@ static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
return res;
}
+static const struct vm_operations_struct aio_ring_vm_ops = {
+ .mremap = aio_ring_mremap,
+ .fault = filemap_fault,
+ .map_pages = filemap_map_pages,
+ .page_mkwrite = filemap_page_mkwrite,
+};
+
+static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_ops = &aio_ring_vm_ops;
+ return 0;
+}
+
static const struct file_operations aio_ring_fops = {
.mmap = aio_ring_mmap,
- .mremap = aio_ring_remap,
};
#if IS_ENABLED(CONFIG_MIGRATION)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 35ec87e..42aac09 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1582,7 +1582,6 @@ struct file_operations {
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
- int (*mremap)(struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a0fe3d3..0295b4a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -244,6 +244,7 @@ struct vm_fault {
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
+ int (*mremap)(struct vm_area_struct * area);
int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
void (*map_pages)(struct vm_area_struct *vma, struct vm_fault *vmf);
diff --git a/mm/mremap.c b/mm/mremap.c
index ed1b13a..aeba807 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -276,8 +276,8 @@ static unsigned long move_vma(struct vm_area_struct *vma,
need_rmap_locks);
if (moved_len < old_len) {
err = -ENOMEM;
- } else if (vma->vm_file && vma->vm_file->f_op->mremap) {
- err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma);
+ } else if (vma->vm_ops && vma->vm_ops->mremap) {
+ err = vma->vm_ops->mremap(new_vma);
}
if (unlikely(err)) {
--
1.5.5.1
On Thu, Jun 25, 2015 at 10:45:04PM +0200, Oleg Nesterov wrote:
> vma->vm_ops->mremap() looks more natural and clean in move_vma(),
> and this way ->mremap() can have more users. Say, vdso.
>
> While at it, s/aio_ring_remap/aio_ring_mremap/.
>
> Signed-off-by: Oleg Nesterov <[email protected]>
> ---
> fs/aio.c | 25 ++++++++++++++++---------
> include/linux/fs.h | 1 -
> include/linux/mm.h | 1 +
> mm/mremap.c | 4 ++--
> 4 files changed, 19 insertions(+), 12 deletions(-)
>
> diff --git a/fs/aio.c b/fs/aio.c
> index 9bc1335..a632f14 100644
> --- a/fs/aio.c
> +++ b/fs/aio.c
> @@ -308,15 +308,9 @@ static void aio_free_ring(struct kioctx *ctx)
> }
> }
>
> -static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
> -{
> - vma->vm_flags |= VM_DONTEXPAND;
> - vma->vm_ops = &generic_file_vm_ops;
> - return 0;
> -}
> -
> -static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
> +static int aio_ring_mremap(struct vm_area_struct *vma)
> {
> + struct file *file = vma->vm_file;
> struct mm_struct *mm = vma->vm_mm;
> struct kioctx_table *table;
> int i, res = -EINVAL;
> @@ -339,9 +333,22 @@ static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
> return res;
> }
>
> +static const struct vm_operations_struct aio_ring_vm_ops = {
> + .mremap = aio_ring_mremap,
> + .fault = filemap_fault,
> + .map_pages = filemap_map_pages,
> + .page_mkwrite = filemap_page_mkwrite,
> +};
> +
> +static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> + vma->vm_flags |= VM_DONTEXPAND;
> + vma->vm_ops = &aio_ring_vm_ops;
> + return 0;
> +}
> +
> static const struct file_operations aio_ring_fops = {
> .mmap = aio_ring_mmap,
> - .mremap = aio_ring_remap,
> };
>
> #if IS_ENABLED(CONFIG_MIGRATION)
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 35ec87e..42aac09 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1582,7 +1582,6 @@ struct file_operations {
> long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
> long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
> int (*mmap) (struct file *, struct vm_area_struct *);
> - int (*mremap)(struct file *, struct vm_area_struct *);
> int (*open) (struct inode *, struct file *);
> int (*flush) (struct file *, fl_owner_t id);
> int (*release) (struct inode *, struct file *);
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index a0fe3d3..0295b4a 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -244,6 +244,7 @@ struct vm_fault {
> struct vm_operations_struct {
> void (*open)(struct vm_area_struct * area);
> void (*close)(struct vm_area_struct * area);
> + int (*mremap)(struct vm_area_struct * area);
> int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
> void (*map_pages)(struct vm_area_struct *vma, struct vm_fault *vmf);
>
> diff --git a/mm/mremap.c b/mm/mremap.c
> index ed1b13a..aeba807 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -276,8 +276,8 @@ static unsigned long move_vma(struct vm_area_struct *vma,
> need_rmap_locks);
> if (moved_len < old_len) {
> err = -ENOMEM;
> - } else if (vma->vm_file && vma->vm_file->f_op->mremap) {
> - err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma);
> + } else if (vma->vm_ops && vma->vm_ops->mremap) {
> + err = vma->vm_ops->mremap(new_vma);
> }
>
> if (unlikely(err)) {
I'm not sure what is target tree for the patch. Last hunk is not going to
apply on Linus' tree or -next. Hm?
Otherwise, looks good.
Acked-by: Kirill A. Shutemov <[email protected]>
--
Kirill A. Shutemov
On 06/26, Kirill A. Shutemov wrote:
>
> > --- a/mm/mremap.c
> > +++ b/mm/mremap.c
> > @@ -276,8 +276,8 @@ static unsigned long move_vma(struct vm_area_struct *vma,
> > need_rmap_locks);
> > if (moved_len < old_len) {
> > err = -ENOMEM;
> > - } else if (vma->vm_file && vma->vm_file->f_op->mremap) {
> > - err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma);
> > + } else if (vma->vm_ops && vma->vm_ops->mremap) {
> > + err = vma->vm_ops->mremap(new_vma);
> > }
> >
> > if (unlikely(err)) {
>
> I'm not sure what is target tree for the patch.
I hope akpm can take this patch into -mm,
> Last hunk is not going to
> apply on Linus' tree or -next. Hm?
Yes, this depends on another fix I sent to Andrew (and you ;), as 0/1
explains the change in move_vma() textually depends on another patch I sent,
[PATCH 1/4] mremap: don't leak new_vma if f_op->mremap() fails
http://marc.info/?l=linux-kernel&m=143475603713622
> Otherwise, looks good.
>
> Acked-by: Kirill A. Shutemov <[email protected]>
Thanks!
Oleg.
On 06/25/2015 11:45 PM, Oleg Nesterov wrote:
> vma->vm_ops->mremap() looks more natural and clean in move_vma(),
> and this way ->mremap() can have more users. Say, vdso.
>
> While at it, s/aio_ring_remap/aio_ring_mremap/.
>
> Signed-off-by: Oleg Nesterov <[email protected]>
Acked-by: Pavel Emelyanov <[email protected]>