Skip to content

Commit bcad588

Browse files
ashutoshxrodrigovivi
authored andcommitted
drm/i915/perf: Do not clear pollin for small user read buffers
It is wrong to block the user thread in the next poll when OA data is already available which could not fit in the user buffer provided in the previous read. In several cases the exact user buffer size is not known. Blocking user space in poll can lead to data loss when the buffer size used is smaller than the available data. This change fixes this issue and allows user space to read all OA data even when using a buffer size smaller than the available data using multiple non-blocking reads rather than staying blocked in poll till the next timer interrupt. v2: Fix ret value for blocking reads (Umesh) v3: Mistake during patch send (Ashutosh) v4: Remove -EAGAIN from comment (Umesh) v5: Improve condition for clearing pollin and return (Lionel) v6: Improve blocking read loop and other cleanups (Lionel) v7: Added Cc stable Testcase: igt/perf/polling-small-buf Reviewed-by: Lionel Landwerlin <[email protected]> Signed-off-by: Ashutosh Dixit <[email protected]> Cc: Umesh Nerlige Ramappa <[email protected]> Cc: <[email protected]> Signed-off-by: Chris Wilson <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] (cherry-picked from commit 6352219) Signed-off-by: Rodrigo Vivi <[email protected]>
1 parent 8f3d9f3 commit bcad588

File tree

1 file changed

+11
-54
lines changed

1 file changed

+11
-54
lines changed

drivers/gpu/drm/i915/i915_perf.c

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,49 +2940,6 @@ void i915_oa_init_reg_state(const struct intel_context *ce,
29402940
gen8_update_reg_state_unlocked(ce, stream);
29412941
}
29422942

2943-
/**
2944-
* i915_perf_read_locked - &i915_perf_stream_ops->read with error normalisation
2945-
* @stream: An i915 perf stream
2946-
* @file: An i915 perf stream file
2947-
* @buf: destination buffer given by userspace
2948-
* @count: the number of bytes userspace wants to read
2949-
* @ppos: (inout) file seek position (unused)
2950-
*
2951-
* Besides wrapping &i915_perf_stream_ops->read this provides a common place to
2952-
* ensure that if we've successfully copied any data then reporting that takes
2953-
* precedence over any internal error status, so the data isn't lost.
2954-
*
2955-
* For example ret will be -ENOSPC whenever there is more buffered data than
2956-
* can be copied to userspace, but that's only interesting if we weren't able
2957-
* to copy some data because it implies the userspace buffer is too small to
2958-
* receive a single record (and we never split records).
2959-
*
2960-
* Another case with ret == -EFAULT is more of a grey area since it would seem
2961-
* like bad form for userspace to ask us to overrun its buffer, but the user
2962-
* knows best:
2963-
*
2964-
* http://yarchive.net/comp/linux/partial_reads_writes.html
2965-
*
2966-
* Returns: The number of bytes copied or a negative error code on failure.
2967-
*/
2968-
static ssize_t i915_perf_read_locked(struct i915_perf_stream *stream,
2969-
struct file *file,
2970-
char __user *buf,
2971-
size_t count,
2972-
loff_t *ppos)
2973-
{
2974-
/* Note we keep the offset (aka bytes read) separate from any
2975-
* error status so that the final check for whether we return
2976-
* the bytes read with a higher precedence than any error (see
2977-
* comment below) doesn't need to be handled/duplicated in
2978-
* stream->ops->read() implementations.
2979-
*/
2980-
size_t offset = 0;
2981-
int ret = stream->ops->read(stream, buf, count, &offset);
2982-
2983-
return offset ?: (ret ?: -EAGAIN);
2984-
}
2985-
29862943
/**
29872944
* i915_perf_read - handles read() FOP for i915 perf stream FDs
29882945
* @file: An i915 perf stream file
@@ -3008,7 +2965,8 @@ static ssize_t i915_perf_read(struct file *file,
30082965
{
30092966
struct i915_perf_stream *stream = file->private_data;
30102967
struct i915_perf *perf = stream->perf;
3011-
ssize_t ret;
2968+
size_t offset = 0;
2969+
int ret;
30122970

30132971
/* To ensure it's handled consistently we simply treat all reads of a
30142972
* disabled stream as an error. In particular it might otherwise lead
@@ -3031,13 +2989,12 @@ static ssize_t i915_perf_read(struct file *file,
30312989
return ret;
30322990

30332991
mutex_lock(&perf->lock);
3034-
ret = i915_perf_read_locked(stream, file,
3035-
buf, count, ppos);
2992+
ret = stream->ops->read(stream, buf, count, &offset);
30362993
mutex_unlock(&perf->lock);
3037-
} while (ret == -EAGAIN);
2994+
} while (!offset && !ret);
30382995
} else {
30392996
mutex_lock(&perf->lock);
3040-
ret = i915_perf_read_locked(stream, file, buf, count, ppos);
2997+
ret = stream->ops->read(stream, buf, count, &offset);
30412998
mutex_unlock(&perf->lock);
30422999
}
30433000

@@ -3048,15 +3005,15 @@ static ssize_t i915_perf_read(struct file *file,
30483005
* and read() returning -EAGAIN. Clearing the oa.pollin state here
30493006
* effectively ensures we back off until the next hrtimer callback
30503007
* before reporting another EPOLLIN event.
3008+
* The exception to this is if ops->read() returned -ENOSPC which means
3009+
* that more OA data is available than could fit in the user provided
3010+
* buffer. In this case we want the next poll() call to not block.
30513011
*/
3052-
if (ret >= 0 || ret == -EAGAIN) {
3053-
/* Maybe make ->pollin per-stream state if we support multiple
3054-
* concurrent streams in the future.
3055-
*/
3012+
if (ret != -ENOSPC)
30563013
stream->pollin = false;
3057-
}
30583014

3059-
return ret;
3015+
/* Possible values for ret are 0, -EFAULT, -ENOSPC, -EIO, ... */
3016+
return offset ?: (ret ?: -EAGAIN);
30603017
}
30613018

30623019
static enum hrtimer_restart oa_poll_check_timer_cb(struct hrtimer *hrtimer)

0 commit comments

Comments
 (0)