video: tegra: nvmap: fix read failures, super user and noref pinning
Gary King [Mon, 11 Oct 2010 21:22:35 +0000 (14:22 -0700)]
a >= vs > error when checking the operating region of the read and
write ioctls was causing failures when reading the last byte of a handle.

the super-user node (knvmap) wasn't registered correctly due to a cut-
and-paste error, and the regular user node was assigned super-user
priveleges.

noref pinning wasn't correctly validating that the specified handle
existed before pinning it, which caused the reference count for the
handle to become imbalanced on a subsequent unpin

Change-Id: I9985b85023705b00389a53fb962c3b60d62da6b8
Signed-off-by: Gary King <gking@nvidia.com>

drivers/video/tegra/nvmap/nvmap.c
drivers/video/tegra/nvmap/nvmap_dev.c
drivers/video/tegra/nvmap/nvmap_ioctl.c

index 7419731..506aef8 100644 (file)
@@ -225,12 +225,17 @@ int nvmap_pin_ids(struct nvmap_client *client,
                if (ref) {
                        atomic_inc(&ref->pin);
                        nvmap_handle_get(h[i]);
-               } else if (!client->super && (h[i]->owner != client) &&
-                          !h[i]->global) {
-                       ret = -EPERM;
                } else {
-                       nvmap_warn(client, "%s pinning unreferenced handle "
-                                  "%p\n", current->group_leader->comm, h[i]);
+                       struct nvmap_handle *verify;
+                       nvmap_ref_unlock(client);
+                       verify = nvmap_validate_get(client, ids[i]);
+                       if (verify)
+                               nvmap_warn(client, "%s pinning unreferenced "
+                                          "handle %p\n",
+                                          current->group_leader->comm, h[i]);
+                       else
+                               ret = -EPERM;
+                       nvmap_ref_lock(client);
                }
        }
        nvmap_ref_unlock(client);
index b84a788..c6669ed 100644 (file)
@@ -353,6 +353,8 @@ struct nvmap_handle *nvmap_validate_get(struct nvmap_client *client,
                if ((unsigned long)h == id) {
                        if (client->super || h->global || (h->owner == client))
                                h = nvmap_handle_get(h);
+                       else
+                               h = NULL;
                        spin_unlock(&client->dev->handle_lock);
                        return h;
                }
@@ -696,9 +698,9 @@ static int nvmap_probe(struct platform_device *pdev)
        dev->dev_user.parent = &pdev->dev;
 
        dev->dev_super.minor = MISC_DYNAMIC_MINOR;
-       dev->dev_super.name = "kvmap";
-       dev->dev_user.fops = &nvmap_super_fops;
-       dev->dev_user.parent = &pdev->dev;
+       dev->dev_super.name = "knvmap";
+       dev->dev_super.fops = &nvmap_super_fops;
+       dev->dev_super.parent = &pdev->dev;
 
        dev->handles = RB_ROOT;
 
index 9051803..b943065 100644 (file)
@@ -459,7 +459,8 @@ static int cache_maint(struct nvmap_client *client, struct nvmap_handle *h,
        }
 
        if (h->flags == NVMAP_HANDLE_UNCACHEABLE ||
-           h->flags == NVMAP_HANDLE_WRITE_COMBINE)
+           h->flags == NVMAP_HANDLE_WRITE_COMBINE ||
+           start == end)
                goto out;
 
        if (WARN_ON_ONCE(op == NVMAP_CACHE_OP_WB_INV))
@@ -607,7 +608,7 @@ static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h,
                return PTR_ERR(pte);
 
        while (count--) {
-               if (h_offs + elem_size >= h->size) {
+               if (h_offs + elem_size > h->size) {
                        nvmap_warn(client, "read/write outside of handle\n");
                        ret = -EFAULT;
                        break;