- patches.apparmor/remove_suid_new_case_in_2.6.22.diff: Merge fix.
[linux-flexiantxendom0-3.2.10.git] / drivers / infiniband / hw / ipath / ipath_mmap.c
index a82157d..937bc33 100644 (file)
@@ -46,6 +46,11 @@ void ipath_release_mmap_info(struct kref *ref)
 {
        struct ipath_mmap_info *ip =
                container_of(ref, struct ipath_mmap_info, ref);
+       struct ipath_ibdev *dev = to_idev(ip->context->device);
+
+       spin_lock_irq(&dev->pending_lock);
+       list_del(&ip->pending_mmaps);
+       spin_unlock_irq(&dev->pending_lock);
 
        vfree(ip->obj);
        kfree(ip);
@@ -60,14 +65,12 @@ static void ipath_vma_open(struct vm_area_struct *vma)
        struct ipath_mmap_info *ip = vma->vm_private_data;
 
        kref_get(&ip->ref);
-       ip->mmap_cnt++;
 }
 
 static void ipath_vma_close(struct vm_area_struct *vma)
 {
        struct ipath_mmap_info *ip = vma->vm_private_data;
 
-       ip->mmap_cnt--;
        kref_put(&ip->ref, ipath_release_mmap_info);
 }
 
@@ -87,7 +90,7 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
        struct ipath_ibdev *dev = to_idev(context->device);
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        unsigned long size = vma->vm_end - vma->vm_start;
-       struct ipath_mmap_info *ip, **pp;
+       struct ipath_mmap_info *ip, *pp;
        int ret = -EINVAL;
 
        /*
@@ -96,15 +99,16 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
         * CQ, QP, or SRQ is soon followed by a call to mmap().
         */
        spin_lock_irq(&dev->pending_lock);
-       for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) {
+       list_for_each_entry_safe(ip, pp, &dev->pending_mmaps,
+                                pending_mmaps) {
                /* Only the creator is allowed to mmap the object */
-               if (context != ip->context || (void *) offset != ip->obj)
+               if (context != ip->context || (__u64) offset != ip->offset)
                        continue;
                /* Don't allow a mmap larger than the object. */
                if (size > ip->size)
                        break;
 
-               *pp = ip->next;
+               list_del_init(&ip->pending_mmaps);
                spin_unlock_irq(&dev->pending_lock);
 
                ret = remap_vmalloc_range(vma, ip->obj, 0);
@@ -119,3 +123,51 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 done:
        return ret;
 }
+
+/*
+ * Allocate information for ipath_mmap
+ */
+struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
+                                              u32 size,
+                                              struct ib_ucontext *context,
+                                              void *obj) {
+       struct ipath_mmap_info *ip;
+
+       ip = kmalloc(sizeof *ip, GFP_KERNEL);
+       if (!ip)
+               goto bail;
+
+       size = PAGE_ALIGN(size);
+
+       spin_lock_irq(&dev->mmap_offset_lock);
+       if (dev->mmap_offset == 0)
+               dev->mmap_offset = PAGE_SIZE;
+       ip->offset = dev->mmap_offset;
+       dev->mmap_offset += size;
+       spin_unlock_irq(&dev->mmap_offset_lock);
+
+       INIT_LIST_HEAD(&ip->pending_mmaps);
+       ip->size = size;
+       ip->context = context;
+       ip->obj = obj;
+       kref_init(&ip->ref);
+
+bail:
+       return ip;
+}
+
+void ipath_update_mmap_info(struct ipath_ibdev *dev,
+                           struct ipath_mmap_info *ip,
+                           u32 size, void *obj) {
+       size = PAGE_ALIGN(size);
+
+       spin_lock_irq(&dev->mmap_offset_lock);
+       if (dev->mmap_offset == 0)
+               dev->mmap_offset = PAGE_SIZE;
+       ip->offset = dev->mmap_offset;
+       dev->mmap_offset += size;
+       spin_unlock_irq(&dev->mmap_offset_lock);
+
+       ip->size = size;
+       ip->obj = obj;
+}