Message ID | CAOQ4uxjA8Z7wnwuHFCKeKT1xz0Gh-qS40Y6cfPi3fAM0MKsRuQ@mail.gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Amir Goldstein <amir73il@gmail.com>: > Sorry I messed up the previous patch. please try this one: I will try it. > + * do the right thing if there are no more events to > + * read (i.e. return bytes read, -EAGAIN or wait). EAGAIN is the right thing to do when FAN_NONBLOCK has been specified. Without FAN_NONBLOCK, EAGAIN is bound to confuse the application. That could be documented, of course. More importantly, does EAGAIN here still guarantee EPOLLET semantics of epoll(7)? IOW, if I get EAGAIN, I shouldn't have to try read(2)ing the fanotify fd again before calling epoll_wait(2). Marko
On Thu, Apr 20, 2017 at 3:43 PM, Marko Rauhamaa <marko.rauhamaa@f-secure.com> wrote: > Amir Goldstein <amir73il@gmail.com>: > >> Sorry I messed up the previous patch. please try this one: > > I will try it. > >> + * do the right thing if there are no more events to >> + * read (i.e. return bytes read, -EAGAIN or wait). > > EAGAIN is the right thing to do when FAN_NONBLOCK has been specified. > Without FAN_NONBLOCK, EAGAIN is bound to confuse the application. That > could be documented, of course. > My comment says "do the right thing ... -EAGAIN or wait", meaning depending FAN_NONBLOCK. The same code that checks for FAN_NONBLOCK will take care of that. My patch only takes care of dropping the stale event and continue to next event. If there is no next event, code will "do the right thing". > More importantly, does EAGAIN here still guarantee EPOLLET semantics of > epoll(7)? IOW, if I get EAGAIN, I shouldn't have to try read(2)ing the > fanotify fd again before calling epoll_wait(2). > Yes, if you get EAGAIN it means there are no more events in the queue, so shouldn't have to try read again. Amir.
On Thu 20-04-17 14:33:04, Amir Goldstein wrote: > > Sorry I messed up the previous patch. please try this one: > > diff --git a/fs/notify/fanotify/fanotify_user.c > b/fs/notify/fanotify/fanotify_user.c > index 2b37f27..7864354 100644 > --- a/fs/notify/fanotify/fanotify_user.c > +++ b/fs/notify/fanotify/fanotify_user.c > @@ -295,6 +295,16 @@ static ssize_t fanotify_read(struct file *file, > char __user *buf, > } > > ret = copy_event_to_user(group, kevent, buf); > + if (unlikely(ret == -EOPENSTALE)) { > + /* > + * We cannot report events with stale fd so drop it. > + * Setting ret to 0 will continue the event loop and > + * do the right thing if there are no more events to > + * read (i.e. return bytes read, -EAGAIN or wait). > + */ > + ret = 0; > + } > + > /* > * Permission events get queued to wait for response. Other > * events can be destroyed now. > @@ -305,7 +315,7 @@ static ssize_t fanotify_read(struct file *file, > char __user *buf, > break; > } else { > #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS > - if (ret < 0) { > + if (ret <= 0) { > FANOTIFY_PE(kevent)->response = FAN_DENY; > wake_up(&group->fanotify_data.access_waitq); > break; I don't think you want to break out of the reading loop when ret == 0 and the code might be more readable as: if (!(kevent->mask & FAN_ALL_PERM_EVENTS)) { fsnotify_destroy_event(group, kevent); } else { #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS if (ret <= 0) { FANOTIFY_PE(kevent)->response = FAN_DENY; wake_up(&group->fanotify_data.access_waitq); } else { spin_lock(&group->notification_lock); list_add_tail(&kevent->list, &group->fanotify_data.access_list); spin_unlock(&group->notification_lock); } #endif } if (ret < 0) break; Hmm? Honza
On Thu, Apr 20, 2017 at 5:20 PM, Jan Kara <jack@suse.cz> wrote: > On Thu 20-04-17 14:33:04, Amir Goldstein wrote: >> >> Sorry I messed up the previous patch. please try this one: >> >> diff --git a/fs/notify/fanotify/fanotify_user.c >> b/fs/notify/fanotify/fanotify_user.c >> index 2b37f27..7864354 100644 >> --- a/fs/notify/fanotify/fanotify_user.c >> +++ b/fs/notify/fanotify/fanotify_user.c >> @@ -295,6 +295,16 @@ static ssize_t fanotify_read(struct file *file, >> char __user *buf, >> } >> >> ret = copy_event_to_user(group, kevent, buf); >> + if (unlikely(ret == -EOPENSTALE)) { >> + /* >> + * We cannot report events with stale fd so drop it. >> + * Setting ret to 0 will continue the event loop and >> + * do the right thing if there are no more events to >> + * read (i.e. return bytes read, -EAGAIN or wait). >> + */ >> + ret = 0; >> + } >> + >> /* >> * Permission events get queued to wait for response. Other >> * events can be destroyed now. >> @@ -305,7 +315,7 @@ static ssize_t fanotify_read(struct file *file, >> char __user *buf, >> break; >> } else { >> #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS >> - if (ret < 0) { >> + if (ret <= 0) { >> FANOTIFY_PE(kevent)->response = FAN_DENY; >> wake_up(&group->fanotify_data.access_waitq); >> break; > > I don't think you want to break out of the reading loop when ret == 0 and > the code might be more readable as: > > if (!(kevent->mask & FAN_ALL_PERM_EVENTS)) { > fsnotify_destroy_event(group, kevent); > } else { > #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS > if (ret <= 0) { > FANOTIFY_PE(kevent)->response = FAN_DENY; > wake_up(&group->fanotify_data.access_waitq); > } else { > spin_lock(&group->notification_lock); > list_add_tail(&kevent->list, > &group->fanotify_data.access_list); > spin_unlock(&group->notification_lock); > } > #endif > } > if (ret < 0) > break; > > Hmm? > Right, I missed that. Thanks.
Amir Goldstein <amir73il@gmail.com>: > On Thu, Apr 20, 2017 at 3:43 PM, Marko Rauhamaa > <marko.rauhamaa@f-secure.com> wrote: >> Amir Goldstein <amir73il@gmail.com>: >> >>> Sorry I messed up the previous patch. please try this one: >> >> I will try it. Tried it. Superficially, it seems to be working, but... >> More importantly, does EAGAIN here still guarantee EPOLLET semantics >> of epoll(7)? IOW, if I get EAGAIN, I shouldn't have to try read(2)ing >> the fanotify fd again before calling epoll_wait(2). > > Yes, if you get EAGAIN it means there are no more events in the queue, > so shouldn't have to try read again. I ran into a system hang with our real product that suggests there might be a problem left. It would be explained if your patch generated an EAGAIN while there were other events waiting in the queue. I will have to investigate further. Marko
On Thu, Apr 20, 2017 at 6:06 PM, Amir Goldstein <amir73il@gmail.com> wrote: > On Thu, Apr 20, 2017 at 5:20 PM, Jan Kara <jack@suse.cz> wrote: >> On Thu 20-04-17 14:33:04, Amir Goldstein wrote: >>> >>> Sorry I messed up the previous patch. please try this one: >>> >>> diff --git a/fs/notify/fanotify/fanotify_user.c >>> b/fs/notify/fanotify/fanotify_user.c >>> index 2b37f27..7864354 100644 >>> --- a/fs/notify/fanotify/fanotify_user.c >>> +++ b/fs/notify/fanotify/fanotify_user.c >>> @@ -295,6 +295,16 @@ static ssize_t fanotify_read(struct file *file, >>> char __user *buf, >>> } >>> >>> ret = copy_event_to_user(group, kevent, buf); >>> + if (unlikely(ret == -EOPENSTALE)) { >>> + /* >>> + * We cannot report events with stale fd so drop it. >>> + * Setting ret to 0 will continue the event loop and >>> + * do the right thing if there are no more events to >>> + * read (i.e. return bytes read, -EAGAIN or wait). >>> + */ >>> + ret = 0; >>> + } >>> + >>> /* >>> * Permission events get queued to wait for response. Other >>> * events can be destroyed now. >>> @@ -305,7 +315,7 @@ static ssize_t fanotify_read(struct file *file, >>> char __user *buf, >>> break; >>> } else { >>> #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS >>> - if (ret < 0) { >>> + if (ret <= 0) { >>> FANOTIFY_PE(kevent)->response = FAN_DENY; >>> wake_up(&group->fanotify_data.access_waitq); >>> break; >> >> I don't think you want to break out of the reading loop when ret == 0 and >> the code might be more readable as: >> >> if (!(kevent->mask & FAN_ALL_PERM_EVENTS)) { >> fsnotify_destroy_event(group, kevent); >> } else { >> #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS >> if (ret <= 0) { >> FANOTIFY_PE(kevent)->response = FAN_DENY; >> wake_up(&group->fanotify_data.access_waitq); >> } else { >> spin_lock(&group->notification_lock); >> list_add_tail(&kevent->list, >> &group->fanotify_data.access_list); >> spin_unlock(&group->notification_lock); >> } >> #endif >> } >> if (ret < 0) >> break; >> >> Hmm? >> > On Fri, Apr 21, 2017 at 5:27 PM, Marko Rauhamaa <marko.rauhamaa@f-secure.com> wrote: > Amir Goldstein <amir73il@gmail.com>: > >> Did you notice Jan's comments on my patch? I had a bug that broke out >> of the loop. Without his corrections read will return even if there >> are more events in the queue. > > Yes, I now tried Jan's fix, and it did the trick. > > It will now take months or years before distros have a proper fix. In > the interim, I will absorb EOPENSTALE and schedule a reread in that > situation. > > Thank you both for your attention. > > Marko, Were you able to verify that both blocking and non-blocking mode work correctly? May I add your Tested-by and Reported-by tags? Thanks! Amir.
Amir Goldstein <amir73il@gmail.com>: > Were you able to verify that both blocking and non-blocking mode work > correctly? May I add your Tested-by and Reported-by tags? I have only verified the nonblocking case in my tests (which are by no means extensive). The reported issue can no longer be reproduced with the patched kernel, and the regular OPEN_PERM function is still operational. Feel free to add me to the tags. Marko
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 2b37f27..7864354 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -295,6 +295,16 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, } ret = copy_event_to_user(group, kevent, buf); + if (unlikely(ret == -EOPENSTALE)) { + /* + * We cannot report events with stale fd so drop it. + * Setting ret to 0 will continue the event loop and + * do the right thing if there are no more events to + * read (i.e. return bytes read, -EAGAIN or wait). + */ + ret = 0; + } + /* * Permission events get queued to wait for response. Other