Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm: allow handling of stacked mmap_prepare hooks in more drivers

While the conversion of mmap hooks to mmap_prepare is underway, we will
encounter situations where mmap hooks need to invoke nested mmap_prepare
hooks.

The nesting of mmap hooks is termed 'stacking'. In order to flexibly
facilitate the conversion of custom mmap hooks in drivers which stack, we
must split up the existing __compat_vma_mmap() function into two separate
functions:

* compat_set_desc_from_vma() - This allows the setting of a vm_area_desc
object's fields to the relevant fields of a VMA.

* __compat_vma_mmap() - Once an mmap_prepare hook has been executed upon a
vm_area_desc object, this function performs any mmap actions specified by
the mmap_prepare hook and then invokes its vm_ops->mapped() hook if any
were specified.

In ordinary cases, where a file's f_op->mmap_prepare() hook simply needs
to be invoked in a stacked mmap() hook, compat_vma_mmap() can be used.

However some drivers define their own nested hooks, which are invoked in
turn by another hook.

A concrete example is vmbus_channel->mmap_ring_buffer(), which is invoked
in turn by bin_attribute->mmap():

vmbus_channel->mmap_ring_buffer() has a signature of:

int (*mmap_ring_buffer)(struct vmbus_channel *channel,
struct vm_area_struct *vma);

And bin_attribute->mmap() has a signature of:

int (*mmap)(struct file *, struct kobject *,
const struct bin_attribute *attr,
struct vm_area_struct *vma);

And so compat_vma_mmap() cannot be used here for incremental conversion of
hooks from mmap() to mmap_prepare().

There are many such instances like this, where conversion to mmap_prepare
would otherwise cascade to a huge change set due to nesting of this kind.

The changes in this patch mean we could now instead convert
vmbus_channel->mmap_ring_buffer() to
vmbus_channel->mmap_prepare_ring_buffer(), and implement something like:

struct vm_area_desc desc;
int err;

compat_set_desc_from_vma(&desc, file, vma);
err = channel->mmap_prepare_ring_buffer(channel, &desc);
if (err)
return err;

return __compat_vma_mmap(&desc, vma);

Allowing us to incrementally update this logic, and other logic like it.

Unfortunately, as part of this change, we need to be able to flexibly
assign to the VMA descriptor, so have to remove some of the const
declarations within the structure.

Also update the VMA tests to reflect the changes.

Link: https://lkml.kernel.org/r/24aac3019dd34740e788d169fccbe3c62781e648.1774045440.git.ljs@kernel.org
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Bodo Stroesser <bostroesser@gmail.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: David Hildenbrand <david@kernel.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Dexuan Cui <decui@microsoft.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Jann Horn <jannh@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Long Li <longli@microsoft.com>
Cc: Marc Dionne <marc.dionne@auristor.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Miquel Raynal <miquel.raynal@bootlin.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Richard Weinberger <richard@nod.at>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vignesh Raghavendra <vigneshr@ti.com>
Cc: Wei Liu <wei.liu@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Lorenzo Stoakes (Oracle) and committed by
Andrew Morton
668937b7 14beec03

+134 -58
+3
include/linux/fs.h
··· 2058 2058 return true; 2059 2059 } 2060 2060 2061 + void compat_set_desc_from_vma(struct vm_area_desc *desc, const struct file *file, 2062 + const struct vm_area_struct *vma); 2063 + int __compat_vma_mmap(struct vm_area_desc *desc, struct vm_area_struct *vma); 2061 2064 int compat_vma_mmap(struct file *file, struct vm_area_struct *vma); 2062 2065 int __vma_check_mmap_hook(struct vm_area_struct *vma); 2063 2066
+2 -2
include/linux/mm_types.h
··· 891 891 */ 892 892 struct vm_area_desc { 893 893 /* Immutable state. */ 894 - const struct mm_struct *const mm; 895 - struct file *const file; /* May vary from vm_file in stacked callers. */ 894 + struct mm_struct *mm; 895 + struct file *file; /* May vary from vm_file in stacked callers. */ 896 896 unsigned long start; 897 897 unsigned long end; 898 898
+83 -30
mm/util.c
··· 1163 1163 EXPORT_SYMBOL(flush_dcache_folio); 1164 1164 #endif 1165 1165 1166 - static int __compat_vma_mmap(struct file *file, struct vm_area_struct *vma) 1166 + /** 1167 + * compat_set_desc_from_vma() - assigns VMA descriptor @desc fields from a VMA. 1168 + * @desc: A VMA descriptor whose fields need to be set. 1169 + * @file: The file object describing the file being mmap()'d. 1170 + * @vma: The VMA whose fields we wish to assign to @desc. 1171 + * 1172 + * This is a compatibility function to allow an mmap() hook to call 1173 + * mmap_prepare() hooks when drivers nest these. This function specifically 1174 + * allows the construction of a vm_area_desc value, @desc, from a VMA @vma for 1175 + * the purposes of doing this. 1176 + * 1177 + * Once the conversion of drivers is complete this function will no longer be 1178 + * required and will be removed. 1179 + */ 1180 + void compat_set_desc_from_vma(struct vm_area_desc *desc, 1181 + const struct file *file, 1182 + const struct vm_area_struct *vma) 1167 1183 { 1168 - struct vm_area_desc desc = { 1169 - .mm = vma->vm_mm, 1170 - .file = file, 1171 - .start = vma->vm_start, 1172 - .end = vma->vm_end, 1184 + memset(desc, 0, sizeof(*desc)); 1173 1185 1174 - .pgoff = vma->vm_pgoff, 1175 - .vm_file = vma->vm_file, 1176 - .vma_flags = vma->flags, 1177 - .page_prot = vma->vm_page_prot, 1186 + desc->mm = vma->vm_mm; 1187 + desc->file = (struct file *)file; 1188 + desc->start = vma->vm_start; 1189 + desc->end = vma->vm_end; 1178 1190 1179 - .action.type = MMAP_NOTHING, /* Default */ 1180 - }; 1181 - struct mmap_action *action = &desc.action; 1191 + desc->pgoff = vma->vm_pgoff; 1192 + desc->vm_file = vma->vm_file; 1193 + desc->vma_flags = vma->flags; 1194 + desc->page_prot = vma->vm_page_prot; 1195 + 1196 + /* Default. */ 1197 + desc->action.type = MMAP_NOTHING; 1198 + } 1199 + EXPORT_SYMBOL(compat_set_desc_from_vma); 1200 + 1201 + /** 1202 + * __compat_vma_mmap() - Similar to compat_vma_mmap(), only it allows 1203 + * flexibility as to how the mmap_prepare callback is invoked, which is useful 1204 + * for drivers which invoke nested mmap_prepare callbacks in an mmap() hook. 1205 + * @desc: A VMA descriptor upon which an mmap_prepare() hook has already been 1206 + * executed. 1207 + * @vma: The VMA to which @desc should be applied. 1208 + * 1209 + * The function assumes that you have obtained a VMA descriptor @desc from 1210 + * compat_set_desc_from_vma(), and already executed the mmap_prepare() hook upon 1211 + * it. 1212 + * 1213 + * It then performs any specified mmap actions, and invokes the vm_ops->mapped() 1214 + * hook if one is present. 1215 + * 1216 + * See the description of compat_vma_mmap() for more details. 1217 + * 1218 + * Once the conversion of drivers is complete this function will no longer be 1219 + * required and will be removed. 1220 + * 1221 + * Returns: 0 on success or error. 1222 + */ 1223 + int __compat_vma_mmap(struct vm_area_desc *desc, 1224 + struct vm_area_struct *vma) 1225 + { 1182 1226 int err; 1183 1227 1184 - err = vfs_mmap_prepare(file, &desc); 1228 + /* Perform any preparatory tasks for mmap action. */ 1229 + err = mmap_action_prepare(desc); 1185 1230 if (err) 1186 1231 return err; 1187 - 1188 - err = mmap_action_prepare(&desc); 1189 - if (err) 1190 - return err; 1191 - 1192 - /* being invoked from .mmap means we don't have to enforce this. */ 1193 - action->hide_from_rmap_until_complete = false; 1194 - 1195 - set_vma_from_desc(vma, &desc); 1196 - return mmap_action_complete(vma, action); 1232 + /* Update the VMA from the descriptor. */ 1233 + compat_set_vma_from_desc(vma, desc); 1234 + /* Complete any specified mmap actions. */ 1235 + return mmap_action_complete(vma, &desc->action); 1197 1236 } 1237 + EXPORT_SYMBOL(__compat_vma_mmap); 1198 1238 1199 1239 /** 1200 1240 * compat_vma_mmap() - Apply the file's .mmap_prepare() hook to an ··· 1243 1203 * @vma: The VMA to apply the .mmap_prepare() hook to. 1244 1204 * 1245 1205 * Ordinarily, .mmap_prepare() is invoked directly upon mmap(). However, certain 1246 - * stacked filesystems invoke a nested mmap hook of an underlying file. 1206 + * stacked drivers invoke a nested mmap hook of an underlying file. 1247 1207 * 1248 - * Until all filesystems are converted to use .mmap_prepare(), we must be 1249 - * conservative and continue to invoke these stacked filesystems using the 1208 + * Until all drivers are converted to use .mmap_prepare(), we must be 1209 + * conservative and continue to invoke these stacked drivers using the 1250 1210 * deprecated .mmap() hook. 1251 1211 * 1252 1212 * However we have a problem if the underlying file system possesses an ··· 1257 1217 * establishes a struct vm_area_desc descriptor, passes to the underlying 1258 1218 * .mmap_prepare() hook and applies any changes performed by it. 1259 1219 * 1260 - * Once the conversion of filesystems is complete this function will no longer 1261 - * be required and will be removed. 1220 + * Once the conversion of drivers is complete this function will no longer be 1221 + * required and will be removed. 1262 1222 * 1263 1223 * Returns: 0 on success or error. 1264 1224 */ 1265 1225 int compat_vma_mmap(struct file *file, struct vm_area_struct *vma) 1266 1226 { 1267 - return __compat_vma_mmap(file, vma); 1227 + struct vm_area_desc desc; 1228 + struct mmap_action *action; 1229 + int err; 1230 + 1231 + compat_set_desc_from_vma(&desc, file, vma); 1232 + err = vfs_mmap_prepare(file, &desc); 1233 + if (err) 1234 + return err; 1235 + action = &desc.action; 1236 + 1237 + /* being invoked from .mmmap means we don't have to enforce this. */ 1238 + action->hide_from_rmap_until_complete = false; 1239 + 1240 + return __compat_vma_mmap(&desc, vma); 1268 1241 } 1269 1242 EXPORT_SYMBOL(compat_vma_mmap); 1270 1243
+1 -1
mm/vma.h
··· 300 300 * f_op->mmap() but which might have an underlying file system which implements 301 301 * f_op->mmap_prepare(). 302 302 */ 303 - static inline void set_vma_from_desc(struct vm_area_struct *vma, 303 + static inline void compat_set_vma_from_desc(struct vm_area_struct *vma, 304 304 struct vm_area_desc *desc) 305 305 { 306 306 /*
+45 -25
tools/testing/vma/include/dup.h
··· 519 519 */ 520 520 struct vm_area_desc { 521 521 /* Immutable state. */ 522 - const struct mm_struct *const mm; 523 - struct file *const file; /* May vary from vm_file in stacked callers. */ 522 + struct mm_struct *mm; 523 + struct file *file; /* May vary from vm_file in stacked callers. */ 524 524 unsigned long start; 525 525 unsigned long end; 526 526 ··· 1278 1278 } 1279 1279 1280 1280 /* Declared in vma.h. */ 1281 - static inline void set_vma_from_desc(struct vm_area_struct *vma, 1281 + static inline void compat_set_vma_from_desc(struct vm_area_struct *vma, 1282 1282 struct vm_area_desc *desc); 1283 + 1284 + static inline void compat_set_desc_from_vma(struct vm_area_desc *desc, 1285 + const struct file *file, 1286 + const struct vm_area_struct *vma) 1287 + { 1288 + memset(desc, 0, sizeof(*desc)); 1289 + 1290 + desc->mm = vma->vm_mm; 1291 + desc->file = (struct file *)file; 1292 + desc->start = vma->vm_start; 1293 + desc->end = vma->vm_end; 1294 + 1295 + desc->pgoff = vma->vm_pgoff; 1296 + desc->vm_file = vma->vm_file; 1297 + desc->vma_flags = vma->flags; 1298 + desc->page_prot = vma->vm_page_prot; 1299 + 1300 + /* Default. */ 1301 + desc->action.type = MMAP_NOTHING; 1302 + } 1303 + 1304 + static inline unsigned long vma_pages(const struct vm_area_struct *vma) 1305 + { 1306 + return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; 1307 + } 1283 1308 1284 1309 static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc) 1285 1310 { 1286 1311 return file->f_op->mmap_prepare(desc); 1287 1312 } 1288 1313 1289 - static inline unsigned long vma_pages(struct vm_area_struct *vma) 1314 + static inline int __compat_vma_mmap(struct vm_area_desc *desc, 1315 + struct vm_area_struct *vma) 1290 1316 { 1291 - return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; 1317 + int err; 1318 + 1319 + /* Perform any preparatory tasks for mmap action. */ 1320 + err = mmap_action_prepare(desc); 1321 + if (err) 1322 + return err; 1323 + /* Update the VMA from the descriptor. */ 1324 + compat_set_vma_from_desc(vma, desc); 1325 + /* Complete any specified mmap actions. */ 1326 + return mmap_action_complete(vma, &desc->action); 1292 1327 } 1293 1328 1294 1329 static inline int compat_vma_mmap(struct file *file, struct vm_area_struct *vma) 1295 1330 { 1296 - struct vm_area_desc desc = { 1297 - .mm = vma->vm_mm, 1298 - .file = file, 1299 - .start = vma->vm_start, 1300 - .end = vma->vm_end, 1301 - 1302 - .pgoff = vma->vm_pgoff, 1303 - .vm_file = vma->vm_file, 1304 - .vma_flags = vma->flags, 1305 - .page_prot = vma->vm_page_prot, 1306 - 1307 - .action.type = MMAP_NOTHING, /* Default */ 1308 - }; 1309 - struct mmap_action *action = &desc.action; 1331 + struct vm_area_desc desc; 1332 + struct mmap_action *action; 1310 1333 int err; 1311 1334 1335 + compat_set_desc_from_vma(&desc, file, vma); 1312 1336 err = vfs_mmap_prepare(file, &desc); 1313 1337 if (err) 1314 1338 return err; 1315 - 1316 - err = mmap_action_prepare(&desc); 1317 - if (err) 1318 - return err; 1339 + action = &desc.action; 1319 1340 1320 1341 /* being invoked from .mmmap means we don't have to enforce this. */ 1321 1342 action->hide_from_rmap_until_complete = false; 1322 1343 1323 - set_vma_from_desc(vma, &desc); 1324 - return mmap_action_complete(vma, action); 1344 + return __compat_vma_mmap(&desc, vma); 1325 1345 } 1326 1346 1327 1347 static inline void vma_iter_init(struct vma_iterator *vmi,