mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Vyacheslav Kovalevsky <slava.kovalevskiy.2014@gmail.com>
To: konishi.ryusuke@gmail.com, slava@dubeyko.com
Cc: linux-nilfs@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: System writes out modified portions of the last memory mapped page beyond file end if file is resized
Date: Fri, 9 Oct 2026 17:09:57 +0300	[thread overview]
Message-ID: <47d7da4a-5029-4c56-a5ac-3e4c526cc569@gmail.com> (raw)

Detailed description
====================

Hello, there seems to be an issue with NILFS2:

1. Create a file, truncate it to some size that is not multiple of OS 
page size (which is usually 4096).
2. Open the file.
3. Create a new shared mapping (MAP_SHARED) using `mmap` from 0 to some 
point beyond file end (but still on the same OS page as the file end, 
otherwise next steps will fail).
4. Write some data beyond file end using the mapping.
5. Resize file (e.g. using `truncate`) so the file end is now after the 
mapping range.
6. Observe that bytes written beyond file end (using the mapping) were 
also written to backing file after resizing.

The last bit violates the POSIX specification, extract from `mmap` 
documentation at 
<https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html>:

 > The system shall always zero-fill any partial page at the end of an 
object. Further, __the system shall never write out any modified 
portions of the last page of an object which are beyond its end__.

Linux manual <https://man7.org/linux/man-pages/man2/mmap.2.html>:

 > For a file that is not a multiple of the page size, the remaining 
bytes in the partial page at the end of the mapping are zeroed when 
mapped, and __modifications to that region are not written out to the 
file__.

For reference: `ext4` / `btrfs` / `xfs` do not write the data to file 
after resizing, as

The exact same issue was recently reported for ZFS: 
<https://github.com/openzfs/zfs/issues/19220>


System info
===========

Linux version 7.0.0-34-generic (Ubuntu 26.04.1 LTS)
nilfs-tools version 2.2.11


How to reproduce
================

```
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define WRITE_OFF 10
#define WRITE_SIZE 10
#define WRITE_DATA "Test data!"
#define MMAP_SIZE WRITE_SIZE + WRITE_OFF
#define FILE_SIZE_INI 10
#define FILE_SIZE_END 32

int main() {
   char buffer[FILE_SIZE_END + 1] = {};
   int status;
   int fd;
   void *addr;

   status = creat("file", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
   printf("CREAT: %d\n", status);
   close(status);

   status = truncate("file", FILE_SIZE_INI);
   printf("TRUNCATE: %d\n", status);

   status = open("file", O_RDWR);
   printf("OPEN: %d\n", status);
   fd = status;

   addr = mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   if (addr == MAP_FAILED) {
     printf("MMAP: FAILED\n");
     return EXIT_FAILURE;
   }
   printf("MMAP: OK\n");
   close(fd);

   memcpy(((char *)addr) + WRITE_OFF, WRITE_DATA, WRITE_SIZE);

   status = munmap(addr, MMAP_SIZE);
   printf("MUNMAP: %d\n", status);

   status = truncate("file", FILE_SIZE_END);
   printf("TRUNCATE: %d\n", status);

   status = open("file", O_RDONLY);
   printf("OPEN: %d\n", status);
   fd = status;

   status = read(fd, buffer, FILE_SIZE_END);
   printf("READ: %d\n", status);
   printf("BYTES: ");
   for (int i = 0; i < status; i++) {
     printf("%02x ", buffer[i]);
   }
   printf("\n");
}

// ::Expected::
// CREAT: 3
// TRUNCATE: 0
// OPEN: 3
// MMAP: OK
// MUNMAP: 0
// TRUNCATE: 0
// OPEN: 3
// READ: 32
// BYTES: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00

// ::Actual::
// CREAT: 3
// TRUNCATE: 0
// OPEN: 3
// MMAP: OK
// MUNMAP: 0
// TRUNCATE: 0
// OPEN: 3
// READ: 32
// BYTES: 00 00 00 00 00 00 00 00 00 00 54 65 73 74 20 64 61 74 61 21 00 
00 00 00 00 00 00 00 00 00 00 00
```

Steps:

1. Create and mount new NILFS2 filesystem in default configuration.
2. Change directory to root of the filesystem and run the compiled test.
3. Observe that last operation returns unexpected value.

             reply	other threads:[~2026-10-09 14:10 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-09 14:09 Vyacheslav Kovalevsky [this message]
2026-10-09 14:47 ` Ryusuke Konishi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=47d7da4a-5029-4c56-a5ac-3e4c526cc569@gmail.com \
    --to=slava.kovalevskiy.2014@gmail.com \
    --cc=konishi.ryusuke@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nilfs@vger.kernel.org \
    --cc=slava@dubeyko.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®