aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Litke <agl@us.ibm.com>2007-03-01 18:46:08 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-01 20:18:39 -0500
commit516dffdcd8827a40532798602830dfcfc672294c (patch)
treec30fae64a30ca95fb896de80fe16ef90e8920410
parent7b965e0884cee430ffe5dc81cdb117b9316b0549 (diff)
[PATCH] Fix get_unmapped_area and fsync for hugetlb shm segments
This patch provides the following hugetlb-related fixes to the recent stacked shm files changes: - Update is_file_hugepages() so it will reconize hugetlb shm segments. - get_unmapped_area must be called with the nested file struct to handle the sfd->file->f_ops->get_unmapped_area == NULL case. - The fsync f_op must be wrapped since it is specified in the hugetlbfs f_ops. This is based on proposed fixes from Eric Biederman that were debugged and tested by me. Without it, attempting to use hugetlb shared memory segments on powerpc (and likely ia64) will kill your box. Signed-off-by: Adam Litke <agl@us.ibm.com> Cc: Eric Biederman <ebiederm@xmission.com> Cc: Andrew Morton <akpm@linux-foundation.org> Acked-by: William Irwin <bill.irwin@oracle.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/hugetlb.h8
-rw-r--r--include/linux/shm.h5
-rw-r--r--ipc/shm.c32
3 files changed, 38 insertions, 7 deletions
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index a60995afe334..3f3e7a648da3 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -4,6 +4,7 @@
4#ifdef CONFIG_HUGETLB_PAGE 4#ifdef CONFIG_HUGETLB_PAGE
5 5
6#include <linux/mempolicy.h> 6#include <linux/mempolicy.h>
7#include <linux/shm.h>
7#include <asm/tlbflush.h> 8#include <asm/tlbflush.h>
8 9
9struct ctl_table; 10struct ctl_table;
@@ -168,7 +169,12 @@ void hugetlb_put_quota(struct address_space *mapping);
168 169
169static inline int is_file_hugepages(struct file *file) 170static inline int is_file_hugepages(struct file *file)
170{ 171{
171 return file->f_op == &hugetlbfs_file_operations; 172 if (file->f_op == &hugetlbfs_file_operations)
173 return 1;
174 if (is_file_shm_hugepages(file))
175 return 1;
176
177 return 0;
172} 178}
173 179
174static inline void set_file_hugepages(struct file *file) 180static inline void set_file_hugepages(struct file *file)
diff --git a/include/linux/shm.h b/include/linux/shm.h
index a2c896ad0bef..ad2e3af65997 100644
--- a/include/linux/shm.h
+++ b/include/linux/shm.h
@@ -96,12 +96,17 @@ struct shmid_kernel /* private to the kernel */
96 96
97#ifdef CONFIG_SYSVIPC 97#ifdef CONFIG_SYSVIPC
98long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr); 98long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr);
99extern int is_file_shm_hugepages(struct file *file);
99#else 100#else
100static inline long do_shmat(int shmid, char __user *shmaddr, 101static inline long do_shmat(int shmid, char __user *shmaddr,
101 int shmflg, unsigned long *addr) 102 int shmflg, unsigned long *addr)
102{ 103{
103 return -ENOSYS; 104 return -ENOSYS;
104} 105}
106static inline int is_file_shm_hugepages(struct file *file)
107{
108 return 0;
109}
105#endif 110#endif
106 111
107#endif /* __KERNEL__ */ 112#endif /* __KERNEL__ */
diff --git a/ipc/shm.c b/ipc/shm.c
index 3d0eb7940e9c..4fefbad7096d 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -285,21 +285,41 @@ static int shm_release(struct inode *ino, struct file *file)
285 return 0; 285 return 0;
286} 286}
287 287
288#ifndef CONFIG_MMU 288static int shm_fsync(struct file *file, struct dentry *dentry, int datasync)
289{
290 int (*fsync) (struct file *, struct dentry *, int datasync);
291 struct shm_file_data *sfd = shm_file_data(file);
292 int ret = -EINVAL;
293
294 fsync = sfd->file->f_op->fsync;
295 if (fsync)
296 ret = fsync(sfd->file, sfd->file->f_path.dentry, datasync);
297 return ret;
298}
299
289static unsigned long shm_get_unmapped_area(struct file *file, 300static unsigned long shm_get_unmapped_area(struct file *file,
290 unsigned long addr, unsigned long len, unsigned long pgoff, 301 unsigned long addr, unsigned long len, unsigned long pgoff,
291 unsigned long flags) 302 unsigned long flags)
292{ 303{
293 struct shm_file_data *sfd = shm_file_data(file); 304 struct shm_file_data *sfd = shm_file_data(file);
294 return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len, pgoff, 305 return get_unmapped_area(sfd->file, addr, len, pgoff, flags);
295 flags); 306}
307
308int is_file_shm_hugepages(struct file *file)
309{
310 int ret = 0;
311
312 if (file->f_op == &shm_file_operations) {
313 struct shm_file_data *sfd;
314 sfd = shm_file_data(file);
315 ret = is_file_hugepages(sfd->file);
316 }
317 return ret;
296} 318}
297#else
298#define shm_get_unmapped_area NULL
299#endif
300 319
301static const struct file_operations shm_file_operations = { 320static const struct file_operations shm_file_operations = {
302 .mmap = shm_mmap, 321 .mmap = shm_mmap,
322 .fsync = shm_fsync,
303 .release = shm_release, 323 .release = shm_release,
304 .get_unmapped_area = shm_get_unmapped_area, 324 .get_unmapped_area = shm_get_unmapped_area,
305}; 325};