update hdmi driver: support 480p
[firefly-linux-kernel-4.4.55.git] / kernel / futex.c
index 3071911eff5be1fe50b579d6963ff87aee1cfaa4..06d08e5eb2fc96d5089220abd5021e31817417af 100644 (file)
@@ -220,6 +220,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
        struct mm_struct *mm = current->mm;
        struct page *page;
        int err;
+       struct vm_area_struct *vma;
 
        /*
         * The futex address must be "naturally" aligned.
@@ -245,6 +246,37 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
                return 0;
        }
 
+       /*
+        * The futex is hashed differently depending on whether
+        * it's in a shared or private mapping.  So check vma first.
+        */
+       vma = find_extend_vma(mm, address);
+       if (unlikely(!vma))
+               return -EFAULT;
+
+       /*
+        * Permissions.
+        */
+       if (unlikely((vma->vm_flags & (VM_IO|VM_READ)) != VM_READ))
+               return (vma->vm_flags & VM_IO) ? -EPERM : -EACCES;
+
+       /*
+        * Private mappings are handled in a simple way.
+        *
+        * NOTE: When userspace waits on a MAP_SHARED mapping, even if
+        * it's a read-only handle, it's expected that futexes attach to
+        * the object not the particular process.  Therefore we use
+        * VM_MAYSHARE here, not VM_SHARED which is restricted to shared
+        * mappings of _writable_ handles.
+        */
+       if (likely(!(vma->vm_flags & VM_MAYSHARE))) {
+               key->both.offset |= FUT_OFF_MMSHARED; /* reference taken on mm */
+               key->private.mm = mm;
+               key->private.address = address;
+               get_futex_key_refs(key);
+               return 0;
+       }
+
 again:
        err = get_user_pages_fast(address, 1, 1, &page);
        if (err < 0)
@@ -1363,7 +1395,6 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
 {
        struct futex_hash_bucket *hb;
 
-       get_futex_key_refs(&q->key);
        hb = hash_futex(&q->key);
        q->lock_ptr = &hb->lock;
 
@@ -1375,7 +1406,6 @@ static inline void
 queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
 {
        spin_unlock(&hb->lock);
-       drop_futex_key_refs(&q->key);
 }
 
 /**
@@ -1480,8 +1510,6 @@ static void unqueue_me_pi(struct futex_q *q)
        q->pi_state = NULL;
 
        spin_unlock(q->lock_ptr);
-
-       drop_futex_key_refs(&q->key);
 }
 
 /*
@@ -1812,7 +1840,10 @@ static int futex_wait(u32 __user *uaddr, int fshared,
        }
 
 retry:
-       /* Prepare to wait on uaddr. */
+       /*
+        * Prepare to wait on uaddr. On success, holds hb lock and increments
+        * q.key refs.
+        */
        ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
        if (ret)
                goto out;
@@ -1822,24 +1853,23 @@ retry:
 
        /* If we were woken (and unqueued), we succeeded, whatever. */
        ret = 0;
+       /* unqueue_me() drops q.key ref */
        if (!unqueue_me(&q))
-               goto out_put_key;
+               goto out;
        ret = -ETIMEDOUT;
        if (to && !to->task)
-               goto out_put_key;
+               goto out;
 
        /*
         * We expect signal_pending(current), but we might be the
         * victim of a spurious wakeup as well.
         */
-       if (!signal_pending(current)) {
-               put_futex_key(fshared, &q.key);
+       if (!signal_pending(current))
                goto retry;
-       }
 
        ret = -ERESTARTSYS;
        if (!abs_time)
-               goto out_put_key;
+               goto out;
 
        restart = &current_thread_info()->restart_block;
        restart->fn = futex_wait_restart;
@@ -1856,8 +1886,6 @@ retry:
 
        ret = -ERESTART_RESTARTBLOCK;
 
-out_put_key:
-       put_futex_key(fshared, &q.key);
 out:
        if (to) {
                hrtimer_cancel(&to->timer);
@@ -2236,7 +2264,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
        q.rt_waiter = &rt_waiter;
        q.requeue_pi_key = &key2;
 
-       /* Prepare to wait on uaddr. */
+       /*
+        * Prepare to wait on uaddr. On success, increments q.key (key1) ref
+        * count.
+        */
        ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
        if (ret)
                goto out_key2;
@@ -2254,7 +2285,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
         * In order for us to be here, we know our q.key == key2, and since
         * we took the hb->lock above, we also know that futex_requeue() has
         * completed and we no longer have to concern ourselves with a wakeup
-        * race with the atomic proxy lock acquition by the requeue code.
+        * race with the atomic proxy lock acquisition by the requeue code. The
+        * futex_requeue dropped our key1 reference and incremented our key2
+        * reference count.
         */
 
        /* Check if the requeue code acquired the second futex for us. */