* [PATCH/RFT 0/7] rsnd: add support for r8a77965
From: Simon Horman @ 2018-07-23 16:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1531856883-19645-1-git-send-email-ykaneko0929@gmail.com>
On Wed, Jul 18, 2018 at 04:47:56AM +0900, Yoshihiro Kaneko wrote:
> This series adds sound support for r8a77965 (R-Car M3-N).
> This series is based on the devel branch of Simon Horman's renesas tree.
>
> Hiroyuki Yokoyama (1):
> ASoC: rsnd: Document R-Car M3-N support
>
> Takeshi Kihara (6):
> arm64: dts: renesas: r8a77965: Add Audio-DMAC device nodes
> arm64: dts: renesas: r8a77965: Add Sound device node and SSI support
> arm64: dts: renesas: r8a77965: Add Sound SRC support
> arm64: dts: renesas: r8a77965: Add Sound DVC device nodes
> arm64: dts: renesas: r8a77965: Add Sound CTU support
> arm64: dts: renesas: r8a77965: Add Sound MIX support
>
> .../devicetree/bindings/sound/renesas,rsnd.txt | 1 +
> arch/arm64/boot/dts/renesas/r8a77965.dtsi | 245 ++++++++++++++++++++-
Thanks Kaneko-san,
in general this series looks good, however, I would like to ask you to
squash all the dts patches (the patches by Kihara-san) into a single patch.
For many years now we have split patches up as this series does.
And no doubt that is why BPS team chose to split up the patches
that you have based this patchset on. However, we were recently
asked by the Olof Johansson to squash patches together to make
the high-level intent of patches clearer to him in his position
of ARM-SoC co-maintainer.
So while what you have done is correct, it is now the "old way".
Please squash the patches together as this is the "new way".
Thanks!
^ permalink raw reply
* Re: Incorrect name of PCM
From: Christopher Head @ 2018-07-23 16:21 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
In-Reply-To: <s5hsh4a3p34.wl-tiwai@suse.de>
[-- Attachment #1.1: Type: text/plain, Size: 619 bytes --]
On July 23, 2018 9:15:59 AM PDT, Takashi Iwai <tiwai@suse.de> wrote:
>Just ignore this entry. alsa-lib tries to parse the all possible
>outputs that are provided from the kernel interface. Due to
>historical reasons, this digital output might be either SPDIF or HDMI,
>and alsa-lib has no knowledge to distinguish easily, hence both spdif
>and hdmi device names are provided equally for such a case.
Not here, they aren’t. There is no PCM named “spdif” at all: it isn’t in the list, and if I type it, I can’t play to it for a reason that looks a lot like it doesn’t exist.
--
Christopher Head
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 244 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [PATCH 06/14] format-patch: allow --interdiff to apply to a lone-patch
From: Duy Nguyen @ 2018-07-23 16:22 UTC (permalink / raw)
To: Eric Sunshine
Cc: Git Mailing List, Johannes Schindelin,
Ævar Arnfjörð Bjarmason, Stefan Beller
In-Reply-To: <20180722095717.17912-7-sunshine@sunshineco.com>
On Sun, Jul 22, 2018 at 11:58 AM Eric Sunshine <sunshine@sunshineco.com> wrote:
> diff --git a/log-tree.c b/log-tree.c
> index 9d38f1cf79..56513fa83d 100644
> --- a/log-tree.c
> +++ b/log-tree.c
> @@ -14,6 +14,7 @@
> #include "sequencer.h"
> #include "line-log.h"
> #include "help.h"
> +#include "interdiff.h"
>
> static struct decoration name_decoration = { "object names" };
> static int decoration_loaded;
> @@ -736,6 +737,19 @@ void show_log(struct rev_info *opt)
>
> strbuf_release(&msgbuf);
> free(ctx.notes_message);
> +
> + if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) {
OK putting idiff stuff in rev_info is probably the right choice. But
we all three fields prefixed with idiff_, maybe you could just add a
new struct "idiff_options" to contain them and add a pointer to that
struct in rev_info. Then "opt->idiff" is enough to know if idiff is
requested instead of relying on idiff_oid1 (seems too random).
> + struct diff_queue_struct dq;
> +
> + memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
> + DIFF_QUEUE_CLEAR(&diff_queued_diff);
> +
> + next_commentary_block(opt, NULL);
> + fprintf_ln(opt->diffopt.file, "%s", opt->idiff_title);
> + show_interdiff(opt, 2);
> +
> + memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
> + }
> }
--
Duy
^ permalink raw reply
* [GIT PULL] Renesas ARM Based SoC Defconfig Updates for v4.19
From: Olof Johansson @ 2018-07-23 16:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMuHMdVbyUa5PtQf4LZQDv-=aqToahX5Eb4TEDvsJniYm-trNQ@mail.gmail.com>
On Mon, Jul 23, 2018 at 2:11 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> Hi Olof,
>
> On Sun, Jul 22, 2018 at 12:27 AM Olof Johansson <olof@lixom.net> wrote:
>> On Fri, Jul 20, 2018 at 02:03:54PM +0200, Simon Horman wrote:
>> > Please consider these Renesas ARM based SoC defconfig updates for v4.19.
>
>> > * Set CONFIG_LOCALVERSION to shmobile_defconfig
>> >
>> > This follows what appears to be common practice in defconfigs
>> > and allows easier management of the kernel flavour at run-time.
>>
>> I replied to the multi-versions of defconfig for this patch -- it's not a good
>> way to solve the problem of detecting config at runtime. Please drop this
>> patch. See:
>>
>> https://lore.kernel.org/lkml/CAOesGMgkU6yBRpAsED2fPyuAo9Tc=YprndGdkmBVrc+0783VwQ at mail.gmail.com/
>
> One more comment to the rescue: it does complicate regression testing,
> as the test software running on the DUT has no easy way to distinguish
> between e.g. shmobile_defconfig and multi_v7_defconfig (and whatever
> other board-specific configs I use for testing).
> Yes, I can have these as local patches in my tree (of course I already have ;-),
> but when bisecting, I have to remember to (un)apply them in every step.
Hi,
It looks like scripts/setlocalversion will look for files named
localversion* in the directory you build in, git won't touch the file
so you don't have to re-apply it every time.
I do see the usefulness for bisect and so on, but there's such a high
chance that people will start changing configs without changing
localversion that the value of it will diminish immediately for
downstream trees. Also, the "local" in localversion sort of indicates
that it shouldn't be set in a central place. :)
-Olof
^ permalink raw reply
* Re: [PATCH 0/4][RFC v2] Introduce the in-kernel hibernation encryption
From: Yu Chen @ 2018-07-23 16:23 UTC (permalink / raw)
To: Oliver Neukum
Cc: Pavel Machek, Rafael J . Wysocki, Eric Biggers, Lee, Chun-Yi,
Theodore Ts o, Stephan Mueller, Denis Kenzior, linux-pm,
linux-crypto, linux-kernel, Gu, Kookoo, Zhang, Rui
In-Reply-To: <1532346156.3057.11.camel@suse.com>
Hi,
On Mon, Jul 23, 2018 at 01:42:36PM +0200, Oliver Neukum wrote:
> On Fr, 2018-07-20 at 12:25 +0200, Pavel Machek wrote:
> > Hi!
>
> Hello,
>
> > > Let me paste the log here:
> > >
> > > 1. (This is not to compare with uswsusp but other
> > > tools) One advantage is: Users do not have to
> > > encrypt the whole swap partition as other tools.
> >
> > Well.. encrypting the partition seems like good idea anyway.
>
> Yes, but it is a policy decision the kernel should not force.
> STD needs to work anyway.
>
If the swap partition is too large, and there's low usage
of memory, then it might a little time costly to encrypt
the whole partition. You are right, people has choice to
choose which mode they like.
> > > 2. Ideally kernel memory should be encrypted by the
> > > kernel itself. We have uswsusp to support user
> > > space hibernation, however doing the encryption
> > > in kernel space has more advantages:
> > > 2.1 Not having to transfer plain text kernel memory to
> > > user space. Per Lee, Chun-Yi, uswsusp is disabled
> > > when the kernel is locked down:
> > > https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/
> > > linux-fs.git/commit/?h=lockdown-20180410&
> > > id=8732c1663d7c0305ae01ba5a1ee4d2299b7b4612
> > > due to:
> > > "There have some functions be locked-down because
> > > there have no appropriate mechanisms to check the
> > > integrity of writing data."
> > > https://patchwork.kernel.org/patch/10476751/
> >
> > So your goal is to make hibernation compatible with kernel
> > lockdown? Do your patches provide sufficient security that hibernation
> > can be enabled with kernel lockdown?
>
> OK, maybe I am dense, but if the key comes from user space, will that
> be enough?
>
Good point, we once tried to generate key in kernel, but people
suggest to generate key in userspace and provide it to the
kernel, which is what ecryptfs do currently, so it seems this
should also be safe for encryption in kernel.
https://www.spinics.net/lists/linux-crypto/msg33145.html
Thus Chun-Yi's signature can use EFI key and both the key from
user space.
Best,
Yu
> > > 2.2 Not having to copy each page to user space
> > > one by one not in parallel, which might introduce
> > > significant amount of copy_to_user() and it might
> > > not be efficient on servers having large amount of DRAM.
> >
> > So how big speedup can be attributed by not doing copy_to_user?
>
> That would be an argument for compression in kernel space.
> Not encrpting would always be faster.
>
> > > 2.3 Distribution has requirement to do snapshot
> > > signature for verification, which can be built
> > > by leveraging this patch set.
> >
> > Signatures can be done by uswsusp, too, right?
>
> Not if you want to keep the chain of trust intact. User space
> is not signed.
>
> > > 2.4 The encryption is in the kernel, so it doesn't
> > > have to worry too much about bugs in user space
> > > utilities and similar, for example.
> >
> > Answer to bugs in userspace is _not_ to move code from userspace to kernel.
>
> Indeed.
>
> > > Joey Lee and I had a discussion on his previous work at
> > > https://patchwork.kernel.org/patch/10476751
> > > We collaborate on this task and his snapshot signature
> > > feature can be based on this patch set.
> >
> > Well, his work can also work without your patchset, right?
>
> Yes. But you are objecting to encryption in kernel space at all,
> aren't you?
>
> Regards
> Oliver
>
^ permalink raw reply
* Re: [PATCH v6 06/13] mm, dev_pagemap: Do not clear ->mapping on final put
From: Jerome Glisse @ 2018-07-23 16:23 UTC (permalink / raw)
To: Dave Jiang
Cc: Dan Williams, linux-nvdimm, Jan Kara, linux-kernel, stable,
linux-mm, linux-fsdevel, Andrew Morton, hch
In-Reply-To: <3fcb3c8a-2a41-7c78-edde-066c10110d34@intel.com>
On Mon, Jul 23, 2018 at 09:12:06AM -0700, Dave Jiang wrote:
> Jerome,
> Is it possible to get an ack for this? Thanks!
>
> On 07/13/2018 09:50 PM, Dan Williams wrote:
> > MEMORY_DEVICE_FS_DAX relies on typical page semantics whereby ->mapping
> > is only ever cleared by truncation, not final put.
> >
> > Without this fix dax pages may forget their mapping association at the
> > end of every page pin event.
> >
> > Move this atypical behavior that HMM wants into the HMM ->page_free()
> > callback.
> >
> > Cc: <stable@vger.kernel.org>
> > Cc: Jan Kara <jack@suse.cz>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> > Fixes: d2c997c0f145 ("fs, dax: use page->mapping...")
> > Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: J�r�me Glisse <jglisse@redhat.com>
> > ---
> > kernel/memremap.c | 1 -
> > mm/hmm.c | 2 ++
> > 2 files changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/memremap.c b/kernel/memremap.c
> > index 5857267a4af5..62603634a1d2 100644
> > --- a/kernel/memremap.c
> > +++ b/kernel/memremap.c
> > @@ -339,7 +339,6 @@ void __put_devmap_managed_page(struct page *page)
> > __ClearPageActive(page);
> > __ClearPageWaiters(page);
> >
> > - page->mapping = NULL;
> > mem_cgroup_uncharge(page);
> >
> > page->pgmap->page_free(page, page->pgmap->data);
> > diff --git a/mm/hmm.c b/mm/hmm.c
> > index de7b6bf77201..f9d1d89dec4d 100644
> > --- a/mm/hmm.c
> > +++ b/mm/hmm.c
> > @@ -963,6 +963,8 @@ static void hmm_devmem_free(struct page *page, void *data)
> > {
> > struct hmm_devmem *devmem = data;
> >
> > + page->mapping = NULL;
> > +
> > devmem->ops->free(devmem, page);
> > }
> >
> >
> > _______________________________________________
> > Linux-nvdimm mailing list
> > Linux-nvdimm@lists.01.org
> > https://lists.01.org/mailman/listinfo/linux-nvdimm
> >
^ permalink raw reply
* Re: [PATCH v6 06/13] mm, dev_pagemap: Do not clear ->mapping on final put
From: Jerome Glisse @ 2018-07-23 16:23 UTC (permalink / raw)
To: Dave Jiang
Cc: Jan Kara, linux-nvdimm, linux-kernel, stable, hch, linux-mm,
linux-fsdevel, Andrew Morton
In-Reply-To: <3fcb3c8a-2a41-7c78-edde-066c10110d34@intel.com>
On Mon, Jul 23, 2018 at 09:12:06AM -0700, Dave Jiang wrote:
> Jerome,
> Is it possible to get an ack for this? Thanks!
>
> On 07/13/2018 09:50 PM, Dan Williams wrote:
> > MEMORY_DEVICE_FS_DAX relies on typical page semantics whereby ->mapping
> > is only ever cleared by truncation, not final put.
> >
> > Without this fix dax pages may forget their mapping association at the
> > end of every page pin event.
> >
> > Move this atypical behavior that HMM wants into the HMM ->page_free()
> > callback.
> >
> > Cc: <stable@vger.kernel.org>
> > Cc: Jan Kara <jack@suse.cz>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> > Fixes: d2c997c0f145 ("fs, dax: use page->mapping...")
> > Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Jérôme Glisse <jglisse@redhat.com>
> > ---
> > kernel/memremap.c | 1 -
> > mm/hmm.c | 2 ++
> > 2 files changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/memremap.c b/kernel/memremap.c
> > index 5857267a4af5..62603634a1d2 100644
> > --- a/kernel/memremap.c
> > +++ b/kernel/memremap.c
> > @@ -339,7 +339,6 @@ void __put_devmap_managed_page(struct page *page)
> > __ClearPageActive(page);
> > __ClearPageWaiters(page);
> >
> > - page->mapping = NULL;
> > mem_cgroup_uncharge(page);
> >
> > page->pgmap->page_free(page, page->pgmap->data);
> > diff --git a/mm/hmm.c b/mm/hmm.c
> > index de7b6bf77201..f9d1d89dec4d 100644
> > --- a/mm/hmm.c
> > +++ b/mm/hmm.c
> > @@ -963,6 +963,8 @@ static void hmm_devmem_free(struct page *page, void *data)
> > {
> > struct hmm_devmem *devmem = data;
> >
> > + page->mapping = NULL;
> > +
> > devmem->ops->free(devmem, page);
> > }
> >
> >
> > _______________________________________________
> > Linux-nvdimm mailing list
> > Linux-nvdimm@lists.01.org
> > https://lists.01.org/mailman/listinfo/linux-nvdimm
> >
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply
* Re: [PATCH v6 06/13] mm, dev_pagemap: Do not clear ->mapping on final put
From: Jerome Glisse @ 2018-07-23 16:23 UTC (permalink / raw)
To: Dave Jiang
Cc: Dan Williams, linux-nvdimm, Jan Kara, linux-kernel, stable,
linux-mm, linux-fsdevel, Andrew Morton, hch
In-Reply-To: <3fcb3c8a-2a41-7c78-edde-066c10110d34@intel.com>
On Mon, Jul 23, 2018 at 09:12:06AM -0700, Dave Jiang wrote:
> Jerome,
> Is it possible to get an ack for this? Thanks!
>
> On 07/13/2018 09:50 PM, Dan Williams wrote:
> > MEMORY_DEVICE_FS_DAX relies on typical page semantics whereby ->mapping
> > is only ever cleared by truncation, not final put.
> >
> > Without this fix dax pages may forget their mapping association at the
> > end of every page pin event.
> >
> > Move this atypical behavior that HMM wants into the HMM ->page_free()
> > callback.
> >
> > Cc: <stable@vger.kernel.org>
> > Cc: Jan Kara <jack@suse.cz>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> > Fixes: d2c997c0f145 ("fs, dax: use page->mapping...")
> > Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Jerome Glisse <jglisse@redhat.com>
> > ---
> > kernel/memremap.c | 1 -
> > mm/hmm.c | 2 ++
> > 2 files changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/memremap.c b/kernel/memremap.c
> > index 5857267a4af5..62603634a1d2 100644
> > --- a/kernel/memremap.c
> > +++ b/kernel/memremap.c
> > @@ -339,7 +339,6 @@ void __put_devmap_managed_page(struct page *page)
> > __ClearPageActive(page);
> > __ClearPageWaiters(page);
> >
> > - page->mapping = NULL;
> > mem_cgroup_uncharge(page);
> >
> > page->pgmap->page_free(page, page->pgmap->data);
> > diff --git a/mm/hmm.c b/mm/hmm.c
> > index de7b6bf77201..f9d1d89dec4d 100644
> > --- a/mm/hmm.c
> > +++ b/mm/hmm.c
> > @@ -963,6 +963,8 @@ static void hmm_devmem_free(struct page *page, void *data)
> > {
> > struct hmm_devmem *devmem = data;
> >
> > + page->mapping = NULL;
> > +
> > devmem->ops->free(devmem, page);
> > }
> >
> >
> > _______________________________________________
> > Linux-nvdimm mailing list
> > Linux-nvdimm@lists.01.org
> > https://lists.01.org/mailman/listinfo/linux-nvdimm
> >
^ permalink raw reply
* Re: [PATCH v6 06/13] mm, dev_pagemap: Do not clear ->mapping on final put
From: Jerome Glisse @ 2018-07-23 16:23 UTC (permalink / raw)
To: Dave Jiang
Cc: Dan Williams, linux-nvdimm, Jan Kara, linux-kernel, stable,
linux-mm, linux-fsdevel, Andrew Morton, hch
In-Reply-To: <3fcb3c8a-2a41-7c78-edde-066c10110d34@intel.com>
On Mon, Jul 23, 2018 at 09:12:06AM -0700, Dave Jiang wrote:
> Jerome,
> Is it possible to get an ack for this? Thanks!
>
> On 07/13/2018 09:50 PM, Dan Williams wrote:
> > MEMORY_DEVICE_FS_DAX relies on typical page semantics whereby ->mapping
> > is only ever cleared by truncation, not final put.
> >
> > Without this fix dax pages may forget their mapping association at the
> > end of every page pin event.
> >
> > Move this atypical behavior that HMM wants into the HMM ->page_free()
> > callback.
> >
> > Cc: <stable@vger.kernel.org>
> > Cc: Jan Kara <jack@suse.cz>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> > Fixes: d2c997c0f145 ("fs, dax: use page->mapping...")
> > Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Jérôme Glisse <jglisse@redhat.com>
> > ---
> > kernel/memremap.c | 1 -
> > mm/hmm.c | 2 ++
> > 2 files changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/memremap.c b/kernel/memremap.c
> > index 5857267a4af5..62603634a1d2 100644
> > --- a/kernel/memremap.c
> > +++ b/kernel/memremap.c
> > @@ -339,7 +339,6 @@ void __put_devmap_managed_page(struct page *page)
> > __ClearPageActive(page);
> > __ClearPageWaiters(page);
> >
> > - page->mapping = NULL;
> > mem_cgroup_uncharge(page);
> >
> > page->pgmap->page_free(page, page->pgmap->data);
> > diff --git a/mm/hmm.c b/mm/hmm.c
> > index de7b6bf77201..f9d1d89dec4d 100644
> > --- a/mm/hmm.c
> > +++ b/mm/hmm.c
> > @@ -963,6 +963,8 @@ static void hmm_devmem_free(struct page *page, void *data)
> > {
> > struct hmm_devmem *devmem = data;
> >
> > + page->mapping = NULL;
> > +
> > devmem->ops->free(devmem, page);
> > }
> >
> >
> > _______________________________________________
> > Linux-nvdimm mailing list
> > Linux-nvdimm@lists.01.org
> > https://lists.01.org/mailman/listinfo/linux-nvdimm
> >
^ permalink raw reply
* Re: [PATCH] ext4: remove abnormal set for I_DATA_SEM subclass
From: Theodore Y. Ts'o @ 2018-07-23 16:23 UTC (permalink / raw)
To: 이준일/연구원/MC연구소 BSP실 BSP6팀(junil0814.lee@lge.com)
Cc: adilger.kernel, linux-ext4, linux-kernel, junil0814.lee
In-Reply-To: <ccb7943b-44af-5031-8410-f1c0851e70c2@lge.com>
On Mon, Jul 23, 2018 at 10:48:37AM +0900, 이준일/연구원/MC연구소 BSP실 BSP6팀(junil0814.lee@lge.com) wrote:
> Then, I have a question.
> quotactl() doesn't have case only to set limits flag, the routine to set
> the DQUOT_LIMITS_ENABLED flag is under dquot_enable() function.
> According to this logic, if users makes duplicate request to set
> DQUOT_LIMITS_ENABLED flags, can lockdep make the false alarm with ext4 ?
With the upstream kernel, if you call quotactl with the Q_QUOTAON
command, it will fail with EEXIST before it ever gets to the file
system specific quota code. This happens in dquot_quota_enable() in
fs/quota/dquot.c.
I'm going to guess you didn't try to reproduce the problem with the
latest mainstream kernel, and then applied the patch, and verified the
problem went away before you submitted it?
Regards,
- Ted
^ permalink raw reply
* [GIT PULL] Amlogic 64-bit DT changes for v4.19 (redo)
From: Olof Johansson @ 2018-07-23 16:23 UTC (permalink / raw)
To: linus-amlogic
In-Reply-To: <1532340120.26720.94.camel@baylibre.com>
On Mon, Jul 23, 2018 at 3:02 AM, Jerome Brunet <jbrunet@baylibre.com> wrote:
> On Sat, 2018-07-21 at 14:52 -0700, Olof Johansson wrote:
>> > ----------------------------------------------------------------
>> > Amlogic 64-bit DT updates for v4.19
>> > - new SoC: S805x
>> > - new board: S805x-based P241 board from Amlogic
>> > - AXG: add ADC support w/buttons, add pins for PDM, SPDIF
>> > - AXG: s400 board: preliminary support for audio
>> > - GX: nanopi-k2: add HDMI, CEC, CVBS support
>> >
>> > ----------------------------------------------------------------
>> > Jerome Brunet (9):
>> > ARM64: dts: meson-axg: add s400 microphone card leds
>> > ARM64: dts: meson-axg: add s400 main 12v supply
>> > ARM64: dts: meson-axg: add s400 speaker amplifier
>> > ARM64: dts: meson-axg: add spdif output pins
>> > ARM64: dts: meson-axg: remove vddio_ao18 from SoC dtsi
>> > ARM64: dts: meson-axg: add adc buttons the S400
>> > ARM64: dts: meson-axg: remove spdif out from gpio a7
>> > ARM64: dts: meson-axg: add spdif input pins
>> > ARM64: dts: meson-axg: add pdm pins
>>
>> I've started being a little grumpy with others to keep it consistent, and
>> you're consistent internally but not against other platforms: We use "arm64" or
>> ARM" as prefixes, not ARM64/arm.
>>
>> I think it's time for a checkpatch rule for this, it's a bit silly to have to
>> point it out all the time since people seem to get it wrong so often.
>>
>> I'll merge this for now and look at adding the rules.
>
> Hi Olof,
>
> Just to be clear, from now on, you request that we use 'arm64' as prefix,
> instead of 'ARM64' ?
>
> And we should continue with 'ARM' for the 32bits arch (and not 'arm'), right ?
Jerome,
Confirmed; Plesae use 'arm64: dts: meson: ..." on 64-bit, and "ARM:
dts: meson: ..." on 32-bit, at least until further notice.
I know, I know, it's not ideal. Getting a fix into checkpatch will help.
-Olof
^ permalink raw reply
* [GIT PULL] Amlogic 64-bit DT changes for v4.19 (redo)
From: Olof Johansson @ 2018-07-23 16:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1532340120.26720.94.camel@baylibre.com>
On Mon, Jul 23, 2018 at 3:02 AM, Jerome Brunet <jbrunet@baylibre.com> wrote:
> On Sat, 2018-07-21 at 14:52 -0700, Olof Johansson wrote:
>> > ----------------------------------------------------------------
>> > Amlogic 64-bit DT updates for v4.19
>> > - new SoC: S805x
>> > - new board: S805x-based P241 board from Amlogic
>> > - AXG: add ADC support w/buttons, add pins for PDM, SPDIF
>> > - AXG: s400 board: preliminary support for audio
>> > - GX: nanopi-k2: add HDMI, CEC, CVBS support
>> >
>> > ----------------------------------------------------------------
>> > Jerome Brunet (9):
>> > ARM64: dts: meson-axg: add s400 microphone card leds
>> > ARM64: dts: meson-axg: add s400 main 12v supply
>> > ARM64: dts: meson-axg: add s400 speaker amplifier
>> > ARM64: dts: meson-axg: add spdif output pins
>> > ARM64: dts: meson-axg: remove vddio_ao18 from SoC dtsi
>> > ARM64: dts: meson-axg: add adc buttons the S400
>> > ARM64: dts: meson-axg: remove spdif out from gpio a7
>> > ARM64: dts: meson-axg: add spdif input pins
>> > ARM64: dts: meson-axg: add pdm pins
>>
>> I've started being a little grumpy with others to keep it consistent, and
>> you're consistent internally but not against other platforms: We use "arm64" or
>> ARM" as prefixes, not ARM64/arm.
>>
>> I think it's time for a checkpatch rule for this, it's a bit silly to have to
>> point it out all the time since people seem to get it wrong so often.
>>
>> I'll merge this for now and look at adding the rules.
>
> Hi Olof,
>
> Just to be clear, from now on, you request that we use 'arm64' as prefix,
> instead of 'ARM64' ?
>
> And we should continue with 'ARM' for the 32bits arch (and not 'arm'), right ?
Jerome,
Confirmed; Plesae use 'arm64: dts: meson: ..." on 64-bit, and "ARM:
dts: meson: ..." on 32-bit, at least until further notice.
I know, I know, it's not ideal. Getting a fix into checkpatch will help.
-Olof
^ permalink raw reply
* [Intel-wired-lan] [RFC PATCH] ixgbe: ixgbe_get_completion_timeout() can be static
From: Alexander Duyck @ 2018-07-23 16:24 UTC (permalink / raw)
To: intel-wired-lan
In-Reply-To: <20180721055327.GA30259@lkp-wsm-ep1>
On Fri, Jul 20, 2018 at 10:53 PM, kbuild test robot
<fengguang.wu@intel.com> wrote:
>
> Fixes: 23f3effc3f69 ("ixgbe: Refactor queue disable logic to take completion time into account")
> Signed-off-by: kbuild test robot <fengguang.wu@intel.com>
Jeff do you think you could fold this into the current completion timeout patch?
Thanks.
- Alex
^ permalink raw reply
* Re: [PATCH 02/10] mm: workingset: tell cache transitions from workingset thrashing
From: Johannes Weiner @ 2018-07-23 16:27 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Peter Zijlstra, Suren Baghdasaryan, Mike Galbraith, Will Deacon,
Linux Kernel Mailing List, kernel-team, Linux-MM, Vinayak Menon,
Ingo Molnar, Shakeel Butt, Catalin Marinas, Tejun Heo, cgroups,
Andrew Morton, Linus Torvalds, Christopher Lameter, Linux ARM
In-Reply-To: <CAK8P3a15K-TXYuFX-ZsJiroqA1GWX2XS4ioZSjcjJYgh1b_xSA@mail.gmail.com>
On Mon, Jul 23, 2018 at 05:35:35PM +0200, Arnd Bergmann wrote:
> On Mon, Jul 23, 2018 at 5:23 PM, Johannes Weiner <hannes@cmpxchg.org> wrote:
> > From 1d24635a6c7cd395bad5c29a3b9e5d2e98d9ab84 Mon Sep 17 00:00:00 2001
> > From: Johannes Weiner <hannes@cmpxchg.org>
> > Date: Mon, 23 Jul 2018 10:18:23 -0400
> > Subject: [PATCH] arm64: fix vmemmap BUILD_BUG_ON() triggering on !vmemmap
> > setups
> >
> > Arnd reports the following arm64 randconfig build error with the PSI
> > patches that add another page flag:
> >
>
> You could add further text here that I had just added to my
> patch description (not sent):
>
> Further experiments show that the build error already existed before,
> but was only triggered with larger values of CONFIG_NR_CPU and/or
> CONFIG_NODES_SHIFT that might be used in actual configurations but
> not in randconfig builds.
>
> With longer CPU and node masks, I could recreate the problem with
> kernels as old as linux-4.7 when arm64 NUMA support got added.
>
> Cc: stable@vger.kernel.org
> Fixes: 1a2db300348b ("arm64, numa: Add NUMA support for arm64 platforms.")
> Fixes: 3e1907d5bf5a ("arm64: mm: move vmemmap region right below
> the linear region")
Sure thing.
> > arch/arm64/mm/init.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> > index 1b18b4722420..72c9b6778b0a 100644
> > --- a/arch/arm64/mm/init.c
> > +++ b/arch/arm64/mm/init.c
> > @@ -611,11 +611,13 @@ void __init mem_init(void)
> > BUILD_BUG_ON(TASK_SIZE_32 > TASK_SIZE_64);
> > #endif
> >
> > +#ifndef CONFIG_SPARSEMEM_VMEMMAP
> > /*
>
> I tested it on two broken configurations, and found that you have
> a typo here, it should be 'ifdef', not 'ifndef'. With that change, it
> seems to build fine.
>
> Tested-by: Arnd Bergmann <arnd@arndb.de>
Thanks for testing it, I don't have a cross-compile toolchain set up.
---
^ permalink raw reply
* [PATCH i2c-next] i2c: aspeed: Add an implicit type casting for *get_clk_reg_val
From: Jae Hyun Yoo @ 2018-07-23 16:26 UTC (permalink / raw)
To: linux-aspeed
This commit fixes this sparse warning:
drivers/i2c/busses/i2c-aspeed.c:875:38: warning: incorrect type in assignment (different modifiers)
drivers/i2c/busses/i2c-aspeed.c:875:38: expected unsigned int ( *get_clk_reg_val )( ... )
drivers/i2c/busses/i2c-aspeed.c:875:38: got void const *const data
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
---
drivers/i2c/busses/i2c-aspeed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index efb89422d496..a4f956c6d567 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -872,7 +872,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
if (!match)
bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;
else
- bus->get_clk_reg_val = match->data;
+ bus->get_clk_reg_val = (u32 (*)(u32))match->data;
/* Initialize the I2C adapter */
spin_lock_init(&bus->lock);
--
2.18.0
^ permalink raw reply related
* [PATCH i2c-next] i2c: aspeed: Add an implicit type casting for *get_clk_reg_val
From: Jae Hyun Yoo @ 2018-07-23 16:26 UTC (permalink / raw)
To: Brendan Higgins, Benjamin Herrenschmidt, Joel Stanley,
Andrew Jeffery
Cc: linux-i2c, openbmc, linux-arm-kernel, linux-aspeed, linux-kernel,
James Feist, Vernon Mauery, Jae Hyun Yoo
This commit fixes this sparse warning:
drivers/i2c/busses/i2c-aspeed.c:875:38: warning: incorrect type in assignment (different modifiers)
drivers/i2c/busses/i2c-aspeed.c:875:38: expected unsigned int ( *get_clk_reg_val )( ... )
drivers/i2c/busses/i2c-aspeed.c:875:38: got void const *const data
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
---
drivers/i2c/busses/i2c-aspeed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index efb89422d496..a4f956c6d567 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -872,7 +872,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
if (!match)
bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;
else
- bus->get_clk_reg_val = match->data;
+ bus->get_clk_reg_val = (u32 (*)(u32))match->data;
/* Initialize the I2C adapter */
spin_lock_init(&bus->lock);
--
2.18.0
^ permalink raw reply related
* [PATCH i2c-next] i2c: aspeed: Add an implicit type casting for *get_clk_reg_val
From: Jae Hyun Yoo @ 2018-07-23 16:26 UTC (permalink / raw)
To: linux-arm-kernel
This commit fixes this sparse warning:
drivers/i2c/busses/i2c-aspeed.c:875:38: warning: incorrect type in assignment (different modifiers)
drivers/i2c/busses/i2c-aspeed.c:875:38: expected unsigned int ( *get_clk_reg_val )( ... )
drivers/i2c/busses/i2c-aspeed.c:875:38: got void const *const data
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
---
drivers/i2c/busses/i2c-aspeed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index efb89422d496..a4f956c6d567 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -872,7 +872,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
if (!match)
bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;
else
- bus->get_clk_reg_val = match->data;
+ bus->get_clk_reg_val = (u32 (*)(u32))match->data;
/* Initialize the I2C adapter */
spin_lock_init(&bus->lock);
--
2.18.0
^ permalink raw reply related
* Re: [Qemu-devel] [PATCH] block/file-posix: add bdrv_attach_aio_context callback for host dev and cdrom
From: Stefan Hajnoczi @ 2018-07-23 16:25 UTC (permalink / raw)
To: Nishanth Aravamudan
Cc: Farhan Ali, Eric Blake, Kevin Wolf, John Snow, Max Reitz,
Fam Zheng, Paolo Bonzini, qemu-block, qemu-devel
In-Reply-To: <20180718211256.29774-1-naravamudan@digitalocean.com>
[-- Attachment #1: Type: text/plain, Size: 1448 bytes --]
On Wed, Jul 18, 2018 at 02:12:56PM -0700, Nishanth Aravamudan wrote:
> In ed6e2161 ("linux-aio: properly bubble up errors from initialzation"),
> I only added a bdrv_attach_aio_context callback for the bdrv_file
> driver. There are several other drivers that use the shared
> aio_plug callback, though, and they will trip the assertion added to
> aio_get_linux_aio because they did not call aio_setup_linux_aio first.
> Add the appropriate callback definition to the affected driver
> definitions.
>
> Fixes: ed6e2161 ("linux-aio: properly bubble up errors from initialization")
> Reported-by: Farhan Ali <alifm@linux.ibm.com>
> Signed-off-by: Nishanth Aravamudan <naravamudan@digitalocean.com>
> Cc: Eric Blake <eblake@redhat.com>
> Cc: Kevin Wolf <kwolf@redhat.com>
> Cc: John Snow <jsnow@redhat.com>
> Cc: Max Reitz <mreitz@redhat.com>
> Cc: Stefan Hajnoczi <stefanha@redhat.com>
> Cc: Fam Zheng <famz@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: qemu-block@nongnu.org
> Cc: qemu-devel@nongnu.org
> ---
> block/file-posix.c | 3 +++
> 1 file changed, 3 insertions(+)
This patch looks good. The remaining s390 crash can be debugged
separately.
The FreeBSD host_cdrom change isn't strictly necessary (no Linux AIO on
FreeBSD), but it doesn't hurt to call raw_aio_attach_aio_context() for
consistency.
Thanks, applied to my block tree:
https://github.com/stefanha/qemu/commits/block
Stefan
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply
* [PATCH v6 3/6] Uprobes: Support SDT markers having reference count (semaphore)
From: Oleg Nesterov @ 2018-07-23 16:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180716084706.28244-4-ravi.bangoria@linux.ibm.com>
I have a mixed feeling about this series... I'll try to summarise my thinking
tomorrow, but I do not see any obvious problem so far. Although I have some
concerns about 5/6, I need to re-read it after sleep.
On 07/16, Ravi Bangoria wrote:
>
> +static int delayed_uprobe_install(struct vm_area_struct *vma)
> +{
> + struct list_head *pos, *q;
> + struct delayed_uprobe *du;
> + unsigned long vaddr;
> + int ret = 0, err = 0;
> +
> + mutex_lock(&delayed_uprobe_lock);
> + list_for_each_safe(pos, q, &delayed_uprobe_list) {
> + du = list_entry(pos, struct delayed_uprobe, list);
> +
> + if (!du->uprobe->ref_ctr_offset ||
Is it possible to see ->ref_ctr_offset == 0 in delayed_uprobe_list?
> @@ -1072,7 +1282,13 @@ int uprobe_mmap(struct vm_area_struct *vma)
> struct uprobe *uprobe, *u;
> struct inode *inode;
>
> - if (no_uprobe_events() || !valid_vma(vma, true))
> + if (no_uprobe_events())
> + return 0;
> +
> + if (vma->vm_flags & VM_WRITE)
> + delayed_uprobe_install(vma);
Obviously not nice performance-wise... OK, I do not know if it will actually
hurt in practice and probably we can use the better data structures if necessary.
But can't we check MMF_HAS_UPROBES at least? I mean,
if (vma->vm_flags & VM_WRITE && test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags))
delayed_uprobe_install(vma);
?
Perhaps we can even add another flag later, MMF_HAS_DELAYED_UPROBES set by
delayed_uprobe_add().
Oleg.
^ permalink raw reply
* Re: [PATCH v6 3/6] Uprobes: Support SDT markers having reference count (semaphore)
From: Oleg Nesterov @ 2018-07-23 16:26 UTC (permalink / raw)
To: Ravi Bangoria
Cc: srikar, rostedt, mhiramat, peterz, mingo, acme,
alexander.shishkin, jolsa, namhyung, linux-kernel, ananth,
alexis.berlemont, naveen.n.rao, linux-arm-kernel, linux-mips,
linux, ralf, paul.burton
In-Reply-To: <20180716084706.28244-4-ravi.bangoria@linux.ibm.com>
I have a mixed feeling about this series... I'll try to summarise my thinking
tomorrow, but I do not see any obvious problem so far. Although I have some
concerns about 5/6, I need to re-read it after sleep.
On 07/16, Ravi Bangoria wrote:
>
> +static int delayed_uprobe_install(struct vm_area_struct *vma)
> +{
> + struct list_head *pos, *q;
> + struct delayed_uprobe *du;
> + unsigned long vaddr;
> + int ret = 0, err = 0;
> +
> + mutex_lock(&delayed_uprobe_lock);
> + list_for_each_safe(pos, q, &delayed_uprobe_list) {
> + du = list_entry(pos, struct delayed_uprobe, list);
> +
> + if (!du->uprobe->ref_ctr_offset ||
Is it possible to see ->ref_ctr_offset == 0 in delayed_uprobe_list?
> @@ -1072,7 +1282,13 @@ int uprobe_mmap(struct vm_area_struct *vma)
> struct uprobe *uprobe, *u;
> struct inode *inode;
>
> - if (no_uprobe_events() || !valid_vma(vma, true))
> + if (no_uprobe_events())
> + return 0;
> +
> + if (vma->vm_flags & VM_WRITE)
> + delayed_uprobe_install(vma);
Obviously not nice performance-wise... OK, I do not know if it will actually
hurt in practice and probably we can use the better data structures if necessary.
But can't we check MMF_HAS_UPROBES at least? I mean,
if (vma->vm_flags & VM_WRITE && test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags))
delayed_uprobe_install(vma);
?
Perhaps we can even add another flag later, MMF_HAS_DELAYED_UPROBES set by
delayed_uprobe_add().
Oleg.
^ permalink raw reply
* [RFC][PATCH 0/5] Mount, Filesystem and Keyrings notifications
From: David Howells @ 2018-07-23 15:25 UTC (permalink / raw)
To: viro
Cc: linux-fsdevel, dhowells, linux-kernel, raven, keyrings,
linux-security-module
Hi Al,
Here's a set of patches to add a general variable-length notification queue
concept and to add sources of events for:
(1) Mount topology and reconfiguration change events.
(2) Superblocks EIO, ENOSPC and EDQUOT events (not complete yet).
(3) Key/keyring changes events
One of the reasons for this is so that we can remove the issue of processes
having to repeatedly and regularly scan /proc/mounts, which has proven to be a
system performance problem.
Design decisions:
(1) A misc chardev is used to create and open a ring buffer:
fd = open("/dev/watch_queue", O_RDWR);
which is then configured and mmap'd into userspace:
ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, BUF_SIZE);
ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter);
buf = mmap(NULL, BUF_SIZE * page_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
The fd cannot be read or written (though there is a facility to use write
to inject records for debugging) and userspace just pulls data directly
out of the buffer.
(2) The ring index pointers are stored inside the ring and are thus
accessible to userspace. Userspace should only update the tail pointer
and never the head pointer or risk breaking the buffer. The kernel
checks that the pointers appear valid before trying to use them. A
'skip' record is maintained around the pointers.
(3) poll() can be used to wait for data to appear in the buffer.
(4) Records in the buffer are binary, typed and have a length so that they
can be of varying size.
This means that multiple heterogeneous sources can share a common
buffer. Tags may be specified when a watchpoint is created to help
distinguish the sources.
(5) The queue is reusable as there are 16 million types available, of which
I've used 4, so there is scope for others to be used.
(6) Records are filterable as types have up to 256 subtypes that can be
individually filtered. Other filtration is also available.
(7) Each time the buffer is opened, a new buffer is created - this means that
there's no interference between watchers.
(8) When recording a notification, the kernel will not sleep, but will rather
mark a queue as overrun if there's insufficient space, thereby avoiding
userspace causing the kernel to hang.
(9) The 'watchpoint' should be specific where possible, meaning that you
specify the object that you want to watch.
(10) The buffer is created and then watchpoints are attached to it, using one
of:
keyctl_watch_key(KEY_SPEC_SESSION_KEYRING, fd, 0x01);
mount_notify(AT_FDCWD, "/", 0, fd, 0x02);
sb_notify(AT_FDCWD, "/mnt", 0, fd, 0x03);
where in all three cases, fd indicates the queue and the number after is
a tag between 0 and 255.
(11) The watch must be removed if either the watch buffer is destroyed or the
watched object is destroyed.
Things I want to avoid:
(1) Introducing features that make the core VFS dependent on the network
stack or networking namespaces (ie. usage of netlink).
(2) Dumping all this stuff into dmesg and having a daemon that sits there
parsing the output and distributing it as this then puts the
responsibility for security into userspace and makes handling namespaces
tricky. Further, dmesg might not exist or might be inaccessible inside a
container.
(3) Letting users see events they shouldn't be able to see.
Further things that need to be done:
(1) fsinfo() syscall needs to find superblocks by ID as well as by path so
that it can query a superblock for information without the need to try
and work out how to reach it - if the calling process even can.
(2) A mount_info() syscall is needed that can enumerate all the children of a
mount. This is necessary because mountpoints can hide each other by
stacking, so paths are not unique keys. This will require the ability to
look up a mount by ID. This avoids the need to parse /proc/mounts.
(3) A keyctl call is needed to allow a watch on a keyring to be extended to
"children" of that keyring, such that the watch is removed from the child
if it is unlinked from the keyring.
(4) A global superblock event queue maybe?
(5) Propagating watches to child superblock over automounts?
The patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=notifications
David
---
David Howells (5):
General notification queue with user mmap()'able ring buffer
KEYS: Add a notification facility
vfs: Add a mount-notification facility
vfs: Add superblock notifications
Add sample notification program
Documentation/security/keys/core.rst | 59 ++
Documentation/watch_queue.rst | 305 ++++++++++++
arch/x86/entry/syscalls/syscall_32.tbl | 2
arch/x86/entry/syscalls/syscall_64.tbl | 2
drivers/misc/Kconfig | 9
drivers/misc/Makefile | 1
drivers/misc/watch_queue.c | 835 ++++++++++++++++++++++++++++++++
fs/Kconfig | 21 +
fs/Makefile | 1
fs/fs_context.c | 1
fs/mount.h | 26 +
fs/mount_notify.c | 178 +++++++
fs/namespace.c | 18 +
fs/super.c | 116 ++++
include/linux/dcache.h | 1
include/linux/fs.h | 77 +++
include/linux/key.h | 4
include/linux/syscalls.h | 4
include/linux/watch_queue.h | 87 +++
include/uapi/linux/keyctl.h | 1
include/uapi/linux/watch_queue.h | 156 ++++++
kernel/sys_ni.c | 6
mm/interval_tree.c | 2
mm/memory.c | 1
samples/Kconfig | 6
samples/Makefile | 2
samples/watch_queue/Makefile | 9
samples/watch_queue/watch_test.c | 232 +++++++++
security/keys/Kconfig | 10
security/keys/compat.c | 3
security/keys/gc.c | 5
security/keys/internal.h | 29 +
security/keys/key.c | 37 +
security/keys/keyctl.c | 90 +++
security/keys/keyring.c | 17 -
security/keys/request_key.c | 4
36 files changed, 2332 insertions(+), 25 deletions(-)
create mode 100644 Documentation/watch_queue.rst
create mode 100644 drivers/misc/watch_queue.c
create mode 100644 fs/mount_notify.c
create mode 100644 include/linux/watch_queue.h
create mode 100644 include/uapi/linux/watch_queue.h
create mode 100644 samples/watch_queue/Makefile
create mode 100644 samples/watch_queue/watch_test.c
^ permalink raw reply
* Re: [PATCH 02/10] mm: workingset: tell cache transitions from workingset thrashing
From: Johannes Weiner @ 2018-07-23 16:27 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Peter Zijlstra, Suren Baghdasaryan, Mike Galbraith, Will Deacon,
Linux Kernel Mailing List, kernel-team, Linux-MM, Vinayak Menon,
Ingo Molnar, Shakeel Butt, Catalin Marinas, Tejun Heo, cgroups,
Andrew Morton, Linus Torvalds, Christopher Lameter, Linux ARM
In-Reply-To: <CAK8P3a15K-TXYuFX-ZsJiroqA1GWX2XS4ioZSjcjJYgh1b_xSA@mail.gmail.com>
On Mon, Jul 23, 2018 at 05:35:35PM +0200, Arnd Bergmann wrote:
> On Mon, Jul 23, 2018 at 5:23 PM, Johannes Weiner <hannes@cmpxchg.org> wrote:
> > From 1d24635a6c7cd395bad5c29a3b9e5d2e98d9ab84 Mon Sep 17 00:00:00 2001
> > From: Johannes Weiner <hannes@cmpxchg.org>
> > Date: Mon, 23 Jul 2018 10:18:23 -0400
> > Subject: [PATCH] arm64: fix vmemmap BUILD_BUG_ON() triggering on !vmemmap
> > setups
> >
> > Arnd reports the following arm64 randconfig build error with the PSI
> > patches that add another page flag:
> >
>
> You could add further text here that I had just added to my
> patch description (not sent):
>
> Further experiments show that the build error already existed before,
> but was only triggered with larger values of CONFIG_NR_CPU and/or
> CONFIG_NODES_SHIFT that might be used in actual configurations but
> not in randconfig builds.
>
> With longer CPU and node masks, I could recreate the problem with
> kernels as old as linux-4.7 when arm64 NUMA support got added.
>
> Cc: stable@vger.kernel.org
> Fixes: 1a2db300348b ("arm64, numa: Add NUMA support for arm64 platforms.")
> Fixes: 3e1907d5bf5a ("arm64: mm: move vmemmap region right below
> the linear region")
Sure thing.
> > arch/arm64/mm/init.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> > index 1b18b4722420..72c9b6778b0a 100644
> > --- a/arch/arm64/mm/init.c
> > +++ b/arch/arm64/mm/init.c
> > @@ -611,11 +611,13 @@ void __init mem_init(void)
> > BUILD_BUG_ON(TASK_SIZE_32 > TASK_SIZE_64);
> > #endif
> >
> > +#ifndef CONFIG_SPARSEMEM_VMEMMAP
> > /*
>
> I tested it on two broken configurations, and found that you have
> a typo here, it should be 'ifdef', not 'ifndef'. With that change, it
> seems to build fine.
>
> Tested-by: Arnd Bergmann <arnd@arndb.de>
Thanks for testing it, I don't have a cross-compile toolchain set up.
---
From 34c4c4549f09f971d2d391a8d652d56cb9b05475 Mon Sep 17 00:00:00 2001
From: Johannes Weiner <hannes@cmpxchg.org>
Date: Mon, 23 Jul 2018 10:18:23 -0400
Subject: [PATCH] arm64: fix vmemmap BUILD_BUG_ON() triggering on !vmemmap
setups
Arnd reports the following arm64 randconfig build error with the PSI
patches that add another page flag:
/git/arm-soc/arch/arm64/mm/init.c: In function 'mem_init':
/git/arm-soc/include/linux/compiler.h:357:38: error: call to
'__compiletime_assert_618' declared with attribute error: BUILD_BUG_ON
failed: sizeof(struct page) > (1 << STRUCT_PAGE_MAX_SHIFT)
The additional page flag causes other information stored in
page->flags to get bumped into their own struct page member:
#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LAST_CPUPID_SHIFT <=
BITS_PER_LONG - NR_PAGEFLAGS
#define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT
#else
#define LAST_CPUPID_WIDTH 0
#endif
#if defined(CONFIG_NUMA_BALANCING) && LAST_CPUPID_WIDTH == 0
#define LAST_CPUPID_NOT_IN_PAGE_FLAGS
#endif
which in turn causes the struct page size to exceed the size set in
STRUCT_PAGE_MAX_SHIFT. This value is an an estimate used to size the
VMEMMAP page array according to address space and struct page size.
However, the check is performed - and triggers here - on a !VMEMMAP
config, which consumes an additional 22 page bits for the sparse
section id. When VMEMMAP is enabled, those bits are returned, cpupid
doesn't need its own member, and the page passes the VMEMMAP check.
Restrict that check to the situation it was meant to check: that we
are sizing the VMEMMAP page array correctly.
Says Arnd:
Further experiments show that the build error already existed before,
but was only triggered with larger values of CONFIG_NR_CPU and/or
CONFIG_NODES_SHIFT that might be used in actual configurations but
not in randconfig builds.
With longer CPU and node masks, I could recreate the problem with
kernels as old as linux-4.7 when arm64 NUMA support got added.
Reported-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Arnd Bergmann <arnd@arndb.de>
Cc: stable@vger.kernel.org
Fixes: 1a2db300348b ("arm64, numa: Add NUMA support for arm64 platforms.")
Fixes: 3e1907d5bf5a ("arm64: mm: move vmemmap region right below the linear region")
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
arch/arm64/mm/init.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 1b18b4722420..86d9f9d303b0 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -611,11 +611,13 @@ void __init mem_init(void)
BUILD_BUG_ON(TASK_SIZE_32 > TASK_SIZE_64);
#endif
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
/*
* Make sure we chose the upper bound of sizeof(struct page)
- * correctly.
+ * correctly when sizing the VMEMMAP array.
*/
BUILD_BUG_ON(sizeof(struct page) > (1 << STRUCT_PAGE_MAX_SHIFT));
+#endif
if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
extern int sysctl_overcommit_memory;
--
2.18.0
^ permalink raw reply related
* [PATCH 02/10] mm: workingset: tell cache transitions from workingset thrashing
From: Johannes Weiner @ 2018-07-23 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAK8P3a15K-TXYuFX-ZsJiroqA1GWX2XS4ioZSjcjJYgh1b_xSA@mail.gmail.com>
On Mon, Jul 23, 2018 at 05:35:35PM +0200, Arnd Bergmann wrote:
> On Mon, Jul 23, 2018 at 5:23 PM, Johannes Weiner <hannes@cmpxchg.org> wrote:
> > From 1d24635a6c7cd395bad5c29a3b9e5d2e98d9ab84 Mon Sep 17 00:00:00 2001
> > From: Johannes Weiner <hannes@cmpxchg.org>
> > Date: Mon, 23 Jul 2018 10:18:23 -0400
> > Subject: [PATCH] arm64: fix vmemmap BUILD_BUG_ON() triggering on !vmemmap
> > setups
> >
> > Arnd reports the following arm64 randconfig build error with the PSI
> > patches that add another page flag:
> >
>
> You could add further text here that I had just added to my
> patch description (not sent):
>
> Further experiments show that the build error already existed before,
> but was only triggered with larger values of CONFIG_NR_CPU and/or
> CONFIG_NODES_SHIFT that might be used in actual configurations but
> not in randconfig builds.
>
> With longer CPU and node masks, I could recreate the problem with
> kernels as old as linux-4.7 when arm64 NUMA support got added.
>
> Cc: stable at vger.kernel.org
> Fixes: 1a2db300348b ("arm64, numa: Add NUMA support for arm64 platforms.")
> Fixes: 3e1907d5bf5a ("arm64: mm: move vmemmap region right below
> the linear region")
Sure thing.
> > arch/arm64/mm/init.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> > index 1b18b4722420..72c9b6778b0a 100644
> > --- a/arch/arm64/mm/init.c
> > +++ b/arch/arm64/mm/init.c
> > @@ -611,11 +611,13 @@ void __init mem_init(void)
> > BUILD_BUG_ON(TASK_SIZE_32 > TASK_SIZE_64);
> > #endif
> >
> > +#ifndef CONFIG_SPARSEMEM_VMEMMAP
> > /*
>
> I tested it on two broken configurations, and found that you have
> a typo here, it should be 'ifdef', not 'ifndef'. With that change, it
> seems to build fine.
>
> Tested-by: Arnd Bergmann <arnd@arndb.de>
Thanks for testing it, I don't have a cross-compile toolchain set up.
---
>From 34c4c4549f09f971d2d391a8d652d56cb9b05475 Mon Sep 17 00:00:00 2001
From: Johannes Weiner <hannes@cmpxchg.org>
Date: Mon, 23 Jul 2018 10:18:23 -0400
Subject: [PATCH] arm64: fix vmemmap BUILD_BUG_ON() triggering on !vmemmap
setups
Arnd reports the following arm64 randconfig build error with the PSI
patches that add another page flag:
/git/arm-soc/arch/arm64/mm/init.c: In function 'mem_init':
/git/arm-soc/include/linux/compiler.h:357:38: error: call to
'__compiletime_assert_618' declared with attribute error: BUILD_BUG_ON
failed: sizeof(struct page) > (1 << STRUCT_PAGE_MAX_SHIFT)
The additional page flag causes other information stored in
page->flags to get bumped into their own struct page member:
#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LAST_CPUPID_SHIFT <=
BITS_PER_LONG - NR_PAGEFLAGS
#define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT
#else
#define LAST_CPUPID_WIDTH 0
#endif
#if defined(CONFIG_NUMA_BALANCING) && LAST_CPUPID_WIDTH == 0
#define LAST_CPUPID_NOT_IN_PAGE_FLAGS
#endif
which in turn causes the struct page size to exceed the size set in
STRUCT_PAGE_MAX_SHIFT. This value is an an estimate used to size the
VMEMMAP page array according to address space and struct page size.
However, the check is performed - and triggers here - on a !VMEMMAP
config, which consumes an additional 22 page bits for the sparse
section id. When VMEMMAP is enabled, those bits are returned, cpupid
doesn't need its own member, and the page passes the VMEMMAP check.
Restrict that check to the situation it was meant to check: that we
are sizing the VMEMMAP page array correctly.
Says Arnd:
Further experiments show that the build error already existed before,
but was only triggered with larger values of CONFIG_NR_CPU and/or
CONFIG_NODES_SHIFT that might be used in actual configurations but
not in randconfig builds.
With longer CPU and node masks, I could recreate the problem with
kernels as old as linux-4.7 when arm64 NUMA support got added.
Reported-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Arnd Bergmann <arnd@arndb.de>
Cc: stable at vger.kernel.org
Fixes: 1a2db300348b ("arm64, numa: Add NUMA support for arm64 platforms.")
Fixes: 3e1907d5bf5a ("arm64: mm: move vmemmap region right below the linear region")
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
---
arch/arm64/mm/init.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 1b18b4722420..86d9f9d303b0 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -611,11 +611,13 @@ void __init mem_init(void)
BUILD_BUG_ON(TASK_SIZE_32 > TASK_SIZE_64);
#endif
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
/*
* Make sure we chose the upper bound of sizeof(struct page)
- * correctly.
+ * correctly when sizing the VMEMMAP array.
*/
BUILD_BUG_ON(sizeof(struct page) > (1 << STRUCT_PAGE_MAX_SHIFT));
+#endif
if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
extern int sysctl_overcommit_memory;
--
2.18.0
^ permalink raw reply related
* [PATCH 1/5] General notification queue with user mmap()'able ring buffer
From: David Howells @ 2018-07-23 15:25 UTC (permalink / raw)
To: viro
Cc: linux-fsdevel, dhowells, linux-kernel, raven, keyrings,
linux-security-module
In-Reply-To: <153235954191.32640.5792167066538704794.stgit@warthog.procyon.org.uk>
Implement a misc device that implements a general notification queue as a
ring buffer that can be mmap()'d from userspace.
The way this is done is:
(1) An application opens the device and indicates the size of the ring
buffer that it wants to reserve in pages (this can only be set once):
fd = open("/dev/sync_user", O_RDWR);
ioctl(fd, IOC_WATCH_QUEUE_NR_PAGES, nr_of_pages);
(2) The application should then map the pages that the device has
reserved. Each instance of the device created by open() allocates
separate pages so that maps of different fds don't interfere with one
another. Multiple mmap() calls on the same fd, however, will all work
together.
page_size = sysconf(_SC_PAGESIZE);
mapping_size = nr_of_pages * page_size;
char *buf = mmap(NULL, mapping_size, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
The ring is divided into 8-byte slots. Entries written into the ring are
variable size and can use between 1 and 63 slots. A special entry is
maintained in the first two slots of the ring that contains the head and tail
pointers. This is skipped when the ring wraps round. Note that multislot
entries, therefore, aren't allowed to be broken over the end of the ring, but
instead "skip" entries are inserted to pad out the buffer.
Each entry has a 1-slot header that describes it:
struct watch_notification {
__u32 type:24;
__u32 subtype:8;
__u32 info;
};
The type indicates the source (eg. mount tree changes, superblock events,
keyring changes) and the subtype indicates the event type (eg. mount, unmount;
EIO, EDQUOT; link, unlink). The info field indicates a number of things,
including the entry length, an ID assigned to a watchpoint contributing to
this buffer, type-specific flags and meta flags, such as an overrun indicator.
Supplementary data, such as the key ID that generated an event, are attached
in additional slots.
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/watch_queue.rst | 305 ++++++++++++++
drivers/misc/Kconfig | 9
drivers/misc/Makefile | 1
drivers/misc/watch_queue.c | 835 ++++++++++++++++++++++++++++++++++++++
include/linux/watch_queue.h | 87 ++++
include/uapi/linux/watch_queue.h | 81 ++++
mm/interval_tree.c | 2
mm/memory.c | 1
8 files changed, 1321 insertions(+)
create mode 100644 Documentation/watch_queue.rst
create mode 100644 drivers/misc/watch_queue.c
create mode 100644 include/linux/watch_queue.h
create mode 100644 include/uapi/linux/watch_queue.h
diff --git a/Documentation/watch_queue.rst b/Documentation/watch_queue.rst
new file mode 100644
index 000000000000..e7dc1007976d
--- /dev/null
+++ b/Documentation/watch_queue.rst
@@ -0,0 +1,305 @@
+============================
+Mappable notifications queue
+============================
+
+This is a misc device that acts as a mapped ring buffer by which userspace can
+receive notifications from the kernel. This is can be used in conjunction
+with::
+
+ * Key/keyring notifications
+
+ * Mount topology change notifications
+
+ * Superblock event notifications
+
+
+The notifications buffers can be enabled by:
+
+ "Device Drivers"/"Misc devices"/"Mappable notification queue"
+ (CONFIG_WATCH_QUEUE)
+
+This document has the following sections:
+
+.. contents:: :local:
+
+
+Overview
+========
+
+This facility appears as a misc device file that is opened and then mapped and
+polled. Each time it is opened, it creates a new buffer specific to the
+returned file descriptor. Then, when the opening process sets watches, it
+indicates that particular buffer it wants notifications from that watch to be
+written into. Note that there are no read() and write() methods (except for
+debugging). The user is expected to access the ring directly and to use poll
+to wait for new data.
+
+If a watch is in place, notifications are only written into the buffer if the
+filter criteria are passed and if there's sufficient space available in the
+ring. If neither of those is so, a notification will be discarded. In the
+latter case, an overrun indicator will also be set.
+
+Note that when producing a notification, the kernel does not wait for the
+consumers to collect it, but rather just continues on. This means that
+notifications can be generated whilst spinlocks are held and also protects the
+kernel from being held up indefinitely by a userspace malfunction.
+
+As far as the ring goes, the head index belongs to the kernel and the tail
+index belongs to userspace. The kernel will refuse to write anything if the
+tail index becomes invalid. Userspace *must* use appropriate memory barriers
+between reading or updating the tail index and reading the ring.
+
+
+Record Structure
+================
+
+Notification records in the ring may occupy a variable number of slots within
+the buffer, beginning with a 1-slot header::
+
+ struct watch_notification {
+ __u16 type;
+ __u16 subtype;
+ __u32 info;
+ };
+
+"type" indicates the source of the notification record and "subtype" indicates
+the type of record from that source (see the Watch Sources section below). The
+type may also be "WATCH_TYPE_META". This is a special record type generated
+internally by the watch queue driver itself. There are two subtypes, one of
+which indicates records that should be just skipped (padding or metadata):
+
+ * watch_meta_skip_notification
+ * watch_meta_removal_notification
+
+The former indicates a record that should just be skipped and the latter
+indicates that an object on which a watchpoint was installed was removed or
+destroyed.
+
+"info" indicates a bunch of things, including:
+
+ * The length of the record (mask with WATCH_INFO_LENGTH). This indicates the
+ size of the record, which may be between 1 and 63 slots. Note that this is
+ placed appropriately within the info value so that no shifting is required
+ to convert number of occupied slots to byte length.
+
+ * The watchpoint ID (mask with WATCH_INFO_ID). This indicates that caller's
+ ID of the watchpoint, which may be between 0 and 255. Multiple watchpoints
+ may share a queue, and this provides a means to distinguish them.
+
+ * A buffer overrun flag (WATCH_INFO_OVERRUN flag). If this is set in a
+ notification record, some of the preceding records were discarded.
+
+ * An ENOMEM-loss flag (WATCH_INFO_ENOMEM flag). This is set to indicate that
+ an event was lost to ENOMEM.
+
+ * A recursive-change flag (WATCH_INFO_RECURSIVE flag). This is set to
+ indicate that the change that happened was recursive - for instance
+ changing the attributes on an entire mount subtree.
+
+ * An exact-match flag (WATCH_INFO_IN_SUBTREE flag). This is set if the event
+ didn't happen exactly at the watchpoint, but rather somewhere in the
+ subtree thereunder.
+
+ * Some type-specific flags (WATCH_INFO_TYPE_FLAGS). These are set by the
+ notification producer to indicate some meaning to the kernel.
+
+Everything in info apart from the length can be used for filtering.
+
+
+Ring Structure
+==============
+
+The ring is divided into 8-byte slots. The caller uses an ioctl() to set the
+size of the ring after opening and this must be a power-of-2 multiple of the
+system page size (so that the mask can be used with AND).
+
+The head and tail indices are stored in the first two slots in the ring, which
+are marked out as a skippable entry::
+
+ struct watch_queue_buffer {
+ union {
+ struct {
+ struct watch_notification watch;
+ volatile __u32 head;
+ volatile __u32 tail;
+ __u32 mask;
+ } meta;
+ struct watch_notification slots[0];
+ };
+ };
+
+In "meta.watch", type will be set to WATCH_TYPE_META and subtype to
+watch_meta_skip_notification so that anyone processing the buffer will just
+skip this record. Also, because this record is here, records cannot wrap round
+the end of the buffer, so a skippable padding element will be inserted at the
+end of the buffer if needed. Thus the contents of a notification record in the
+buffer are always contiguous.
+
+"meta.mask" is an AND'able mask to turn the index counters into slots array
+indices.
+
+The buffer is empty if "meta.head" == "meta.tail".
+
+[!] NOTE that the ring indices "meta.head" and "meta.tail" are indices into
+"slots[]" not byte offsets into the buffer.
+
+[!] NOTE that userspace must never change the head pointer. This belongs to
+the kernel and will be updated by that. The kernel will never change the tail
+pointer.
+
+[!] NOTE that userspace must never AND-off the tail pointer before updating it,
+but should just keep adding to it and letting it wrap naturally. The value
+*should* be masked off when used as an index into slots[].
+
+[!] NOTE that if the distance between head and tail becomes too great, the
+kernel will assume the buffer is full and write no more until the issue is
+resolved.
+
+
+Watch Sources
+=============
+
+Any particular buffer can be fed from multiple sources. Sources include:
+
+ * WATCH_TYPE_MOUNT_NOTIFY
+
+ Notifications of this type indicate mount tree topology changes and mount
+ attribute changes. A watchpoint can be set on a particular file or
+ directory and notifications from the path subtree rooted at that point will
+ be intercepted.
+
+ * WATCH_TYPE_SB_NOTIFY
+
+ Notifications of this type indicate superblock events, such as quota limits
+ being hit, I/O errors being produced or network server loss/reconnection.
+ Watchpoints of this type are set directly on superblocks.
+
+ * WATCH_TYPE_KEY_NOTIFY
+
+ Notifications of this type indicate changes to keys and keyrings, including
+ the changes of keyring contents or the attributes of keys.
+
+ See Documentation/security/keys/core.rst for more information.
+
+
+Configuring Watchpoints
+=======================
+
+When a watchpoint is set up, the caller assigns an ID and can set filtering
+parameters. The following structure is filled out and passed to the
+watchpoint creation system call::
+
+ struct watch_notification_filter {
+ __u64 subtype_filter[4];
+ __u32 info_filter;
+ __u32 info_mask;
+ __u32 info_id;
+ __u32 __reserved;
+ };
+
+"subtype_filter" is a bitmask indicating the subtypes that are of interest. In
+this version of the structure, only the first 256 subtypes are supported. Bit
+0 of subtype_filter[0] corresponds to subtype 0, bit 1 to subtype 1, and so on.
+
+"info_filter" and "info_mask" act as a filter on the info field of the
+notification record. The notification is only written into the buffer if::
+
+ (watch.info & info_mask) == info_filter
+
+This can be used, for example, to ignore events that are not exactly on the
+watched point in a mount tree by specifying WATCH_INFO_IN_SUBTREE must be 0.
+
+"info_id" is OR'd into watch.info. This indicates the watchpoint ID in the top
+8 bits. All bits outside of WATCH_INFO_ID must be 0.
+
+"__reserved" must be 0.
+
+If the pointer to this structure is NULL, this indicates to the system call
+that the watchpoint should be removed.
+
+
+Polling
+=======
+
+The file descriptor that holds the buffer may be used with poll() and similar.
+POLLIN and POLLRDNORM are set if the buffer indices differ. POLLERR is set if
+the buffer indices are further apart than the size of the buffer. Wake-up
+events are only generated if the buffer is transitioned from an empty state.
+
+
+Example
+=======
+
+A buffer is created with something like the following::
+
+ fd = open("/dev/watch_queue", O_RDWR);
+
+ #define BUF_SIZE 4
+ ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, BUF_SIZE);
+
+ page_size = sysconf(_SC_PAGESIZE);
+ buf = mmap(NULL, BUF_SIZE * page_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+It can then be set to receive mount topology change notifications, keyring
+change notifications and superblock notifications::
+
+ memset(&filter, 0, sizeof(filter));
+ filter.subtype_filter[0] = ~0ULL;
+ filter.info_mask = WATCH_INFO_IN_SUBTREE;
+ filter.info_filter = 0;
+ filter.info_id = 0x01000000;
+
+ keyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fd, &filter);
+
+ mount_notify(AT_FDCWD, "/", 0, fd, &filter);
+
+ sb_notify(AT_FDCWD, "/", 0, fd, &filter);
+
+The notifications can then be consumed by something like the following::
+
+ extern void saw_mount_change(struct watch_notification *n);
+ extern void saw_key_change(struct watch_notification *n);
+
+ static int consumer(int fd, struct watch_queue_buffer *buf)
+ {
+ struct watch_notification *n;
+ struct pollfd p[1];
+ unsigned int head, tail, mask = buf->meta.mask;
+
+ for (;;) {
+ p[0].fd = fd;
+ p[0].events = POLLIN | POLLERR;
+ p[0].revents = 0;
+
+ if (poll(p, 1, -1) == -1 || p[0].revents & POLLERR)
+ goto went_wrong;
+
+ while (head = _atomic_load_acquire(buf->meta.head),
+ tail = buf->meta.tail,
+ tail != head
+ ) {
+ n = &buf->slots[tail & mask];
+ if ((n->info & WATCH_INFO_LENGTH) == 0)
+ goto went_wrong;
+
+ switch (n->type) {
+ case WATCH_TYPE_MOUNT_NOTIFY:
+ saw_mount_change(n);
+ break;
+ case WATCH_TYPE_KEY_NOTIFY:
+ saw_key_change(n);
+ break;
+ }
+
+ tail += (n->info & WATCH_INFO_LENGTH) >> WATCH_LENGTH_SHIFT;
+ _atomic_store_release(buf->meta.tail, tail);
+ }
+ }
+
+ went_wrong:
+ return 0;
+ }
+
+Note the memory barriers when loading the head pointer and storing the tail
+pointer!
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3726eacdf65d..fa381a8620a7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -4,6 +4,15 @@
menu "Misc devices"
+config WATCH_QUEUE
+ bool "Mappable notification queue"
+ default n
+ help
+ This is a general notification queue for the kernel to pass events to
+ userspace through a mmap()'able ring buffer. It can be used in
+ conjunction with watches for mount topology change notifications,
+ superblock change notifications and key/keyring change notifications.
+
config SENSORS_LIS3LV02D
tristate
depends on INPUT
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index af22bbc3d00c..823f2f99b183 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -3,6 +3,7 @@
# Makefile for misc devices that really don't fit anywhere else.
#
+obj-$(CONFIG_WATCH_QUEUE) += watch_queue.o
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_IBMVMC) += ibmvmc.o
obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
diff --git a/drivers/misc/watch_queue.c b/drivers/misc/watch_queue.c
new file mode 100644
index 000000000000..4e4d9262622d
--- /dev/null
+++ b/drivers/misc/watch_queue.c
@@ -0,0 +1,835 @@
+/* User-mappable watch queue
+ *
+ * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "[%05u] watchq: " fmt, current->pid
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/printk.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/file.h>
+#include <linux/watch_queue.h>
+
+#define DEBUG_WITH_WRITE /* Allow use of write() to record notifications */
+
+MODULE_DESCRIPTION("Watch queue");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+struct watch_type_filter {
+ enum watch_notification_type type;
+ __u32 subtype_filter[1]; /* Bitmask of subtypes to filter on */
+ __u32 info_filter; /* Filter on watch_notification::info */
+ __u32 info_mask; /* Mask of relevant bits in info_filter */
+};
+
+struct watch_filter {
+ union {
+ struct rcu_head rcu;
+ unsigned long type_filter[2]; /* Bitmask of accepted types */
+ };
+ u32 nr_filters; /* Number of filters */
+ struct watch_type_filter filters[];
+};
+
+struct watch_queue {
+ struct rcu_head rcu;
+ struct address_space mapping;
+ struct watch_filter *filter;
+ wait_queue_head_t waiters;
+ struct hlist_head watches; /* Contributory watches */
+ refcount_t usage;
+ spinlock_t lock;
+ bool defunct; /* T when queues closed */
+ u8 nr_pages; /* Size of pages[] */
+ u8 flag_next; /* Flag to apply to next item */
+#ifdef DEBUG_WITH_WRITE
+ u8 debug;
+#endif
+ u32 size;
+ struct watch_queue_buffer *buffer; /* Pointer to first record */
+
+ /* The mappable pages. The zeroth page holds the ring pointers. */
+ struct page **pages;
+};
+
+/**
+ * post_one_notification - Post an event notification to one queue
+ * @wqueue: The watch queue to add the event to.
+ * @n: The notification record to post.
+ *
+ * Post a notification of an event into an mmap'd queue and let the user know.
+ * Returns true if successful and false on failure (eg. buffer overrun or
+ * userspace mucked up the ring indices).
+ *
+ *
+ * The size of the notification should be set in n->flags & WATCH_LENGTH and
+ * should be in units of sizeof(*n).
+ */
+static bool post_one_notification(struct watch_queue *wqueue,
+ struct watch_notification *n)
+{
+ struct watch_queue_buffer *buf = wqueue->buffer;
+ unsigned int metalen = sizeof(buf->meta) / sizeof(buf->slots[0]);
+ unsigned int size = wqueue->size, mask = size - 1;
+ unsigned int len;
+ unsigned int ring_tail, tail, head, used, segment, h;
+
+ if (!buf)
+ return false;
+
+ len = (n->info & WATCH_INFO_LENGTH) >> WATCH_LENGTH_SHIFT;
+ if (len == 0)
+ return false;
+
+ spin_lock(&wqueue->lock); /* Protect head pointer */
+
+ if (wqueue->defunct)
+ goto out;
+
+ ring_tail = READ_ONCE(buf->meta.tail);
+ head = READ_ONCE(buf->meta.head);
+ used = head - ring_tail;
+
+ /* Check to see if userspace mucked up the pointers */
+ if (used >= size)
+ goto overrun;
+ tail = ring_tail & mask;
+ if (tail > 0 && tail < metalen)
+ goto overrun;
+
+ h = head & mask;
+ if (h >= tail) {
+ /* Head is at or after tail in the buffer. There may then be
+ * two segments: one to the end of buffer and one at the
+ * beginning of the buffer between the metadata block and the
+ * tail pointer.
+ */
+ segment = size - h;
+ if (len > segment) {
+ /* Not enough space in the post-head segment; we need
+ * to wrap. When wrapping, we will have to skip the
+ * metadata at the beginning of the buffer.
+ */
+ if (len > tail - metalen)
+ goto overrun;
+
+ /* Fill the space at the end of the page */
+ buf->slots[h].type = WATCH_TYPE_META;
+ buf->slots[h].subtype = watch_meta_skip_notification;
+ buf->slots[h].info = segment << WATCH_LENGTH_SHIFT;
+ head += segment;
+ h = 0;
+ if (h >= tail)
+ goto overrun;
+ }
+ }
+
+ if (h == 0) {
+ /* Reset and skip the header metadata */
+ buf->meta.watch.type = WATCH_TYPE_META;
+ buf->meta.watch.subtype = watch_meta_skip_notification;
+ buf->meta.watch.info = metalen << WATCH_LENGTH_SHIFT;
+ head += metalen;
+ h = metalen;
+ if (h >= tail)
+ goto overrun;
+ }
+
+ if (h < tail) {
+ /* Head is before tail in the buffer. There may be one segment
+ * between the two, but we may need to skip the metadata block.
+ */
+ segment = tail - h;
+ if (len > segment)
+ goto overrun;
+ }
+
+ n->info |= wqueue->flag_next;
+ wqueue->flag_next = 0;
+ memcpy(buf->slots + h, n, len * sizeof(buf->slots[0]));
+ head += len;
+
+ smp_store_release(&buf->meta.head, head);
+ spin_unlock(&wqueue->lock);
+ if (used == 0)
+ wake_up(&wqueue->waiters);
+ return true;
+
+overrun:
+ wqueue->flag_next = WATCH_INFO_OVERRUN;
+out:
+ spin_unlock(&wqueue->lock);
+ return false;
+}
+
+/*
+ * Apply filter rules to a notification.
+ */
+static bool filter_watch_notification(const struct watch_filter *wf,
+ const struct watch_notification *n)
+{
+ const struct watch_type_filter *wt;
+ int i;
+
+ if (!test_bit(n->type, wf->type_filter))
+ return false;
+
+ for (i = 0; i < wf->nr_filters; i++) {
+ wt = &wf->filters[i];
+ if (n->type == wt->type &&
+ ((1U << n->subtype) & wt->subtype_filter[0]) &&
+ (n->info & wt->info_mask) == wt->info_filter)
+ return true;
+ }
+
+ return false; /* If there is a filter, the default is to reject. */
+}
+
+/**
+ * __post_watch_notification - Post an event notification
+ * @wlist: The watch list to post the event to.
+ * @n: The notification record to post.
+ * @id: The ID to match on the watch.
+ *
+ * Post a notification of an event into a set of watch queues and let the users
+ * know.
+ *
+ * If @n is NULL then WATCH_INFO_LENGTH will be set on the next event posted.
+ *
+ * The size of the notification should be set in n->info & WATCH_INFO_LENGTH and
+ * should be in units of sizeof(*n).
+ */
+void __post_watch_notification(struct watch_list *wlist,
+ struct watch_notification *n,
+ u64 id)
+{
+ const struct watch_filter *wf;
+ struct watch_queue *wqueue;
+ struct watch *watch;
+
+ rcu_read_lock();
+
+ hlist_for_each_entry_rcu(watch, &wlist->watchers, list_node) {
+ if (watch->id != id)
+ continue;
+ n->info &= ~(WATCH_INFO_ID | WATCH_INFO_OVERRUN);
+ n->info |= watch->info_id;
+
+ wqueue = rcu_dereference(watch->queue);
+ wf = rcu_dereference(wqueue->filter);
+ if (wf && !filter_watch_notification(wf, n))
+ continue;
+
+ post_one_notification(wqueue, n);
+ }
+
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(__post_watch_notification);
+
+/*
+ * Allow the queue to be polled.
+ */
+static unsigned int watch_queue_poll(struct file *file, poll_table *wait)
+{
+ struct watch_queue *wqueue = file->private_data;
+ struct watch_queue_buffer *buf = wqueue->buffer;
+ unsigned int mask = 0, head, tail;
+
+ poll_wait(file, &wqueue->waiters, wait);
+
+ head = READ_ONCE(buf->meta.head);
+ tail = READ_ONCE(buf->meta.tail);
+ if (head != tail)
+ mask |= POLLIN | POLLRDNORM;
+ if (head - tail > wqueue->size)
+ mask |= POLLERR;
+ return mask;
+}
+
+static int watch_queue_set_page_dirty(struct page *page)
+{
+ SetPageDirty(page);
+ return 0;
+}
+
+static const struct address_space_operations watch_queue_aops = {
+ .set_page_dirty = watch_queue_set_page_dirty,
+};
+
+static int watch_queue_fault(struct vm_fault *vmf)
+{
+ struct watch_queue *wqueue = vmf->vma->vm_file->private_data;
+ struct page *page;
+
+ page = wqueue->pages[vmf->pgoff];
+ get_page(page);
+ if (!lock_page_or_retry(page, vmf->vma->vm_mm, vmf->flags)) {
+ put_page(page);
+ return VM_FAULT_RETRY;
+ }
+ vmf->page = page;
+ return VM_FAULT_LOCKED;
+}
+
+static void watch_queue_map_pages(struct vm_fault *vmf,
+ pgoff_t start_pgoff, pgoff_t end_pgoff)
+{
+ struct watch_queue *wqueue = vmf->vma->vm_file->private_data;
+ struct page *page;
+
+ rcu_read_lock();
+
+ do {
+ page = wqueue->pages[start_pgoff];
+ if (trylock_page(page)) {
+ int ret;
+ get_page(page);
+ ret = alloc_set_pte(vmf, NULL, page);
+ if (ret != 0)
+ put_page(page);
+
+ unlock_page(page);
+ }
+ } while (++start_pgoff < end_pgoff);
+
+ rcu_read_unlock();
+}
+
+static const struct vm_operations_struct watch_queue_vm_ops = {
+ .fault = watch_queue_fault,
+ .map_pages = watch_queue_map_pages,
+};
+
+/*
+ * Map the buffer.
+ */
+static int watch_queue_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct watch_queue *wqueue = file->private_data;
+
+ if (vma->vm_pgoff != 0 ||
+ vma->vm_end - vma->vm_start > wqueue->nr_pages * PAGE_SIZE ||
+ !(pgprot_val(vma->vm_page_prot) & pgprot_val(PAGE_SHARED)))
+ return -EINVAL;
+
+ vma->vm_ops = &watch_queue_vm_ops;
+
+ vma_interval_tree_insert(vma, &wqueue->mapping.i_mmap);
+ return 0;
+}
+
+/*
+ * Allocate the required number of pages.
+ */
+static long watch_queue_set_size(struct watch_queue *wqueue, unsigned long nr_pages)
+{
+ struct watch_queue_buffer *buf;
+ u32 len;
+ int i;
+
+ if (nr_pages == 0 ||
+ nr_pages > 16 || /* TODO: choose a better hard limit */
+ !is_power_of_2(nr_pages))
+ return -EINVAL;
+
+ wqueue->pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
+ if (!wqueue->pages)
+ goto err;
+
+ for (i = 0; i < nr_pages; i++) {
+ wqueue->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!wqueue->pages[i])
+ goto err_some_pages;
+ wqueue->pages[i]->mapping = &wqueue->mapping;
+ SetPageUptodate(wqueue->pages[i]);
+ }
+
+ buf = vmap(wqueue->pages, nr_pages, VM_MAP, PAGE_SHARED);
+ if (!buf)
+ goto err_some_pages;
+
+ wqueue->buffer = buf;
+ wqueue->nr_pages = nr_pages;
+ wqueue->size = ((nr_pages * PAGE_SIZE) / sizeof(struct watch_notification));
+
+ /* The first four slots in the buffer contain metadata about the ring,
+ * including the head and tail indices and mask.
+ */
+ len = sizeof(buf->meta) / sizeof(buf->slots[0]);
+ buf->meta.watch.info = len << WATCH_LENGTH_SHIFT;
+ buf->meta.watch.type = WATCH_TYPE_META;
+ buf->meta.watch.subtype = watch_meta_skip_notification;
+ buf->meta.tail = len;
+ buf->meta.mask = wqueue->size - 1;
+ smp_store_release(&buf->meta.head, len);
+ return 0;
+
+err_some_pages:
+ for (i--; i >= 0; i--) {
+ ClearPageUptodate(wqueue->pages[i]);
+ wqueue->pages[i]->mapping = NULL;
+ put_page(wqueue->pages[i]);
+ }
+
+ kfree(wqueue->pages);
+ wqueue->pages = NULL;
+err:
+ return -ENOMEM;
+}
+
+/*
+ * Set the filter on a watch queue.
+ */
+static long watch_queue_set_filter(struct watch_queue *wqueue,
+ struct watch_notification_filter __user *_filter)
+{
+ struct watch_notification_type_filter *tf;
+ struct watch_notification_filter filter;
+ struct watch_type_filter *q;
+ struct watch_filter *old, *wfilter;
+ int ret, nr_filter = 0, i;
+
+ if (!_filter) {
+ /* Remove the old filter */
+ wfilter = NULL;
+ goto set;
+ }
+
+ /* Grab the user's filter specification */
+ if (copy_from_user(&filter, _filter, sizeof(filter)) != 0)
+ return -EFAULT;
+ if (filter.nr_filters == 0 ||
+ filter.nr_filters > 16 ||
+ filter.__reserved != 0)
+ return -EINVAL;
+
+ tf = memdup_user(_filter->filters, filter.nr_filters * sizeof(*tf));
+ if (IS_ERR(tf))
+ return PTR_ERR(tf);
+
+ ret = -EINVAL;
+ for (i = 0; i < filter.nr_filters; i++) {
+ if ((tf[i].info_filter & ~tf[i].info_mask) ||
+ tf[i].info_mask & WATCH_INFO_LENGTH)
+ goto err_filter;
+ /* Ignore any unknown types */
+ if (tf[i].type >= sizeof(wfilter->type_filter) * 8)
+ continue;
+ nr_filter++;
+ }
+
+ /* Now we need to build the internal filter from only the
+ * relevant user-specified filters.
+ */
+ ret = -ENOMEM;
+ wfilter = kzalloc(sizeof(*wfilter) + nr_filter * sizeof(*q), GFP_KERNEL);
+ if (!wfilter)
+ goto err_filter;
+ wfilter->nr_filters = nr_filter;
+
+ q = wfilter->filters;
+ for (i = 0; i < filter.nr_filters; i++) {
+ if (tf[i].type >= sizeof(wfilter->type_filter) * BITS_PER_LONG)
+ continue;
+
+ q->type = tf[i].type;
+ q->info_filter = tf[i].info_filter;
+ q->info_mask = tf[i].info_mask;
+ q->subtype_filter[0] = tf[i].subtype_filter[0];
+ __set_bit(q->type, wfilter->type_filter);
+ q++;
+ }
+
+ kfree(tf);
+set:
+ rcu_swap_protected(wqueue->filter, wfilter, true /* inode lock */);
+ if (old)
+ kfree_rcu(wfilter, rcu);
+ return 0;
+
+err_filter:
+ kfree(tf);
+ return ret;
+}
+
+/*
+ * Set parameters.
+ */
+static long watch_queue_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct watch_queue *wqueue = file->private_data;
+ long ret;
+
+ switch (cmd) {
+ case IOC_WATCH_QUEUE_SET_SIZE:
+ if (wqueue->buffer)
+ return -EBUSY;
+ inode_lock(file_inode(file));
+ ret = watch_queue_set_size(wqueue, arg);
+ inode_unlock(file_inode(file));
+ return ret;
+
+ case IOC_WATCH_QUEUE_SET_FILTER:
+ inode_lock(file_inode(file));
+ ret = watch_queue_set_filter(
+ wqueue, (struct watch_notification_filter __user *)arg);
+ inode_unlock(file_inode(file));
+ return ret;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/*
+ * Open the file.
+ */
+static int watch_queue_open(struct inode *inode, struct file *file)
+{
+ struct watch_queue *wqueue;
+
+ wqueue = kzalloc(sizeof(*wqueue), GFP_KERNEL);
+ if (!wqueue)
+ return -ENOMEM;
+
+ wqueue->mapping.a_ops = &watch_queue_aops;
+ wqueue->mapping.i_mmap = RB_ROOT_CACHED;
+ init_rwsem(&wqueue->mapping.i_mmap_rwsem);
+ spin_lock_init(&wqueue->mapping.private_lock);
+
+ refcount_set(&wqueue->usage, 1);
+ spin_lock_init(&wqueue->lock);
+ init_waitqueue_head(&wqueue->waiters);
+
+ file->private_data = wqueue;
+ return 0;
+}
+
+/**
+ * put_watch_queue - Dispose of a ref on a watchqueue.
+ * @wq: The watch queue to unref.
+ */
+void put_watch_queue(struct watch_queue *wqueue)
+{
+ if (refcount_dec_and_test(&wqueue->usage))
+ kfree_rcu(wqueue, rcu);
+}
+EXPORT_SYMBOL(put_watch_queue);
+
+/*
+ * Discard a watch.
+ */
+static void put_watch(struct watch *watch)
+{
+ if (refcount_dec_and_test(&watch->usage)) {
+ put_watch_queue(watch->queue);
+ kfree_rcu(watch, rcu);
+ }
+}
+
+/**
+ * add_watch_to_object - Add a watch on an object
+ * @watch: The watch to add
+ *
+ * @watch->queue and @watch->watch_list must have been set to point to the
+ * queue to post notifications to and the watch list of the object to be
+ * watched.
+ *
+ * The caller must pin the queue and the list both and must hold the list
+ * locked against racing watch additions/removals.
+ */
+int add_watch_to_object(struct watch *watch)
+{
+ struct watch_queue *wqueue = watch->queue;
+ struct watch_list *wlist = watch->watch_list;
+ struct watch *w;
+
+ hlist_for_each_entry(w, &wlist->watchers, list_node) {
+ if (watch->id == w->id)
+ return -EBUSY;
+ }
+
+ spin_lock(&wqueue->lock);
+ refcount_inc(&wqueue->usage);
+ hlist_add_head(&watch->queue_node, &wqueue->watches);
+ spin_unlock(&wqueue->lock);
+
+ hlist_add_head(&watch->list_node, &wlist->watchers);
+ return 0;
+}
+EXPORT_SYMBOL(add_watch_to_object);
+
+/**
+ * remove_watch_from_object - Remove a watch or all watches from an object.
+ * @wlist: The watch list to remove from
+ * @wq: The watch queue of interest (ignored if @all is true)
+ * @id: The ID of the watch to remove (ignored if @all is true)
+ * @all: True to remove all objects
+ *
+ * Remove a specific watch or all watches from an object. A notification is
+ * sent to the watcher to tell them that this happened.
+ */
+int remove_watch_from_object(struct watch_list *wlist, struct watch_queue *wq,
+ u64 id, bool all)
+{
+ struct watch_notification n;
+ struct watch_queue *wqueue;
+ struct watch *watch;
+ int ret = -EBADSLT;
+
+ rcu_read_lock();
+
+again:
+ spin_lock(&wlist->lock);
+ hlist_for_each_entry(watch, &wlist->watchers, list_node) {
+ if (all || (watch->id == id && watch->queue == wq))
+ goto found;
+ }
+ spin_unlock(&wlist->lock);
+ goto out;
+
+found:
+ ret = 0;
+ hlist_del_init_rcu(&watch->list_node);
+ rcu_assign_pointer(watch->watch_list, NULL);
+ spin_unlock(&wlist->lock);
+
+ n.type = WATCH_TYPE_META;
+ n.subtype = watch_meta_removal_notification;
+ n.info = watch->info_id | sizeof(n);
+
+ post_one_notification(watch->queue, &n);
+
+ /* We don't need the watch list lock for the next bit as RCU is
+ * protecting everything from being deallocated.
+ */
+ wqueue = rcu_dereference(watch->queue);
+ if (wqueue) {
+ spin_lock(&wqueue->lock);
+
+ if (!hlist_unhashed(&watch->queue_node)) {
+ hlist_del_init_rcu(&watch->queue_node);
+ put_watch(watch);
+ }
+
+ spin_unlock(&wqueue->lock);
+ }
+
+ if (wlist->release_watch) {
+ rcu_read_unlock();
+ wlist->release_watch(wlist, watch);
+ rcu_read_lock();
+ }
+ put_watch(watch);
+
+ if (all && !hlist_empty(&wlist->watchers))
+ goto again;
+out:
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL(remove_watch_from_object);
+
+/*
+ * Remove all the watches that are contributory to a queue. This will
+ * potentially race with removal of the watches by the destruction of the
+ * objects being watched or the distribution of notifications.
+ */
+static void watch_queue_clear(struct watch_queue *wqueue)
+{
+ struct watch_list *wlist;
+ struct watch *watch;
+ bool release;
+
+ rcu_read_lock();
+ spin_lock(&wqueue->lock);
+
+ /* Prevent new additions and prevent notifications from happening */
+ wqueue->defunct = true;
+
+ while (!hlist_empty(&wqueue->watches)) {
+ watch = hlist_entry(wqueue->watches.first, struct watch, queue_node);
+ hlist_del_init_rcu(&watch->queue_node);
+ spin_unlock(&wqueue->lock);
+
+ /* We can't do the next bit under the queue lock as we need to
+ * get the list lock - which would cause a deadlock if someone
+ * was removing from the opposite direction at the same time or
+ * posting a notification.
+ */
+ wlist = rcu_dereference(watch->watch_list);
+ if (wlist) {
+ spin_lock(&wlist->lock);
+
+ release = !hlist_unhashed(&watch->list_node);
+ if (release) {
+ hlist_del_init_rcu(&watch->list_node);
+ rcu_assign_pointer(watch->watch_list, NULL);
+ }
+
+ spin_unlock(&wlist->lock);
+
+ if (release) {
+ if (wlist->release_watch) {
+ rcu_read_unlock();
+ /* This might need to call dput(), so
+ * we have to drop all the locks.
+ */
+ wlist->release_watch(wlist, watch);
+ rcu_read_lock();
+ }
+ put_watch(watch);
+ }
+ }
+
+ put_watch(watch);
+ spin_lock(&wqueue->lock);
+ }
+
+ spin_unlock(&wqueue->lock);
+ rcu_read_unlock();
+}
+
+/*
+ * Release the file.
+ */
+static int watch_queue_release(struct inode *inode, struct file *file)
+{
+ struct watch_queue *wqueue = file->private_data;
+ int i, pgref;
+
+ watch_queue_clear(wqueue);
+
+ if (wqueue->pages && wqueue->pages[0])
+ WARN_ON(page_ref_count(wqueue->pages[0]) != 1);
+
+ if (wqueue->buffer)
+ vfree(wqueue->buffer);
+ for (i = 0; i < wqueue->nr_pages; i++) {
+ ClearPageUptodate(wqueue->pages[i]);
+ wqueue->pages[i]->mapping = NULL;
+ pgref = page_ref_count(wqueue->pages[i]);
+ WARN(pgref != 1,
+ "FREE PAGE[%d] refcount %d\n", i, page_ref_count(wqueue->pages[i]));
+ __free_page(wqueue->pages[i]);
+ }
+ if (wqueue->filter)
+ kfree_rcu(wqueue->filter, rcu);
+ kfree(wqueue->pages);
+ put_watch_queue(wqueue);
+ return 0;
+}
+
+#ifdef DEBUG_WITH_WRITE
+static ssize_t watch_queue_write(struct file *file,
+ const char __user *_buf, size_t len, loff_t *pos)
+{
+ struct watch_notification *n;
+ struct watch_queue *wqueue = file->private_data;
+ ssize_t ret;
+
+ if (!wqueue->buffer)
+ return -ENOBUFS;
+
+ if (len & ~WATCH_INFO_LENGTH || len == 0 || !_buf)
+ return -EINVAL;
+
+ n = memdup_user(_buf, len);
+ if (IS_ERR(n))
+ return PTR_ERR(n);
+
+ ret = -EINVAL;
+ if ((n->info & WATCH_INFO_LENGTH) != len)
+ goto error;
+ n->info &= (WATCH_INFO_LENGTH | WATCH_INFO_TYPE_FLAGS | WATCH_INFO_ID);
+
+ if (post_one_notification(wqueue, n))
+ wqueue->debug = 0;
+ else
+ wqueue->debug++;
+ ret = len;
+ if (wqueue->debug > 20)
+ ret = -EIO;
+
+error:
+ kfree(n);
+ return ret;
+}
+#endif
+
+static const struct file_operations watch_queue_fops = {
+ .owner = THIS_MODULE,
+ .open = watch_queue_open,
+ .release = watch_queue_release,
+ .unlocked_ioctl = watch_queue_ioctl,
+ .poll = watch_queue_poll,
+ .mmap = watch_queue_mmap,
+#ifdef DEBUG_WITH_WRITE
+ .write = watch_queue_write,
+#endif
+ .llseek = no_llseek,
+};
+
+/**
+ * get_watch_queue - Get a watch queue from its file descriptor.
+ * @fd: The fd to query.
+ */
+struct watch_queue *get_watch_queue(int fd)
+{
+ struct watch_queue *wqueue = ERR_PTR(-EBADF);
+ struct fd f;
+
+ f = fdget(fd);
+ if (f.file) {
+ wqueue = ERR_PTR(-EINVAL);
+ if (f.file->f_op == &watch_queue_fops) {
+ wqueue = f.file->private_data;
+ refcount_inc(&wqueue->usage);
+ }
+ fdput(f);
+ }
+
+ return wqueue;
+}
+EXPORT_SYMBOL(get_watch_queue);
+
+static struct miscdevice watch_queue_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "watch_queue",
+ .fops = &watch_queue_fops,
+ .mode = 0666,
+};
+
+static int __init watch_queue_init(void)
+{
+ int ret;
+
+ ret = misc_register(&watch_queue_dev);
+ if (ret < 0)
+ pr_err("Failed to register %d\n", ret);
+ return ret;
+}
+fs_initcall(watch_queue_init);
+
+static void __exit watch_queue_exit(void)
+{
+ misc_deregister(&watch_queue_dev);
+}
+module_exit(watch_queue_exit);
diff --git a/include/linux/watch_queue.h b/include/linux/watch_queue.h
new file mode 100644
index 000000000000..465b14f3ad42
--- /dev/null
+++ b/include/linux/watch_queue.h
@@ -0,0 +1,87 @@
+/* User-mappable watch queue
+ *
+ * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_WATCH_QUEUE_H
+#define _LINUX_WATCH_QUEUE_H
+
+#include <uapi/linux/watch_queue.h>
+
+#ifdef CONFIG_WATCH_QUEUE
+
+struct watch_queue;
+
+/*
+ * Representation of a watch on an object.
+ */
+struct watch {
+ union {
+ struct rcu_head rcu;
+ u32 info_id; /* ID to be OR'd in to info field */
+ };
+ struct watch_queue __rcu *queue; /* Queue to post events to */
+ struct hlist_node queue_node; /* Link in queue->watches */
+ struct watch_list __rcu *watch_list;
+ struct hlist_node list_node; /* Link in watch_list->watchers */
+ void *private; /* Private data for the watched object */
+ u64 id; /* Internal identifier */
+ refcount_t usage;
+};
+
+/*
+ * List of watches on an object.
+ */
+struct watch_list {
+ struct rcu_head rcu;
+ struct hlist_head watchers;
+ void (*release_watch)(struct watch_list *, struct watch *);
+ spinlock_t lock;
+};
+
+extern void __post_watch_notification(struct watch_list *,
+ struct watch_notification *, u64);
+extern struct watch_queue *get_watch_queue(int);
+extern void put_watch_queue(struct watch_queue *);
+extern void put_watch_list(struct watch_list *);
+extern int add_watch_to_object(struct watch *);
+extern int remove_watch_from_object(struct watch_list *, struct watch_queue *, u64, bool);
+
+static inline void init_watch_list(struct watch_list *wlist)
+{
+ INIT_HLIST_HEAD(&wlist->watchers);
+ spin_lock_init(&wlist->lock);
+}
+
+static inline void init_watch(struct watch *watch)
+{
+ refcount_set(&watch->usage, 1);
+ INIT_HLIST_NODE(&watch->list_node);
+ INIT_HLIST_NODE(&watch->queue_node);
+}
+
+static inline void post_watch_notification(struct watch_list *wlist,
+ struct watch_notification *n,
+ u64 id)
+{
+ if (unlikely(wlist))
+ __post_watch_notification(wlist, n, id);
+}
+
+static inline void remove_watch_list(struct watch_list *wlist)
+{
+ if (wlist) {
+ remove_watch_from_object(wlist, NULL, 0, true);
+ kfree_rcu(wlist, rcu);
+ }
+}
+
+#endif
+
+#endif /* _LINUX_WATCH_QUEUE_H */
diff --git a/include/uapi/linux/watch_queue.h b/include/uapi/linux/watch_queue.h
new file mode 100644
index 000000000000..98ac4d46ab0d
--- /dev/null
+++ b/include/uapi/linux/watch_queue.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_WATCH_QUEUE_H
+#define _UAPI_LINUX_WATCH_QUEUE_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define IOC_WATCH_QUEUE_SET_SIZE _IO('s', 0x01) /* Set the size in pages */
+#define IOC_WATCH_QUEUE_SET_FILTER _IO('s', 0x02) /* Set the filter */
+
+enum watch_notification_type {
+ WATCH_TYPE_META = 0, /* Special record */
+ WATCH_TYPE_MOUNT_NOTIFY = 1, /* Mount notification record */
+ WATCH_TYPE_SB_NOTIFY = 2, /* Superblock notification */
+ WATCH_TYPE_KEY_NOTIFY = 3, /* Key/keyring change notification */
+#define WATCH_TYPE___NR 4
+};
+
+enum watch_meta_notification_subtype {
+ watch_meta_skip_notification = 0, /* Just skip this record */
+ watch_meta_removal_notification = 1, /* Watched object was removed */
+};
+
+/*
+ * Notification record
+ */
+struct watch_notification {
+ __u32 type:24; /* enum watch_notification_type */
+ __u32 subtype:8; /* Type-specific subtype (filterable) */
+ __u32 info;
+#define WATCH_INFO_OVERRUN 0x00000001 /* Event(s) lost due to overrun */
+#define WATCH_INFO_ENOMEM 0x00000002 /* Event(s) lost due to ENOMEM */
+#define WATCH_INFO_RECURSIVE 0x00000004 /* Change was recursive */
+#define WATCH_INFO_LENGTH 0x000001f8 /* Length of record / sizeof(watch_notification) */
+#define WATCH_INFO_IN_SUBTREE 0x00000200 /* Change was not at watched root */
+#define WATCH_INFO_TYPE_FLAGS 0x00ff0000 /* Type-specific flags */
+#define WATCH_INFO_FLAG_0 0x00010000
+#define WATCH_INFO_FLAG_1 0x00020000
+#define WATCH_INFO_FLAG_2 0x00040000
+#define WATCH_INFO_FLAG_3 0x00080000
+#define WATCH_INFO_FLAG_4 0x00100000
+#define WATCH_INFO_FLAG_5 0x00200000
+#define WATCH_INFO_FLAG_6 0x00400000
+#define WATCH_INFO_FLAG_7 0x00800000
+#define WATCH_INFO_ID 0xff000000 /* ID of watchpoint */
+};
+
+#define WATCH_LENGTH_SHIFT 3
+
+struct watch_queue_buffer {
+ union {
+ /* The first few entries are special, containing the
+ * ring management variables.
+ */
+ struct {
+ struct watch_notification watch; /* WATCH_TYPE_SKIP */
+ volatile __u32 head; /* Ring head index */
+ volatile __u32 tail; /* Ring tail index */
+ __u32 mask; /* Ring index mask */
+ } meta;
+ struct watch_notification slots[0];
+ };
+};
+
+/*
+ * Notification filtering rules (IOC_WATCH_QUEUE_SET_FILTER).
+ */
+struct watch_notification_type_filter {
+ __u32 type; /* Type to apply filter to */
+ __u32 info_filter; /* Filter on watch_notification::info */
+ __u32 info_mask; /* Mask of relevant bits in info_filter */
+ __u32 subtype_filter[8]; /* Bitmask of subtypes to filter on */
+};
+
+struct watch_notification_filter {
+ __u32 nr_filters; /* Number of filters */
+ __u32 __reserved; /* Must be 0 */
+ struct watch_notification_type_filter filters[];
+};
+
+#endif /* _UAPI_LINUX_WATCH_QUEUE_H */
diff --git a/mm/interval_tree.c b/mm/interval_tree.c
index 27ddfd29112a..9a53ddf4bd62 100644
--- a/mm/interval_tree.c
+++ b/mm/interval_tree.c
@@ -25,6 +25,8 @@ INTERVAL_TREE_DEFINE(struct vm_area_struct, shared.rb,
unsigned long, shared.rb_subtree_last,
vma_start_pgoff, vma_last_pgoff,, vma_interval_tree)
+EXPORT_SYMBOL_GPL(vma_interval_tree_insert);
+
/* Insert node immediately after prev in the interval tree */
void vma_interval_tree_insert_after(struct vm_area_struct *node,
struct vm_area_struct *prev,
diff --git a/mm/memory.c b/mm/memory.c
index 7206a634270b..79a2b13cc7cc 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3462,6 +3462,7 @@ int alloc_set_pte(struct vm_fault *vmf, struct mem_cgroup *memcg,
return 0;
}
+EXPORT_SYMBOL_GPL(alloc_set_pte);
/**
^ permalink raw reply related
* [PATCH 5/5] Add sample notification program
From: David Howells @ 2018-07-23 15:26 UTC (permalink / raw)
To: viro
Cc: linux-fsdevel, dhowells, linux-kernel, raven, keyrings,
linux-security-module
In-Reply-To: <153235954191.32640.5792167066538704794.stgit@warthog.procyon.org.uk>
This needs to be linked with -lkeyutils.
It is run like:
./watch_test
and watches "/" for mount changes and the current session keyring for key
changes:
# keyctl add user a a @s
1035096409
# keyctl unlink 1035096409 @s
# mount -t tmpfs none /mnt/nfsv3tcp/
# umount /mnt/nfsv3tcp
producing:
# ./watch_test
ptrs h=4 t=2 m=20003
NOTIFY[00000004-00000002] ty=0003 sy=0002 i=01000010
KEY 2ffc2e5d change=2[linked] aux=1035096409
ptrs h=6 t=4 m=20003
NOTIFY[00000006-00000004] ty=0003 sy=0003 i=01000010
KEY 2ffc2e5d change=3[unlinked] aux=1035096409
ptrs h=8 t=6 m=20003
NOTIFY[00000008-00000006] ty=0001 sy=0000 i=02000010
MOUNT 00000013 change=0[new_mount] aux=168
ptrs h=a t=8 m=20003
NOTIFY[0000000a-00000008] ty=0001 sy=0001 i=02000010
MOUNT 00000013 change=1[unmount] aux=168
---
samples/Kconfig | 6 +
samples/Makefile | 2
samples/watch_queue/Makefile | 9 +
samples/watch_queue/watch_test.c | 232 ++++++++++++++++++++++++++++++++++++++
4 files changed, 248 insertions(+), 1 deletion(-)
create mode 100644 samples/watch_queue/Makefile
create mode 100644 samples/watch_queue/watch_test.c
diff --git a/samples/Kconfig b/samples/Kconfig
index 1c5658bc6224..dac30cefe895 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -156,4 +156,10 @@ config SAMPLE_MOUNT_API
help
Build example userspace program(s) that use the new mount API.
+config SAMPLE_WATCH_QUEUE
+ bool "Build example /dev/watch_queue notification consumer"
+ help
+ Build example userspace program to use the new mount_notify(),
+ sb_notify() syscalls and the KEYCTL_WATCH_KEY keyctl() function.
+
endif # SAMPLES
diff --git a/samples/Makefile b/samples/Makefile
index 31d08cc71a5c..ed545cbf65c8 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -3,4 +3,4 @@
obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \
hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
configfs/ connector/ v4l/ trace_printk/ \
- vfio-mdev/ statx/ qmi/ mount_api/
+ vfio-mdev/ statx/ qmi/ mount_api/ watch_queue/
diff --git a/samples/watch_queue/Makefile b/samples/watch_queue/Makefile
new file mode 100644
index 000000000000..1f20ee2b0add
--- /dev/null
+++ b/samples/watch_queue/Makefile
@@ -0,0 +1,9 @@
+# List of programs to build
+hostprogs-$(CONFIG_SAMPLE_WATCH_QUEUE) := watch_test
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_watch_test.o += -I$(objtree)/usr/include
+
+HOSTLOADLIBES_watch_test += -lkeyutils
diff --git a/samples/watch_queue/watch_test.c b/samples/watch_queue/watch_test.c
new file mode 100644
index 000000000000..cdbaaf5a1163
--- /dev/null
+++ b/samples/watch_queue/watch_test.c
@@ -0,0 +1,232 @@
+/* Use /dev/watch_queue to watch for keyring and mount topology changes.
+ *
+ * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <limits.h>
+#include <linux/watch_queue.h>
+#include <linux/unistd.h>
+#include <linux/keyctl.h>
+
+#define BUF_SIZE 4
+
+static const char *key_subtypes[] = {
+ [notify_key_instantiated] = "instantiated",
+ [notify_key_updated] = "updated",
+ [notify_key_linked] = "linked",
+ [notify_key_unlinked] = "unlinked",
+ [notify_key_cleared] = "cleared",
+ [notify_key_revoked] = "revoked",
+ [notify_key_invalidated] = "invalidated",
+ [notify_key_setattr] = "setattr",
+};
+
+static void saw_key_change(struct watch_notification *n)
+{
+ struct key_notification *k = (struct key_notification *)n;
+ unsigned int len = n->info & WATCH_INFO_LENGTH;
+
+ if (len != sizeof(struct key_notification))
+ return;
+
+ printf("KEY %08x change=%u[%s] aux=%u\n",
+ k->key_id, n->subtype, key_subtypes[n->subtype], k->aux);
+}
+
+static const char *mount_subtypes[] = {
+ [notify_mount_new_mount] = "new_mount",
+ [notify_mount_unmount] = "unmount",
+ [notify_mount_expiry] = "expiry",
+ [notify_mount_readonly] = "readonly",
+ [notify_mount_setattr] = "setattr",
+ [notify_mount_move_from] = "move_from",
+ [notify_mount_move_to] = "move_to",
+};
+
+static long keyctl_watch_key(int key, int watch_fd, int watch_id)
+{
+ return syscall(__NR_keyctl, KEYCTL_WATCH_KEY, key, watch_fd, watch_id);
+}
+
+static void saw_mount_change(struct watch_notification *n)
+{
+ struct mount_notification *m = (struct mount_notification *)n;
+ unsigned int len = n->info & WATCH_INFO_LENGTH;
+
+ if (len != sizeof(struct mount_notification))
+ return;
+
+ printf("MOUNT %08x change=%u[%s] aux=%u\n",
+ m->triggered_on, n->subtype, mount_subtypes[n->subtype], m->changed_mount);
+}
+
+static const char *super_subtypes[] = {
+ [notify_superblock_readonly] = "readonly",
+ [notify_superblock_error] = "error",
+ [notify_superblock_edquot] = "edquot",
+ [notify_superblock_network] = "network",
+};
+
+static void saw_super_change(struct watch_notification *n)
+{
+ struct superblock_notification *s = (struct superblock_notification *)n;
+ unsigned int len = n->info & WATCH_INFO_LENGTH;
+
+ if (len < sizeof(struct superblock_notification))
+ return;
+
+ printf("SUPER %08llx change=%u[%s]\n",
+ s->sb_id, n->subtype, super_subtypes[n->subtype]);
+}
+
+/*
+ * Consume and display events.
+ */
+static int consumer(int fd, struct watch_queue_buffer *buf)
+{
+ struct watch_notification *n;
+ struct pollfd p[1];
+ unsigned int head, tail, mask = buf->meta.mask;
+
+ for (;;) {
+ p[0].fd = fd;
+ p[0].events = POLLIN | POLLERR;
+ p[0].revents = 0;
+
+ if (poll(p, 1, -1) == -1) {
+ perror("poll");
+ break;
+ }
+
+ printf("ptrs h=%x t=%x m=%x\n",
+ buf->meta.head, buf->meta.tail, buf->meta.mask);
+
+ while (head = buf->meta.head,
+ tail = buf->meta.tail,
+ tail != head
+ ) {
+ asm ("lfence" : : : "memory" );
+ n = &buf->slots[tail & mask];
+ printf("NOTIFY[%08x-%08x] ty=%04x sy=%04x i=%08x\n",
+ head, tail, n->type, n->subtype, n->info);
+ if ((n->info & WATCH_INFO_LENGTH) == 0)
+ goto out;
+
+ switch (n->type) {
+ case WATCH_TYPE_META:
+ if (n->subtype == watch_meta_removal_notification)
+ printf("REMOVAL of watchpoint %08x\n",
+ n->info & WATCH_INFO_ID);
+ break;
+ case WATCH_TYPE_MOUNT_NOTIFY:
+ saw_mount_change(n);
+ break;
+ case WATCH_TYPE_SB_NOTIFY:
+ saw_super_change(n);
+ break;
+ case WATCH_TYPE_KEY_NOTIFY:
+ saw_key_change(n);
+ break;
+ }
+
+ tail += (n->info & WATCH_INFO_LENGTH) >> WATCH_LENGTH_SHIFT;
+ asm("mfence" ::: "memory");
+ buf->meta.tail = tail;
+ }
+ }
+
+out:
+ return 0;
+}
+
+static struct watch_notification_filter filter = {
+ .nr_filters = 3,
+ .__reserved = 0,
+ .filters = {
+ [0] = {
+ .type = WATCH_TYPE_MOUNT_NOTIFY,
+ // Reject move-from notifications
+ .subtype_filter[0] = UINT_MAX & ~(1 << notify_mount_move_from),
+ },
+ [1] = {
+ .type = WATCH_TYPE_SB_NOTIFY,
+ // Only accept notification of changes to R/O state
+ .subtype_filter[0] = (1 << notify_superblock_readonly),
+ // Only accept notifications of change-to-R/O
+ .info_mask = WATCH_INFO_FLAG_0,
+ .info_filter = WATCH_INFO_FLAG_0,
+ },
+ [2] = {
+ .type = WATCH_TYPE_KEY_NOTIFY,
+ .subtype_filter[0] = UINT_MAX,
+ },
+ },
+};
+
+int main(int argc, char **argv)
+{
+ struct watch_queue_buffer *buf;
+ size_t page_size;
+ int fd;
+
+ fd = open("/dev/watch_queue", O_RDWR);
+ if (fd == -1) {
+ perror("/dev/watch_queue");
+ exit(1);
+ }
+
+ if (ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, BUF_SIZE) == -1) {
+ perror("/dev/watch_queue(size)");
+ exit(1);
+ }
+
+ if (ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter) == -1) {
+ perror("/dev/watch_queue(filter)");
+ exit(1);
+ }
+
+ page_size = sysconf(_SC_PAGESIZE);
+ buf = mmap(NULL, BUF_SIZE * page_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (buf == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+
+ if (keyctl_watch_key(KEY_SPEC_SESSION_KEYRING, fd, 0x01) == -1) {
+ perror("keyctl");
+ exit(1);
+ }
+
+ if (syscall(__NR_mount_notify, AT_FDCWD, "/", 0, fd, 0x02) == -1) {
+ perror("mount_notify");
+ exit(1);
+ }
+
+ if (syscall(__NR_sb_notify, AT_FDCWD, "/mnt", 0, fd, 0x03) == -1) {
+ perror("sb_notify");
+ exit(1);
+ }
+
+ return consumer(fd, buf);
+}
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.