|
@@ -77,9 +77,36 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
|
|
|
return dmabuf->ops->mmap(dmabuf, vma);
|
|
|
}
|
|
|
|
|
|
+static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
|
|
|
+{
|
|
|
+ struct dma_buf *dmabuf;
|
|
|
+ loff_t base;
|
|
|
+
|
|
|
+ if (!is_dma_buf_file(file))
|
|
|
+ return -EBADF;
|
|
|
+
|
|
|
+ dmabuf = file->private_data;
|
|
|
+
|
|
|
+ /* only support discovering the end of the buffer,
|
|
|
+ but also allow SEEK_SET to maintain the idiomatic
|
|
|
+ SEEK_END(0), SEEK_CUR(0) pattern */
|
|
|
+ if (whence == SEEK_END)
|
|
|
+ base = dmabuf->size;
|
|
|
+ else if (whence == SEEK_SET)
|
|
|
+ base = 0;
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (offset != 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return base + offset;
|
|
|
+}
|
|
|
+
|
|
|
static const struct file_operations dma_buf_fops = {
|
|
|
.release = dma_buf_release,
|
|
|
.mmap = dma_buf_mmap_internal,
|
|
|
+ .llseek = dma_buf_llseek,
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -137,6 +164,8 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
|
|
|
kfree(dmabuf);
|
|
|
return ERR_CAST(file);
|
|
|
}
|
|
|
+
|
|
|
+ file->f_mode |= FMODE_LSEEK;
|
|
|
dmabuf->file = file;
|
|
|
|
|
|
mutex_init(&dmabuf->lock);
|