Skip to content

Commit

Permalink
Merge branch 'akpm' (patches from Andrew)
Browse files Browse the repository at this point in the history
Merge fixes from Andrew Morton:
 "20 fixes"

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  rapidio/rio_cm: avoid GFP_KERNEL in atomic context
  Revert "ocfs2: bump up o2cb network protocol version"
  ocfs2: fix start offset to ocfs2_zero_range_for_truncate()
  cgroup: duplicate cgroup reference when cloning sockets
  mm: memcontrol: make per-cpu charge cache IRQ-safe for socket accounting
  ocfs2: fix double unlock in case retry after free truncate log
  fanotify: fix list corruption in fanotify_get_response()
  fsnotify: add a way to stop queueing events on group shutdown
  ocfs2: fix trans extend while free cached blocks
  ocfs2: fix trans extend while flush truncate log
  ipc/shm: fix crash if CONFIG_SHMEM is not set
  mm: fix the page_swap_info() BUG_ON check
  autofs: use dentry flags to block walks during expire
  MAINTAINERS: update email for VLYNQ bus entry
  mm: avoid endless recursion in dump_page()
  mm, thp: fix leaking mapped pte in __collapse_huge_page_swapin()
  khugepaged: fix use-after-free in collapse_huge_page()
  MAINTAINERS: Maik has moved
  ocfs2/dlm: fix race between convert and migration
  mem-hotplug: don't clear the only node in new_node_page()
  • Loading branch information
torvalds committed Sep 19, 2016
2 parents 7fadce0 + b92ae13 commit d2ffb01
Show file tree
Hide file tree
Showing 22 changed files with 240 additions and 146 deletions.
4 changes: 2 additions & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -6103,7 +6103,7 @@ S: Supported
F: drivers/cpufreq/intel_pstate.c

INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
M: Maik Broemme <mbroemme@plusserver.de>
M: Maik Broemme <mbroemme@libmpq.org>
L: linux-fbdev@vger.kernel.org
S: Maintained
F: Documentation/fb/intelfb.txt
Expand Down Expand Up @@ -12569,7 +12569,7 @@ F: include/linux/if_*vlan.h
F: net/8021q/

VLYNQ BUS
M: Florian Fainelli <florian@openwrt.org>
M: Florian Fainelli <f.fainelli@gmail.com>
L: openwrt-devel@lists.openwrt.org (subscribers-only)
S: Maintained
F: drivers/vlynq/vlynq.c
Expand Down
19 changes: 16 additions & 3 deletions drivers/rapidio/rio_cm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2247,17 +2247,30 @@ static int rio_cm_shutdown(struct notifier_block *nb, unsigned long code,
{
struct rio_channel *ch;
unsigned int i;
LIST_HEAD(list);

riocm_debug(EXIT, ".");

/*
* If there are any channels left in connected state send
* close notification to the connection partner.
* First build a list of channels that require a closing
* notification because function riocm_send_close() should
* be called outside of spinlock protected code.
*/
spin_lock_bh(&idr_lock);
idr_for_each_entry(&ch_idr, ch, i) {
riocm_debug(EXIT, "close ch %d", ch->id);
if (ch->state == RIO_CM_CONNECTED)
riocm_send_close(ch);
if (ch->state == RIO_CM_CONNECTED) {
riocm_debug(EXIT, "close ch %d", ch->id);
idr_remove(&ch_idr, ch->id);
list_add(&ch->ch_node, &list);
}
}
spin_unlock_bh(&idr_lock);

list_for_each_entry(ch, &list, ch_node)
riocm_send_close(ch);

return NOTIFY_DONE;
}

Expand Down
55 changes: 42 additions & 13 deletions fs/autofs4/expire.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ static struct dentry *should_expire(struct dentry *dentry,
}
return NULL;
}

