From: Greg Kroah-Hartman Date: Mon, 14 Jan 2013 18:32:43 +0000 (-0800) Subject: 3.7-stable patches X-Git-Tag: v3.7.3~60 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=53f1f93cd22fc3050f631e65f5d46b9ce4987a7a;p=thirdparty%2Fkernel%2Fstable-queue.git 3.7-stable patches added patches: drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch drm-i915-don-t-disable-disconnected-outputs.patch drm-i915-fix-flags-in-dma-buf-exporting.patch drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch --- diff --git a/queue-3.7/drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch b/queue-3.7/drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch new file mode 100644 index 00000000000..80fd7ab9163 --- /dev/null +++ b/queue-3.7/drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch @@ -0,0 +1,187 @@ +From e7d841ca03b7ab668620045cd7b428eda9f41601 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Mon, 3 Dec 2012 11:36:30 +0000 +Subject: drm/i915: Close race between processing unpin task and queueing the flip + +From: Chris Wilson + +commit e7d841ca03b7ab668620045cd7b428eda9f41601 upstream. + +Before queuing the flip but crucially after attaching the unpin-work to +the crtc, we continue to setup the unpin-work. However, should the +hardware fire early, we see the connected unpin-work and queue the task. +The task then promptly runs and unpins the fb before we finish taking +the required references or even pinning it... Havoc. + +To close the race, we use the flip-pending atomic to indicate when the +flip is finally setup and enqueued. So during the flip-done processing, +we can check more accurately whether the flip was expected. + +v2: Add the appropriate mb() to ensure that the writes to the page-flip +worker are complete prior to marking it active and emitting the MI_FLIP. +On the read side, the mb should be enforced by the spinlocks. + +Signed-off-by: Chris Wilson +[danvet: Review the barriers a bit, we need a write barrier both +before and after updating ->pending. Similarly we need a read barrier +in the interrupt handler both before and after reading ->pending. With +well-ordered irqs only one barrier in each place should be required, +but since this patch explicitly sets out to combat spurious interrupts +with is staged activation of the unpin work we need to go full-bore on +the barriers, too. Discussed with Chris Wilson on irc and changes +acked by him.] +Signed-off-by: Daniel Vetter +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/i915_debugfs.c | 4 +-- + drivers/gpu/drm/i915/i915_irq.c | 4 ++- + drivers/gpu/drm/i915/intel_display.c | 39 ++++++++++++++++++++++++++++------- + drivers/gpu/drm/i915/intel_drv.h | 5 +++- + 4 files changed, 41 insertions(+), 11 deletions(-) + +--- a/drivers/gpu/drm/i915/i915_debugfs.c ++++ b/drivers/gpu/drm/i915/i915_debugfs.c +@@ -317,7 +317,7 @@ static int i915_gem_pageflip_info(struct + seq_printf(m, "No flip due on pipe %c (plane %c)\n", + pipe, plane); + } else { +- if (!work->pending) { ++ if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) { + seq_printf(m, "Flip queued on pipe %c (plane %c)\n", + pipe, plane); + } else { +@@ -328,7 +328,7 @@ static int i915_gem_pageflip_info(struct + seq_printf(m, "Stall check enabled, "); + else + seq_printf(m, "Stall check waiting for page flip ioctl, "); +- seq_printf(m, "%d prepares\n", work->pending); ++ seq_printf(m, "%d prepares\n", atomic_read(&work->pending)); + + if (work->old_fb_obj) { + struct drm_i915_gem_object *obj = work->old_fb_obj; +--- a/drivers/gpu/drm/i915/i915_irq.c ++++ b/drivers/gpu/drm/i915/i915_irq.c +@@ -1464,7 +1464,9 @@ static void i915_pageflip_stall_check(st + spin_lock_irqsave(&dev->event_lock, flags); + work = intel_crtc->unpin_work; + +- if (work == NULL || work->pending || !work->enable_stall_check) { ++ if (work == NULL || ++ atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE || ++ !work->enable_stall_check) { + /* Either the pending flip IRQ arrived, or we're too early. Don't check */ + spin_unlock_irqrestore(&dev->event_lock, flags); + return; +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -6215,11 +6215,18 @@ static void do_intel_finish_page_flip(st + + spin_lock_irqsave(&dev->event_lock, flags); + work = intel_crtc->unpin_work; +- if (work == NULL || !work->pending) { ++ ++ /* Ensure we don't miss a work->pending update ... */ ++ smp_rmb(); ++ ++ if (work == NULL || atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) { + spin_unlock_irqrestore(&dev->event_lock, flags); + return; + } + ++ /* and that the unpin work is consistent wrt ->pending. */ ++ smp_rmb(); ++ + intel_crtc->unpin_work = NULL; + + if (work->event) { +@@ -6272,16 +6279,25 @@ void intel_prepare_page_flip(struct drm_ + to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]); + unsigned long flags; + ++ /* NB: An MMIO update of the plane base pointer will also ++ * generate a page-flip completion irq, i.e. every modeset ++ * is also accompanied by a spurious intel_prepare_page_flip(). ++ */ + spin_lock_irqsave(&dev->event_lock, flags); +- if (intel_crtc->unpin_work) { +- if ((++intel_crtc->unpin_work->pending) > 1) +- DRM_ERROR("Prepared flip multiple times\n"); +- } else { +- DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n"); +- } ++ if (intel_crtc->unpin_work) ++ atomic_inc_not_zero(&intel_crtc->unpin_work->pending); + spin_unlock_irqrestore(&dev->event_lock, flags); + } + ++inline static void intel_mark_page_flip_active(struct intel_crtc *intel_crtc) ++{ ++ /* Ensure that the work item is consistent when activating it ... */ ++ smp_wmb(); ++ atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING); ++ /* and that it is marked active as soon as the irq could fire. */ ++ smp_wmb(); ++} ++ + static int intel_gen2_queue_flip(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, +@@ -6315,6 +6331,8 @@ static int intel_gen2_queue_flip(struct + intel_ring_emit(ring, fb->pitches[0]); + intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, 0); /* aux display base address, unused */ ++ ++ intel_mark_page_flip_active(intel_crtc); + intel_ring_advance(ring); + return 0; + +@@ -6355,6 +6373,7 @@ static int intel_gen3_queue_flip(struct + intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, MI_NOOP); + ++ intel_mark_page_flip_active(intel_crtc); + intel_ring_advance(ring); + return 0; + +@@ -6401,6 +6420,8 @@ static int intel_gen4_queue_flip(struct + pf = 0; + pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; + intel_ring_emit(ring, pf | pipesrc); ++ ++ intel_mark_page_flip_active(intel_crtc); + intel_ring_advance(ring); + return 0; + +@@ -6443,6 +6464,8 @@ static int intel_gen6_queue_flip(struct + pf = 0; + pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; + intel_ring_emit(ring, pf | pipesrc); ++ ++ intel_mark_page_flip_active(intel_crtc); + intel_ring_advance(ring); + return 0; + +@@ -6497,6 +6520,8 @@ static int intel_gen7_queue_flip(struct + intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); + intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, (MI_NOOP)); ++ ++ intel_mark_page_flip_active(intel_crtc); + intel_ring_advance(ring); + return 0; + +--- a/drivers/gpu/drm/i915/intel_drv.h ++++ b/drivers/gpu/drm/i915/intel_drv.h +@@ -384,7 +384,10 @@ struct intel_unpin_work { + struct drm_i915_gem_object *old_fb_obj; + struct drm_i915_gem_object *pending_flip_obj; + struct drm_pending_vblank_event *event; +- int pending; ++ atomic_t pending; ++#define INTEL_FLIP_INACTIVE 0 ++#define INTEL_FLIP_PENDING 1 ++#define INTEL_FLIP_COMPLETE 2 + bool enable_stall_check; + }; + diff --git a/queue-3.7/drm-i915-don-t-disable-disconnected-outputs.patch b/queue-3.7/drm-i915-don-t-disable-disconnected-outputs.patch new file mode 100644 index 00000000000..a7ab6638e04 --- /dev/null +++ b/queue-3.7/drm-i915-don-t-disable-disconnected-outputs.patch @@ -0,0 +1,65 @@ +From b0a2658acb5bf9ca86b4aab011b7106de3af0add Mon Sep 17 00:00:00 2001 +From: Daniel Vetter +Date: Tue, 18 Dec 2012 09:37:54 +0100 +Subject: drm/i915: don't disable disconnected outputs + +From: Daniel Vetter + +commit b0a2658acb5bf9ca86b4aab011b7106de3af0add upstream. + +This piece of neat lore has been ported painstakingly and bug-for-bug +compatible from the old crtc helper code. + +Imo it's utter nonsense. + +If you disconnected a cable and before you reconnect it, userspace (or +the kernel) does an set_crtc call, this will result in that connector +getting disabled. Which will result in a nice black screen when +plugging in the cable again. + +There's absolutely no reason the kernel does such policy enforcements +- if userspace tries to set up a mode on something disconnected we +might fail loudly (since the dp link training fails), but silently +adjusting the output configuration behind userspace's back is a recipe +for disaster. Specifically I think that this could explain some of our +MI_WAIT hangs around suspend, where userspace issues a scanline wait +on a disable pipe. This mechanisims here could explain how that pipe +got disabled without userspace noticing. + +Note that this fixes a NULL deref at BIOS takeover when the firmware +sets up a disconnected output in a clone configuration with a +connected output on the 2nd pipe: When doing the full modeset we don't +have a mode for the 2nd pipe and OOPS. On the first pipe this doesn't +matter, since at boot-up the fbdev helpers will set up the choosen +configuration on that on first. Since this is now the umptenth bug +around handling this imo brain-dead semantics correctly, I think it's +time to kill it and see whether there's any userspace out there which +relies on this. + +It also nicely demonstrates that we have a tiny window where DP +hotplug can still kill the driver. + +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=58396 +Tested-by: Peter Ujfalusi +Reviewed-by: Rodrigo Vivi +Reviewed-by: Jesse Barnes +Signed-off-by: Daniel Vetter +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/intel_display.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -7298,10 +7298,6 @@ intel_modeset_stage_output_state(struct + DRM_DEBUG_KMS("encoder changed, full mode switch\n"); + config->mode_changed = true; + } +- +- /* Disable all disconnected encoders. */ +- if (connector->base.status == connector_status_disconnected) +- connector->new_encoder = NULL; + } + /* connector->new_encoder is now updated for all connectors. */ + diff --git a/queue-3.7/drm-i915-fix-flags-in-dma-buf-exporting.patch b/queue-3.7/drm-i915-fix-flags-in-dma-buf-exporting.patch new file mode 100644 index 00000000000..8d65d64a948 --- /dev/null +++ b/queue-3.7/drm-i915-fix-flags-in-dma-buf-exporting.patch @@ -0,0 +1,31 @@ +From 5b42427fc38ecb9056c4e64deaff36d6d6ba1b67 Mon Sep 17 00:00:00 2001 +From: Dave Airlie +Date: Thu, 20 Dec 2012 10:51:09 +1000 +Subject: drm/i915: fix flags in dma buf exporting + +From: Dave Airlie + +commit 5b42427fc38ecb9056c4e64deaff36d6d6ba1b67 upstream. + +As pointed out by Seung-Woo Kim this should have been +passing flags like nouveau/radeon have. + +Signed-off-by: Dave Airlie +Signed-off-by: Daniel Vetter +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/i915_gem_dmabuf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c ++++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c +@@ -226,7 +226,7 @@ struct dma_buf *i915_gem_prime_export(st + { + struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); + +- return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, 0600); ++ return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, flags); + } + + static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj) diff --git a/queue-3.7/drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch b/queue-3.7/drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch new file mode 100644 index 00000000000..65367343ca7 --- /dev/null +++ b/queue-3.7/drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch @@ -0,0 +1,131 @@ +From b4a98e57fc27854b5938fc8b08b68e5e68b91e1f Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 1 Nov 2012 09:26:26 +0000 +Subject: drm/i915: Flush outstanding unpin tasks before pageflipping + +From: Chris Wilson + +commit b4a98e57fc27854b5938fc8b08b68e5e68b91e1f upstream. + +If we accumulate unpin tasks because we are pageflipping faster than the +system can schedule its workers, we can effectively create a +pin-leak. The solution taken here is to limit the number of unpin tasks +we have per-crtc and to flush those outstanding tasks if we accumulate +too many. This should prevent any jitter in the normal case, and also +prevent the hang if we should run too fast. + +Note: It is important that we switch from the system workqueue to our +own dev_priv->wq since all work items on that queue are guaranteed to +only need the dev->struct_mutex and not any modeset resources. For +otherwise if we have a work item ahead in the queue which needs the +modeset lock (like the output detect work used by both polling or +hpd), this work and so the unpin work will never execute since the +pageflip code already holds that lock. Unfortunately there's no +lockdep support for this scenario in the workqueue code. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=46991 +Reported-and-tested-by: Tvrtko Ursulin +Signed-off-by: Chris Wilson +[danvet: Added note about workqueu deadlock.] +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=56337 +Signed-off-by: Daniel Vetter +Tested-by: Daniel Gnoutcheff +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/intel_display.c | 22 ++++++++++++++++------ + drivers/gpu/drm/i915/intel_drv.h | 4 +++- + 2 files changed, 19 insertions(+), 7 deletions(-) + +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -6187,14 +6187,19 @@ static void intel_unpin_work_fn(struct w + { + struct intel_unpin_work *work = + container_of(__work, struct intel_unpin_work, work); ++ struct drm_device *dev = work->crtc->dev; + +- mutex_lock(&work->dev->struct_mutex); ++ mutex_lock(&dev->struct_mutex); + intel_unpin_fb_obj(work->old_fb_obj); + drm_gem_object_unreference(&work->pending_flip_obj->base); + drm_gem_object_unreference(&work->old_fb_obj->base); + +- intel_update_fbc(work->dev); +- mutex_unlock(&work->dev->struct_mutex); ++ intel_update_fbc(dev); ++ mutex_unlock(&dev->struct_mutex); ++ ++ BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0); ++ atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count); ++ + kfree(work); + } + +@@ -6249,9 +6254,9 @@ static void do_intel_finish_page_flip(st + + atomic_clear_mask(1 << intel_crtc->plane, + &obj->pending_flip.counter); +- + wake_up(&dev_priv->pending_flip_queue); +- schedule_work(&work->work); ++ ++ queue_work(dev_priv->wq, &work->work); + + trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); + } +@@ -6570,7 +6575,7 @@ static int intel_crtc_page_flip(struct d + return -ENOMEM; + + work->event = event; +- work->dev = crtc->dev; ++ work->crtc = crtc; + intel_fb = to_intel_framebuffer(crtc->fb); + work->old_fb_obj = intel_fb->obj; + INIT_WORK(&work->work, intel_unpin_work_fn); +@@ -6595,6 +6600,9 @@ static int intel_crtc_page_flip(struct d + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + ++ if (atomic_read(&intel_crtc->unpin_work_count) >= 2) ++ flush_workqueue(dev_priv->wq); ++ + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto cleanup; +@@ -6613,6 +6621,7 @@ static int intel_crtc_page_flip(struct d + * the flip occurs and the object is no longer visible. + */ + atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); ++ atomic_inc(&intel_crtc->unpin_work_count); + + ret = dev_priv->display.queue_flip(dev, crtc, fb, obj); + if (ret) +@@ -6627,6 +6636,7 @@ static int intel_crtc_page_flip(struct d + return 0; + + cleanup_pending: ++ atomic_dec(&intel_crtc->unpin_work_count); + atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); + drm_gem_object_unreference(&work->old_fb_obj->base); + drm_gem_object_unreference(&obj->base); +--- a/drivers/gpu/drm/i915/intel_drv.h ++++ b/drivers/gpu/drm/i915/intel_drv.h +@@ -198,6 +198,8 @@ struct intel_crtc { + struct intel_unpin_work *unpin_work; + int fdi_lanes; + ++ atomic_t unpin_work_count; ++ + /* Display surface base address adjustement for pageflips. Note that on + * gen4+ this only adjusts up to a tile, offsets within a tile are + * handled in the hw itself (with the TILEOFF register). */ +@@ -380,7 +382,7 @@ intel_get_crtc_for_plane(struct drm_devi + + struct intel_unpin_work { + struct work_struct work; +- struct drm_device *dev; ++ struct drm_crtc *crtc; + struct drm_i915_gem_object *old_fb_obj; + struct drm_i915_gem_object *pending_flip_obj; + struct drm_pending_vblank_event *event; diff --git a/queue-3.7/drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch b/queue-3.7/drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch new file mode 100644 index 00000000000..4d22253451d --- /dev/null +++ b/queue-3.7/drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch @@ -0,0 +1,42 @@ +From 93be8788e648817d62fda33e2998eb6ca6ebf3a3 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Wed, 2 Jan 2013 10:31:22 +0000 +Subject: drm/i915; Only increment the user-pin-count after successfully pinning the bo + +From: Chris Wilson + +commit 93be8788e648817d62fda33e2998eb6ca6ebf3a3 upstream. + +As along the error path we do not correct the user pin-count for the +failure, we may end up with userspace believing that it has a pinned +object at offset 0 (when interrupted by a signal for example). + +Signed-off-by: Chris Wilson +Signed-off-by: Daniel Vetter +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/i915_gem.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/i915/i915_gem.c ++++ b/drivers/gpu/drm/i915/i915_gem.c +@@ -3511,14 +3511,15 @@ i915_gem_pin_ioctl(struct drm_device *de + goto out; + } + +- obj->user_pin_count++; +- obj->pin_filp = file; +- if (obj->user_pin_count == 1) { ++ if (obj->user_pin_count == 0) { + ret = i915_gem_object_pin(obj, args->alignment, true, false); + if (ret) + goto out; + } + ++ obj->user_pin_count++; ++ obj->pin_filp = file; ++ + /* XXX - flush the CPU caches for pinned objects + * as the X server doesn't manage domains yet + */ diff --git a/queue-3.7/drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch b/queue-3.7/drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch new file mode 100644 index 00000000000..c5f482a96e7 --- /dev/null +++ b/queue-3.7/drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch @@ -0,0 +1,145 @@ +From 93927ca52a55c23e0a6a305e7e9082e8411ac9fa Mon Sep 17 00:00:00 2001 +From: Daniel Vetter +Date: Thu, 10 Jan 2013 18:03:00 +0100 +Subject: drm/i915: Revert shrinker changes from "Track unbound pages" + +From: Daniel Vetter + +commit 93927ca52a55c23e0a6a305e7e9082e8411ac9fa upstream. + +This partially reverts + +commit 6c085a728cf000ac1865d66f8c9b52935558b328 +Author: Chris Wilson +Date: Mon Aug 20 11:40:46 2012 +0200 + + drm/i915: Track unbound pages + +Closer inspection of that patch revealed a bunch of unrelated changes +in the shrinker: +- The shrinker count is now in pages instead of objects. +- For counting the shrinkable objects the old code only looked at the + inactive list, the new code looks at all bounds objects (including + pinned ones). That is obviously in addition to the new unbound list. +- The shrinker cound is no longer scaled with + sysctl_vfs_cache_pressure. Note though that with the default tuning + value of vfs_cache_pressue = 100 this doesn't affect the shrinker + behaviour. +- When actually shrinking objects, the old code first dropped + purgeable objects, then normal (inactive) objects. Only then did it, + in a last-ditch effort idle the gpu and evict everything. The new + code omits the intermediate step of evicting normal inactive + objects. + +Safe for the first change, which seems benign, and the shrinker count +scaling, which is a bit a different story, the endresult of all these +changes is that the shrinker is _much_ more likely to fall back to the +last-ditch resort of idling the gpu and evicting everything. The old +code could only do that if something else evicted lots of objects +meanwhile (since without any other changes the nr_to_scan will be +smaller than the object count). + +Reverting the vfs_cache_pressure behaviour itself is a bit bogus: Only +dentry/inode object caches should scale their shrinker counts with +vfs_cache_pressure. Originally I've had that change reverted, too. But +Chris Wilson insisted that it's too bogus and shouldn't again see the +light of day. + +Hence revert all these other changes and restore the old shrinker +behaviour, with the minor adjustment that we now first scan the +unbound list, then the inactive list for each object category +(purgeable or normal). + +A similar patch has been tested by a few people affected by the gen4/5 +hangs which started to appear in 3.7, which some people bisected to +the "drm/i915: Track unbound pages" commit. But just disabling the +unbound logic alone didn't change things at all. + +Note that this patch doesn't fix the referenced bugs, it only hides +the underlying bug(s) well enough to restore pre-3.7 behaviour. The +key to achieve that is to massively reduce the likelyhood of going +into a full gpu stall and evicting everything. + +v2: Reword commit message a bit, taking Chris Wilson's comment into +account. + +v3: On Chris Wilson's insistency, do not reinstate the rather bogus +vfs_cache_pressure change. + +Tested-by: Greg KH +Tested-by: Dave Kleikamp +References: https://bugs.freedesktop.org/show_bug.cgi?id=55984 +References: https://bugs.freedesktop.org/show_bug.cgi?id=57122 +References: https://bugs.freedesktop.org/show_bug.cgi?id=56916 +References: https://bugs.freedesktop.org/show_bug.cgi?id=57136 +Cc: Chris Wilson +Acked-by: Chris Wilson +Signed-off-by: Daniel Vetter +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/i915_gem.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/i915/i915_gem.c ++++ b/drivers/gpu/drm/i915/i915_gem.c +@@ -1718,7 +1718,8 @@ i915_gem_object_put_pages(struct drm_i91 + } + + static long +-i915_gem_purge(struct drm_i915_private *dev_priv, long target) ++__i915_gem_shrink(struct drm_i915_private *dev_priv, long target, ++ bool purgeable_only) + { + struct drm_i915_gem_object *obj, *next; + long count = 0; +@@ -1726,7 +1727,7 @@ i915_gem_purge(struct drm_i915_private * + list_for_each_entry_safe(obj, next, + &dev_priv->mm.unbound_list, + gtt_list) { +- if (i915_gem_object_is_purgeable(obj) && ++ if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && + i915_gem_object_put_pages(obj) == 0) { + count += obj->base.size >> PAGE_SHIFT; + if (count >= target) +@@ -1737,7 +1738,7 @@ i915_gem_purge(struct drm_i915_private * + list_for_each_entry_safe(obj, next, + &dev_priv->mm.inactive_list, + mm_list) { +- if (i915_gem_object_is_purgeable(obj) && ++ if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && + i915_gem_object_unbind(obj) == 0 && + i915_gem_object_put_pages(obj) == 0) { + count += obj->base.size >> PAGE_SHIFT; +@@ -1749,6 +1750,12 @@ i915_gem_purge(struct drm_i915_private * + return count; + } + ++static long ++i915_gem_purge(struct drm_i915_private *dev_priv, long target) ++{ ++ return __i915_gem_shrink(dev_priv, target, true); ++} ++ + static void + i915_gem_shrink_all(struct drm_i915_private *dev_priv) + { +@@ -4426,6 +4433,9 @@ i915_gem_inactive_shrink(struct shrinker + if (nr_to_scan) { + nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan); + if (nr_to_scan > 0) ++ nr_to_scan -= __i915_gem_shrink(dev_priv, nr_to_scan, ++ false); ++ if (nr_to_scan > 0) + i915_gem_shrink_all(dev_priv); + } + +@@ -4433,7 +4443,7 @@ i915_gem_inactive_shrink(struct shrinker + list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) + if (obj->pages_pin_count == 0) + cnt += obj->base.size >> PAGE_SHIFT; +- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) ++ list_for_each_entry(obj, &dev_priv->mm.inactive_list, gtt_list) + if (obj->pin_count == 0 && obj->pages_pin_count == 0) + cnt += obj->base.size >> PAGE_SHIFT; + diff --git a/queue-3.7/drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch b/queue-3.7/drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch new file mode 100644 index 00000000000..40086f7c500 --- /dev/null +++ b/queue-3.7/drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch @@ -0,0 +1,162 @@ +From 901593f2bf221659a605bdc1dcb11376ea934163 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Wed, 19 Dec 2012 16:51:06 +0000 +Subject: drm: Only evict the blocks required to create the requested hole + +From: Chris Wilson + +commit 901593f2bf221659a605bdc1dcb11376ea934163 upstream. + +Avoid clobbering adjacent blocks if they happen to expire earlier and +amalgamate together to form the requested hole. + +In passing this fixes a regression from +commit ea7b1dd44867e9cd6bac67e7c9fc3f128b5b255c +Author: Daniel Vetter +Date: Fri Feb 18 17:59:12 2011 +0100 + + drm: mm: track free areas implicitly + +which swaps the end address for size (with a potential overflow) and +effectively causes the eviction code to clobber almost all earlier +buffers above the evictee. + +v2: Check the original hole not the adjusted as the coloring may confuse +us when later searching for the overlapping nodes. Also make sure that +we do apply the range restriction and color adjustment in the same +order for both scanning, searching and insertion. + +v3: Send the version that was actually tested. + +Note that this seems to be ducttape of decent quality ot paper over +some of our unbind related gpu hangs reported since 3.7. It is not +fully effective though, and certainly doesn't fix the underlying bug. + +Signed-off-by: Chris Wilson +Cc: Daniel Vetter +[danvet: Added note plus bugzilla link and tested-by.] +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55984 +Tested-by: Norbert Preining +Acked-by: Dave Airlie +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/drm_mm.c | 45 +++++++++++++++++---------------------------- + include/drm/drm_mm.h | 2 +- + 2 files changed, 18 insertions(+), 29 deletions(-) + +--- a/drivers/gpu/drm/drm_mm.c ++++ b/drivers/gpu/drm/drm_mm.c +@@ -213,11 +213,13 @@ static void drm_mm_insert_helper_range(s + + BUG_ON(!hole_node->hole_follows || node->allocated); + +- if (mm->color_adjust) +- mm->color_adjust(hole_node, color, &adj_start, &adj_end); +- + if (adj_start < start) + adj_start = start; ++ if (adj_end > end) ++ adj_end = end; ++ ++ if (mm->color_adjust) ++ mm->color_adjust(hole_node, color, &adj_start, &adj_end); + + if (alignment) { + unsigned tmp = adj_start % alignment; +@@ -489,7 +491,7 @@ void drm_mm_init_scan(struct drm_mm *mm, + mm->scan_size = size; + mm->scanned_blocks = 0; + mm->scan_hit_start = 0; +- mm->scan_hit_size = 0; ++ mm->scan_hit_end = 0; + mm->scan_check_range = 0; + mm->prev_scanned_node = NULL; + } +@@ -516,7 +518,7 @@ void drm_mm_init_scan_with_range(struct + mm->scan_size = size; + mm->scanned_blocks = 0; + mm->scan_hit_start = 0; +- mm->scan_hit_size = 0; ++ mm->scan_hit_end = 0; + mm->scan_start = start; + mm->scan_end = end; + mm->scan_check_range = 1; +@@ -535,8 +537,7 @@ int drm_mm_scan_add_block(struct drm_mm_ + struct drm_mm *mm = node->mm; + struct drm_mm_node *prev_node; + unsigned long hole_start, hole_end; +- unsigned long adj_start; +- unsigned long adj_end; ++ unsigned long adj_start, adj_end; + + mm->scanned_blocks++; + +@@ -553,14 +554,8 @@ int drm_mm_scan_add_block(struct drm_mm_ + node->node_list.next = &mm->prev_scanned_node->node_list; + mm->prev_scanned_node = node; + +- hole_start = drm_mm_hole_node_start(prev_node); +- hole_end = drm_mm_hole_node_end(prev_node); +- +- adj_start = hole_start; +- adj_end = hole_end; +- +- if (mm->color_adjust) +- mm->color_adjust(prev_node, mm->scan_color, &adj_start, &adj_end); ++ adj_start = hole_start = drm_mm_hole_node_start(prev_node); ++ adj_end = hole_end = drm_mm_hole_node_end(prev_node); + + if (mm->scan_check_range) { + if (adj_start < mm->scan_start) +@@ -569,11 +564,14 @@ int drm_mm_scan_add_block(struct drm_mm_ + adj_end = mm->scan_end; + } + ++ if (mm->color_adjust) ++ mm->color_adjust(prev_node, mm->scan_color, ++ &adj_start, &adj_end); ++ + if (check_free_hole(adj_start, adj_end, + mm->scan_size, mm->scan_alignment)) { + mm->scan_hit_start = hole_start; +- mm->scan_hit_size = hole_end; +- ++ mm->scan_hit_end = hole_end; + return 1; + } + +@@ -609,19 +607,10 @@ int drm_mm_scan_remove_block(struct drm_ + node_list); + + prev_node->hole_follows = node->scanned_preceeds_hole; +- INIT_LIST_HEAD(&node->node_list); + list_add(&node->node_list, &prev_node->node_list); + +- /* Only need to check for containement because start&size for the +- * complete resulting free block (not just the desired part) is +- * stored. */ +- if (node->start >= mm->scan_hit_start && +- node->start + node->size +- <= mm->scan_hit_start + mm->scan_hit_size) { +- return 1; +- } +- +- return 0; ++ return (drm_mm_hole_node_end(node) > mm->scan_hit_start && ++ node->start < mm->scan_hit_end); + } + EXPORT_SYMBOL(drm_mm_scan_remove_block); + +--- a/include/drm/drm_mm.h ++++ b/include/drm/drm_mm.h +@@ -70,7 +70,7 @@ struct drm_mm { + unsigned long scan_color; + unsigned long scan_size; + unsigned long scan_hit_start; +- unsigned scan_hit_size; ++ unsigned long scan_hit_end; + unsigned scanned_blocks; + unsigned long scan_start; + unsigned long scan_end; diff --git a/queue-3.7/drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch b/queue-3.7/drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch new file mode 100644 index 00000000000..e3bea46e430 --- /dev/null +++ b/queue-3.7/drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch @@ -0,0 +1,100 @@ +From be8a42ae60addd8b6092535c11b42d099d6470ec Mon Sep 17 00:00:00 2001 +From: Seung-Woo Kim +Date: Thu, 27 Sep 2012 15:30:06 +0900 +Subject: drm/prime: drop reference on imported dma-buf come from gem + +From: Seung-Woo Kim + +commit be8a42ae60addd8b6092535c11b42d099d6470ec upstream. + +Increasing ref counts of both dma-buf and gem for imported dma-buf come from gem +makes memory leak. release function of dma-buf cannot be called because f_count +of dma-buf increased by importing gem and gem ref count cannot be decrease +because of exported dma-buf. + +So I add dma_buf_put() for imported gem come from its own gem into each drivers +having prime_import and prime_export capabilities. With this, only gem ref +count is increased if importing gem exported from gem of same driver. + +Signed-off-by: Seung-Woo Kim +Signed-off-by: Kyungmin.park +Cc: Inki Dae +Cc: Daniel Vetter +Cc: Rob Clark +Cc: Alex Deucher +Signed-off-by: Dave Airlie +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | 5 +++++ + drivers/gpu/drm/i915/i915_gem_dmabuf.c | 5 +++++ + drivers/gpu/drm/nouveau/nouveau_prime.c | 1 + + drivers/gpu/drm/radeon/radeon_prime.c | 1 + + drivers/staging/omapdrm/omap_gem_dmabuf.c | 5 +++++ + 5 files changed, 17 insertions(+) + +--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +@@ -210,7 +210,12 @@ struct drm_gem_object *exynos_dmabuf_pri + + /* is it from our device? */ + if (obj->dev == drm_dev) { ++ /* ++ * Importing dmabuf exported from out own gem increases ++ * refcount on gem itself instead of f_count of dmabuf. ++ */ + drm_gem_object_reference(obj); ++ dma_buf_put(dma_buf); + return obj; + } + } +--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c ++++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c +@@ -266,7 +266,12 @@ struct drm_gem_object *i915_gem_prime_im + obj = dma_buf->priv; + /* is it from our device? */ + if (obj->base.dev == dev) { ++ /* ++ * Importing dmabuf exported from out own gem increases ++ * refcount on gem itself instead of f_count of dmabuf. ++ */ + drm_gem_object_reference(&obj->base); ++ dma_buf_put(dma_buf); + return &obj->base; + } + } +--- a/drivers/gpu/drm/nouveau/nouveau_prime.c ++++ b/drivers/gpu/drm/nouveau/nouveau_prime.c +@@ -197,6 +197,7 @@ struct drm_gem_object *nouveau_gem_prime + if (nvbo->gem) { + if (nvbo->gem->dev == dev) { + drm_gem_object_reference(nvbo->gem); ++ dma_buf_put(dma_buf); + return nvbo->gem; + } + } +--- a/drivers/gpu/drm/radeon/radeon_prime.c ++++ b/drivers/gpu/drm/radeon/radeon_prime.c +@@ -194,6 +194,7 @@ struct drm_gem_object *radeon_gem_prime_ + bo = dma_buf->priv; + if (bo->gem_base.dev == dev) { + drm_gem_object_reference(&bo->gem_base); ++ dma_buf_put(dma_buf); + return &bo->gem_base; + } + } +--- a/drivers/staging/omapdrm/omap_gem_dmabuf.c ++++ b/drivers/staging/omapdrm/omap_gem_dmabuf.c +@@ -207,7 +207,12 @@ struct drm_gem_object * omap_gem_prime_i + obj = buffer->priv; + /* is it from our device? */ + if (obj->dev == dev) { ++ /* ++ * Importing dmabuf exported from out own gem increases ++ * refcount on gem itself instead of f_count of dmabuf. ++ */ + drm_gem_object_reference(obj); ++ dma_buf_put(buffer); + return obj; + } + } diff --git a/queue-3.7/mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch b/queue-3.7/mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch new file mode 100644 index 00000000000..e24f8e07bda --- /dev/null +++ b/queue-3.7/mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch @@ -0,0 +1,355 @@ +From 8fb74b9fb2b182d54beee592350d9ea1f325917a Mon Sep 17 00:00:00 2001 +From: Mel Gorman +Date: Fri, 11 Jan 2013 14:32:16 -0800 +Subject: mm: compaction: partially revert capture of suitable high-order page + +From: Mel Gorman + +commit 8fb74b9fb2b182d54beee592350d9ea1f325917a upstream. + +Eric Wong reported on 3.7 and 3.8-rc2 that ppoll() got stuck when +waiting for POLLIN on a local TCP socket. It was easier to trigger if +there was disk IO and dirty pages at the same time and he bisected it to +commit 1fb3f8ca0e92 ("mm: compaction: capture a suitable high-order page +immediately when it is made available"). + +The intention of that patch was to improve high-order allocations under +memory pressure after changes made to reclaim in 3.6 drastically hurt +THP allocations but the approach was flawed. For Eric, the problem was +that page->pfmemalloc was not being cleared for captured pages leading +to a poor interaction with swap-over-NFS support causing the packets to +be dropped. However, I identified a few more problems with the patch +including the fact that it can increase contention on zone->lock in some +cases which could result in async direct compaction being aborted early. + +In retrospect the capture patch took the wrong approach. What it should +have done is mark the pageblock being migrated as MIGRATE_ISOLATE if it +was allocating for THP and avoided races that way. While the patch was +showing to improve allocation success rates at the time, the benefit is +marginal given the relative complexity and it should be revisited from +scratch in the context of the other reclaim-related changes that have +taken place since the patch was first written and tested. This patch +partially reverts commit 1fb3f8ca0e92 ("mm: compaction: capture a +suitable high-order page immediately when it is made available"). + +Reported-and-tested-by: Eric Wong +Tested-by: Eric Dumazet +Signed-off-by: Mel Gorman +Cc: David Miller +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/compaction.h | 4 - + include/linux/mm.h | 1 + mm/compaction.c | 92 ++++++--------------------------------------- + mm/internal.h | 1 + mm/page_alloc.c | 35 +++-------------- + 5 files changed, 23 insertions(+), 110 deletions(-) + +--- a/include/linux/compaction.h ++++ b/include/linux/compaction.h +@@ -22,7 +22,7 @@ extern int sysctl_extfrag_handler(struct + extern int fragmentation_index(struct zone *zone, unsigned int order); + extern unsigned long try_to_compact_pages(struct zonelist *zonelist, + int order, gfp_t gfp_mask, nodemask_t *mask, +- bool sync, bool *contended, struct page **page); ++ bool sync, bool *contended); + extern int compact_pgdat(pg_data_t *pgdat, int order); + extern void reset_isolation_suitable(pg_data_t *pgdat); + extern unsigned long compaction_suitable(struct zone *zone, int order); +@@ -75,7 +75,7 @@ static inline bool compaction_restarting + #else + static inline unsigned long try_to_compact_pages(struct zonelist *zonelist, + int order, gfp_t gfp_mask, nodemask_t *nodemask, +- bool sync, bool *contended, struct page **page) ++ bool sync, bool *contended) + { + return COMPACT_CONTINUE; + } +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -455,7 +455,6 @@ void put_pages_list(struct list_head *pa + + void split_page(struct page *page, unsigned int order); + int split_free_page(struct page *page); +-int capture_free_page(struct page *page, int alloc_order, int migratetype); + + /* + * Compound pages have a destructor function. Provide a +--- a/mm/compaction.c ++++ b/mm/compaction.c +@@ -214,60 +214,6 @@ static bool suitable_migration_target(st + return false; + } + +-static void compact_capture_page(struct compact_control *cc) +-{ +- unsigned long flags; +- int mtype, mtype_low, mtype_high; +- +- if (!cc->page || *cc->page) +- return; +- +- /* +- * For MIGRATE_MOVABLE allocations we capture a suitable page ASAP +- * regardless of the migratetype of the freelist is is captured from. +- * This is fine because the order for a high-order MIGRATE_MOVABLE +- * allocation is typically at least a pageblock size and overall +- * fragmentation is not impaired. Other allocation types must +- * capture pages from their own migratelist because otherwise they +- * could pollute other pageblocks like MIGRATE_MOVABLE with +- * difficult to move pages and making fragmentation worse overall. +- */ +- if (cc->migratetype == MIGRATE_MOVABLE) { +- mtype_low = 0; +- mtype_high = MIGRATE_PCPTYPES; +- } else { +- mtype_low = cc->migratetype; +- mtype_high = cc->migratetype + 1; +- } +- +- /* Speculatively examine the free lists without zone lock */ +- for (mtype = mtype_low; mtype < mtype_high; mtype++) { +- int order; +- for (order = cc->order; order < MAX_ORDER; order++) { +- struct page *page; +- struct free_area *area; +- area = &(cc->zone->free_area[order]); +- if (list_empty(&area->free_list[mtype])) +- continue; +- +- /* Take the lock and attempt capture of the page */ +- if (!compact_trylock_irqsave(&cc->zone->lock, &flags, cc)) +- return; +- if (!list_empty(&area->free_list[mtype])) { +- page = list_entry(area->free_list[mtype].next, +- struct page, lru); +- if (capture_free_page(page, cc->order, mtype)) { +- spin_unlock_irqrestore(&cc->zone->lock, +- flags); +- *cc->page = page; +- return; +- } +- } +- spin_unlock_irqrestore(&cc->zone->lock, flags); +- } +- } +-} +- + /* + * Isolate free pages onto a private freelist. Caller must hold zone->lock. + * If @strict is true, will abort returning 0 on any invalid PFNs or non-free +@@ -831,6 +777,7 @@ static isolate_migrate_t isolate_migrate + static int compact_finished(struct zone *zone, + struct compact_control *cc) + { ++ unsigned int order; + unsigned long watermark; + + if (fatal_signal_pending(current)) +@@ -865,22 +812,16 @@ static int compact_finished(struct zone + return COMPACT_CONTINUE; + + /* Direct compactor: Is a suitable page free? */ +- if (cc->page) { +- /* Was a suitable page captured? */ +- if (*cc->page) ++ for (order = cc->order; order < MAX_ORDER; order++) { ++ struct free_area *area = &zone->free_area[order]; ++ ++ /* Job done if page is free of the right migratetype */ ++ if (!list_empty(&area->free_list[cc->migratetype])) ++ return COMPACT_PARTIAL; ++ ++ /* Job done if allocation would set block type */ ++ if (cc->order >= pageblock_order && area->nr_free) + return COMPACT_PARTIAL; +- } else { +- unsigned int order; +- for (order = cc->order; order < MAX_ORDER; order++) { +- struct free_area *area = &zone->free_area[cc->order]; +- /* Job done if page is free of the right migratetype */ +- if (!list_empty(&area->free_list[cc->migratetype])) +- return COMPACT_PARTIAL; +- +- /* Job done if allocation would set block type */ +- if (cc->order >= pageblock_order && area->nr_free) +- return COMPACT_PARTIAL; +- } + } + + return COMPACT_CONTINUE; +@@ -1018,9 +959,6 @@ static int compact_zone(struct zone *zon + goto out; + } + } +- +- /* Capture a page now if it is a suitable size */ +- compact_capture_page(cc); + } + + out: +@@ -1033,8 +971,7 @@ out: + + static unsigned long compact_zone_order(struct zone *zone, + int order, gfp_t gfp_mask, +- bool sync, bool *contended, +- struct page **page) ++ bool sync, bool *contended) + { + unsigned long ret; + struct compact_control cc = { +@@ -1044,7 +981,6 @@ static unsigned long compact_zone_order( + .migratetype = allocflags_to_migratetype(gfp_mask), + .zone = zone, + .sync = sync, +- .page = page, + }; + INIT_LIST_HEAD(&cc.freepages); + INIT_LIST_HEAD(&cc.migratepages); +@@ -1074,7 +1010,7 @@ int sysctl_extfrag_threshold = 500; + */ + unsigned long try_to_compact_pages(struct zonelist *zonelist, + int order, gfp_t gfp_mask, nodemask_t *nodemask, +- bool sync, bool *contended, struct page **page) ++ bool sync, bool *contended) + { + enum zone_type high_zoneidx = gfp_zone(gfp_mask); + int may_enter_fs = gfp_mask & __GFP_FS; +@@ -1100,7 +1036,7 @@ unsigned long try_to_compact_pages(struc + int status; + + status = compact_zone_order(zone, order, gfp_mask, sync, +- contended, page); ++ contended); + rc = max(status, rc); + + /* If a normal allocation would succeed, stop compacting */ +@@ -1156,7 +1092,6 @@ int compact_pgdat(pg_data_t *pgdat, int + struct compact_control cc = { + .order = order, + .sync = false, +- .page = NULL, + }; + + return __compact_pgdat(pgdat, &cc); +@@ -1167,7 +1102,6 @@ static int compact_node(int nid) + struct compact_control cc = { + .order = -1, + .sync = true, +- .page = NULL, + }; + + return __compact_pgdat(NODE_DATA(nid), &cc); +--- a/mm/internal.h ++++ b/mm/internal.h +@@ -130,7 +130,6 @@ struct compact_control { + int migratetype; /* MOVABLE, RECLAIMABLE etc */ + struct zone *zone; + bool contended; /* True if a lock was contended */ +- struct page **page; /* Page captured of requested size */ + }; + + unsigned long +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1376,14 +1376,8 @@ void split_page(struct page *page, unsig + set_page_refcounted(page + i); + } + +-/* +- * Similar to the split_page family of functions except that the page +- * required at the given order and being isolated now to prevent races +- * with parallel allocators +- */ +-int capture_free_page(struct page *page, int alloc_order, int migratetype) ++static int __isolate_free_page(struct page *page, unsigned int order) + { +- unsigned int order; + unsigned long watermark; + struct zone *zone; + int mt; +@@ -1391,7 +1385,6 @@ int capture_free_page(struct page *page, + BUG_ON(!PageBuddy(page)); + + zone = page_zone(page); +- order = page_order(page); + + /* Obey watermarks as if the page was being allocated */ + watermark = low_wmark_pages(zone) + (1 << order); +@@ -1405,13 +1398,9 @@ int capture_free_page(struct page *page, + + mt = get_pageblock_migratetype(page); + if (unlikely(mt != MIGRATE_ISOLATE)) +- __mod_zone_freepage_state(zone, -(1UL << alloc_order), mt); +- +- if (alloc_order != order) +- expand(zone, page, alloc_order, order, +- &zone->free_area[order], migratetype); ++ __mod_zone_freepage_state(zone, -(1UL << order), mt); + +- /* Set the pageblock if the captured page is at least a pageblock */ ++ /* Set the pageblock if the isolated page is at least a pageblock */ + if (order >= pageblock_order - 1) { + struct page *endpage = page + (1 << order) - 1; + for (; page < endpage; page += pageblock_nr_pages) { +@@ -1422,7 +1411,7 @@ int capture_free_page(struct page *page, + } + } + +- return 1UL << alloc_order; ++ return 1UL << order; + } + + /* +@@ -1440,10 +1429,9 @@ int split_free_page(struct page *page) + unsigned int order; + int nr_pages; + +- BUG_ON(!PageBuddy(page)); + order = page_order(page); + +- nr_pages = capture_free_page(page, order, 0); ++ nr_pages = __isolate_free_page(page, order); + if (!nr_pages) + return 0; + +@@ -2148,8 +2136,6 @@ __alloc_pages_direct_compact(gfp_t gfp_m + bool *contended_compaction, bool *deferred_compaction, + unsigned long *did_some_progress) + { +- struct page *page = NULL; +- + if (!order) + return NULL; + +@@ -2161,16 +2147,12 @@ __alloc_pages_direct_compact(gfp_t gfp_m + current->flags |= PF_MEMALLOC; + *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask, + nodemask, sync_migration, +- contended_compaction, &page); ++ contended_compaction); + current->flags &= ~PF_MEMALLOC; + +- /* If compaction captured a page, prep and use it */ +- if (page) { +- prep_new_page(page, order, gfp_mask); +- goto got_page; +- } +- + if (*did_some_progress != COMPACT_SKIPPED) { ++ struct page *page; ++ + /* Page migration frees to the PCP lists but we want merging */ + drain_pages(get_cpu()); + put_cpu(); +@@ -2180,7 +2162,6 @@ __alloc_pages_direct_compact(gfp_t gfp_m + alloc_flags & ~ALLOC_NO_WATERMARKS, + preferred_zone, migratetype); + if (page) { +-got_page: + preferred_zone->compact_blockskip_flush = false; + preferred_zone->compact_considered = 0; + preferred_zone->compact_defer_shift = 0; diff --git a/queue-3.7/series b/queue-3.7/series index 062d2178058..1ad6a1c811b 100644 --- a/queue-3.7/series +++ b/queue-3.7/series @@ -77,3 +77,12 @@ drm-radeon-add-connector-table-for-mac-g4-silver.patch drm-radeon-properly-handle-ddc-probe-for-dp-bridges.patch drm-nouveau-fix-init-with-agpgart-uninorth.patch drm-i915-make-the-panel-fitter-work-on-pipes-b-and-c-on-ivb.patch +mm-compaction-partially-revert-capture-of-suitable-high-order-page.patch +drm-i915-close-race-between-processing-unpin-task-and-queueing-the-flip.patch +drm-i915-flush-outstanding-unpin-tasks-before-pageflipping.patch +drm-i915-don-t-disable-disconnected-outputs.patch +drm-i915-fix-flags-in-dma-buf-exporting.patch +drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch +drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch +drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch +drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch