Browse Source

[LibOS] Fix sched_getaffinity to return byte size, not bit size

Fixes the following bugs:
* sched_getaffinity(2) should return # of bytes, not bits.
* It should honor `len` argument.
* Linux sched_getaffinity() aligns the result to sizeof(long).
Isaku Yamahata 7 years ago
parent
commit
6d31302e35
1 changed files with 17 additions and 2 deletions
  1. 17 2
      LibOS/shim/src/sys/shim_sched.c

+ 17 - 2
LibOS/shim/src/sys/shim_sched.c

@@ -40,11 +40,26 @@ int shim_do_sched_getaffinity (pid_t pid, size_t len,
                                __kernel_cpu_set_t * user_mask_ptr)
 {
     int ncpus = PAL_CB(cpu_info.cpu_num);
-    // Check that user_mask_ptr is valid; if not, should return -EFAULT
+
+    /* Check that user_mask_ptr is valid; if not, should return -EFAULT */
     if (test_user_memory(user_mask_ptr, len, 1))
         return -EFAULT;
+
+    /* Linux kernel bitmap is based on long. So according to its
+     * implementation, round up the result to sizeof(long) */
+    int bitmask_long_count = (ncpus + sizeof(long) * 8 - 1) /
+        (sizeof(long) * 8);
+    int bitmask_size_in_bytes = bitmask_long_count * sizeof(long);
+    if (len < bitmask_size_in_bytes)
+        return -EINVAL;
+    /* Linux kernel also rejects non-natural size */
+    if (len & (sizeof(long) - 1))
+        return -EINVAL;
+
     memset(user_mask_ptr, 0, len);
     for (int i = 0 ; i < ncpus ; i++)
         ((uint8_t *) user_mask_ptr)[i / 8] |= 1 << (i % 8);
-    return ncpus;
+    /* imitate the Linux kernel implementation
+     * See SYSCALL_DEFINE3(sched_getaffinity) */
+    return bitmask_size_in_bytes;
 }