/*
* Find an eligible tree to time-out
* A tree is eligible if :-
Expand All @@ -432,6 +433,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
struct dentry *root = sb->s_root;
struct dentry *dentry;
struct dentry *expired;
struct dentry *found;
struct autofs_info *ino;

if (!root)
Expand All @@ -442,31 +444,46 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,

dentry = NULL;
while ((dentry = get_next_positive_subdir(dentry, root))) {
int flags = how;

spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry);
if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
expired = NULL;
else
expired = should_expire(dentry, mnt, timeout, how);
if (!expired) {
if (ino->flags & AUTOFS_INF_WANT_EXPIRE) {
spin_unlock(&sbi->fs_lock);
continue;
}
spin_unlock(&sbi->fs_lock);

expired = should_expire(dentry, mnt, timeout, flags);
if (!expired)
continue;

spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(expired);
ino->flags |= AUTOFS_INF_WANT_EXPIRE;
spin_unlock(&sbi->fs_lock);
synchronize_rcu();
spin_lock(&sbi->fs_lock);
if (should_expire(expired, mnt, timeout, how)) {
if (expired != dentry)
dput(dentry);
goto found;
}

/* Make sure a reference is not taken on found if
* things have changed.
*/
flags &= ~AUTOFS_EXP_LEAVES;
found = should_expire(expired, mnt, timeout, how);
if (!found || found != expired)
/* Something has changed, continue */
goto next;

if (expired != dentry)
dput(dentry);

spin_lock(&sbi->fs_lock);
goto found;
next:
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
spin_unlock(&sbi->fs_lock);
if (expired != dentry)
dput(expired);
spin_unlock(&sbi->fs_lock);
}
return NULL;

Expand All @@ -483,15 +500,27 @@ int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
int status;
int state;

/* Block on any pending expire */
if (!(ino->flags & AUTOFS_INF_WANT_EXPIRE))
return 0;
if (rcu_walk)
return -ECHILD;

