Copilot commented on code in PR #21754:
URL: https://github.com/apache/nuttx/pull/21754#discussion_r4547573856


##########
fs/shm/shmfs.c:
##########
@@ -479,6 +479,59 @@ static int shmfs_unmap_area(FAR struct task_group_s *group,
   return ret;
 }
 
+/****************************************************************************
+ * Name: shmfs_munmap_partial
+ *
+ * Description:
+ *   Shrink the mapping, or split it in two when the middle is unmapped.
+ *   Each resulting mapping holds one inode reference.  The object's pages
+ *   stay allocated until its last mapping is removed.
+ *
+ ****************************************************************************/
+
+static int shmfs_munmap_partial(FAR struct task_group_s *group,
+                                FAR struct mm_map_entry_s *entry,
+                                FAR void *start, size_t length)
+{
+  FAR char *entry_end = (FAR char *)entry->vaddr + entry->length;
+  FAR char *unmap_end = (FAR char *)start + length;
+  off_t head = (FAR char *)start - (FAR char *)entry->vaddr;
+  off_t tail = entry_end - unmap_end;

Review Comment:
   In kernel builds, `shmfs_unmap_area()` removes whole pages, but the 
surviving entries use byte-based boundaries. With 4 KiB pages, `munmap(base, 
1)` on an 8 KiB mapping leaves a tail at `base + 1`, inside the removed page; 
unmapping that tail then violates `up_shmdt()`'s alignment assertion. Validate 
start alignment and use a page-rounded removal interval for both unmapping and 
bookkeeping, including full-unmap cleanup when rounding removes the entire 
mapping.



##########
fs/mmap/fs_mmap.c:
##########
@@ -155,8 +155,14 @@ static int file_mmap_(FAR struct file *filep, FAR void 
*start,
    * in memory.
    */
 
+  /* A writable MAP_PRIVATE mapping of a file gets a private copy from
+   * rammap() below; a driver's own mmap() defines its own semantics.
+   */
+
   if (filep->f_inode &&
-      filep->f_inode->u.i_ops->mmap != NULL)
+      filep->f_inode->u.i_ops->mmap != NULL &&
+      ((flags & MAP_SHARED) != 0 || (prot & PROT_WRITE) == 0 ||
+       INODE_IS_DRIVER(filep->f_inode)))

Review Comment:
   This also switches writable private tmpfs mappings from `tmpfs_unmap()` to 
`unmap_rammap()`, whose partial-unmap path resizes and records the remaining 
allocation using the number of bytes removed rather than the offset of `start`. 
For example, unmapping the last 4 KiB of a 12 KiB mapping now leaves a recorded 
length of 4 KiB instead of 8 KiB, discarding a still-live portion of the 
mapping. Correct `unmap_rammap()` to retain the prefix length before routing 
these mappings through it.



##########
fs/shm/shmfs.c:
##########
@@ -479,6 +479,59 @@ static int shmfs_unmap_area(FAR struct task_group_s *group,
   return ret;
 }
 
+/****************************************************************************
+ * Name: shmfs_munmap_partial
+ *
+ * Description:
+ *   Shrink the mapping, or split it in two when the middle is unmapped.
+ *   Each resulting mapping holds one inode reference.  The object's pages
+ *   stay allocated until its last mapping is removed.
+ *
+ ****************************************************************************/
+
+static int shmfs_munmap_partial(FAR struct task_group_s *group,
+                                FAR struct mm_map_entry_s *entry,
+                                FAR void *start, size_t length)
+{
+  FAR char *entry_end = (FAR char *)entry->vaddr + entry->length;
+  FAR char *unmap_end = (FAR char *)start + length;
+  off_t head = (FAR char *)start - (FAR char *)entry->vaddr;
+  off_t tail = entry_end - unmap_end;
+  int ret;
+
+  ret = shmfs_unmap_area(group, start, length);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (head > 0 && tail > 0)
+    {
+      struct mm_map_entry_s tailmap = *entry;
+
+      tailmap.vaddr   = unmap_end;
+      tailmap.length  = tail;
+      tailmap.offset  = entry->offset + head + length;
+
+      entry->length = head;
+
+      inode_addref((FAR struct inode *)entry->priv.p);
+      return mm_map_add(get_group_mm(group), &tailmap);

Review Comment:
   If `mm_map_add()` fails, the middle has already been unmapped, the original 
entry shortened, and an inode reference added. This leaves the still-mapped 
tail untracked and leaks its inode reference. Reserve the tail entry before 
changing the mapping, and remove that reservation if unmapping fails.



##########
fs/mmap/fs_mmap.c:
##########
@@ -155,8 +155,14 @@ static int file_mmap_(FAR struct file *filep, FAR void 
*start,
    * in memory.
    */
 
+  /* A writable MAP_PRIVATE mapping of a file gets a private copy from
+   * rammap() below; a driver's own mmap() defines its own semantics.
+   */
+
   if (filep->f_inode &&
-      filep->f_inode->u.i_ops->mmap != NULL)
+      filep->f_inode->u.i_ops->mmap != NULL &&
+      ((flags & MAP_SHARED) != 0 || (prot & PROT_WRITE) == 0 ||
+       INODE_IS_DRIVER(filep->f_inode)))

Review Comment:
   Routing writable private tmpfs/shm mappings through `rammap()` changes the 
descriptor's file position because that helper seeks and reads without 
restoring it. Mapping all four bytes of a tmpfs file positioned at byte 1 now 
leaves it at EOF, so the next read uses the wrong offset. Make the RAM-copy 
path preserve the file position on both success and error paths.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to