pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


Linux kernel linux6_17_rc4_rt3_fnctl_allocfree20260624_002 fnctl() F_ALLOCSP/F_FREESP patch
Posted by Anonymous on Wed 24th Jun 2026 16:37
raw | new post
view followups (newest first): Linux kernel linux6_17_rc4_rt3_fnctl_allocfree20260630_003 fnctl() F_ALLOCSP/F_FREESP patch by Anonymous

  1. diff --git a/fs/fcntl.c b/fs/fcntl.c
  2. index 5598e4d57422..52555e6f5a8b 100644
  3. --- a/fs/fcntl.c
  4. +++ b/fs/fcntl.c
  5. @@ -18,11 +18,14 @@
  6.  #include <linux/module.h>
  7.  #include <linux/pipe_fs_i.h>
  8.  #include <linux/security.h>
  9. +#include <linux/falloc.h>
  10.  #include <linux/ptrace.h>
  11.  #include <linux/signal.h>
  12.  #include <linux/rcupdate.h>
  13.  #include <linux/pid_namespace.h>
  14.  #include <linux/user_namespace.h>
  15. +#include <linux/fsnotify.h>
  16. +#include <linux/mnt_idmapping.h>
  17.  #include <linux/memfd.h>
  18.  #include <linux/compat.h>
  19.  #include <linux/mount.h>
  20. @@ -36,6 +39,122 @@
  21.  
  22.  #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
  23.  
  24. +static int flock_to_abs_range(struct file *file, struct flock *fl,
  25. +       loff_t *start, loff_t *len)
  26. +{
  27. +       struct inode *inode = file_inode(file);
  28. +       loff_t base;
  29. +
  30. +       if (!fl || !start || !len)
  31. +               return -EINVAL;
  32. +
  33. +       switch (fl->l_whence) {
  34. +               case SEEK_SET:
  35. +                       base = 0;
  36. +                       break;
  37. +               case SEEK_CUR:
  38. +                       base = file->f_pos;
  39. +                       break;
  40. +               case SEEK_END:
  41. +                       base = i_size_read(inode);
  42. +                       break;
  43. +               default:
  44. +                       return -EINVAL;
  45. +       }
  46. +
  47. +       /*
  48. +        * Keep the implementation simple:
  49. +        *   l_len > 0 : fixed byte range
  50. +        *   l_len == 0: [start, EOF)
  51. +        *   l_len < 0 : reject for now
  52. +        */
  53. +       if (fl->l_len < 0)
  54. +               return -EINVAL;
  55. +
  56. +       if (check_add_overflow(base, (loff_t)fl->l_start, start))
  57. +               return -EOVERFLOW;
  58. +
  59. +       if (*start < 0)
  60. +               return -EINVAL;
  61. +
  62. +       *len = fl->l_len;
  63. +       return 0;
  64. +}
  65. +
  66. +static int do_fcntl_allocsp(struct file *file, struct flock *fl)
  67. +{
  68. +       loff_t start, len;
  69. +       int error;
  70. +
  71. +       error = flock_to_abs_range(file, fl, &start, &len);
  72. +       if (error)
  73. +               return error;
  74. +
  75. +       /* Empty allocation request: NO-OP */
  76. +       if (len == 0)
  77. +               return 0;
  78. +
  79. +       return vfs_fallocate(file, 0, start, len);
  80. +}
  81. +
  82. +static int do_fcntl_freesp(struct file *file, struct flock *fl)
  83. +{
  84. +       struct inode *inode = file_inode(file);
  85. +       struct mnt_idmap *idmap = file_mnt_idmap(file);
  86. +       loff_t start, len, isize, end;
  87. +       int error;
  88. +
  89. +       error = flock_to_abs_range(file, fl, &start, &len);
  90. +       if (error)
  91. +               return error;
  92. +
  93. +       isize = i_size_read(inode);
  94. +
  95. +       if (start >= isize)
  96. +               return 0;
  97. +
  98. +       /*
  99. +        * { Solaris, FreeBSD, SUPER/UX, ... }-style |l_len == 0| means
  100. +        * "from start to EOF".
  101. +        * Linux hole punching keeps |i_size| unchanged, so use truncate
  102. +        * whenever we are freeing through EOF.
  103. +        */
  104. +       if (len == 0)
  105. +               return do_truncate(idmap, file->f_path.dentry, start, 0, file);
  106. +
  107. +       if (check_add_overflow(start, len, &end))
  108. +               return -EOVERFLOW;
  109. +
  110. +       if (end >= isize)
  111. +               return do_truncate(idmap, file->f_path.dentry, start, 0, file);
  112. +
  113. +       return vfs_fallocate(file,
  114. +               FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
  115. +               start, len);
  116. +}
  117. +
  118. +static int do_fcntl_space(struct file *file, unsigned int cmd, unsigned long arg)
  119. +{
  120. +       struct flock fl;
  121. +
  122. +       if (copy_from_user(&fl, (void __user *)arg, sizeof(fl)))
  123. +               return -EFAULT;
  124. +
  125. +       /*
  126. +        * Linux uses |fcntl()| record locking for byte ranges, but these
  127. +        * commands are not locks; only the range fields are interpreted
  128. +        * here.
  129. +       */
  130. +       switch (cmd) {
  131. +               case F_ALLOCSP:
  132. +                       return do_fcntl_allocsp(file, &fl);
  133. +               case F_FREESP:
  134. +                       return do_fcntl_freesp(file, &fl);
  135. +               default:
  136. +                       return -EINVAL;
  137. +       }
  138. +}
  139. +
  140.  static int setfl(int fd, struct file * filp, unsigned int arg)
  141.  {
  142.         struct inode * inode = file_inode(filp);
  143. @@ -552,6 +671,13 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
  144.         case F_SET_RW_HINT:
  145.                 err = fcntl_set_rw_hint(filp, cmd, arg);
  146.                 break;
  147. +       case F_ALLOCSP:
  148. +       case F_FREESP:
  149. +               if (!(filp->f_mode & FMODE_WRITE))
  150. +                       err = -EBADF;
  151. +               else
  152. +                       err = do_fcntl_space(filp, cmd, arg);
  153. +               break;
  154.         default:
  155.                 break;
  156.         }
  157. diff --git a/fs/internal.h b/fs/internal.h
  158. index 38e8aab27bbd..178e564b1940 100644
  159. --- a/fs/internal.h
  160. +++ b/fs/internal.h
  161. @@ -59,6 +59,9 @@ int do_unlinkat(int dfd, struct filename *name);
  162.  int may_linkat(struct mnt_idmap *idmap, const struct path *link);
  163.  int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
  164.                  struct filename *newname, unsigned int flags);
  165. +int do_truncate(struct mnt_idmap *idmap, struct dentry *dentry,
  166. +               loff_t length, unsigned int time_attrs,
  167. +               struct file *filp);
  168.  int do_mkdirat(int dfd, struct filename *name, umode_t mode);
  169.  int do_symlinkat(struct filename *from, int newdfd, struct filename *to);
  170.  int do_linkat(int olddfd, struct filename *old, int newdfd,
  171. diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
  172. index f291ab4f94eb..6076cb439542 100644
  173. --- a/include/uapi/linux/fcntl.h
  174. +++ b/include/uapi/linux/fcntl.h
  175. @@ -61,6 +61,13 @@
  176.  #define F_GET_FILE_RW_HINT     (F_LINUX_SPECIFIC_BASE + 13)
  177.  #define F_SET_FILE_RW_HINT     (F_LINUX_SPECIFIC_BASE + 14)
  178.  
  179. +/*
  180. + * { Solaris, FreeBSD, SUPER/UX, ... }-style sparse file space
  181. + * allocation/freeing
  182. + */
  183. +#define F_ALLOCSP              (F_LINUX_SPECIFIC_BASE + 15)
  184. +#define F_FREESP               (F_LINUX_SPECIFIC_BASE + 16)
  185. +
  186.  /*
  187.   * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be
  188.   * used to clear any hints previously set.

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at