From: Greg Kroah-Hartman Date: Wed, 8 May 2013 21:25:07 +0000 (-0700) Subject: 3.9-stable patches X-Git-Tag: v3.9.2~62 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5439fdb4c36efa612510c3e11e011d369dc3a94c;p=thirdparty%2Fkernel%2Fstable-queue.git 3.9-stable patches added patches: hugetlbfs-fix-mmap-failure-in-unaligned-size-request.patch --- diff --git a/queue-3.9/hugetlbfs-fix-mmap-failure-in-unaligned-size-request.patch b/queue-3.9/hugetlbfs-fix-mmap-failure-in-unaligned-size-request.patch new file mode 100644 index 00000000000..d3654e5ae6e --- /dev/null +++ b/queue-3.9/hugetlbfs-fix-mmap-failure-in-unaligned-size-request.patch @@ -0,0 +1,199 @@ +From af73e4d9506d3b797509f3c030e7dcd554f7d9c4 Mon Sep 17 00:00:00 2001 +From: Naoya Horiguchi +Date: Tue, 7 May 2013 16:18:13 -0700 +Subject: hugetlbfs: fix mmap failure in unaligned size request + +From: Naoya Horiguchi + +commit af73e4d9506d3b797509f3c030e7dcd554f7d9c4 upstream. + +The current kernel returns -EINVAL unless a given mmap length is +"almost" hugepage aligned. This is because in sys_mmap_pgoff() the +given length is passed to vm_mmap_pgoff() as it is without being aligned +with hugepage boundary. + +This is a regression introduced in commit 40716e29243d ("hugetlbfs: fix +alignment of huge page requests"), where alignment code is pushed into +hugetlb_file_setup() and the variable len in caller side is not changed. + +To fix this, this patch partially reverts that commit, and adds +alignment code in caller side. And it also introduces hstate_sizelog() +in order to get proper hstate to specified hugepage size. + +Addresses https://bugzilla.kernel.org/show_bug.cgi?id=56881 + +[akpm@linux-foundation.org: fix warning when CONFIG_HUGETLB_PAGE=n] +Signed-off-by: Naoya Horiguchi +Signed-off-by: Johannes Weiner +Reported-by: +Cc: Steven Truelove +Cc: Jianguo Wu +Cc: Hugh Dickins +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/hugetlbfs/inode.c | 24 ++++++++++-------------- + include/linux/hugetlb.h | 19 +++++++++++++------ + ipc/shm.c | 6 +++++- + mm/mmap.c | 7 ++++++- + 4 files changed, 34 insertions(+), 22 deletions(-) + +--- a/fs/hugetlbfs/inode.c ++++ b/fs/hugetlbfs/inode.c +@@ -909,11 +909,8 @@ static int can_do_hugetlb_shm(void) + + static int get_hstate_idx(int page_size_log) + { +- struct hstate *h; ++ struct hstate *h = hstate_sizelog(page_size_log); + +- if (!page_size_log) +- return default_hstate_idx; +- h = size_to_hstate(1 << page_size_log); + if (!h) + return -1; + return h - hstates; +@@ -929,9 +926,12 @@ static struct dentry_operations anon_ops + .d_dname = hugetlb_dname + }; + +-struct file *hugetlb_file_setup(const char *name, unsigned long addr, +- size_t size, vm_flags_t acctflag, +- struct user_struct **user, ++/* ++ * Note that size should be aligned to proper hugepage size in caller side, ++ * otherwise hugetlb_reserve_pages reserves one less hugepages than intended. ++ */ ++struct file *hugetlb_file_setup(const char *name, size_t size, ++ vm_flags_t acctflag, struct user_struct **user, + int creat_flags, int page_size_log) + { + struct file *file = ERR_PTR(-ENOMEM); +@@ -939,8 +939,6 @@ struct file *hugetlb_file_setup(const ch + struct path path; + struct super_block *sb; + struct qstr quick_string; +- struct hstate *hstate; +- unsigned long num_pages; + int hstate_idx; + + hstate_idx = get_hstate_idx(page_size_log); +@@ -980,12 +978,10 @@ struct file *hugetlb_file_setup(const ch + if (!inode) + goto out_dentry; + +- hstate = hstate_inode(inode); +- size += addr & ~huge_page_mask(hstate); +- num_pages = ALIGN(size, huge_page_size(hstate)) >> +- huge_page_shift(hstate); + file = ERR_PTR(-ENOMEM); +- if (hugetlb_reserve_pages(inode, 0, num_pages, NULL, acctflag)) ++ if (hugetlb_reserve_pages(inode, 0, ++ size >> huge_page_shift(hstate_inode(inode)), NULL, ++ acctflag)) + goto out_inode; + + d_instantiate(path.dentry, inode); +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -185,8 +185,7 @@ static inline struct hugetlbfs_sb_info * + + extern const struct file_operations hugetlbfs_file_operations; + extern const struct vm_operations_struct hugetlb_vm_ops; +-struct file *hugetlb_file_setup(const char *name, unsigned long addr, +- size_t size, vm_flags_t acct, ++struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct, + struct user_struct **user, int creat_flags, + int page_size_log); + +@@ -205,8 +204,8 @@ static inline int is_file_hugepages(stru + + #define is_file_hugepages(file) 0 + static inline struct file * +-hugetlb_file_setup(const char *name, unsigned long addr, size_t size, +- vm_flags_t acctflag, struct user_struct **user, int creat_flags, ++hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag, ++ struct user_struct **user, int creat_flags, + int page_size_log) + { + return ERR_PTR(-ENOSYS); +@@ -284,6 +283,13 @@ static inline struct hstate *hstate_file + return hstate_inode(file_inode(f)); + } + ++static inline struct hstate *hstate_sizelog(int page_size_log) ++{ ++ if (!page_size_log) ++ return &default_hstate; ++ return size_to_hstate(1 << page_size_log); ++} ++ + static inline struct hstate *hstate_vma(struct vm_area_struct *vma) + { + return hstate_file(vma->vm_file); +@@ -348,11 +354,12 @@ static inline int hstate_index(struct hs + return h - hstates; + } + +-#else ++#else /* CONFIG_HUGETLB_PAGE */ + struct hstate {}; + #define alloc_huge_page_node(h, nid) NULL + #define alloc_bootmem_huge_page(h) NULL + #define hstate_file(f) NULL ++#define hstate_sizelog(s) NULL + #define hstate_vma(v) NULL + #define hstate_inode(i) NULL + #define huge_page_size(h) PAGE_SIZE +@@ -367,6 +374,6 @@ static inline unsigned int pages_per_hug + } + #define hstate_index_to_shift(index) 0 + #define hstate_index(h) 0 +-#endif ++#endif /* CONFIG_HUGETLB_PAGE */ + + #endif /* _LINUX_HUGETLB_H */ +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -491,10 +491,14 @@ static int newseg(struct ipc_namespace * + + sprintf (name, "SYSV%08x", key); + if (shmflg & SHM_HUGETLB) { ++ struct hstate *hs = hstate_sizelog((shmflg >> SHM_HUGE_SHIFT) ++ & SHM_HUGE_MASK); ++ size_t hugesize = ALIGN(size, huge_page_size(hs)); ++ + /* hugetlb_file_setup applies strict accounting */ + if (shmflg & SHM_NORESERVE) + acctflag = VM_NORESERVE; +- file = hugetlb_file_setup(name, 0, size, acctflag, ++ file = hugetlb_file_setup(name, hugesize, acctflag, + &shp->mlock_user, HUGETLB_SHMFS_INODE, + (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK); + } else { +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -1327,15 +1327,20 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned lon + file = fget(fd); + if (!file) + goto out; ++ if (is_file_hugepages(file)) ++ len = ALIGN(len, huge_page_size(hstate_file(file))); + } else if (flags & MAP_HUGETLB) { + struct user_struct *user = NULL; ++ ++ len = ALIGN(len, huge_page_size(hstate_sizelog( ++ (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK))); + /* + * VM_NORESERVE is used because the reservations will be + * taken when vm_ops->mmap() is called + * A dummy user value is used because we are not locking + * memory so no accounting is necessary + */ +- file = hugetlb_file_setup(HUGETLB_ANON_FILE, addr, len, ++ file = hugetlb_file_setup(HUGETLB_ANON_FILE, len, + VM_NORESERVE, + &user, HUGETLB_ANONHUGE_INODE, + (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK); diff --git a/queue-3.9/series b/queue-3.9/series index 4624ed83853..bf8a28378d3 100644 --- a/queue-3.9/series +++ b/queue-3.9/series @@ -6,3 +6,4 @@ pwm-spear-fix-checking-return-value-of-clk_enable-and-clk_prepare.patch autofs-remove-autofs-dentry-mount-check.patch rpmsg-fix-kconfig-dependencies-for-virtio.patch remoteproc-fix-kconfig-dependencies-for-virtio.patch +hugetlbfs-fix-mmap-failure-in-unaligned-size-request.patch