@@ -1212,85 +1212,72 @@ sg_fasync(int fd, struct file *filp, int mode)
return fasync_helper(fd, filp, mode, &sfp->async_qp);
}
-static vm_fault_t
-sg_vma_fault(struct vm_fault *vmf)
+static int sg_discontig_init(void *vm_private_data, void **private)
{
- struct vm_area_struct *vma = vmf->vma;
- Sg_fd *sfp;
- unsigned long offset, len, sa;
- Sg_scatter_hold *rsv_schp;
- int k, length;
-
- if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data)))
- return VM_FAULT_SIGBUS;
- rsv_schp = &sfp->reserve;
- offset = vmf->pgoff << PAGE_SHIFT;
- if (offset >= rsv_schp->bufflen)
- return VM_FAULT_SIGBUS;
- SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp,
- "sg_vma_fault: offset=%lu, scatg=%d\n",
- offset, rsv_schp->k_use_sg));
- sa = vma->vm_start;
- length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
- for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
- len = vma->vm_end - sa;
- len = (len < length) ? len : length;
- if (offset < len) {
- struct page *page = rsv_schp->pages[k] + (offset >> PAGE_SHIFT);
- get_page(page); /* increment page count */
- vmf->page = page;
- return 0; /* success */
- }
- sa += len;
- offset -= len;
+ const unsigned long req_sz = (unsigned long)*private;
+ Sg_fd *sfp = vm_private_data;
+ Sg_scatter_hold *rsv_schp = &sfp->reserve;
+ int err = 0;
+
+ mutex_lock(&sfp->f_mutex);
+ if (req_sz > rsv_schp->bufflen) {
+ err = -ENOMEM; /* cannot map more than reserved buffer */
+ goto out;
+ }
+ sfp->mmap_called = 1; /* Prevents changes to buffer size. */
+out:
+ mutex_unlock(&sfp->f_mutex);
+ return err;
+}
+
+static int
+sg_discontig_get(struct discontig_kernel_page_state *state)
+{
+ Sg_fd *sfp = state->vm_private_data;
+ Sg_scatter_hold *rsv_schp = &sfp->reserve;
+ const unsigned int order = rsv_schp->page_order;
+ const pgoff_t nr_pages = state->nr_pages_mapped;
+
+ if (nr_pages >= (rsv_schp->bufflen >> PAGE_SHIFT)) {
+ discontig_kernel_map_abort(state);
+ return 0;
}
- return VM_FAULT_SIGBUS;
+ SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp,
+ "%s: offset=%lu, scatg=%d\n", __func__,
+ nr_pages << PAGE_SHIFT, rsv_schp->k_use_sg));
+
+ discontig_kernel_map_page(state, rsv_schp->pages[nr_pages >> order]);
+ return 0;
}
-static const struct vm_operations_struct sg_mmap_vm_ops = {
- .fault = sg_vma_fault,
+static const struct discontig_kernel_page_ops sg_discontig_ops = {
+ .init = sg_discontig_init,
+ .get = sg_discontig_get,
};
static int
-sg_mmap(struct file *filp, struct vm_area_struct *vma)
+sg_mmap_prepare(struct vm_area_desc *desc)
{
- Sg_fd *sfp;
- unsigned long req_sz, len, sa;
- Sg_scatter_hold *rsv_schp;
- int k, length;
- int ret = 0;
+ Sg_fd *sfp = desc->file->private_data;
+ const unsigned long req_sz = vma_desc_size(desc);
- if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
+ if (!sfp)
return -ENXIO;
- req_sz = vma->vm_end - vma->vm_start;
+
SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sfp->parentdp,
"sg_mmap starting, vm_start=%p, len=%d\n",
- (void *) vma->vm_start, (int) req_sz));
- if (vma->vm_pgoff)
+ (void *) desc->start, (int) req_sz));
+
+ if (desc->pgoff)
return -EINVAL; /* want no offset */
- rsv_schp = &sfp->reserve;
- mutex_lock(&sfp->f_mutex);
- if (req_sz > rsv_schp->bufflen) {
- ret = -ENOMEM; /* cannot map more than reserved buffer */
- goto out;
- }
- sa = vma->vm_start;
- length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
- for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
- len = vma->vm_end - sa;
- len = (len < length) ? len : length;
- sa += len;
- }
+ vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT);
+ desc->private_data = sfp;
- sfp->mmap_called = 1;
- vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_private_data = sfp;
- vma->vm_ops = &sg_mmap_vm_ops;
-out:
- mutex_unlock(&sfp->f_mutex);
- return ret;
+ mmap_action_map_discontig_kernel_pages(desc, (void *)req_sz,
+ &sg_discontig_ops);
+ return 0;
}
static void@@ -1415,7 +1402,7 @@ static const struct file_operations sg_fops = {
.unlocked_ioctl = sg_ioctl,
.compat_ioctl = compat_ptr_ioctl,
.open = sg_open,
- .mmap = sg_mmap,
+ .mmap_prepare = sg_mmap_prepare,
.release = sg_release,
.fasync = sg_fasync,
};