retry:
spin_lock(&sbi->fs_lock);
if (ino->flags & AUTOFS_INF_EXPIRING) {
state = ino->flags & (AUTOFS_INF_WANT_EXPIRE | AUTOFS_INF_EXPIRING);
if (state == AUTOFS_INF_WANT_EXPIRE) {
spin_unlock(&sbi->fs_lock);
/*
* Possibly being selected for expire, wait until
* it's selected or not.
*/
schedule_timeout_uninterruptible(HZ/10);
goto retry;
}
if (state & AUTOFS_INF_EXPIRING) {
spin_unlock(&sbi->fs_lock);

pr_debug("waiting for expire %p name=%pd\n", dentry, dentry);
Expand Down
13 changes: 1 addition & 12 deletions fs/notify/fanotify/fanotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,7 @@ static int fanotify_get_response(struct fsnotify_group *group,

pr_debug("%s: group=%p event=%p\n", __func__, group, event);

wait_event(group->fanotify_data.access_waitq, event->response ||
atomic_read(&group->fanotify_data.bypass_perm));

if (!event->response) { /* bypass_perm set */
/*
* Event was canceled because group is being destroyed. Remove
* it from group's event list because we are responsible for
* freeing the permission event.
*/
fsnotify_remove_event(group, &event->fae.fse);
return 0;
}
wait_event(group->fanotify_data.access_waitq, event->response);

/* userspace responded, convert to something usable */
switch (event->response) {
Expand Down
36 changes: 24 additions & 12 deletions fs/notify/fanotify/fanotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,16 +358,20 @@ static int fanotify_release(struct inode *ignored, struct file *file)

#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
struct fanotify_perm_event_info *event, *next;
struct fsnotify_event *fsn_event;

/*
* There may be still new events arriving in the notification queue
* but since userspace cannot use fanotify fd anymore, no event can
* enter or leave access_list by now.
* Stop new events from arriving in the notification queue. since
* userspace cannot use fanotify fd anymore, no event can enter or
* leave access_list by now either.
*/
spin_lock(&group->fanotify_data.access_lock);

atomic_inc(&group->fanotify_data.bypass_perm);
fsnotify_group_stop_queueing(group);

/*
* Process all permission events on access_list and notification queue
* and simulate reply from userspace.
*/
spin_lock(&group->fanotify_data.access_lock);
list_for_each_entry_safe(event, next, &group->fanotify_data.access_list,
fae.fse.list) {
pr_debug("%s: found group=%p event=%p\n", __func__, group,
Expand All @@ -379,12 +383,21 @@ static int fanotify_release(struct inode *ignored, struct file *file)
spin_unlock(&group->fanotify_data.access_lock);

/*
* Since bypass_perm is set, newly queued events will not wait for
* access response. Wake up the already sleeping ones now.
* synchronize_srcu() in fsnotify_destroy_group() will wait for all
* processes sleeping in fanotify_handle_event() waiting for access
* response and thus also for all permission events to be freed.
* Destroy all non-permission events. For permission events just
* dequeue them and set the response. They will be freed once the
* response is consumed and fanotify_get_response() returns.
*/
mutex_lock(&group->notification_mutex);
while (!fsnotify_notify_queue_is_empty(group)) {
fsn_event = fsnotify_remove_first_event(group);
if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS))
fsnotify_destroy_event(group, fsn_event);
else
FANOTIFY_PE(fsn_event)->response = FAN_ALLOW;
}
mutex_unlock(&group->notification_mutex);

/* Response for all permission events it set, wakeup waiters */
wake_up(&group->fanotify_data.access_waitq);
#endif

Expand Down Expand Up @@ -755,7 +768,6 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
spin_lock_init(&group->fanotify_data.access_lock);
init_waitqueue_head(&group->fanotify_data.access_waitq);
INIT_LIST_HEAD(&group->fanotify_data.access_list);
atomic_set(&group->fanotify_data.bypass_perm, 0);
#endif
switch (flags & FAN_ALL_CLASS_BITS) {
case FAN_CLASS_NOTIF:
Expand Down
19 changes: 19 additions & 0 deletions fs/notify/group.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
kfree(group);
}

/*
* Stop queueing new events for this group. Once this function returns
* fsnotify_add_event() will not add any new events to the group's queue.
*/
void fsnotify_group_stop_queueing(struct fsnotify_group *group)
{
mutex_lock(&group->notification_mutex);
group->shutdown = true;
mutex_unlock(&group->notification_mutex);
}

/*
* Trying to get rid of a group. Remove all marks, flush all events and release
* the group reference.
Expand All @@ -47,6 +58,14 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
*/
void fsnotify_destroy_group(struct fsnotify_group *group)
{
/*
* Stop queueing new events. The code below is careful enough to not
* require this but fanotify needs to stop queuing events even before
* fsnotify_destroy_group() is called and this makes the other callers
* of fsnotify_destroy_group() to see the same behavior.
*/
fsnotify_group_stop_queueing(group);

/* clear all inode marks for this group, attach them to destroy_list */
fsnotify_detach_group_marks(group);

Expand Down
23 changes: 7 additions & 16 deletions fs/notify/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
* Add an event to the group notification queue. The group can later pull this
* event off the queue to deal with. The function returns 0 if the event was
* added to the queue, 1 if the event was merged with some other queued event,
* 2 if the queue of events has overflown.
* 2 if the event was not queued - either the queue of events has overflown
* or the group is shutting down.
*/
int fsnotify_add_event(struct fsnotify_group *group,
struct fsnotify_event *event,
Expand All @@ -96,6 +97,11 @@ int fsnotify_add_event(struct fsnotify_group *group,

mutex_lock(&group->notification_mutex);

if (group->shutdown) {
mutex_unlock(&group->notification_mutex);
return 2;
}

if (group->q_len >= group->max_events) {
ret = 2;
/* Queue overflow event only if it isn't already queued */
Expand Down Expand Up @@ -125,21 +131,6 @@ int fsnotify_add_event(struct fsnotify_group *group,
return ret;
}

/*
* Remove @event from group's notification queue. It is the responsibility of
* the caller to destroy the event.
*/
void fsnotify_remove_event(struct fsnotify_group *group,
struct fsnotify_event *event)
{
mutex_lock(&group->notification_mutex);
if (!list_empty(&event->list)) {
list_del_init(&event->list);
group->q_len--;
}
mutex_unlock(&group->notification_mutex);
}

/*
* Remove and return the first event from the notification list. It is the
* responsibility of the caller to destroy the obtained event
Expand Down
Loading

0 comments on commit d2ffb01

Please sign in to comment.