瀏覽代碼

[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 年之前
父節點
當前提交
6d31302e35
共有 1 個文件被更改,包括 17 次插入2 次删除
  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)
                                __kernel_cpu_set_t * user_mask_ptr)
 {
 {
     int ncpus = PAL_CB(cpu_info.cpu_num);
     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))
     if (test_user_memory(user_mask_ptr, len, 1))
         return -EFAULT;
         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);
     memset(user_mask_ptr, 0, len);
     for (int i = 0 ; i < ncpus ; i++)
     for (int i = 0 ; i < ncpus ; i++)
         ((uint8_t *) user_mask_ptr)[i / 8] |= 1 << (i % 8);
         ((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;
 }
 }