From 786235eeba0e1e85e5cbbb9f97d1087ad03dfa21 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 12 Nov 2013 15:06:45 -0800 Subject: kthread: make kthread_create() killable Any user process callers of wait_for_completion() except global init process might be chosen by the OOM killer while waiting for completion() call by some other process which does memory allocation. See CVE-2012-4398 "kernel: request_module() OOM local DoS" can happen. When such users are chosen by the OOM killer when they are waiting for completion() in TASK_UNINTERRUPTIBLE, the system will be kept stressed due to memory starvation because the OOM killer cannot kill such users. kthread_create() is one of such users and this patch fixes the problem for kthreadd by making kthread_create() killable - the same approach used for fixing CVE-2012-4398. Signed-off-by: Tetsuo Handa Cc: Oleg Nesterov Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/kthread.c b/kernel/kthread.c index 760e86d..b5ae3ee 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -33,7 +33,7 @@ struct kthread_create_info /* Result passed back to kthread_create() from kthreadd. */ struct task_struct *result; - struct completion done; + struct completion *done; struct list_head list; }; @@ -178,6 +178,7 @@ static int kthread(void *_create) struct kthread_create_info *create = _create; int (*threadfn)(void *data) = create->threadfn; void *data = create->data; + struct completion *done; struct kthread self; int ret; @@ -187,10 +188,16 @@ static int kthread(void *_create) init_completion(&self.parked); current->vfork_done = &self.exited; + /* If user was SIGKILLed, I release the structure. */ + done = xchg(&create->done, NULL); + if (!done) { + kfree(create); + do_exit(-EINTR); + } /* OK, tell user we're spawned, wait for stop or wakeup */ __set_current_state(TASK_UNINTERRUPTIBLE); create->result = current; - complete(&create->done); + complete(done); schedule(); ret = -EINTR; @@ -223,8 +230,15 @@ static void create_kthread(struct kthread_create_info *create) /* We want our own signal handler (we take no signals by default). */ pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD); if (pid < 0) { + /* If user was SIGKILLed, I release the structure. */ + struct completion *done = xchg(&create->done, NULL); + + if (!done) { + kfree(create); + return; + } create->result = ERR_PTR(pid); - complete(&create->done); + complete(done); } } @@ -255,36 +269,59 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), const char namefmt[], ...) { - struct kthread_create_info create; - - create.threadfn = threadfn; - create.data = data; - create.node = node; - init_completion(&create.done); + DECLARE_COMPLETION_ONSTACK(done); + struct task_struct *task; + struct kthread_create_info *create = kmalloc(sizeof(*create), + GFP_KERNEL); + + if (!create) + return ERR_PTR(-ENOMEM); + create->threadfn = threadfn; + create->data = data; + create->node = node; + create->done = &done; spin_lock(&kthread_create_lock); - list_add_tail(&create.list, &kthread_create_list); + list_add_tail(&create->list, &kthread_create_list); spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task); - wait_for_completion(&create.done); - - if (!IS_ERR(create.result)) { + /* + * Wait for completion in killable state, for I might be chosen by + * the OOM killer while kthreadd is trying to allocate memory for + * new kernel thread. + */ + if (unlikely(wait_for_completion_killable(&done))) { + /* + * If I was SIGKILLed before kthreadd (or new kernel thread) + * calls complete(), leave the cleanup of this structure to + * that thread. + */ + if (xchg(&create->done, NULL)) + return ERR_PTR(-ENOMEM); + /* + * kthreadd (or new kernel thread) will call complete() + * shortly. + */ + wait_for_completion(&done); + } + task = create->result; + if (!IS_ERR(task)) { static const struct sched_param param = { .sched_priority = 0 }; va_list args; va_start(args, namefmt); - vsnprintf(create.result->comm, sizeof(create.result->comm), - namefmt, args); + vsnprintf(task->comm, sizeof(task->comm), namefmt, args); va_end(args); /* * root may have changed our (kthreadd's) priority or CPU mask. * The kernel thread should not inherit these properties. */ - sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m); - set_cpus_allowed_ptr(create.result, cpu_all_mask); + sched_setscheduler_nocheck(task, SCHED_NORMAL, ¶m); + set_cpus_allowed_ptr(task, cpu_all_mask); } - return create.result; + kfree(create); + return task; } EXPORT_SYMBOL(kthread_create_on_node); -- cgit v0.10.2 From 42b43341b045227c5ffca04c2d9424c77abed4fb Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 12 Nov 2013 15:06:46 -0800 Subject: sh64: kernel: use 'usp' instead of 'fn' 'fn' is not defined, according to the implementation copy_thread() in 'sh32', need use 'usp' instead of. Signed-off-by: Chen Gang Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 174d124..eac5947 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -393,7 +393,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, if (unlikely(p->flags & PF_KTHREAD)) { memset(childregs, 0, sizeof(struct pt_regs)); childregs->regs[2] = (unsigned long)arg; - childregs->regs[3] = (unsigned long)fn; + childregs->regs[3] = (unsigned long)usp; childregs->sr = (1 << 30); /* not user_mode */ childregs->sr |= SR_FD; /* Invalidate FPU flag */ p->thread.pc = (unsigned long) ret_from_kernel_thread; -- cgit v0.10.2 From 8d28df813e5077913a60c61aaef2e6bf940d8cd9 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 12 Nov 2013 15:06:48 -0800 Subject: sh64: kernel: remove useless variable 'regs' Remove useless variable 'regs' to avoid the related warnings (warning is treated as error). Signed-off-by: Chen Gang Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index eac5947..e2062e6 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -374,7 +374,7 @@ asmlinkage void ret_from_kernel_thread(void); int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, struct task_struct *p) { - struct pt_regs *childregs, *regs = current_pt_regs(); + struct pt_regs *childregs; #ifdef CONFIG_SH_FPU /* can't happen for a kernel thread */ -- cgit v0.10.2 From 72a0c5571351f5184195754d23db3e14495b2080 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Nov 2013 15:06:49 -0800 Subject: cris: media platform drivers: fix build On cris arch, the functions below aren't defined: drivers/media/platform/sh_veu.c: In function 'sh_veu_reg_read': drivers/media/platform/sh_veu.c:228:2: error: implicit declaration of function 'ioread32' [-Werror=implicit-function-declaration] drivers/media/platform/sh_veu.c: In function 'sh_veu_reg_write': drivers/media/platform/sh_veu.c:234:2: error: implicit declaration of function 'iowrite32' [-Werror=implicit-function-declaration] drivers/media/platform/vsp1/vsp1.h: In function 'vsp1_read': drivers/media/platform/vsp1/vsp1.h:66:2: error: implicit declaration of function 'ioread32' [-Werror=implicit-function-declaration] drivers/media/platform/vsp1/vsp1.h: In function 'vsp1_write': drivers/media/platform/vsp1/vsp1.h:71:2: error: implicit declaration of function 'iowrite32' [-Werror=implicit-function-declaration] drivers/media/platform/vsp1/vsp1.h: In function 'vsp1_read': drivers/media/platform/vsp1/vsp1.h:66:2: error: implicit declaration of function 'ioread32' [-Werror=implicit-function-declaration] drivers/media/platform/vsp1/vsp1.h: In function 'vsp1_write': drivers/media/platform/vsp1/vsp1.h:71:2: error: implicit declaration of function 'iowrite32' [-Werror=implicit-function-declaration] drivers/media/platform/soc_camera/rcar_vin.c: In function 'rcar_vin_setup': drivers/media/platform/soc_camera/rcar_vin.c:284:3: error: implicit declaration of function 'iowrite32' [-Werror=implicit-function-declaration] drivers/media/platform/soc_camera/rcar_vin.c: In function 'rcar_vin_request_capture_stop': drivers/media/platform/soc_camera/rcar_vin.c:353:2: error: implicit declaration of function 'ioread32' [-Werror=implicit-function-declaration] Yet, they're available, as CONFIG_GENERIC_IOMAP is defined. What happens is that asm/io.h was not including asm-generic/iomap.h. Suggested-by: Ben Hutchings Signed-off-by: Mauro Carvalho Chehab Cc: Mikael Starvik Cc: Jesper Nilsson Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/cris/include/asm/io.h b/arch/cris/include/asm/io.h index 5d3047e..4353cf2 100644 --- a/arch/cris/include/asm/io.h +++ b/arch/cris/include/asm/io.h @@ -3,6 +3,7 @@ #include /* for __va, __pa */ #include +#include #include struct cris_io_operations -- cgit v0.10.2 From a2529ad9e5bed1935ac30cbe5b53de805485b171 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:06:50 -0800 Subject: drivers/iommu/omap-iopgtable.h: remove unneeded cast of void* Signed-off-by: Jingoo Han Cc: Joerg Roedel Cc: Tony Lindgren Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h index f4003d5..b6f9a51 100644 --- a/drivers/iommu/omap-iopgtable.h +++ b/drivers/iommu/omap-iopgtable.h @@ -95,4 +95,4 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask) #define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da)) #define to_iommu(dev) \ - ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))) + (platform_get_drvdata(to_platform_device(dev))) -- cgit v0.10.2 From 59c36455d061e200f386e1817362f6afd6265b6a Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 12 Nov 2013 15:06:51 -0800 Subject: scripts/sortextable: support objects with more than 64K sections. Building with a large config and -ffunction-sections results in a large number of sections and sortextable needs to be able to handle that. Implement support for > 64K sections as modpost does. Signed-off-by: Jamie Iles Cc: Rusty Russell Cc: Michal Marek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/sortextable.c b/scripts/sortextable.c index 7c2310c..5f7a8b6 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c @@ -152,6 +152,30 @@ static void (*w2)(uint16_t, uint16_t *); typedef void (*table_sort_t)(char *, int); +/* + * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of + * the way to -256..-1, to avoid conflicting with real section + * indices. + */ +#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) + +static inline int is_shndx_special(unsigned int i) +{ + return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; +} + +/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ +static inline unsigned int get_secindex(unsigned int shndx, + unsigned int sym_offs, + const Elf32_Word *symtab_shndx_start) +{ + if (is_shndx_special(shndx)) + return SPECIAL(shndx); + if (shndx != SHN_XINDEX) + return shndx; + return r(&symtab_shndx_start[sym_offs]); +} + /* 32 bit and 64 bit are very similar */ #include "sortextable.h" #define SORTEXTABLE_64 diff --git a/scripts/sortextable.h b/scripts/sortextable.h index f5eb43d..8fac3fd 100644 --- a/scripts/sortextable.h +++ b/scripts/sortextable.h @@ -98,6 +98,8 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) Elf_Shdr *symtab_sec = NULL; Elf_Shdr *extab_sec = NULL; Elf_Sym *sym; + const Elf_Sym *symtab; + Elf32_Word *symtab_shndx_start = NULL; Elf_Sym *sort_needed_sym; Elf_Shdr *sort_needed_sec; Elf_Rel *relocs = NULL; @@ -109,11 +111,22 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) int extab_index = 0; int i; int idx; + unsigned int num_sections; + unsigned int secindex_strings; shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); - shstrtab_sec = shdr + r2(&ehdr->e_shstrndx); + + num_sections = r2(&ehdr->e_shnum); + if (num_sections == SHN_UNDEF) + num_sections = _r(&shdr[0].sh_size); + + secindex_strings = r2(&ehdr->e_shstrndx); + if (secindex_strings == SHN_XINDEX) + secindex_strings = r(&shdr[0].sh_link); + + shstrtab_sec = shdr + secindex_strings; secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); - for (i = 0; i < r2(&ehdr->e_shnum); i++) { + for (i = 0; i < num_sections; i++) { idx = r(&shdr[i].sh_name); if (strcmp(secstrtab + idx, "__ex_table") == 0) { extab_sec = shdr + i; @@ -129,6 +142,9 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) symtab_sec = shdr + i; if (strcmp(secstrtab + idx, ".strtab") == 0) strtab_sec = shdr + i; + if (r(&shdr[i].sh_type) == SHT_SYMTAB_SHNDX) + symtab_shndx_start = (Elf32_Word *)( + (const char *)ehdr + _r(&shdr[i].sh_offset)); } if (strtab_sec == NULL) { fprintf(stderr, "no .strtab in file: %s\n", fname); @@ -138,6 +154,8 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) fprintf(stderr, "no .symtab in file: %s\n", fname); fail_file(); } + symtab = (const Elf_Sym *)((const char *)ehdr + + _r(&symtab_sec->sh_offset)); if (extab_sec == NULL) { fprintf(stderr, "no __ex_table in file: %s\n", fname); fail_file(); @@ -176,7 +194,9 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) fname); fail_file(); } - sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)]; + sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx), + sort_needed_sym - symtab, + symtab_shndx_start)]; sort_done_location = (void *)ehdr + _r(&sort_needed_sec->sh_offset) + _r(&sort_needed_sym->st_value) - -- cgit v0.10.2 From 06f9da6e826a0b459652b98a21541bca274bd440 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Tue, 12 Nov 2013 15:06:52 -0800 Subject: fs/ocfs2: remove unnecessary variable bits_wanted from ocfs2_calc_extend_credits Code cleanup to remove unnecessary variable passed but never used to ocfs2_calc_extend_credits. Signed-off-by: Goldwyn Rodrigues Cc: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index f37d3c0..c0d4797 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -1802,8 +1802,7 @@ try_again: data_ac->ac_resv = &OCFS2_I(inode)->ip_la_data_resv; credits = ocfs2_calc_extend_credits(inode->i_sb, - &di->id2.i_list, - clusters_to_alloc); + &di->id2.i_list); } diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 30544ce..93b0791 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -3284,7 +3284,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, if (ocfs2_dir_resv_allowed(osb)) data_ac->ac_resv = &OCFS2_I(dir)->ip_la_data_resv; - credits = ocfs2_calc_extend_credits(sb, el, 1); + credits = ocfs2_calc_extend_credits(sb, el); } else { spin_unlock(&OCFS2_I(dir)->ip_lock); credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; @@ -3716,7 +3716,7 @@ static int ocfs2_dx_dir_rebalance_credits(struct ocfs2_super *osb, { int credits = ocfs2_clusters_to_blocks(osb->sb, 2); - credits += ocfs2_calc_extend_credits(osb->sb, &dx_root->dr_list, 1); + credits += ocfs2_calc_extend_credits(osb->sb, &dx_root->dr_list); credits += ocfs2_quota_trans_credits(osb->sb); return credits; } diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index d71903c..67c037a 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -603,8 +603,7 @@ restart_all: goto leave; } - credits = ocfs2_calc_extend_credits(osb->sb, &fe->id2.i_list, - clusters_to_add); + credits = ocfs2_calc_extend_credits(osb->sb, &fe->id2.i_list); handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 0b479ba..9ff4e8c 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -524,8 +524,7 @@ static inline int ocfs2_calc_dxi_expand_credits(struct super_block *sb) * the result may be wrong. */ static inline int ocfs2_calc_extend_credits(struct super_block *sb, - struct ocfs2_extent_list *root_el, - u32 bits_wanted) + struct ocfs2_extent_list *root_el) { int bitmap_blocks, sysfile_bitmap_blocks, extent_blocks; diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index 3d3f3c8..445678d 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c @@ -201,8 +201,7 @@ static int ocfs2_lock_allocators_move_extents(struct inode *inode, } } - *credits += ocfs2_calc_extend_credits(osb->sb, et->et_root_el, - clusters_to_move + 2); + *credits += ocfs2_calc_extend_credits(osb->sb, et->et_root_el); mlog(0, "reserve metadata_blocks: %d, data_clusters: %u, credits: %d\n", extra_blocks, clusters_to_move, *credits); diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index bf4dfc1..0022192 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -2502,8 +2502,7 @@ static int ocfs2_calc_refcount_meta_credits(struct super_block *sb, ocfs2_init_refcount_extent_tree(&et, ci, ref_root_bh); *meta_add += ocfs2_extend_meta_needed(et.et_root_el); *credits += ocfs2_calc_extend_credits(sb, - et.et_root_el, - ref_blocks); + et.et_root_el); } else { *credits += OCFS2_EXPAND_REFCOUNT_TREE_CREDITS; *meta_add += 1; @@ -2874,8 +2873,7 @@ static int ocfs2_lock_refcount_allocators(struct super_block *sb, meta_add = ocfs2_extend_meta_needed(et->et_root_el); - *credits += ocfs2_calc_extend_credits(sb, et->et_root_el, - num_clusters + 2); + *credits += ocfs2_calc_extend_credits(sb, et->et_root_el); ret = ocfs2_calc_refcount_meta_credits(sb, ref_ci, ref_root_bh, p_cluster, num_clusters, @@ -3625,8 +3623,7 @@ int ocfs2_refcounted_xattr_delete_need(struct inode *inode, ocfs2_init_refcount_extent_tree(&et, ref_ci, ref_root_bh); *credits += ocfs2_calc_extend_credits(inode->i_sb, - et.et_root_el, - ref_blocks); + et.et_root_el); } out: diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 6ce0686..aaaab8b 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -754,8 +754,7 @@ static int ocfs2_xattr_extend_allocation(struct inode *inode, BUG_ON(why == RESTART_META); credits = ocfs2_calc_extend_credits(inode->i_sb, - &vb->vb_xv->xr_list, - clusters_to_add); + &vb->vb_xv->xr_list); status = ocfs2_extend_trans(handle, credits); if (status < 0) { status = -ENOMEM; @@ -3040,8 +3039,7 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) { clusters_add += new_clusters; credits += ocfs2_calc_extend_credits(inode->i_sb, - &def_xv.xv.xr_list, - new_clusters); + &def_xv.xv.xr_list); } goto meta_guess; @@ -3106,8 +3104,7 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, if (!ocfs2_xattr_is_local(xe)) credits += ocfs2_calc_extend_credits( inode->i_sb, - &def_xv.xv.xr_list, - new_clusters); + &def_xv.xv.xr_list); goto out; } } @@ -3132,9 +3129,7 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, meta_add += ocfs2_extend_meta_needed(&xv->xr_list); clusters_add += new_clusters - old_clusters; credits += ocfs2_calc_extend_credits(inode->i_sb, - &xv->xr_list, - new_clusters - - old_clusters); + &xv->xr_list); if (value_size >= OCFS2_XATTR_ROOT_SIZE) goto out; } @@ -3180,7 +3175,7 @@ meta_guess: &xb->xb_attrs.xb_root.xt_list; meta_add += ocfs2_extend_meta_needed(el); credits += ocfs2_calc_extend_credits(inode->i_sb, - el, 1); + el); } else credits += OCFS2_SUBALLOC_ALLOC + 1; @@ -6216,8 +6211,7 @@ static int ocfs2_value_metas_in_xattr_header(struct super_block *sb, le16_to_cpu(xv->xr_list.l_next_free_rec); *credits += ocfs2_calc_extend_credits(sb, - &def_xv.xv.xr_list, - le32_to_cpu(xv->xr_clusters)); + &def_xv.xv.xr_list); /* * If the value is a tree with depth > 1, We don't go deep @@ -6782,7 +6776,7 @@ static int ocfs2_lock_reflink_xattr_rec_allocators( metas.num_metas += ocfs2_extend_meta_needed(xt_et->et_root_el); *credits += ocfs2_calc_extend_credits(osb->sb, - xt_et->et_root_el, len); + xt_et->et_root_el); if (metas.num_metas) { ret = ocfs2_reserve_new_metadata_blocks(osb, metas.num_metas, -- cgit v0.10.2 From f0cb0f0bca233935ac70707d47f5885419a7fd31 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Tue, 12 Nov 2013 15:06:53 -0800 Subject: fs/ocfs2/file.c: fix wrong comment Unwritten extent only exists for file systems which support holes. But the comment said was opposite meaning and also the comment is not very clear, so rephase it. Signed-off-by: Junxiao Bi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 67c037a..6fff128 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -580,7 +580,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, int did_quota = 0; /* - * This function only exists for file systems which don't + * Unwritten extent only exists for file systems which * support holes. */ BUG_ON(mark_unwritten && !ocfs2_sparse_alloc(osb)); -- cgit v0.10.2 From 7391a294b861bf2c3b762dfdcf61b9c5f1bffa1f Mon Sep 17 00:00:00 2001 From: Rui Xiang Date: Tue, 12 Nov 2013 15:06:54 -0800 Subject: ocfs2: return ENOMEM when sb_getblk() fails The only reason for sb_getblk() failing is if it can't allocate the buffer_head. So return ENOMEM instead when it fails. [joseph.qi@huawei.com: ocfs2_symlink_get_block() and ocfs2_read_blocks_sync() and ocfs2_read_blocks() need the same change] Signed-off-by: Rui Xiang Reviewed-by: Jie Liu Reviewed-by: Mark Fasheh Cc: Joel Becker Cc: Joseph Qi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 17e6bdd..dc7411f 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -1025,7 +1025,7 @@ static int ocfs2_create_new_meta_bhs(handle_t *handle, for(i = count; i < (num_got + count); i++) { bhs[i] = sb_getblk(osb->sb, first_blkno); if (bhs[i] == NULL) { - status = -EIO; + status = -ENOMEM; mlog_errno(status); goto bail; } diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index c0d4797..c203600 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -80,6 +80,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, if ((u64)iblock >= ocfs2_clusters_to_blocks(inode->i_sb, le32_to_cpu(fe->i_clusters))) { + err = -ENOMEM; mlog(ML_ERROR, "block offset is outside the allocated size: " "%llu\n", (unsigned long long)iblock); goto bail; @@ -92,6 +93,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, iblock; buffer_cache_bh = sb_getblk(osb->sb, blkno); if (!buffer_cache_bh) { + err = -ENOMEM; mlog(ML_ERROR, "couldn't getblock for symlink!\n"); goto bail; } diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c index 5d18ad1..5b704c6 100644 --- a/fs/ocfs2/buffer_head_io.c +++ b/fs/ocfs2/buffer_head_io.c @@ -115,7 +115,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block, if (bhs[i] == NULL) { bhs[i] = sb_getblk(osb->sb, block++); if (bhs[i] == NULL) { - status = -EIO; + status = -ENOMEM; mlog_errno(status); goto bail; } @@ -214,7 +214,7 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr, bhs[i] = sb_getblk(sb, block++); if (bhs[i] == NULL) { ocfs2_metadata_cache_io_unlock(ci); - status = -EIO; + status = -ENOMEM; mlog_errno(status); goto bail; } diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 93b0791..91a7e85 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -2349,7 +2349,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, dx_root_bh = sb_getblk(osb->sb, dr_blkno); if (dx_root_bh == NULL) { - ret = -EIO; + ret = -ENOMEM; goto out; } ocfs2_set_new_buffer_uptodate(INODE_CACHE(dir), dx_root_bh); @@ -2422,7 +2422,7 @@ static int ocfs2_dx_dir_format_cluster(struct ocfs2_super *osb, for (i = 0; i < num_dx_leaves; i++) { bh = sb_getblk(osb->sb, start_blk + i); if (bh == NULL) { - ret = -EIO; + ret = -ENOMEM; goto out; } dx_leaves[i] = bh; @@ -2929,7 +2929,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); dirdata_bh = sb_getblk(sb, blkno); if (!dirdata_bh) { - ret = -EIO; + ret = -ENOMEM; mlog_errno(ret); goto out_commit; } @@ -3159,7 +3159,7 @@ static int ocfs2_do_extend_dir(struct super_block *sb, *new_bh = sb_getblk(sb, p_blkno); if (!*new_bh) { - status = -EIO; + status = -ENOMEM; mlog_errno(status); goto bail; } diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index be3f867..4f791f6 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -489,7 +489,7 @@ static int __ocfs2_mknod_locked(struct inode *dir, *new_fe_bh = sb_getblk(osb->sb, fe_blkno); if (!*new_fe_bh) { - status = -EIO; + status = -ENOMEM; mlog_errno(status); goto leave; } diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 0022192..70d083e 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -1310,7 +1310,7 @@ static int ocfs2_expand_inline_ref_root(handle_t *handle, new_bh = sb_getblk(sb, blkno); if (new_bh == NULL) { - ret = -EIO; + ret = -ENOMEM; mlog_errno(ret); goto out; } @@ -1561,7 +1561,7 @@ static int ocfs2_new_leaf_refcount_block(handle_t *handle, new_bh = sb_getblk(sb, blkno); if (new_bh == NULL) { - ret = -EIO; + ret = -ENOMEM; mlog_errno(ret); goto out; } @@ -3029,7 +3029,7 @@ int ocfs2_duplicate_clusters_by_jbd(handle_t *handle, for (i = 0; i < blocks; i++, old_block++, new_block++) { new_bh = sb_getblk(osb->sb, new_block); if (new_bh == NULL) { - ret = -EIO; + ret = -ENOMEM; mlog_errno(ret); break; } diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 5397c07..2c91452 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -481,7 +481,7 @@ ocfs2_block_group_alloc_contig(struct ocfs2_super *osb, handle_t *handle, bg_bh = sb_getblk(osb->sb, bg_blkno); if (!bg_bh) { - status = -EIO; + status = -ENOMEM; mlog_errno(status); goto bail; } @@ -661,7 +661,7 @@ ocfs2_block_group_alloc_discontig(handle_t *handle, bg_bh = sb_getblk(osb->sb, bg_blkno); if (!bg_bh) { - status = -EIO; + status = -ENOMEM; mlog_errno(status); goto bail; } diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index d4e81e4..c414929 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1848,8 +1848,8 @@ static int ocfs2_get_sector(struct super_block *sb, *bh = sb_getblk(sb, block); if (!*bh) { - mlog_errno(-EIO); - return -EIO; + mlog_errno(-ENOMEM); + return -ENOMEM; } lock_buffer(*bh); if (!buffer_dirty(*bh)) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index aaaab8b..8225729 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -377,7 +377,7 @@ static int ocfs2_init_xattr_bucket(struct ocfs2_xattr_bucket *bucket, bucket->bu_bhs[i] = sb_getblk(bucket->bu_inode->i_sb, xb_blkno + i); if (!bucket->bu_bhs[i]) { - rc = -EIO; + rc = -ENOMEM; mlog_errno(rc); break; } -- cgit v0.10.2 From 58796207cf09552706b0c3e0669f2ce52ea6cee1 Mon Sep 17 00:00:00 2001 From: Rui Xiang Date: Tue, 12 Nov 2013 15:06:55 -0800 Subject: ocfs2: add necessary check in case sb_getblk() fails sb_getblk() may return an err, so add a check for bh. [joseph.qi@huawei.com: also add a check after calling sb_getblk() in ocfs2_create_xattr_block()] Signed-off-by: Rui Xiang Reviewed-by: Jie Liu Reviewed-by: Mark Fasheh Cc: Joel Becker Cc: Joseph Qi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 70d083e..55767e1 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -612,6 +612,11 @@ static int ocfs2_create_refcount_tree(struct inode *inode, } new_bh = sb_getblk(inode->i_sb, first_blkno); + if (!new_bh) { + ret = -ENOMEM; + mlog_errno(ret); + goto out_commit; + } ocfs2_set_new_buffer_uptodate(&new_tree->rf_ci, new_bh); ret = ocfs2_journal_access_rb(handle, &new_tree->rf_ci, new_bh, diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 8225729..f0a1326 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -2864,6 +2864,12 @@ static int ocfs2_create_xattr_block(struct inode *inode, } new_bh = sb_getblk(inode->i_sb, first_blkno); + if (!new_bh) { + ret = -ENOMEM; + mlog_errno(ret); + goto end; + } + ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), new_bh); ret = ocfs2_journal_access_xb(ctxt->handle, INODE_CACHE(inode), -- cgit v0.10.2 From 910bffe0861c956096c31ad7e887cc23169955ed Mon Sep 17 00:00:00 2001 From: Joel Becker Date: Tue, 12 Nov 2013 15:06:57 -0800 Subject: ocfs2: don't spam on -EDQUOT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -EDQUOT is a user-visible error, not a logic problem. Teach mlog_errno() to ignore it like it ignores -ENOSPC, etc. Signed-off-by: Joel Becker Reviewed-by: Jan Kara Reported-by: Marek Królikowski Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index baa2b9e..2260fb9 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h @@ -199,7 +199,8 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits; #define mlog_errno(st) do { \ int _st = (st); \ if (_st != -ERESTARTSYS && _st != -EINTR && \ - _st != AOP_TRUNCATED_PAGE && _st != -ENOSPC) \ + _st != AOP_TRUNCATED_PAGE && _st != -ENOSPC && \ + _st != -EDQUOT) \ mlog(ML_ERROR, "status = %lld\n", (long long)_st); \ } while (0) -- cgit v0.10.2 From a8f70de37bbb991033208edff7758d997d68db37 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 12 Nov 2013 15:06:58 -0800 Subject: ocfs2: use bitmap_weight() Use bitmap_weight() instead of reinventing the wheel. Signed-off-by: Akinobu Mita Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 363f0dc..292a13b 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "heartbeat.h" #include "tcp.h" @@ -282,15 +283,6 @@ struct o2hb_bio_wait_ctxt { int wc_error; }; -static int o2hb_pop_count(void *map, int count) -{ - int i = -1, pop = 0; - - while ((i = find_next_bit(map, count, i + 1)) < count) - pop++; - return pop; -} - static void o2hb_write_timeout(struct work_struct *work) { int failed, quorum; @@ -307,9 +299,9 @@ static void o2hb_write_timeout(struct work_struct *work) spin_lock_irqsave(&o2hb_live_lock, flags); if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap)) set_bit(reg->hr_region_num, o2hb_failed_region_bitmap); - failed = o2hb_pop_count(&o2hb_failed_region_bitmap, + failed = bitmap_weight(o2hb_failed_region_bitmap, O2NM_MAX_REGIONS); - quorum = o2hb_pop_count(&o2hb_quorum_region_bitmap, + quorum = bitmap_weight(o2hb_quorum_region_bitmap, O2NM_MAX_REGIONS); spin_unlock_irqrestore(&o2hb_live_lock, flags); @@ -765,7 +757,7 @@ static void o2hb_set_quorum_device(struct o2hb_region *reg) * If global heartbeat active, unpin all regions if the * region count > CUT_OFF */ - if (o2hb_pop_count(&o2hb_quorum_region_bitmap, + if (bitmap_weight(o2hb_quorum_region_bitmap, O2NM_MAX_REGIONS) > O2HB_PIN_CUT_OFF) o2hb_region_unpin(NULL); unlock: @@ -1829,7 +1821,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, live_threshold = O2HB_LIVE_THRESHOLD; if (o2hb_global_heartbeat_active()) { spin_lock(&o2hb_live_lock); - if (o2hb_pop_count(&o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1) + if (bitmap_weight(o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1) live_threshold <<= 1; spin_unlock(&o2hb_live_lock); } @@ -2180,7 +2172,7 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group, if (!o2hb_dependent_users) goto unlock; - if (o2hb_pop_count(&o2hb_quorum_region_bitmap, + if (bitmap_weight(o2hb_quorum_region_bitmap, O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF) o2hb_region_pin(NULL); @@ -2480,7 +2472,7 @@ static int o2hb_region_inc_user(const char *region_uuid) if (o2hb_dependent_users > 1) goto unlock; - if (o2hb_pop_count(&o2hb_quorum_region_bitmap, + if (bitmap_weight(o2hb_quorum_region_bitmap, O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF) ret = o2hb_region_pin(NULL); -- cgit v0.10.2 From 750e3c6581304c7dff813ac2317f5d733f84cb23 Mon Sep 17 00:00:00 2001 From: Xue jiufei Date: Tue, 12 Nov 2013 15:06:59 -0800 Subject: ocfs2: skip locks in the blocked list A parallel umount on 4 nodes triggered a bug in dlm_process_recovery_date(). Here's the situation: Receiving MIG_LOCKRES message, A node processes the locks in migratable lockres. It copys lvb from migratable lockres when processing the first valid lock. If there is a lock in the blocked list with the EX level, it triggers the BUG. Since valid lvbs are set when locks are granted with EX or PR levels, locks in the blocked list cannot have valid lvbs. Therefore I think we should skip the locks in the blocked list. Signed-off-by: Xuejiufei Signed-off-by: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 0b5adca..7035af0 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -1886,6 +1886,13 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, if (ml->type == LKM_NLMODE) goto skip_lvb; + /* + * If the lock is in the blocked list it can't have a valid lvb, + * so skip it + */ + if (ml->list == DLM_BLOCKED_LIST) + goto skip_lvb; + if (!dlm_lvb_is_empty(mres->lvb)) { if (lksb->flags & DLM_LKSB_PUT_LVB) { /* other node was trying to update -- cgit v0.10.2 From fae477b6f005d6bd8a6fb3f052b30d55cfa70c26 Mon Sep 17 00:00:00 2001 From: Xue jiufei Date: Tue, 12 Nov 2013 15:07:00 -0800 Subject: ocfs2: delay migration when the lockres is in migration state We trigger a bug in __dlm_lockres_reserve_ast() when we parallel umount 4 nodes. The situation is as follows: 1) Node A migrate all lockres it owned(eg. lockres A) to other nodes say node B when it umounts. 2) Receiving MIG_LOCKRES message from A, Node B masters the lockres A with DLM_LOCK_RES_MIGRATING state set. 3) Then we umount ocfs2 on node B. It also should migrate lockres A to another node, say node C. But now, DLM_LOCK_RES_MIGRATING state of lockers A is not cleared. Node B triggered the BUG on lockres with state DLM_LOCK_RES_MIGRATING. Signed-off-by: Xuejiufei Signed-off-by: Joel Becker Cc: Mark Fasheh Cc: Tariq Saeed Cc: Srinivas Eeda Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index cf0f103..5a0ef78 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -2354,6 +2354,10 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, assert_spin_locked(&res->spinlock); + /* delay migration when the lockres is in MIGRATING state */ + if (res->state & DLM_LOCK_RES_MIGRATING) + return 0; + if (res->owner != dlm->node_num) return 0; -- cgit v0.10.2 From 518df6bdf38559247ee90b9e59a40fae779d57d0 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 12 Nov 2013 15:07:01 -0800 Subject: ocfs2: use find_last_bit() We already have find_last_bit(). So just use it as described in the comment. Signed-off-by: Akinobu Mita Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 292a13b..73920ff 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -946,23 +946,9 @@ out: return changed; } -/* This could be faster if we just implmented a find_last_bit, but I - * don't think the circumstances warrant it. */ -static int o2hb_highest_node(unsigned long *nodes, - int numbits) +static int o2hb_highest_node(unsigned long *nodes, int numbits) { - int highest, node; - - highest = numbits; - node = -1; - while ((node = find_next_bit(nodes, numbits, node + 1)) != -1) { - if (node >= numbits) - break; - - highest = node; - } - - return highest; + return find_last_bit(nodes, numbits); } static int o2hb_do_disk_heartbeat(struct o2hb_region *reg) -- cgit v0.10.2 From 728b98059a2f19393f906ba4febc0f2d1d15f280 Mon Sep 17 00:00:00 2001 From: Junxiao Bi Date: Tue, 12 Nov 2013 15:07:02 -0800 Subject: ocfs2: break useless while loop Signed-off-by: Junxiao Bi Signed-off-by: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 5a0ef78..af3f7aa 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -1885,8 +1885,10 @@ ok: * up nodes that this node contacted */ while ((nn = find_next_bit (mle->response_map, O2NM_MAX_NODES, nn+1)) < O2NM_MAX_NODES) { - if (nn != dlm->node_num && nn != assert->node_idx) + if (nn != dlm->node_num && nn != assert->node_idx) { master_request = 1; + break; + } } } mle->master = assert->node_idx; -- cgit v0.10.2 From eedd40e1cad4217c9b7e2577debcdd0c48732cc3 Mon Sep 17 00:00:00 2001 From: Younger Liu Date: Tue, 12 Nov 2013 15:07:03 -0800 Subject: ocfs2: rollback transaction in ocfs2_group_add() If ocfs2_journal_access_di() fails, group->bg_next_group should rollback. Otherwise, there would be a inconsistency between group_bh and main_bm_bh. Signed-off-by: Younger Liu Cc: Mark Fasheh Acked-by: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c index ec55add..376750f 100644 --- a/fs/ocfs2/resize.c +++ b/fs/ocfs2/resize.c @@ -469,6 +469,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) struct ocfs2_chain_list *cl; struct ocfs2_chain_rec *cr; u16 cl_bpc; + u64 bg_ptr; if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) return -EROFS; @@ -538,12 +539,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) } group = (struct ocfs2_group_desc *)group_bh->b_data; + bg_ptr = le64_to_cpu(group->bg_next_group); group->bg_next_group = cr->c_blkno; ocfs2_journal_dirty(handle, group_bh); ret = ocfs2_journal_access_di(handle, INODE_CACHE(main_bm_inode), main_bm_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret < 0) { + group->bg_next_group = cpu_to_le64(bg_ptr); mlog_errno(ret); goto out_commit; } -- cgit v0.10.2 From 8abaae8d85d4e1de0fcc81b733ba04a5d318ba7a Mon Sep 17 00:00:00 2001 From: Younger Liu Date: Tue, 12 Nov 2013 15:07:04 -0800 Subject: ocfs2: do not call brelse() if group_bh is not initialized in ocfs2_group_add() If group_bh is not initialized, there is no need to release. This problem does not cause anything wrong, but the patch would make the code more logical. Signed-off-by: Younger Liu Cc: Mark Fasheh Acked-by: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c index 376750f..822ebc1 100644 --- a/fs/ocfs2/resize.c +++ b/fs/ocfs2/resize.c @@ -514,7 +514,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); if (ret) { mlog_errno(ret); - goto out_unlock; + goto out_free_group_bh; } trace_ocfs2_group_add((unsigned long long)input->group, @@ -524,7 +524,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) if (IS_ERR(handle)) { mlog_errno(PTR_ERR(handle)); ret = -EINVAL; - goto out_unlock; + goto out_free_group_bh; } cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); @@ -577,8 +577,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) out_commit: ocfs2_commit_trans(osb, handle); -out_unlock: + +out_free_group_bh: brelse(group_bh); + +out_unlock: brelse(main_bm_bh); ocfs2_inode_unlock(main_bm_inode, 1); -- cgit v0.10.2 From bfbca926d67c9bf3212d1077c6afd48d2995a285 Mon Sep 17 00:00:00 2001 From: Younger Liu Date: Tue, 12 Nov 2013 15:07:05 -0800 Subject: ocfs2: add missing errno in ocfs2_ioctl_move_extents() If the file is not regular or writeable, it should return errno(EPERM). This patch is based on 85a258b70d ("ocfs2: fix error handling in ocfs2_ioctl_move_extents()"). Signed-off-by: Younger Liu Signed-off-by: Jie Liu Reviewed-by: Dan Carpenter Reviewed-by: Jie Liu Cc: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index 445678d..631a982 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c @@ -1066,8 +1066,10 @@ int ocfs2_ioctl_move_extents(struct file *filp, void __user *argp) if (status) return status; - if ((!S_ISREG(inode->i_mode)) || !(filp->f_mode & FMODE_WRITE)) + if ((!S_ISREG(inode->i_mode)) || !(filp->f_mode & FMODE_WRITE)) { + status = -EPERM; goto out_drop; + } if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) { status = -EPERM; @@ -1089,8 +1091,10 @@ int ocfs2_ioctl_move_extents(struct file *filp, void __user *argp) goto out_free; } - if (range.me_start > i_size_read(inode)) + if (range.me_start > i_size_read(inode)) { + status = -EINVAL; goto out_free; + } if (range.me_start + range.me_len > i_size_read(inode)) range.me_len = i_size_read(inode) - range.me_start; -- cgit v0.10.2 From b1214e4757b7d5fcea483b927e130361d41430a5 Mon Sep 17 00:00:00 2001 From: Xue jiufei Date: Tue, 12 Nov 2013 15:07:06 -0800 Subject: ocfs2: fix possible double free in ocfs2_write_begin_nolock When ocfs2_write_cluster_by_desc() failed in ocfs2_write_begin_nolock() because of ENOSPC, it goes to out_quota, freeing data_ac(meta_ac). Then it calls ocfs2_try_to_free_truncate_log() to free space. If enough space freed, it will try to write again. Unfortunately, some error happenes before ocfs2_lock_allocators(), it goes to out and free data_ac(meta_ac) again. Signed-off-by: joyce Reviewed-by: Jie Liu Acked-by: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index c203600..f959a15 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -1898,10 +1898,14 @@ out_commit: out: ocfs2_free_write_ctxt(wc); - if (data_ac) + if (data_ac) { ocfs2_free_alloc_context(data_ac); - if (meta_ac) + data_ac = NULL; + } + if (meta_ac) { ocfs2_free_alloc_context(meta_ac); + meta_ac = NULL; + } if (ret == -ENOSPC && try_free) { /* -- cgit v0.10.2 From d00d2f8ab9f20f8e6a0fc3804847b418498d80b8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:07:07 -0800 Subject: ocfs2: convert use of typedef ctl_table to struct ctl_table This typedef is unnecessary and should just be removed. Signed-off-by: Joe Perches Cc: Mark Fasheh Acked-by: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index 39abf89..cb7ec0b 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c @@ -643,7 +643,7 @@ error: #define FS_OCFS2_NM 1 -static ctl_table ocfs2_nm_table[] = { +static struct ctl_table ocfs2_nm_table[] = { { .procname = "hb_ctl_path", .data = ocfs2_hb_ctl_path, @@ -654,7 +654,7 @@ static ctl_table ocfs2_nm_table[] = { { } }; -static ctl_table ocfs2_mod_table[] = { +static struct ctl_table ocfs2_mod_table[] = { { .procname = "nm", .data = NULL, @@ -665,7 +665,7 @@ static ctl_table ocfs2_mod_table[] = { { } }; -static ctl_table ocfs2_kern_table[] = { +static struct ctl_table ocfs2_kern_table[] = { { .procname = "ocfs2", .data = NULL, @@ -676,7 +676,7 @@ static ctl_table ocfs2_kern_table[] = { { } }; -static ctl_table ocfs2_root_table[] = { +static struct ctl_table ocfs2_root_table[] = { { .procname = "fs", .data = NULL, -- cgit v0.10.2 From 41ecc345984bcc8bf341a3e758c1eb3fc543dd83 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 12 Nov 2013 15:07:08 -0800 Subject: ocfs2: simplify ocfs2_invalidatepage() and ocfs2_releasepage() Ocfs2 doesn't do data journalling. Thus its ->invalidatepage and ->releasepage functions never get called on buffers that have journal heads attached. So just use standard variants of functions from buffer.c. Signed-off-by: Jan Kara Cc: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index f959a15..aeb44e8 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -594,26 +594,11 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, ocfs2_rw_unlock(inode, level); } -/* - * ocfs2_invalidatepage() and ocfs2_releasepage() are shamelessly stolen - * from ext3. PageChecked() bits have been removed as OCFS2 does not - * do journalled data. - */ -static void ocfs2_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) -{ - journal_t *journal = OCFS2_SB(page->mapping->host->i_sb)->journal->j_journal; - - jbd2_journal_invalidatepage(journal, page, offset, length); -} - static int ocfs2_releasepage(struct page *page, gfp_t wait) { - journal_t *journal = OCFS2_SB(page->mapping->host->i_sb)->journal->j_journal; - if (!page_has_buffers(page)) return 0; - return jbd2_journal_try_to_free_buffers(journal, page, wait); + return try_to_free_buffers(page); } static ssize_t ocfs2_direct_IO(int rw, @@ -2092,7 +2077,7 @@ const struct address_space_operations ocfs2_aops = { .write_end = ocfs2_write_end, .bmap = ocfs2_bmap, .direct_IO = ocfs2_direct_IO, - .invalidatepage = ocfs2_invalidatepage, + .invalidatepage = block_invalidatepage, .releasepage = ocfs2_releasepage, .migratepage = buffer_migrate_page, .is_partially_uptodate = block_is_partially_uptodate, -- cgit v0.10.2 From 63d0f0a3c7e1281fd79268a8d988167eff607fb6 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 12 Nov 2013 15:07:09 -0800 Subject: mm/readahead.c:do_readhead(): don't check for ->readpage The callee force_page_cache_readahead() already does this and unlike do_readahead(), force_page_cache_readahead() remembers to check for ->readpages() as well. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/readahead.c b/mm/readahead.c index e4ed041..5024183 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -569,7 +569,7 @@ static ssize_t do_readahead(struct address_space *mapping, struct file *filp, pgoff_t index, unsigned long nr) { - if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage) + if (!mapping || !mapping->a_ops) return -EINVAL; force_page_cache_readahead(mapping, filp, index, nr); -- cgit v0.10.2 From bafe1e14403ad40714ffcfa1fb173b371cc87a1f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:07:10 -0800 Subject: ksm: remove redundant __GFP_ZERO from kcalloc kcalloc returns zeroed memory. There's no need to use this flag. Signed-off-by: Joe Perches Reviewed-by: Wanpeng Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/ksm.c b/mm/ksm.c index 0bea2b2..175fff7 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -2309,8 +2309,8 @@ static ssize_t merge_across_nodes_store(struct kobject *kobj, * Allocate stable and unstable together: * MAXSMP NODES_SHIFT 10 will use 16kB. */ - buf = kcalloc(nr_node_ids + nr_node_ids, - sizeof(*buf), GFP_KERNEL | __GFP_ZERO); + buf = kcalloc(nr_node_ids + nr_node_ids, sizeof(*buf), + GFP_KERNEL); /* Let us assume that RB_ROOT is NULL is zero */ if (!buf) err = -ENOMEM; -- cgit v0.10.2 From 4b90951c0bd8ca6695837354a253794192f6dfd5 Mon Sep 17 00:00:00 2001 From: Jianguo Wu Date: Tue, 12 Nov 2013 15:07:11 -0800 Subject: mm/vmalloc: use NUMA_NO_NODE Use more appropriate "if (node == NUMA_NO_NODE)" instead of "if (node < 0)" Signed-off-by: Jianguo Wu Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 1074543..dea15e6 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1577,7 +1577,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, struct page *page; gfp_t tmp_mask = gfp_mask | __GFP_NOWARN; - if (node < 0) + if (node == NUMA_NO_NODE) page = alloc_page(tmp_mask); else page = alloc_pages_node(node, tmp_mask, order); -- cgit v0.10.2 From 9e4be4708e9e88da46ae1f0bb1054c3619cc476e Mon Sep 17 00:00:00 2001 From: Jerome Marchand Date: Tue, 12 Nov 2013 15:07:12 -0800 Subject: mm/compaction.c: update comment about zone lock in isolate_freepages_block Since commit f40d1e42bb98 ("mm: compaction: acquire the zone->lock as late as possible"), isolate_freepages_block() takes the zone->lock itself. The function description however still states that the zone->lock must be held. This patch removes this outdated statement. Signed-off-by: Jerome Marchand Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/compaction.c b/mm/compaction.c index b5326b1..805165b 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -235,10 +235,9 @@ static bool suitable_migration_target(struct page *page) } /* - * Isolate free pages onto a private freelist. Caller must hold zone->lock. - * If @strict is true, will abort returning 0 on any invalid PFNs or non-free - * pages inside of the pageblock (even though it may still end up isolating - * some pages). + * Isolate free pages onto a private freelist. If @strict is true, will abort + * returning 0 on any invalid PFNs or non-free pages inside of the pageblock + * (even though it may still end up isolating some pages). */ static unsigned long isolate_freepages_block(struct compact_control *cc, unsigned long blockpfn, -- cgit v0.10.2 From c1ce4b375fa7b76d8b553d4f8d6cc5a09f063691 Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Tue, 12 Nov 2013 15:07:13 -0800 Subject: mm/arch: use __free_reserved_page() to simplify the code Use __free_reserved_page() to simplify the code in arch. It used split_page() in consistent_alloc()/__dma_alloc_coherent()/dma_alloc_coherent(), so page->_count == 1, and we can free it safely. __free_reserved_page() ClearPageReserved() init_page_count() // it won't change the value __free_page() Signed-off-by: Xishi Qiu Cc: James Hogan Cc: Michal Simek Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/metag/kernel/dma.c b/arch/metag/kernel/dma.c index 8c00ded..db589ad 100644 --- a/arch/metag/kernel/dma.c +++ b/arch/metag/kernel/dma.c @@ -305,9 +305,7 @@ void dma_free_coherent(struct device *dev, size_t size, if (pfn_valid(pfn)) { struct page *page = pfn_to_page(pfn); - ClearPageReserved(page); - - __free_page(page); + __free_reserved_page(page); continue; } } diff --git a/arch/microblaze/mm/consistent.c b/arch/microblaze/mm/consistent.c index 5226b09..dbbf224 100644 --- a/arch/microblaze/mm/consistent.c +++ b/arch/microblaze/mm/consistent.c @@ -176,8 +176,7 @@ void consistent_free(size_t size, void *vaddr) page = virt_to_page(vaddr); do { - ClearPageReserved(page); - __free_page(page); + __free_reserved_page(page); page++; } while (size -= PAGE_SIZE); #else @@ -194,9 +193,7 @@ void consistent_free(size_t size, void *vaddr) pte_clear(&init_mm, (unsigned int)vaddr, ptep); if (pfn_valid(pfn)) { page = pfn_to_page(pfn); - - ClearPageReserved(page); - __free_page(page); + __free_reserved_page(page); } } vaddr += PAGE_SIZE; diff --git a/arch/powerpc/mm/dma-noncoherent.c b/arch/powerpc/mm/dma-noncoherent.c index 6747eec..7b6c107 100644 --- a/arch/powerpc/mm/dma-noncoherent.c +++ b/arch/powerpc/mm/dma-noncoherent.c @@ -287,9 +287,7 @@ void __dma_free_coherent(size_t size, void *vaddr) pte_clear(&init_mm, addr, ptep); if (pfn_valid(pfn)) { struct page *page = pfn_to_page(pfn); - - ClearPageReserved(page); - __free_page(page); + __free_reserved_page(page); } } addr += PAGE_SIZE; -- cgit v0.10.2 From 3207d9e72c6227b0a9a2624ae7984b32af5fb288 Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Tue, 12 Nov 2013 15:07:14 -0800 Subject: drivers/video/acornfb.c: use __free_reserved_page() to simplify the code Use __free_reserved_page() to simplify the code in the others. Signed-off-by: Xishi Qiu Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 7e8346e..a305cae 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -949,9 +949,7 @@ free_unused_pages(unsigned int virtual_start, unsigned int virtual_end) * the page. */ page = virt_to_page(virtual_start); - ClearPageReserved(page); - init_page_count(page); - free_page(virtual_start); + __free_reserved_page(page); virtual_start += PAGE_SIZE; mb_freed += PAGE_SIZE / 1024; -- cgit v0.10.2 From c69ded84a968e8ecc529b4de68522e4a2dcbf92a Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Tue, 12 Nov 2013 15:07:15 -0800 Subject: mm: remove obsolete comments about page table lock The callers of free_pgd_range() and hugetlb_free_pgd_range() don't hold page table locks. The comments seems to be obsolete, so let's remove them. Signed-off-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index d67db4b..90bb6d9 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -633,8 +633,6 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd, /* * This function frees user-level page tables of a process. - * - * Must be called with pagetable lock held. */ void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr, unsigned long end, diff --git a/mm/memory.c b/mm/memory.c index 1f2287e..15744b2 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -453,8 +453,6 @@ static inline void free_pud_range(struct mmu_gather *tlb, pgd_t *pgd, /* * This function frees user-level page tables of a process. - * - * Must be called with pagetable lock held. */ void free_pgd_range(struct mmu_gather *tlb, unsigned long addr, unsigned long end, -- cgit v0.10.2 From 8bfa3f9a012c4049f3d661f7a772cd9c27a7da99 Mon Sep 17 00:00:00 2001 From: Jianguo Wu Date: Tue, 12 Nov 2013 15:07:16 -0800 Subject: mm/huge_memory.c: fix stale comments of transparent_hugepage_flags Since commit 13ece886d99c ("thp: transparent hugepage config choice"), transparent hugepage support is disabled by default, and TRANSPARENT_HUGEPAGE_ALWAYS is configured when TRANSPARENT_HUGEPAGE=y. And since commit d39d33c332c6 ("thp: enable direct defrag"), defrag is enable for all transparent hugepage page faults by default, not only in MADV_HUGEPAGE regions. Signed-off-by: Jianguo Wu Reviewed-by: Wanpeng Li Acked-by: Kirill A. Shutemov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 2612f60..4f7e211 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -27,11 +27,12 @@ #include "internal.h" /* - * By default transparent hugepage support is enabled for all mappings - * and khugepaged scans all mappings. Defrag is only invoked by - * khugepaged hugepage allocations and by page faults inside - * MADV_HUGEPAGE regions to avoid the risk of slowing down short lived - * allocations. + * By default transparent hugepage support is disabled in order that avoid + * to risk increase the memory footprint of applications without a guaranteed + * benefit. When transparent hugepage support is enabled, is for all mappings, + * and khugepaged scans all mappings. + * Defrag is invoked by khugepaged hugepage allocations and by page faults + * for all hugepage allocations. */ unsigned long transparent_hugepage_flags __read_mostly = #ifdef CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS -- cgit v0.10.2 From 6408068ee6ce9d80d66908a2c01a24ee88afd47d Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Tue, 12 Nov 2013 15:07:17 -0800 Subject: mm: use pgdat_end_pfn() to simplify the code in arch Use "pgdat_end_pfn()" instead of "pgdat->node_start_pfn + pgdat->node_spanned_pages". Simplify the code, no functional change. Signed-off-by: Xishi Qiu Cc: James Hogan Cc: "Luck, Tony" Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index b6f7f43..88504ab 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -357,9 +357,7 @@ int vmemmap_find_next_valid_pfn(int node, int i) end_address = (unsigned long) &vmem_map[pgdat->node_start_pfn + i]; end_address = PAGE_ALIGN(end_address); - - stop_address = (unsigned long) &vmem_map[ - pgdat->node_start_pfn + pgdat->node_spanned_pages]; + stop_address = (unsigned long) &vmem_map[pgdat_end_pfn(pgdat)]; do { pgd_t *pgd; diff --git a/arch/metag/mm/init.c b/arch/metag/mm/init.c index 249fff6..3cd6288f 100644 --- a/arch/metag/mm/init.c +++ b/arch/metag/mm/init.c @@ -148,7 +148,7 @@ static void __init bootmem_init_one_node(unsigned int nid) if (!p->node_spanned_pages) return; - end_pfn = p->node_start_pfn + p->node_spanned_pages; + end_pfn = pgdat_end_pfn(p); #ifdef CONFIG_HIGHMEM if (end_pfn > max_low_pfn) end_pfn = max_low_pfn; diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 33d6784..078d3e0 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -938,8 +938,7 @@ static void __init mark_reserved_regions_for_nid(int nid) unsigned long start_pfn = physbase >> PAGE_SHIFT; unsigned long end_pfn = PFN_UP(physbase + size); struct node_active_region node_ar; - unsigned long node_end_pfn = node->node_start_pfn + - node->node_spanned_pages; + unsigned long node_end_pfn = pgdat_end_pfn(node); /* * Check to make sure that this memblock.reserved area is diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 33890fd..2d089fe 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -231,7 +231,7 @@ static void __init bootmem_init_one_node(unsigned int nid) if (!p->node_spanned_pages) return; - end_pfn = p->node_start_pfn + p->node_spanned_pages; + end_pfn = pgdat_end_pfn(p); total_pages = bootmem_bootmap_pages(p->node_spanned_pages); -- cgit v0.10.2 From 83285c72e08c42848808039ef2d3b67a1bb88832 Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Tue, 12 Nov 2013 15:07:19 -0800 Subject: mm: use pgdat_end_pfn() to simplify the code in others Use "pgdat_end_pfn()" instead of "pgdat->node_start_pfn + pgdat->node_spanned_pages". Simplify the code, no functional change. Signed-off-by: Xishi Qiu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 06ea155..5ed0e52 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -255,8 +255,7 @@ static int kcore_update_ram(void) end_pfn = 0; for_each_node_state(nid, N_MEMORY) { unsigned long node_end; - node_end = NODE_DATA(nid)->node_start_pfn + - NODE_DATA(nid)->node_spanned_pages; + node_end = node_end_pfn(nid); if (end_pfn < node_end) end_pfn = node_end; } diff --git a/mm/bootmem.c b/mm/bootmem.c index 6ab7744..95b528c 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -784,7 +784,7 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size, return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); /* update goal according ...MAX_DMA32_PFN */ - end_pfn = pgdat->node_start_pfn + pgdat->node_spanned_pages; + end_pfn = pgdat_end_pfn(pgdat); if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) && (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) { diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index ed85fe3..375a42d 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -365,8 +365,7 @@ out_fail: static void grow_pgdat_span(struct pglist_data *pgdat, unsigned long start_pfn, unsigned long end_pfn) { - unsigned long old_pgdat_end_pfn = - pgdat->node_start_pfn + pgdat->node_spanned_pages; + unsigned long old_pgdat_end_pfn = pgdat_end_pfn(pgdat); if (!pgdat->node_spanned_pages || start_pfn < pgdat->node_start_pfn) pgdat->node_start_pfn = start_pfn; @@ -579,9 +578,9 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn, static void shrink_pgdat_span(struct pglist_data *pgdat, unsigned long start_pfn, unsigned long end_pfn) { - unsigned long pgdat_start_pfn = pgdat->node_start_pfn; - unsigned long pgdat_end_pfn = - pgdat->node_start_pfn + pgdat->node_spanned_pages; + unsigned long pgdat_start_pfn = pgdat->node_start_pfn; + unsigned long p = pgdat_end_pfn(pgdat); /* pgdat_end_pfn namespace clash */ + unsigned long pgdat_end_pfn = p; unsigned long pfn; struct mem_section *ms; int nid = pgdat->node_id; -- cgit v0.10.2 From b38a872596dad80bd77d98f5fdbc58cc8f438dbb Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Tue, 12 Nov 2013 15:07:20 -0800 Subject: mm: use populated_zone() instead of if(zone->present_pages) Use "if (zone->present_pages)" instead of "if (zone->present_pages)". Simplify the code, no functional change. Signed-off-by: Xishi Qiu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 73d812f..3d1d75a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4266,7 +4266,7 @@ static __meminit void zone_pcp_init(struct zone *zone) */ zone->pageset = &boot_pageset; - if (zone->present_pages) + if (populated_zone(zone)) printk(KERN_DEBUG " %s zone: %lu pages, LIFO batch:%u\n", zone->name, zone->present_pages, zone_batchsize(zone)); @@ -5160,7 +5160,7 @@ static void check_for_memory(pg_data_t *pgdat, int nid) for (zone_type = 0; zone_type <= ZONE_MOVABLE - 1; zone_type++) { struct zone *zone = &pgdat->node_zones[zone_type]; - if (zone->present_pages) { + if (populated_zone(zone)) { node_set_state(nid, N_HIGH_MEMORY); if (N_NORMAL_MEMORY != N_HIGH_MEMORY && zone_type <= ZONE_NORMAL) -- cgit v0.10.2 From d6de9d5349db61e134ab7fb6b2436a4c7938714c Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Tue, 12 Nov 2013 15:07:20 -0800 Subject: mm/memory_hotplug.c: rename the function is_memblock_offlined_cb() A is_memblock_offlined() return or 1 means memory block is offlined, but is_memblock_offlined_cb() returning 1 means memory block is not offlined, this will confuse somebody, so rename the function. Signed-off-by: Xishi Qiu Acked-by: Yasuaki Ishimatsu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 375a42d..133a4e1 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1701,7 +1701,7 @@ int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, } #ifdef CONFIG_MEMORY_HOTREMOVE -static int is_memblock_offlined_cb(struct memory_block *mem, void *arg) +static int check_memblock_offlined_cb(struct memory_block *mem, void *arg) { int ret = !is_memblock_offlined(mem); @@ -1853,7 +1853,7 @@ void __ref remove_memory(int nid, u64 start, u64 size) * if this is not the case. */ ret = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL, - is_memblock_offlined_cb); + check_memblock_offlined_cb); if (ret) { unlock_memory_hotplug(); BUG(); -- cgit v0.10.2 From 9c2606b77d6bffb422928bca66c8dc84d85089be Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Tue, 12 Nov 2013 15:07:21 -0800 Subject: mm/memory_hotplug.c: use pfn_to_nid() instead of page_to_nid(pfn_to_page()) Use "pfn_to_nid(pfn)" instead of "page_to_nid(pfn_to_page(pfn))". Signed-off-by: Xishi Qiu Acked-by: Yasuaki Ishimatsu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 133a4e1..5118028 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -934,7 +934,7 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ arg.nr_pages = nr_pages; node_states_check_changes_online(nr_pages, zone, &arg); - nid = page_to_nid(pfn_to_page(pfn)); + nid = pfn_to_nid(pfn); ret = memory_notify(MEM_GOING_ONLINE, &arg); ret = notifier_to_errno(ret); -- cgit v0.10.2 From b9921ecdee66984b00c38c00a358ef3f611d2b50 Mon Sep 17 00:00:00 2001 From: Qiang Huang Date: Tue, 12 Nov 2013 15:07:22 -0800 Subject: mm: add a helper function to check may oom condition Use helper function to check if we need to deal with oom condition. Signed-off-by: Qiang Huang Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/oom.h b/include/linux/oom.h index da60007..4cd6267 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -82,6 +82,11 @@ static inline void oom_killer_enable(void) oom_killer_disabled = false; } +static inline bool oom_gfp_allowed(gfp_t gfp_mask) +{ + return (gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY); +} + extern struct task_struct *find_lock_task_mm(struct task_struct *p); /* sysctls */ diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 13b9d0f..3427de98 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2984,21 +2984,14 @@ static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size) struct res_counter *fail_res; struct mem_cgroup *_memcg; int ret = 0; - bool may_oom; ret = res_counter_charge(&memcg->kmem, size, &fail_res); if (ret) return ret; - /* - * Conditions under which we can wait for the oom_killer. Those are - * the same conditions tested by the core page allocator - */ - may_oom = (gfp & __GFP_FS) && !(gfp & __GFP_NORETRY); - _memcg = memcg; ret = __mem_cgroup_try_charge(NULL, gfp, size >> PAGE_SHIFT, - &_memcg, may_oom); + &_memcg, oom_gfp_allowed(gfp)); if (ret == -EINTR) { /* diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3d1d75a..e0412c0 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2593,7 +2593,7 @@ rebalance: * running out of options and have to consider going OOM */ if (!did_some_progress) { - if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) { + if (oom_gfp_allowed(gfp_mask)) { if (oom_killer_disabled) goto nopage; /* Coredumps can quickly deplete all memory reserves */ -- cgit v0.10.2 From 309d0b3917387b48d1fa1a15aa6762de489c9123 Mon Sep 17 00:00:00 2001 From: Robin Holt Date: Tue, 12 Nov 2013 15:07:23 -0800 Subject: mm/nobootmem.c: have __free_pages_memory() free in larger chunks. On large memory machines it can take a few minutes to get through free_all_bootmem(). Currently, when free_all_bootmem() calls __free_pages_memory(), the number of contiguous pages that __free_pages_memory() passes to the buddy allocator is limited to BITS_PER_LONG. BITS_PER_LONG was originally chosen to keep things similar to mm/nobootmem.c. But it is more efficient to limit it to MAX_ORDER. base new change 8TB 202s 172s 30s 16TB 401s 351s 50s That is around 1%-3% improvement on total boot time. This patch was spun off from the boot time rfc Robin and I had been working on. Signed-off-by: Robin Holt Signed-off-by: Nathan Zimmer Cc: Robin Holt Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Mike Travis Cc: Yinghai Lu Cc: Mel Gorman Acked-by: Johannes Weiner Reviewed-by: Wanpeng Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/nobootmem.c b/mm/nobootmem.c index 61107cf..2c254d3 100644 --- a/mm/nobootmem.c +++ b/mm/nobootmem.c @@ -82,27 +82,18 @@ void __init free_bootmem_late(unsigned long addr, unsigned long size) static void __init __free_pages_memory(unsigned long start, unsigned long end) { - unsigned long i, start_aligned, end_aligned; - int order = ilog2(BITS_PER_LONG); + int order; - start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1); - end_aligned = end & ~(BITS_PER_LONG - 1); + while (start < end) { + order = min(MAX_ORDER - 1UL, __ffs(start)); - if (end_aligned <= start_aligned) { - for (i = start; i < end; i++) - __free_pages_bootmem(pfn_to_page(i), 0); + while (start + (1UL << order) > end) + order--; - return; - } - - for (i = start; i < start_aligned; i++) - __free_pages_bootmem(pfn_to_page(i), 0); + __free_pages_bootmem(pfn_to_page(start), order); - for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG) - __free_pages_bootmem(pfn_to_page(i), order); - - for (i = end_aligned; i < end; i++) - __free_pages_bootmem(pfn_to_page(i), 0); + start += (1UL << order); + } } static unsigned long __init __free_memory_core(phys_addr_t start, -- cgit v0.10.2 From 01b0f19707c51ef247404e6af1d4a97a11ba34f7 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 12 Nov 2013 15:07:25 -0800 Subject: cpu/mem hotplug: add try_online_node() for cpu_up() cpu_up() has #ifdef CONFIG_MEMORY_HOTPLUG code blocks, which call mem_online_node() to put its node online if offlined and then call build_all_zonelists() to initialize the zone list. These steps are specific to memory hotplug, and should be managed in mm/memory_hotplug.c. lock_memory_hotplug() should also be held for the whole steps. For this reason, this patch replaces mem_online_node() with try_online_node(), which performs the whole steps with lock_memory_hotplug() held. try_online_node() is named after try_offline_node() as they have similar purpose. There is no functional change in this patch. Signed-off-by: Toshi Kani Reviewed-by: Yasuaki Ishimatsu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index dd38e62..22203c2 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -94,6 +94,8 @@ extern void __online_page_set_limits(struct page *page); extern void __online_page_increment_counters(struct page *page); extern void __online_page_free(struct page *page); +extern int try_online_node(int nid); + #ifdef CONFIG_MEMORY_HOTREMOVE extern bool is_pageblock_removable_nolock(struct page *page); extern int arch_remove_memory(u64 start, u64 size); @@ -225,6 +227,11 @@ static inline void register_page_bootmem_info_node(struct pglist_data *pgdat) { } +static inline int try_online_node(int nid) +{ + return 0; +} + static inline void lock_memory_hotplug(void) {} static inline void unlock_memory_hotplug(void) {} @@ -256,7 +263,6 @@ static inline void remove_memory(int nid, u64 start, u64 size) {} extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, void *arg, int (*func)(struct memory_block *, void *)); -extern int mem_online_node(int nid); extern int add_memory(int nid, u64 start, u64 size); extern int arch_add_memory(int nid, u64 start, u64 size); extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); diff --git a/kernel/cpu.c b/kernel/cpu.c index 63aa50d..973d034 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -437,11 +437,6 @@ int cpu_up(unsigned int cpu) { int err = 0; -#ifdef CONFIG_MEMORY_HOTPLUG - int nid; - pg_data_t *pgdat; -#endif - if (!cpu_possible(cpu)) { printk(KERN_ERR "can't online cpu %d because it is not " "configured as may-hotadd at boot time\n", cpu); @@ -452,27 +447,9 @@ int cpu_up(unsigned int cpu) return -EINVAL; } -#ifdef CONFIG_MEMORY_HOTPLUG - nid = cpu_to_node(cpu); - if (!node_online(nid)) { - err = mem_online_node(nid); - if (err) - return err; - } - - pgdat = NODE_DATA(nid); - if (!pgdat) { - printk(KERN_ERR - "Can't online cpu %d due to NULL pgdat\n", cpu); - return -ENOMEM; - } - - if (pgdat->node_zonelists->_zonerefs->zone == NULL) { - mutex_lock(&zonelists_mutex); - build_all_zonelists(NULL, NULL); - mutex_unlock(&zonelists_mutex); - } -#endif + err = try_online_node(cpu_to_node(cpu)); + if (err) + return err; cpu_maps_update_begin(); diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 5118028..8285346 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1043,17 +1043,23 @@ static void rollback_node_hotadd(int nid, pg_data_t *pgdat) } -/* +/** + * try_online_node - online a node if offlined + * * called by cpu_up() to online a node without onlined memory. */ -int mem_online_node(int nid) +int try_online_node(int nid) { pg_data_t *pgdat; int ret; + if (node_online(nid)) + return 0; + lock_memory_hotplug(); pgdat = hotadd_new_pgdat(nid, 0); if (!pgdat) { + pr_err("Cannot online node %d due to NULL pgdat\n", nid); ret = -ENOMEM; goto out; } @@ -1061,6 +1067,12 @@ int mem_online_node(int nid) ret = register_one_node(nid); BUG_ON(ret); + if (pgdat->node_zonelists->_zonerefs->zone == NULL) { + mutex_lock(&zonelists_mutex); + build_all_zonelists(NULL, NULL); + mutex_unlock(&zonelists_mutex); + } + out: unlock_memory_hotplug(); return ret; -- cgit v0.10.2 From 03b61ff3c324e094944b663cc611a8bab252539c Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Tue, 12 Nov 2013 15:07:26 -0800 Subject: mm/memory-failure.c: move set_migratetype_isolate() outside get_any_page() Chen Gong pointed out that set/unset_migratetype_isolate() was done in different functions in mm/memory-failure.c, which makes the code less readable/maintainable. So this patch does it in soft_offline_page(). With this patch, we get to hold lock_memory_hotplug() longer but it's not a problem because races between memory hotplug and soft offline are very rare. Signed-off-by: Naoya Horiguchi Reviewed-by: Chen, Gong Acked-by: Andi Kleen Reviewed-by: Wanpeng Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory-failure.c b/mm/memory-failure.c index bf3351b..f9d78ec 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1423,19 +1423,6 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags) return 1; /* - * The lock_memory_hotplug prevents a race with memory hotplug. - * This is a big hammer, a better would be nicer. - */ - lock_memory_hotplug(); - - /* - * Isolate the page, so that it doesn't get reallocated if it - * was free. This flag should be kept set until the source page - * is freed and PG_hwpoison on it is set. - */ - if (get_pageblock_migratetype(p) != MIGRATE_ISOLATE) - set_migratetype_isolate(p, true); - /* * When the target page is a free hugepage, just remove it * from free hugepage list. */ @@ -1455,7 +1442,6 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags) /* Not a free page */ ret = 1; } - unlock_memory_hotplug(); return ret; } @@ -1654,15 +1640,28 @@ int soft_offline_page(struct page *page, int flags) } } + /* + * The lock_memory_hotplug prevents a race with memory hotplug. + * This is a big hammer, a better would be nicer. + */ + lock_memory_hotplug(); + + /* + * Isolate the page, so that it doesn't get reallocated if it + * was free. This flag should be kept set until the source page + * is freed and PG_hwpoison on it is set. + */ + if (get_pageblock_migratetype(page) != MIGRATE_ISOLATE) + set_migratetype_isolate(page, true); + ret = get_any_page(page, pfn, flags); - if (ret < 0) - goto unset; - if (ret) { /* for in-use pages */ + unlock_memory_hotplug(); + if (ret > 0) { /* for in-use pages */ if (PageHuge(page)) ret = soft_offline_huge_page(page, flags); else ret = __soft_offline_page(page, flags); - } else { /* for free pages */ + } else if (ret == 0) { /* for free pages */ if (PageHuge(page)) { set_page_hwpoison_huge_page(hpage); dequeue_hwpoisoned_huge_page(hpage); @@ -1673,7 +1672,6 @@ int soft_offline_page(struct page *page, int flags) atomic_long_inc(&num_poisoned_pages); } } -unset: unset_migratetype_isolate(page, MIGRATE_MOVABLE); return ret; } -- cgit v0.10.2 From 40c3baa7c66f1352521378ee83509fb8f4c465de Mon Sep 17 00:00:00 2001 From: Jianguo Wu Date: Tue, 12 Nov 2013 15:07:27 -0800 Subject: mm/arch: use NUMA_NO_NODE Use more appropriate NUMA_NO_NODE instead of -1 in all archs' module_alloc() Signed-off-by: Jianguo Wu Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 084dc88..c9dfff3 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -40,7 +40,7 @@ void *module_alloc(unsigned long size) { return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL_EXEC, -1, + GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE, __builtin_return_address(0)); } #endif diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 2c28a6c..e2ad0d8 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -29,7 +29,7 @@ void *module_alloc(unsigned long size) { return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL_EXEC, -1, + GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE, __builtin_return_address(0)); } diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 2a625fb..50dfafc 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -219,7 +219,7 @@ void *module_alloc(unsigned long size) * init_data correctly */ return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, GFP_KERNEL | __GFP_HIGHMEM, - PAGE_KERNEL_RWX, -1, + PAGE_KERNEL_RWX, NUMA_NO_NODE, __builtin_return_address(0)); } diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 7845e15..b89b591 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -50,7 +50,7 @@ void *module_alloc(unsigned long size) if (PAGE_ALIGN(size) > MODULES_LEN) return NULL; return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL, -1, + GFP_KERNEL, PAGE_KERNEL, NUMA_NO_NODE, __builtin_return_address(0)); } #endif diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 4435488..97655e0 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -29,7 +29,7 @@ static void *module_map(unsigned long size) if (PAGE_ALIGN(size) > MODULES_LEN) return NULL; return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL, -1, + GFP_KERNEL, PAGE_KERNEL, NUMA_NO_NODE, __builtin_return_address(0)); } #else diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 216a4d7..18be189 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -49,7 +49,7 @@ void *module_alloc(unsigned long size) return NULL; return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC, - -1, __builtin_return_address(0)); + NUMA_NO_NODE, __builtin_return_address(0)); } #ifdef CONFIG_X86_32 -- cgit v0.10.2 From 948927ee9e4f35f287e61a79c9f0e85ca2202c7d Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 12 Nov 2013 15:07:28 -0800 Subject: mm, mempolicy: make mpol_to_str robust and always succeed mpol_to_str() should not fail. Currently, it either fails because the string buffer is too small or because a string hasn't been defined for a mempolicy mode. If a new mempolicy mode is introduced and no string is defined for it, just warn and return "unknown". If the buffer is too small, just truncate the string and return, the same behavior as snprintf(). This also fixes a bug where there was no NULL-byte termination when doing *p++ = '=' and *p++ ':' and maxlen has been reached. Signed-off-by: David Rientjes Cc: KOSAKI Motohiro Cc: Chen Gang Cc: Rik van Riel Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 390bdab..9f1369f 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1387,8 +1387,8 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) struct mm_struct *mm = vma->vm_mm; struct mm_walk walk = {}; struct mempolicy *pol; - int n; - char buffer[50]; + char buffer[64]; + int nid; if (!mm) return 0; @@ -1404,10 +1404,8 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) walk.mm = mm; pol = get_vma_policy(task, vma, vma->vm_start); - n = mpol_to_str(buffer, sizeof(buffer), pol); + mpol_to_str(buffer, sizeof(buffer), pol); mpol_cond_put(pol); - if (n < 0) - return n; seq_printf(m, "%08lx %s", vma->vm_start, buffer); @@ -1460,9 +1458,9 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) if (md->writeback) seq_printf(m, " writeback=%lu", md->writeback); - for_each_node_state(n, N_MEMORY) - if (md->node[n]) - seq_printf(m, " N%d=%lu", n, md->node[n]); + for_each_node_state(nid, N_MEMORY) + if (md->node[nid]) + seq_printf(m, " N%d=%lu", nid, md->node[nid]); out: seq_putc(m, '\n'); diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index ea4d249..9fe426b 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -169,7 +169,7 @@ int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from, extern int mpol_parse_str(char *str, struct mempolicy **mpol); #endif -extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol); +extern void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol); /* Check if a vma is migratable */ static inline int vma_migratable(struct vm_area_struct *vma) @@ -307,9 +307,8 @@ static inline int mpol_parse_str(char *str, struct mempolicy **mpol) } #endif -static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) +static inline void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) { - return 0; } static inline int mpol_misplaced(struct page *page, struct vm_area_struct *vma, diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 71cb253..260b821 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2914,62 +2914,45 @@ out: * @maxlen: length of @buffer * @pol: pointer to mempolicy to be formatted * - * Convert a mempolicy into a string. - * Returns the number of characters in buffer (if positive) - * or an error (negative) + * Convert @pol into a string. If @buffer is too short, truncate the string. + * Recommend a @maxlen of at least 32 for the longest mode, "interleave", the + * longest flag, "relative", and to display at least a few node ids. */ -int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) +void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) { char *p = buffer; - int l; - nodemask_t nodes; - unsigned short mode; - unsigned short flags = pol ? pol->flags : 0; - - /* - * Sanity check: room for longest mode, flag and some nodes - */ - VM_BUG_ON(maxlen < strlen("interleave") + strlen("relative") + 16); + nodemask_t nodes = NODE_MASK_NONE; + unsigned short mode = MPOL_DEFAULT; + unsigned short flags = 0; - if (!pol || pol == &default_policy) - mode = MPOL_DEFAULT; - else + if (pol && pol != &default_policy) { mode = pol->mode; + flags = pol->flags; + } switch (mode) { case MPOL_DEFAULT: - nodes_clear(nodes); break; - case MPOL_PREFERRED: - nodes_clear(nodes); if (flags & MPOL_F_LOCAL) mode = MPOL_LOCAL; else node_set(pol->v.preferred_node, nodes); break; - case MPOL_BIND: - /* Fall through */ case MPOL_INTERLEAVE: nodes = pol->v.nodes; break; - default: - return -EINVAL; + WARN_ON_ONCE(1); + snprintf(p, maxlen, "unknown"); + return; } - l = strlen(policy_modes[mode]); - if (buffer + maxlen < p + l + 1) - return -ENOSPC; - - strcpy(p, policy_modes[mode]); - p += l; + p += snprintf(p, maxlen, policy_modes[mode]); if (flags & MPOL_MODE_FLAGS) { - if (buffer + maxlen < p + 2) - return -ENOSPC; - *p++ = '='; + p += snprintf(p, buffer + maxlen - p, "="); /* * Currently, the only defined flags are mutually exclusive @@ -2981,10 +2964,7 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) } if (!nodes_empty(nodes)) { - if (buffer + maxlen < p + 2) - return -ENOSPC; - *p++ = ':'; + p += snprintf(p, buffer + maxlen - p, ":"); p += nodelist_scnprintf(p, buffer + maxlen - p, nodes); } - return p - buffer; } -- cgit v0.10.2 From 3722e13cff361035583f6ecfa784437b824fe659 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 12 Nov 2013 15:07:29 -0800 Subject: mm/vmalloc: don't set area->caller twice The caller address has already been set in set_vmalloc_vm(), there's no need to set it again in __vmalloc_area_node. Reviewed-by: Zhang Yanfei Signed-off-by: Wanpeng Li Cc: Joonsoo Kim Cc: KOSAKI Motohiro Cc: Mitsuo Hayasaka Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmalloc.c b/mm/vmalloc.c index dea15e6..285f0e7 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1546,7 +1546,7 @@ static void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask, pgprot_t prot, int node, const void *caller); static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, - pgprot_t prot, int node, const void *caller) + pgprot_t prot, int node) { const int order = 0; struct page **pages; @@ -1560,13 +1560,12 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, /* Please note that the recursion is strictly bounded. */ if (array_size > PAGE_SIZE) { pages = __vmalloc_node(array_size, 1, nested_gfp|__GFP_HIGHMEM, - PAGE_KERNEL, node, caller); + PAGE_KERNEL, node, area->caller); area->flags |= VM_VPAGES; } else { pages = kmalloc_node(array_size, nested_gfp, node); } area->pages = pages; - area->caller = caller; if (!area->pages) { remove_vm_area(area->addr); kfree(area); @@ -1634,7 +1633,7 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align, if (!area) goto fail; - addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller); + addr = __vmalloc_area_node(area, gfp_mask, prot, node); if (!addr) goto fail; -- cgit v0.10.2 From c2ce8c142c43c360047e173d2018d94a4d0f7a59 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 12 Nov 2013 15:07:31 -0800 Subject: mm/vmalloc: fix show vmap_area information race with vmap_area tear down There is a race window between vmap_area tear down and show vmap_area information. A B remove_vm_area spin_lock(&vmap_area_lock); va->vm = NULL; va->flags &= ~VM_VM_AREA; spin_unlock(&vmap_area_lock); spin_lock(&vmap_area_lock); if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEZING)) return 0; if (!(va->flags & VM_VM_AREA)) { seq_printf(m, "0x%pK-0x%pK %7ld vm_map_ram\n", (void *)va->va_start, (void *)va->va_end, va->va_end - va->va_start); return 0; } free_unmap_vmap_area(va); flush_cache_vunmap free_unmap_vmap_area_noflush unmap_vmap_area free_vmap_area_noflush va->flags |= VM_LAZY_FREE The assumption !VM_VM_AREA represents vm_map_ram allocation is introduced by d4033afdf828 ("mm, vmalloc: iterate vmap_area_list, instead of vmlist, in vmallocinfo()"). However, !VM_VM_AREA also represents vmap_area is being tear down in race window mentioned above. This patch fix it by don't dump any information for !VM_VM_AREA case and also remove (VM_LAZY_FREE | VM_LAZY_FREEING) check since they are not possible for !VM_VM_AREA case. Suggested-by: Joonsoo Kim Acked-by: KOSAKI Motohiro Signed-off-by: Wanpeng Li Cc: Mitsuo Hayasaka Cc: Zhang Yanfei Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 285f0e7..814ce91 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -2578,15 +2578,12 @@ static int s_show(struct seq_file *m, void *p) struct vmap_area *va = p; struct vm_struct *v; - if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEING)) - return 0; - - if (!(va->flags & VM_VM_AREA)) { - seq_printf(m, "0x%pK-0x%pK %7ld vm_map_ram\n", - (void *)va->va_start, (void *)va->va_end, - va->va_end - va->va_start); + /* + * s_show can encounter race with remove_vm_area, !VM_VM_AREA on + * behalf of vmap area is being tear down or vm_map_ram allocation. + */ + if (!(va->flags & VM_VM_AREA)) return 0; - } v = va->vm; -- cgit v0.10.2 From af12346cdacda36f0c35c657088282b8ecd0df72 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 12 Nov 2013 15:07:32 -0800 Subject: mm/vmalloc: revert "mm/vmalloc.c: check VM_UNINITIALIZED flag in s_show instead of show_numa_info" The VM_UNINITIALIZED/VM_UNLIST flag introduced by f5252e009d5b ("mm: avoid null pointer access in vm_struct via /proc/vmallocinfo") is used to avoid accessing the pages field with unallocated page when show_numa_info() is called. This patch moves the check just before show_numa_info in order that some messages still can be dumped via /proc/vmallocinfo. This patch reverts commit d157a55815ff ("mm/vmalloc.c: check VM_UNINITIALIZED flag in s_show instead of show_numa_info"); Reviewed-by: Zhang Yanfei Signed-off-by: Wanpeng Li Cc: Mitsuo Hayasaka Cc: Joonsoo Kim Cc: KOSAKI Motohiro Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 814ce91..67535f8 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -2562,6 +2562,11 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v) if (!counters) return; + /* Pair with smp_wmb() in clear_vm_uninitialized_flag() */ + smp_rmb(); + if (v->flags & VM_UNINITIALIZED) + return; + memset(counters, 0, nr_node_ids * sizeof(unsigned int)); for (nr = 0; nr < v->nr_pages; nr++) @@ -2587,11 +2592,6 @@ static int s_show(struct seq_file *m, void *p) v = va->vm; - /* Pair with smp_wmb() in clear_vm_uninitialized_flag() */ - smp_rmb(); - if (v->flags & VM_UNINITIALIZED) - return 0; - seq_printf(m, "0x%pK-0x%pK %7ld", v->addr, v->addr + v->size, v->size); -- cgit v0.10.2 From b82225f3ff5be4c52cb588a4a53686db50aa6eb6 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 12 Nov 2013 15:07:33 -0800 Subject: revert mm/vmalloc.c: emit the failure message before return Don't warn twice in __vmalloc_area_node and __vmalloc_node_range if __vmalloc_area_node allocation failure. This patch reverts commit 46c001a2753f ("mm/vmalloc.c: emit the failure message before return"). Signed-off-by: Wanpeng Li Reviewed-by: Zhang Yanfei Cc: Joonsoo Kim Cc: KOSAKI Motohiro Cc: Mitsuo Hayasaka Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 67535f8..745fa95 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1635,7 +1635,7 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align, addr = __vmalloc_area_node(area, gfp_mask, prot, node); if (!addr) - goto fail; + return NULL; /* * In this function, newly allocated vm_struct has VM_UNINITIALIZED -- cgit v0.10.2 From 0151e3d6d9d72df8f823c3f991a14ba63fb13f28 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 12 Nov 2013 15:07:34 -0800 Subject: Documentation/vm/zswap.txt: fix typos Signed-off-by: Christian Hesse Acked-by: Seth Jennings Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/vm/zswap.txt b/Documentation/vm/zswap.txt index 7e492d8..00c3d31 100644 --- a/Documentation/vm/zswap.txt +++ b/Documentation/vm/zswap.txt @@ -8,7 +8,7 @@ significant performance improvement if reads from the compressed cache are faster than reads from a swap device. NOTE: Zswap is a new feature as of v3.11 and interacts heavily with memory -reclaim. This interaction has not be fully explored on the large set of +reclaim. This interaction has not been fully explored on the large set of potential configurations and workloads that exist. For this reason, zswap is a work in progress and should be considered experimental. @@ -23,7 +23,7 @@ Some potential benefits:     drastically reducing life-shortening writes. Zswap evicts pages from compressed cache on an LRU basis to the backing swap -device when the compressed pool reaches it size limit. This requirement had +device when the compressed pool reaches its size limit. This requirement had been identified in prior community discussions. To enabled zswap, the "enabled" attribute must be set to 1 at boot time. e.g. @@ -37,7 +37,7 @@ the backing swap device in the case that the compressed pool is full. Zswap makes use of zbud for the managing the compressed memory pool. Each allocation in zbud is not directly accessible by address. Rather, a handle is -return by the allocation routine and that handle must be mapped before being +returned by the allocation routine and that handle must be mapped before being accessed. The compressed memory pool grows on demand and shrinks as compressed pages are freed. The pool is not preallocated. @@ -56,7 +56,7 @@ in the swap_map goes to 0) the swap code calls the zswap invalidate function, via frontswap, to free the compressed entry. Zswap seeks to be simple in its policies. Sysfs attributes allow for one user -controlled policies: +controlled policy: * max_pool_percent - The maximum percentage of memory that the compressed pool can occupy. -- cgit v0.10.2 From 10dc4155c7714f508fe2e4667164925ea971fb25 Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Tue, 12 Nov 2013 15:07:35 -0800 Subject: mm: thp: cleanup: mv alloc_hugepage to better place Move alloc_hugepage() to a better place, no need for a seperate #ifndef CONFIG_NUMA Signed-off-by: Bob Liu Reviewed-by: Yasuaki Ishimatsu Acked-by: Kirill A. Shutemov Cc: Andrea Arcangeli Cc: Mel Gorman Cc: Andrew Davidoff Cc: Wanpeng Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 4f7e211..411c4f2 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -759,14 +759,6 @@ static inline struct page *alloc_hugepage_vma(int defrag, HPAGE_PMD_ORDER, vma, haddr, nd); } -#ifndef CONFIG_NUMA -static inline struct page *alloc_hugepage(int defrag) -{ - return alloc_pages(alloc_hugepage_gfpmask(defrag, 0), - HPAGE_PMD_ORDER); -} -#endif - static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long haddr, pmd_t *pmd, struct page *zero_page) @@ -2251,6 +2243,12 @@ static struct page return *hpage; } #else +static inline struct page *alloc_hugepage(int defrag) +{ + return alloc_pages(alloc_hugepage_gfpmask(defrag, 0), + HPAGE_PMD_ORDER); +} + static struct page *khugepaged_alloc_hugepage(bool *wait) { struct page *hpage; -- cgit v0.10.2 From 9f1b868a13ac36bd207a571f5ea1193d823ab18d Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Tue, 12 Nov 2013 15:07:37 -0800 Subject: mm: thp: khugepaged: add policy for finding target node Khugepaged will scan/free HPAGE_PMD_NR normal pages and replace with a hugepage which is allocated from the node of the first scanned normal page, but this policy is too rough and may end with unexpected result to upper users. The problem is the original page-balancing among all nodes will be broken after hugepaged started. Thinking about the case if the first scanned normal page is allocated from node A, most of other scanned normal pages are allocated from node B or C.. But hugepaged will always allocate hugepage from node A which will cause extra memory pressure on node A which is not the situation before khugepaged started. This patch try to fix this problem by making khugepaged allocate hugepage from the node which have max record of scaned normal pages hit, so that the effect to original page-balancing can be minimized. The other problem is if normal scanned pages are equally allocated from Node A,B and C, after khugepaged started Node A will still suffer extra memory pressure. Andrew Davidoff reported a related issue several days ago. He wanted his application interleaving among all nodes and "numactl --interleave=all ./test" was used to run the testcase, but the result wasn't not as expected. cat /proc/2814/numa_maps: 7f50bd440000 interleave:0-3 anon=51403 dirty=51403 N0=435 N1=435 N2=435 N3=50098 The end result showed that most pages are from Node3 instead of interleave among node0-3 which was unreasonable. This patch also fix this issue by allocating hugepage round robin from all nodes have the same record, after this patch the result was as expected: 7f78399c0000 interleave:0-3 anon=51403 dirty=51403 N0=12723 N1=12723 N2=13235 N3=12722 The simple testcase is like this: int main() { char *p; int i; int j; for (i=0; i < 200; i++) { p = (char *)malloc(1048576); printf("malloc done\n"); if (p == 0) { printf("Out of memory\n"); return 1; } for (j=0; j < 1048576; j++) { p[j] = 'A'; } printf("touched memory\n"); sleep(1); } printf("enter sleep\n"); while(1) { sleep(100); } } [akpm@linux-foundation.org: make last_khugepaged_target_node local to khugepaged_find_target_node()] Reported-by: Andrew Davidoff Tested-by: Andrew Davidoff Signed-off-by: Bob Liu Cc: Andrea Arcangeli Cc: Kirill A. Shutemov Cc: Mel Gorman Cc: Yasuaki Ishimatsu Cc: Wanpeng Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 411c4f2..0556c6a 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2191,7 +2191,34 @@ static void khugepaged_alloc_sleep(void) msecs_to_jiffies(khugepaged_alloc_sleep_millisecs)); } +static int khugepaged_node_load[MAX_NUMNODES]; + #ifdef CONFIG_NUMA +static int khugepaged_find_target_node(void) +{ + static int last_khugepaged_target_node = NUMA_NO_NODE; + int nid, target_node = 0, max_value = 0; + + /* find first node with max normal pages hit */ + for (nid = 0; nid < MAX_NUMNODES; nid++) + if (khugepaged_node_load[nid] > max_value) { + max_value = khugepaged_node_load[nid]; + target_node = nid; + } + + /* do some balance if several nodes have the same hit record */ + if (target_node <= last_khugepaged_target_node) + for (nid = last_khugepaged_target_node + 1; nid < MAX_NUMNODES; + nid++) + if (max_value == khugepaged_node_load[nid]) { + target_node = nid; + break; + } + + last_khugepaged_target_node = target_node; + return target_node; +} + static bool khugepaged_prealloc_page(struct page **hpage, bool *wait) { if (IS_ERR(*hpage)) { @@ -2225,9 +2252,8 @@ static struct page * mmap_sem in read mode is good idea also to allow greater * scalability. */ - *hpage = alloc_hugepage_vma(khugepaged_defrag(), vma, address, - node, __GFP_OTHER_NODE); - + *hpage = alloc_pages_exact_node(node, alloc_hugepage_gfpmask( + khugepaged_defrag(), __GFP_OTHER_NODE), HPAGE_PMD_ORDER); /* * After allocating the hugepage, release the mmap_sem read lock in * preparation for taking it in write mode. @@ -2243,6 +2269,11 @@ static struct page return *hpage; } #else +static int khugepaged_find_target_node(void) +{ + return 0; +} + static inline struct page *alloc_hugepage(int defrag) { return alloc_pages(alloc_hugepage_gfpmask(defrag, 0), @@ -2455,6 +2486,7 @@ static int khugepaged_scan_pmd(struct mm_struct *mm, if (pmd_trans_huge(*pmd)) goto out; + memset(khugepaged_node_load, 0, sizeof(khugepaged_node_load)); pte = pte_offset_map_lock(mm, pmd, address, &ptl); for (_address = address, _pte = pte; _pte < pte+HPAGE_PMD_NR; _pte++, _address += PAGE_SIZE) { @@ -2471,12 +2503,13 @@ static int khugepaged_scan_pmd(struct mm_struct *mm, if (unlikely(!page)) goto out_unmap; /* - * Chose the node of the first page. This could - * be more sophisticated and look at more pages, - * but isn't for now. + * Record which node the original page is from and save this + * information to khugepaged_node_load[]. + * Khupaged will allocate hugepage from the node has the max + * hit record. */ - if (node == NUMA_NO_NODE) - node = page_to_nid(page); + node = page_to_nid(page); + khugepaged_node_load[node]++; VM_BUG_ON(PageCompound(page)); if (!PageLRU(page) || PageLocked(page) || !PageAnon(page)) goto out_unmap; @@ -2491,9 +2524,11 @@ static int khugepaged_scan_pmd(struct mm_struct *mm, ret = 1; out_unmap: pte_unmap_unlock(pte, ptl); - if (ret) + if (ret) { + node = khugepaged_find_target_node(); /* collapse_huge_page will return with the mmap_sem released */ collapse_huge_page(mm, address, hpage, vma, node); + } out: return ret; } -- cgit v0.10.2 From b76ac7e734608d706bf225be062a7a46d165dda6 Mon Sep 17 00:00:00 2001 From: Jianguo Wu Date: Tue, 12 Nov 2013 15:07:39 -0800 Subject: mm/mempolicy: use NUMA_NO_NODE Use more appropriate NUMA_NO_NODE instead of -1 Signed-off-by: Jianguo Wu Acked-by: KOSAKI Motohiro Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 260b821..4cc19f6 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1125,7 +1125,7 @@ int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from, tmp = *from; while (!nodes_empty(tmp)) { int s,d; - int source = -1; + int source = NUMA_NO_NODE; int dest = 0; for_each_node_mask(s, tmp) { @@ -1160,7 +1160,7 @@ int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from, if (!node_isset(dest, tmp)) break; } - if (source == -1) + if (source == NUMA_NO_NODE) break; node_clear(source, tmp); @@ -1835,7 +1835,7 @@ static unsigned offset_il_node(struct mempolicy *pol, unsigned nnodes = nodes_weight(pol->v.nodes); unsigned target; int c; - int nid = -1; + int nid = NUMA_NO_NODE; if (!nnodes) return numa_node_id(); @@ -1872,11 +1872,11 @@ static inline unsigned interleave_nid(struct mempolicy *pol, /* * Return the bit number of a random bit set in the nodemask. - * (returns -1 if nodemask is empty) + * (returns NUMA_NO_NODE if nodemask is empty) */ int node_random(const nodemask_t *maskp) { - int w, bit = -1; + int w, bit = NUMA_NO_NODE; w = nodes_weight(*maskp); if (w) -- cgit v0.10.2 From 25485de6e90ef1684c55a203988fad5eab7a45d6 Mon Sep 17 00:00:00 2001 From: Greg Thelen Date: Tue, 12 Nov 2013 15:07:40 -0800 Subject: memcg: refactor mem_control_numa_stat_show() Refactor mem_control_numa_stat_show() to use a new stats structure for smaller and simpler code. This consolidates nearly identical code. text data bss dec hex filename 8,137,679 1,703,496 1,896,448 11,737,623 b31a17 vmlinux.before 8,136,911 1,703,496 1,896,448 11,736,855 b31717 vmlinux.after Signed-off-by: Greg Thelen Signed-off-by: Ying Han Cc: Johannes Weiner Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3427de98..91b5d3a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5369,45 +5369,33 @@ static int mem_cgroup_move_charge_write(struct cgroup_subsys_state *css, static int memcg_numa_stat_show(struct cgroup_subsys_state *css, struct cftype *cft, struct seq_file *m) { + struct numa_stat { + const char *name; + unsigned int lru_mask; + }; + + static const struct numa_stat stats[] = { + { "total", LRU_ALL }, + { "file", LRU_ALL_FILE }, + { "anon", LRU_ALL_ANON }, + { "unevictable", BIT(LRU_UNEVICTABLE) }, + }; + const struct numa_stat *stat; int nid; - unsigned long total_nr, file_nr, anon_nr, unevictable_nr; - unsigned long node_nr; + unsigned long nr; struct mem_cgroup *memcg = mem_cgroup_from_css(css); - total_nr = mem_cgroup_nr_lru_pages(memcg, LRU_ALL); - seq_printf(m, "total=%lu", total_nr); - for_each_node_state(nid, N_MEMORY) { - node_nr = mem_cgroup_node_nr_lru_pages(memcg, nid, LRU_ALL); - seq_printf(m, " N%d=%lu", nid, node_nr); - } - seq_putc(m, '\n'); - - file_nr = mem_cgroup_nr_lru_pages(memcg, LRU_ALL_FILE); - seq_printf(m, "file=%lu", file_nr); - for_each_node_state(nid, N_MEMORY) { - node_nr = mem_cgroup_node_nr_lru_pages(memcg, nid, - LRU_ALL_FILE); - seq_printf(m, " N%d=%lu", nid, node_nr); - } - seq_putc(m, '\n'); - - anon_nr = mem_cgroup_nr_lru_pages(memcg, LRU_ALL_ANON); - seq_printf(m, "anon=%lu", anon_nr); - for_each_node_state(nid, N_MEMORY) { - node_nr = mem_cgroup_node_nr_lru_pages(memcg, nid, - LRU_ALL_ANON); - seq_printf(m, " N%d=%lu", nid, node_nr); + for (stat = stats; stat < stats + ARRAY_SIZE(stats); stat++) { + nr = mem_cgroup_nr_lru_pages(memcg, stat->lru_mask); + seq_printf(m, "%s=%lu", stat->name, nr); + for_each_node_state(nid, N_MEMORY) { + nr = mem_cgroup_node_nr_lru_pages(memcg, nid, + stat->lru_mask); + seq_printf(m, " N%d=%lu", nid, nr); + } + seq_putc(m, '\n'); } - seq_putc(m, '\n'); - unevictable_nr = mem_cgroup_nr_lru_pages(memcg, BIT(LRU_UNEVICTABLE)); - seq_printf(m, "unevictable=%lu", unevictable_nr); - for_each_node_state(nid, N_MEMORY) { - node_nr = mem_cgroup_node_nr_lru_pages(memcg, nid, - BIT(LRU_UNEVICTABLE)); - seq_printf(m, " N%d=%lu", nid, node_nr); - } - seq_putc(m, '\n'); return 0; } #endif /* CONFIG_NUMA */ -- cgit v0.10.2 From 071aee138410210e3764f3ae8d37ef46dc6d3b42 Mon Sep 17 00:00:00 2001 From: Ying Han Date: Tue, 12 Nov 2013 15:07:41 -0800 Subject: memcg: support hierarchical memory.numa_stats The memory.numa_stat file was not hierarchical. Memory charged to the children was not shown in parent's numa_stat. This change adds the "hierarchical_" stats to the existing stats. The new hierarchical stats include the sum of all children's values in addition to the value of the memcg. Tested: Create cgroup a, a/b and run workload under b. The values of b are included in the "hierarchical_*" under a. $ cd /sys/fs/cgroup $ echo 1 > memory.use_hierarchy $ mkdir a a/b Run workload in a/b: $ (echo $BASHPID >> a/b/cgroup.procs && cat /some/file && bash) & The hierarchical_ fields in parent (a) show use of workload in a/b: $ cat a/memory.numa_stat total=0 N0=0 N1=0 N2=0 N3=0 file=0 N0=0 N1=0 N2=0 N3=0 anon=0 N0=0 N1=0 N2=0 N3=0 unevictable=0 N0=0 N1=0 N2=0 N3=0 hierarchical_total=908 N0=552 N1=317 N2=39 N3=0 hierarchical_file=850 N0=549 N1=301 N2=0 N3=0 hierarchical_anon=58 N0=3 N1=16 N2=39 N3=0 hierarchical_unevictable=0 N0=0 N1=0 N2=0 N3=0 $ cat a/b/memory.numa_stat total=908 N0=552 N1=317 N2=39 N3=0 file=850 N0=549 N1=301 N2=0 N3=0 anon=58 N0=3 N1=16 N2=39 N3=0 unevictable=0 N0=0 N1=0 N2=0 N3=0 hierarchical_total=908 N0=552 N1=317 N2=39 N3=0 hierarchical_file=850 N0=549 N1=301 N2=0 N3=0 hierarchical_anon=58 N0=3 N1=16 N2=39 N3=0 hierarchical_unevictable=0 N0=0 N1=0 N2=0 N3=0 Signed-off-by: Ying Han Signed-off-by: Greg Thelen Cc: Johannes Weiner Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 8af4ad1..e2bc132 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -573,15 +573,19 @@ an memcg since the pages are allowed to be allocated from any physical node. One of the use cases is evaluating application performance by combining this information with the application's CPU allocation. -We export "total", "file", "anon" and "unevictable" pages per-node for -each memcg. The ouput format of memory.numa_stat is: +Each memcg's numa_stat file includes "total", "file", "anon" and "unevictable" +per-node page counts including "hierarchical_" which sums up all +hierarchical children's values in addition to the memcg's own value. + +The ouput format of memory.numa_stat is: total= N0= N1= ... file= N0= N1= ... anon= N0= N1= ... unevictable= N0= N1= ... +hierarchical_= N0= N1= ... -And we have total = file + anon + unevictable. +The "total" count is sum of file + anon + unevictable. 6. Hierarchy support diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 91b5d3a..c890724 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5396,6 +5396,23 @@ static int memcg_numa_stat_show(struct cgroup_subsys_state *css, seq_putc(m, '\n'); } + for (stat = stats; stat < stats + ARRAY_SIZE(stats); stat++) { + struct mem_cgroup *iter; + + nr = 0; + for_each_mem_cgroup_tree(iter, memcg) + nr += mem_cgroup_nr_lru_pages(iter, stat->lru_mask); + seq_printf(m, "hierarchical_%s=%lu", stat->name, nr); + for_each_node_state(nid, N_MEMORY) { + nr = 0; + for_each_mem_cgroup_tree(iter, memcg) + nr += mem_cgroup_node_nr_lru_pages( + iter, nid, stat->lru_mask); + seq_printf(m, " N%d=%lu", nid, nr); + } + seq_putc(m, '\n'); + } + return 0; } #endif /* CONFIG_NUMA */ -- cgit v0.10.2 From 85b35feaecd4d2284505b22708795bc1f03fc897 Mon Sep 17 00:00:00 2001 From: Zhang Yanfei Date: Tue, 12 Nov 2013 15:07:42 -0800 Subject: mm/sparsemem: use PAGES_PER_SECTION to remove redundant nr_pages parameter For below functions, - sparse_add_one_section() - kmalloc_section_memmap() - __kmalloc_section_memmap() - __kfree_section_memmap() they are always invoked to operate on one memory section, so it is redundant to always pass a nr_pages parameter, which is the page numbers in one section. So we can directly use predefined macro PAGES_PER_SECTION instead of passing the parameter. Signed-off-by: Zhang Yanfei Cc: Wen Congyang Cc: Tang Chen Cc: Toshi Kani Cc: Yasuaki Ishimatsu Cc: Yinghai Lu Cc: Yasunori Goto Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 22203c2..4ca3d95 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -268,8 +268,7 @@ extern int arch_add_memory(int nid, u64 start, u64 size); extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); extern bool is_memblock_offlined(struct memory_block *mem); extern void remove_memory(int nid, u64 start, u64 size); -extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, - int nr_pages); +extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn); extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms); extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum); diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 8285346..1b6fe8c 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -401,13 +401,12 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn) static int __meminit __add_section(int nid, struct zone *zone, unsigned long phys_start_pfn) { - int nr_pages = PAGES_PER_SECTION; int ret; if (pfn_valid(phys_start_pfn)) return -EEXIST; - ret = sparse_add_one_section(zone, phys_start_pfn, nr_pages); + ret = sparse_add_one_section(zone, phys_start_pfn); if (ret < 0) return ret; diff --git a/mm/sparse.c b/mm/sparse.c index 4ac1d7e..fbb9dbc 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -590,16 +590,15 @@ void __init sparse_init(void) #ifdef CONFIG_MEMORY_HOTPLUG #ifdef CONFIG_SPARSEMEM_VMEMMAP -static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid, - unsigned long nr_pages) +static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid) { /* This will make the necessary allocations eventually. */ return sparse_mem_map_populate(pnum, nid); } -static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages) +static void __kfree_section_memmap(struct page *memmap) { unsigned long start = (unsigned long)memmap; - unsigned long end = (unsigned long)(memmap + nr_pages); + unsigned long end = (unsigned long)(memmap + PAGES_PER_SECTION); vmemmap_free(start, end); } @@ -613,10 +612,10 @@ static void free_map_bootmem(struct page *memmap, unsigned long nr_pages) } #endif /* CONFIG_MEMORY_HOTREMOVE */ #else -static struct page *__kmalloc_section_memmap(unsigned long nr_pages) +static struct page *__kmalloc_section_memmap(void) { struct page *page, *ret; - unsigned long memmap_size = sizeof(struct page) * nr_pages; + unsigned long memmap_size = sizeof(struct page) * PAGES_PER_SECTION; page = alloc_pages(GFP_KERNEL|__GFP_NOWARN, get_order(memmap_size)); if (page) @@ -634,19 +633,18 @@ got_map_ptr: return ret; } -static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid, - unsigned long nr_pages) +static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid) { - return __kmalloc_section_memmap(nr_pages); + return __kmalloc_section_memmap(); } -static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages) +static void __kfree_section_memmap(struct page *memmap) { if (is_vmalloc_addr(memmap)) vfree(memmap); else free_pages((unsigned long)memmap, - get_order(sizeof(struct page) * nr_pages)); + get_order(sizeof(struct page) * PAGES_PER_SECTION)); } #ifdef CONFIG_MEMORY_HOTREMOVE @@ -684,8 +682,7 @@ static void free_map_bootmem(struct page *memmap, unsigned long nr_pages) * set. If this is <=0, then that means that the passed-in * map was not consumed and must be freed. */ -int __meminit sparse_add_one_section(struct zone *zone, unsigned long start_pfn, - int nr_pages) +int __meminit sparse_add_one_section(struct zone *zone, unsigned long start_pfn) { unsigned long section_nr = pfn_to_section_nr(start_pfn); struct pglist_data *pgdat = zone->zone_pgdat; @@ -702,12 +699,12 @@ int __meminit sparse_add_one_section(struct zone *zone, unsigned long start_pfn, ret = sparse_index_init(section_nr, pgdat->node_id); if (ret < 0 && ret != -EEXIST) return ret; - memmap = kmalloc_section_memmap(section_nr, pgdat->node_id, nr_pages); + memmap = kmalloc_section_memmap(section_nr, pgdat->node_id); if (!memmap) return -ENOMEM; usemap = __kmalloc_section_usemap(); if (!usemap) { - __kfree_section_memmap(memmap, nr_pages); + __kfree_section_memmap(memmap); return -ENOMEM; } @@ -719,7 +716,7 @@ int __meminit sparse_add_one_section(struct zone *zone, unsigned long start_pfn, goto out; } - memset(memmap, 0, sizeof(struct page) * nr_pages); + memset(memmap, 0, sizeof(struct page) * PAGES_PER_SECTION); ms->section_mem_map |= SECTION_MARKED_PRESENT; @@ -729,7 +726,7 @@ out: pgdat_resize_unlock(pgdat, &flags); if (ret <= 0) { kfree(usemap); - __kfree_section_memmap(memmap, nr_pages); + __kfree_section_memmap(memmap); } return ret; } @@ -771,7 +768,7 @@ static void free_section_usemap(struct page *memmap, unsigned long *usemap) if (PageSlab(usemap_page) || PageCompound(usemap_page)) { kfree(usemap); if (memmap) - __kfree_section_memmap(memmap, PAGES_PER_SECTION); + __kfree_section_memmap(memmap); return; } -- cgit v0.10.2 From 81556b02525181e19ef073a798ba9d48db96f708 Mon Sep 17 00:00:00 2001 From: Zhang Yanfei Date: Tue, 12 Nov 2013 15:07:43 -0800 Subject: mm/sparsemem: fix a bug in free_map_bootmem when CONFIG_SPARSEMEM_VMEMMAP We pass the number of pages which hold page structs of a memory section to free_map_bootmem(). This is right when !CONFIG_SPARSEMEM_VMEMMAP but wrong when CONFIG_SPARSEMEM_VMEMMAP. When CONFIG_SPARSEMEM_VMEMMAP, we should pass the number of pages of a memory section to free_map_bootmem. So the fix is removing the nr_pages parameter. When CONFIG_SPARSEMEM_VMEMMAP, we directly use the prefined marco PAGES_PER_SECTION in free_map_bootmem. When !CONFIG_SPARSEMEM_VMEMMAP, we calculate page numbers needed to hold the page structs for a memory section and use the value in free_map_bootmem(). This was found by reading the code. And I have no machine that support memory hot-remove to test the bug now. Signed-off-by: Zhang Yanfei Reviewed-by: Wanpeng Li Cc: Wen Congyang Cc: Tang Chen Cc: Toshi Kani Cc: Yasuaki Ishimatsu Cc: Yinghai Lu Cc: Yasunori Goto Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/sparse.c b/mm/sparse.c index fbb9dbc..8cc7be0 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -603,10 +603,10 @@ static void __kfree_section_memmap(struct page *memmap) vmemmap_free(start, end); } #ifdef CONFIG_MEMORY_HOTREMOVE -static void free_map_bootmem(struct page *memmap, unsigned long nr_pages) +static void free_map_bootmem(struct page *memmap) { unsigned long start = (unsigned long)memmap; - unsigned long end = (unsigned long)(memmap + nr_pages); + unsigned long end = (unsigned long)(memmap + PAGES_PER_SECTION); vmemmap_free(start, end); } @@ -648,12 +648,15 @@ static void __kfree_section_memmap(struct page *memmap) } #ifdef CONFIG_MEMORY_HOTREMOVE -static void free_map_bootmem(struct page *memmap, unsigned long nr_pages) +static void free_map_bootmem(struct page *memmap) { unsigned long maps_section_nr, removing_section_nr, i; - unsigned long magic; + unsigned long magic, nr_pages; struct page *page = virt_to_page(memmap); + nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page)) + >> PAGE_SHIFT; + for (i = 0; i < nr_pages; i++, page++) { magic = (unsigned long) page->lru.next; @@ -756,7 +759,6 @@ static inline void clear_hwpoisoned_pages(struct page *memmap, int nr_pages) static void free_section_usemap(struct page *memmap, unsigned long *usemap) { struct page *usemap_page; - unsigned long nr_pages; if (!usemap) return; @@ -777,12 +779,8 @@ static void free_section_usemap(struct page *memmap, unsigned long *usemap) * on the section which has pgdat at boot time. Just keep it as is now. */ - if (memmap) { - nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page)) - >> PAGE_SHIFT; - - free_map_bootmem(memmap, nr_pages); - } + if (memmap) + free_map_bootmem(memmap); } void sparse_remove_one_section(struct zone *zone, struct mem_section *ms) -- cgit v0.10.2 From 7f88f88f83ed609650a01b18572e605ea50cd163 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 12 Nov 2013 15:07:45 -0800 Subject: mm: kmemleak: avoid false negatives on vmalloc'ed objects Commit 248ac0e1943a ("mm/vmalloc: remove guard page from between vmap blocks") had the side effect of making vmap_area.va_end member point to the next vmap_area.va_start. This was creating an artificial reference to vmalloc'ed objects and kmemleak was rarely reporting vmalloc() leaks. This patch marks the vmap_area containing pointers explicitly and reduces the min ref_count to 2 as vm_struct still contains a reference to the vmalloc'ed object. The kmemleak add_scan_area() function has been improved to allow a SIZE_MAX argument covering the rest of the object (for simpler calling sites). Signed-off-by: Catalin Marinas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/kmemleak.c b/mm/kmemleak.c index e126b0e..31f01c5 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -753,7 +753,9 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp) } spin_lock_irqsave(&object->lock, flags); - if (ptr + size > object->pointer + object->size) { + if (size == SIZE_MAX) { + size = object->pointer + object->size - ptr; + } else if (ptr + size > object->pointer + object->size) { kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr); dump_object_info(object); kmem_cache_free(scan_area_cache, area); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 745fa95..0fdf968 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -359,6 +359,12 @@ static struct vmap_area *alloc_vmap_area(unsigned long size, if (unlikely(!va)) return ERR_PTR(-ENOMEM); + /* + * Only scan the relevant parts containing pointers to other objects + * to avoid false negatives. + */ + kmemleak_scan_area(&va->rb_node, SIZE_MAX, gfp_mask & GFP_RECLAIM_MASK); + retry: spin_lock(&vmap_area_lock); /* @@ -1645,11 +1651,11 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align, clear_vm_uninitialized_flag(area); /* - * A ref_count = 3 is needed because the vm_struct and vmap_area - * structures allocated in the __get_vm_area_node() function contain - * references to the virtual address of the vmalloc'ed block. + * A ref_count = 2 is needed because vm_struct allocated in + * __get_vm_area_node() contains a reference to the virtual address of + * the vmalloc'ed block. */ - kmemleak_alloc(addr, real_size, 3, gfp_mask); + kmemleak_alloc(addr, real_size, 2, gfp_mask); return addr; -- cgit v0.10.2 From 2de1a7e40a30bed83f3da60d8cf0937354d9e7d1 Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Tue, 12 Nov 2013 15:07:46 -0800 Subject: mm/swapfile.c: fix comment typos Signed-off-by: Seth Jennings Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/swapfile.c b/mm/swapfile.c index de7c904..64458e3 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -707,7 +707,7 @@ noswap: return (swp_entry_t) {0}; } -/* The only caller of this function is now susupend routine */ +/* The only caller of this function is now suspend routine */ swp_entry_t get_swap_page_of_type(int type) { struct swap_info_struct *si; @@ -845,7 +845,7 @@ static unsigned char swap_entry_free(struct swap_info_struct *p, } /* - * Caller has made sure that the swapdevice corresponding to entry + * Caller has made sure that the swap device corresponding to entry * is still around or has not been recycled. */ void swap_free(swp_entry_t entry) @@ -947,7 +947,7 @@ int try_to_free_swap(struct page *page) * original page might be freed under memory pressure, then * later read back in from swap, now with the wrong data. * - * Hibration suspends storage while it is writing the image + * Hibernation suspends storage while it is writing the image * to disk so check that here. */ if (pm_suspended_storage()) @@ -1179,7 +1179,7 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd, * some architectures (e.g. x86_32 with PAE) we might catch a glimpse * of unmatched parts which look like swp_pte, so unuse_pte must * recheck under pte lock. Scanning without pte lock lets it be - * preemptible whenever CONFIG_PREEMPT but not CONFIG_HIGHPTE. + * preemptable whenever CONFIG_PREEMPT but not CONFIG_HIGHPTE. */ pte = pte_offset_map(pmd, addr); do { @@ -1934,7 +1934,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) vfree(swap_map); vfree(cluster_info); vfree(frontswap_map); - /* Destroy swap account informatin */ + /* Destroy swap account information */ swap_cgroup_swapoff(type); inode = mapping->host; @@ -2786,8 +2786,8 @@ int add_swap_count_continuation(swp_entry_t entry, gfp_t gfp_mask) /* * We are fortunate that although vmalloc_to_page uses pte_offset_map, - * no architecture is using highmem pages for kernel pagetables: so it - * will not corrupt the GFP_ATOMIC caller's atomic pagetable kmaps. + * no architecture is using highmem pages for kernel page tables: so it + * will not corrupt the GFP_ATOMIC caller's atomic page table kmaps. */ head = vmalloc_to_page(si->swap_map + offset); offset &= ~PAGE_MASK; -- cgit v0.10.2 From 58e97ba6b1a0c78d0c847998cf3bcfa5344c19aa Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 12 Nov 2013 15:07:47 -0800 Subject: frontswap: enable call to invalidate area on swapoff During swapoff the frontswap_map was NULL-ified before calling frontswap_invalidate_area(). However the frontswap_invalidate_area() exits early if frontswap_map is NULL. Invalidate was never called during swapoff. This patch moves frontswap_map_set() in swapoff just after calling frontswap_invalidate_area() so outside of locks (swap_lock and swap_info_struct->lock). This shouldn't be a problem as during swapon the frontswap_map_set() is called also outside of any locks. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Seth Jennings Cc: Konrad Rzeszutek Wilk Cc: Shaohua Li Cc: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/swapfile.c b/mm/swapfile.c index 64458e3..612a7c9 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1924,10 +1924,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) p->cluster_info = NULL; p->flags = 0; frontswap_map = frontswap_map_get(p); - frontswap_map_set(p, NULL); spin_unlock(&p->lock); spin_unlock(&swap_lock); frontswap_invalidate_area(type); + frontswap_map_set(p, NULL); mutex_unlock(&swapon_mutex); free_percpu(p->percpu_cluster); p->percpu_cluster = NULL; -- cgit v0.10.2 From bfc4f9d5206739d0612782508a39e93b0793609d Mon Sep 17 00:00:00 2001 From: Zhang Yanfei Date: Tue, 12 Nov 2013 15:07:48 -0800 Subject: mm/page_alloc.c: remove unused marco LONG_ALIGN Signed-off-by: Zhang Yanfei Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index e0412c0..770dbb4 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3881,8 +3881,6 @@ static inline unsigned long wait_table_bits(unsigned long size) return ffz(~size); } -#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) - /* * Check if a pageblock contains reserved pages */ -- cgit v0.10.2 From ec8e41aec13005fed0dbee002fb8c99b4e001d50 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Tue, 12 Nov 2013 15:07:49 -0800 Subject: /proc/pid/smaps: show VM_SOFTDIRTY flag in VmFlags line This flag shows that the VMA is "newly created" and thus represents "dirty" in the task's VM. You can clear it by "echo 4 > /proc/pid/clear_refs." Signed-off-by: Naoya Horiguchi Cc: Wu Fengguang Cc: Pavel Emelyanov Acked-by: Cyrill Gorcunov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 823c95f..22d89aa3 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -460,6 +460,7 @@ manner. The codes are the following: nl - non-linear mapping ar - architecture specific flag dd - do not include area into core dump + sd - soft-dirty flag mm - mixed map area hg - huge page advise flag nh - no-huge page advise flag diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 9f1369f..abbe825 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -561,6 +561,9 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma) [ilog2(VM_NONLINEAR)] = "nl", [ilog2(VM_ARCH_1)] = "ar", [ilog2(VM_DONTDUMP)] = "dd", +#ifdef CONFIG_MEM_SOFT_DIRTY + [ilog2(VM_SOFTDIRTY)] = "sd", +#endif [ilog2(VM_MIXEDMAP)] = "mm", [ilog2(VM_HUGEPAGE)] = "hg", [ilog2(VM_NOHUGEPAGE)] = "nh", -- cgit v0.10.2 From 46c77e2bb07eba3b38edfec76873f12942c49dd3 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Tue, 12 Nov 2013 15:07:50 -0800 Subject: tools/vm/page-types.c: support KPF_SOFTDIRTY bit Soft dirty bit allows us to track which pages are written since the last clear_ref (by "echo 4 > /proc/pid/clear_refs".) This is useful for userspace applications to know their memory footprints. Note that the kernel exposes this flag via bit[55] of /proc/pid/pagemap, and the semantics is not a default one (scheduled to be the default in the near future.) However, it shifts to the new semantics at the first clear_ref, and the users of soft dirty bit always do it before utilizing the bit, so that's not a big deal. Users must avoid relying on the bit in page-types before the first clear_ref. Signed-off-by: Naoya Horiguchi Cc: Wu Fengguang Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/kernel-page-flags.h b/include/linux/kernel-page-flags.h index 546eb6a..f65ce09 100644 --- a/include/linux/kernel-page-flags.h +++ b/include/linux/kernel-page-flags.h @@ -15,5 +15,6 @@ #define KPF_OWNER_PRIVATE 37 #define KPF_ARCH 38 #define KPF_UNCACHED 39 +#define KPF_SOFTDIRTY 40 #endif /* LINUX_KERNEL_PAGE_FLAGS_H */ diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index 71c9c25..d5e9d6d 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -59,12 +59,14 @@ #define PM_PSHIFT_BITS 6 #define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) #define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) -#define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) +#define __PM_PSHIFT(x) (((uint64_t) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) #define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) +#define __PM_SOFT_DIRTY (1LL) #define PM_PRESENT PM_STATUS(4LL) #define PM_SWAP PM_STATUS(2LL) +#define PM_SOFT_DIRTY __PM_PSHIFT(__PM_SOFT_DIRTY) /* @@ -83,6 +85,7 @@ #define KPF_OWNER_PRIVATE 37 #define KPF_ARCH 38 #define KPF_UNCACHED 39 +#define KPF_SOFTDIRTY 40 /* [48-] take some arbitrary free slots for expanding overloaded flags * not part of kernel API @@ -132,6 +135,7 @@ static const char * const page_flag_names[] = { [KPF_OWNER_PRIVATE] = "O:owner_private", [KPF_ARCH] = "h:arch", [KPF_UNCACHED] = "c:uncached", + [KPF_SOFTDIRTY] = "f:softdirty", [KPF_READAHEAD] = "I:readahead", [KPF_SLOB_FREE] = "P:slob_free", @@ -417,7 +421,7 @@ static int bit_mask_ok(uint64_t flags) return 1; } -static uint64_t expand_overloaded_flags(uint64_t flags) +static uint64_t expand_overloaded_flags(uint64_t flags, uint64_t pme) { /* SLOB/SLUB overload several page flags */ if (flags & BIT(SLAB)) { @@ -433,6 +437,9 @@ static uint64_t expand_overloaded_flags(uint64_t flags) if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) flags ^= BIT(RECLAIM) | BIT(READAHEAD); + if (pme & PM_SOFT_DIRTY) + flags |= BIT(SOFTDIRTY); + return flags; } @@ -448,11 +455,11 @@ static uint64_t well_known_flags(uint64_t flags) return flags; } -static uint64_t kpageflags_flags(uint64_t flags) +static uint64_t kpageflags_flags(uint64_t flags, uint64_t pme) { - flags = expand_overloaded_flags(flags); - - if (!opt_raw) + if (opt_raw) + flags = expand_overloaded_flags(flags, pme); + else flags = well_known_flags(flags); return flags; @@ -545,9 +552,9 @@ static size_t hash_slot(uint64_t flags) } static void add_page(unsigned long voffset, - unsigned long offset, uint64_t flags) + unsigned long offset, uint64_t flags, uint64_t pme) { - flags = kpageflags_flags(flags); + flags = kpageflags_flags(flags, pme); if (!bit_mask_ok(flags)) return; @@ -569,7 +576,8 @@ static void add_page(unsigned long voffset, #define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */ static void walk_pfn(unsigned long voffset, unsigned long index, - unsigned long count) + unsigned long count, + uint64_t pme) { uint64_t buf[KPAGEFLAGS_BATCH]; unsigned long batch; @@ -583,7 +591,7 @@ static void walk_pfn(unsigned long voffset, break; for (i = 0; i < pages; i++) - add_page(voffset + i, index + i, buf[i]); + add_page(voffset + i, index + i, buf[i], pme); index += pages; count -= pages; @@ -608,7 +616,7 @@ static void walk_vma(unsigned long index, unsigned long count) for (i = 0; i < pages; i++) { pfn = pagemap_pfn(buf[i]); if (pfn) - walk_pfn(index + i, pfn, 1); + walk_pfn(index + i, pfn, 1, buf[i]); } index += pages; @@ -659,7 +667,7 @@ static void walk_addr_ranges(void) for (i = 0; i < nr_addr_ranges; i++) if (!opt_pid) - walk_pfn(0, opt_offset[i], opt_size[i]); + walk_pfn(0, opt_offset[i], opt_size[i], 0); else walk_task(opt_offset[i], opt_size[i]); -- cgit v0.10.2 From c4a391b53a72d2df4ee97f96f78c1d5971b47489 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 12 Nov 2013 15:07:51 -0800 Subject: writeback: do not sync data dirtied after sync start When there are processes heavily creating small files while sync(2) is running, it can easily happen that quite some new files are created between WB_SYNC_NONE and WB_SYNC_ALL pass of sync(2). That can happen especially if there are several busy filesystems (remember that sync traverses filesystems sequentially and waits in WB_SYNC_ALL phase on one fs before starting it on another fs). Because WB_SYNC_ALL pass is slow (e.g. causes a transaction commit and cache flush for each inode in ext3), resulting sync(2) times are rather large. The following script reproduces the problem: function run_writers { for (( i = 0; i < 10; i++ )); do mkdir $1/dir$i for (( j = 0; j < 40000; j++ )); do dd if=/dev/zero of=$1/dir$i/$j bs=4k count=4 &>/dev/null done & done } for dir in "$@"; do run_writers $dir done sleep 40 time sync Fix the problem by disregarding inodes dirtied after sync(2) was called in the WB_SYNC_ALL pass. To allow for this, sync_inodes_sb() now takes a time stamp when sync has started which is used for setting up work for flusher threads. To give some numbers, when above script is run on two ext4 filesystems on simple SATA drive, the average sync time from 10 runs is 267.549 seconds with standard deviation 104.799426. With the patched kernel, the average sync time from 10 runs is 2.995 seconds with standard deviation 0.096. Signed-off-by: Jan Kara Reviewed-by: Fengguang Wu Reviewed-by: Dave Chinner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 9f4935b..4afdbd6 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -39,13 +39,18 @@ struct wb_writeback_work { long nr_pages; struct super_block *sb; - unsigned long *older_than_this; + /* + * Write only inodes dirtied before this time. Don't forget to set + * older_than_this_is_set when you set this. + */ + unsigned long older_than_this; enum writeback_sync_modes sync_mode; unsigned int tagged_writepages:1; unsigned int for_kupdate:1; unsigned int range_cyclic:1; unsigned int for_background:1; unsigned int for_sync:1; /* sync(2) WB_SYNC_ALL writeback */ + unsigned int older_than_this_is_set:1; enum wb_reason reason; /* why was writeback initiated? */ struct list_head list; /* pending work list */ @@ -246,10 +251,10 @@ static int move_expired_inodes(struct list_head *delaying_queue, int do_sb_sort = 0; int moved = 0; + WARN_ON_ONCE(!work->older_than_this_is_set); while (!list_empty(delaying_queue)) { inode = wb_inode(delaying_queue->prev); - if (work->older_than_this && - inode_dirtied_after(inode, *work->older_than_this)) + if (inode_dirtied_after(inode, work->older_than_this)) break; list_move(&inode->i_wb_list, &tmp); moved++; @@ -733,6 +738,8 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages, .sync_mode = WB_SYNC_NONE, .range_cyclic = 1, .reason = reason, + .older_than_this = jiffies, + .older_than_this_is_set = 1, }; spin_lock(&wb->list_lock); @@ -791,12 +798,13 @@ static long wb_writeback(struct bdi_writeback *wb, { unsigned long wb_start = jiffies; long nr_pages = work->nr_pages; - unsigned long oldest_jif; struct inode *inode; long progress; - oldest_jif = jiffies; - work->older_than_this = &oldest_jif; + if (!work->older_than_this_is_set) { + work->older_than_this = jiffies; + work->older_than_this_is_set = 1; + } spin_lock(&wb->list_lock); for (;;) { @@ -830,10 +838,10 @@ static long wb_writeback(struct bdi_writeback *wb, * safe. */ if (work->for_kupdate) { - oldest_jif = jiffies - + work->older_than_this = jiffies - msecs_to_jiffies(dirty_expire_interval * 10); } else if (work->for_background) - oldest_jif = jiffies; + work->older_than_this = jiffies; trace_writeback_start(wb->bdi, work); if (list_empty(&wb->b_io)) @@ -1345,18 +1353,21 @@ EXPORT_SYMBOL(try_to_writeback_inodes_sb); /** * sync_inodes_sb - sync sb inode pages - * @sb: the superblock + * @sb: the superblock + * @older_than_this: timestamp * * This function writes and waits on any dirty inode belonging to this - * super_block. + * superblock that has been dirtied before given timestamp. */ -void sync_inodes_sb(struct super_block *sb) +void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this) { DECLARE_COMPLETION_ONSTACK(done); struct wb_writeback_work work = { .sb = sb, .sync_mode = WB_SYNC_ALL, .nr_pages = LONG_MAX, + .older_than_this = older_than_this, + .older_than_this_is_set = 1, .range_cyclic = 0, .done = &done, .reason = WB_REASON_SYNC, diff --git a/fs/sync.c b/fs/sync.c index 905f3f6..ff96f99 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -27,10 +27,11 @@ * wait == 1 case since in that case write_inode() functions do * sync_dirty_buffer() and thus effectively write one block at a time. */ -static int __sync_filesystem(struct super_block *sb, int wait) +static int __sync_filesystem(struct super_block *sb, int wait, + unsigned long start) { if (wait) - sync_inodes_sb(sb); + sync_inodes_sb(sb, start); else writeback_inodes_sb(sb, WB_REASON_SYNC); @@ -47,6 +48,7 @@ static int __sync_filesystem(struct super_block *sb, int wait) int sync_filesystem(struct super_block *sb) { int ret; + unsigned long start = jiffies; /* * We need to be protected against the filesystem going from @@ -60,17 +62,17 @@ int sync_filesystem(struct super_block *sb) if (sb->s_flags & MS_RDONLY) return 0; - ret = __sync_filesystem(sb, 0); + ret = __sync_filesystem(sb, 0, start); if (ret < 0) return ret; - return __sync_filesystem(sb, 1); + return __sync_filesystem(sb, 1, start); } EXPORT_SYMBOL_GPL(sync_filesystem); static void sync_inodes_one_sb(struct super_block *sb, void *arg) { if (!(sb->s_flags & MS_RDONLY)) - sync_inodes_sb(sb); + sync_inodes_sb(sb, *((unsigned long *)arg)); } static void sync_fs_one_sb(struct super_block *sb, void *arg) @@ -102,9 +104,10 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg) SYSCALL_DEFINE0(sync) { int nowait = 0, wait = 1; + unsigned long start = jiffies; wakeup_flusher_threads(0, WB_REASON_SYNC); - iterate_supers(sync_inodes_one_sb, NULL); + iterate_supers(sync_inodes_one_sb, &start); iterate_supers(sync_fs_one_sb, &nowait); iterate_supers(sync_fs_one_sb, &wait); iterate_bdevs(fdatawrite_one_bdev, NULL); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 15188cc..8968f50 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -918,7 +918,7 @@ xfs_flush_inodes( struct super_block *sb = mp->m_super; if (down_read_trylock(&sb->s_umount)) { - sync_inodes_sb(sb); + sync_inodes_sb(sb, jiffies); up_read(&sb->s_umount); } } diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 021b8a3..fc0e432 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -97,7 +97,7 @@ void writeback_inodes_sb_nr(struct super_block *, unsigned long nr, int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason); int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr, enum wb_reason reason); -void sync_inodes_sb(struct super_block *); +void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this); void wakeup_flusher_threads(long nr_pages, enum wb_reason reason); void inode_wait_for_writeback(struct inode *inode); diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index 464ea82..c7bbbe7 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -287,11 +287,11 @@ TRACE_EVENT(writeback_queue_io, __field(int, reason) ), TP_fast_assign( - unsigned long *older_than_this = work->older_than_this; + unsigned long older_than_this = work->older_than_this; strncpy(__entry->name, dev_name(wb->bdi->dev), 32); - __entry->older = older_than_this ? *older_than_this : 0; + __entry->older = older_than_this; __entry->age = older_than_this ? - (jiffies - *older_than_this) * 1000 / HZ : -1; + (jiffies - older_than_this) * 1000 / HZ : -1; __entry->moved = moved; __entry->reason = work->reason; ), -- cgit v0.10.2 From b349acc76b7f65400b85abd09a5379ddd6fa5a97 Mon Sep 17 00:00:00 2001 From: Weijie Yang Date: Tue, 12 Nov 2013 15:07:52 -0800 Subject: mm/zswap: avoid unnecessary page scanning Add SetPageReclaim() before __swap_writepage() so that page can be moved to the tail of the inactive list, which can avoid unnecessary page scanning as this page was reclaimed by swap subsystem before. Signed-off-by: Weijie Yang Reviewed-by: Bob Liu Reviewed-by: Minchan Kim Acked-by: Seth Jennings Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/zswap.c b/mm/zswap.c index d93510c..001474c 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -556,6 +556,9 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle) SetPageUptodate(page); } + /* move it to the tail of the inactive list after end_writeback */ + SetPageReclaim(page); + /* start writeback */ __swap_writepage(page, &wbc, end_swap_bio_write); page_cache_release(page); -- cgit v0.10.2 From 4e99b02131b280b064d30a5926ef1c4763f3097b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 12 Nov 2013 15:07:54 -0800 Subject: mmap: arch_get_unmapped_area(): use proper mmap base for bottom up direction This is more or less the generic variant of commit 41aacc1eea64 ("x86 get_unmapped_area: Access mmap_legacy_base through mm_struct member"). So effectively architectures which use an own arch_pick_mmap_layout() implementation but call the generic arch_get_unmapped_area() now can also randomize their mmap_base. All architectures which have an own arch_pick_mmap_layout() and call the generic arch_get_unmapped_area() (arm64, s390, tile) currently set mmap_base to TASK_UNMAPPED_BASE. This is also true for the generic arch_pick_mmap_layout() function. So this change is a no-op currently. Signed-off-by: Heiko Carstens Cc: Radu Caragea Cc: Michel Lespinasse Cc: Catalin Marinas Cc: Will Deacon Cc: Chris Metcalf Cc: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mmap.c b/mm/mmap.c index 9d54851..fa206ab 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1872,7 +1872,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, info.flags = 0; info.length = len; - info.low_limit = TASK_UNMAPPED_BASE; + info.low_limit = mm->mmap_base; info.high_limit = TASK_SIZE; info.align_mask = 0; return vm_unmapped_area(&info); -- cgit v0.10.2 From 7aba842f08bb9e8485ff40067dc090ada4c7f575 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 12 Nov 2013 15:07:55 -0800 Subject: s390/mmap: randomize mmap base for bottom up direction Implement mmap base randomization for the bottom up direction, so ASLR works for both mmap layouts on s390. See also commit df54d6fa5427 ("x86 get_unmapped_area(): use proper mmap base for bottom-up direction"). Signed-off-by: Heiko Carstens Cc: Radu Caragea Cc: Michel Lespinasse Cc: Catalin Marinas Cc: Will Deacon Cc: Chris Metcalf Cc: Martin Schwidefsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 6bcb045..9b436c2 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -64,6 +64,11 @@ static unsigned long mmap_rnd(void) return (get_random_int() & 0x7ffUL) << PAGE_SHIFT; } +static unsigned long mmap_base_legacy(void) +{ + return TASK_UNMAPPED_BASE + mmap_rnd(); +} + static inline unsigned long mmap_base(void) { unsigned long gap = rlimit(RLIMIT_STACK); @@ -89,7 +94,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm) * bit is set, or if the expected stack growth is unlimited: */ if (mmap_is_legacy()) { - mm->mmap_base = TASK_UNMAPPED_BASE; + mm->mmap_base = mmap_base_legacy(); mm->get_unmapped_area = arch_get_unmapped_area; } else { mm->mmap_base = mmap_base(); @@ -164,7 +169,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm) * bit is set, or if the expected stack growth is unlimited: */ if (mmap_is_legacy()) { - mm->mmap_base = TASK_UNMAPPED_BASE; + mm->mmap_base = mmap_base_legacy(); mm->get_unmapped_area = s390_get_unmapped_area; } else { mm->mmap_base = mmap_base(); -- cgit v0.10.2 From 1402899e43fda490f08d2c47a7558931f8b9c60c Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Tue, 12 Nov 2013 15:07:57 -0800 Subject: mm/memblock.c: factor out of top-down allocation [Problem] The current Linux cannot migrate pages used by the kernel because of the kernel direct mapping. In Linux kernel space, va = pa + PAGE_OFFSET. When the pa is changed, we cannot simply update the pagetable and keep the va unmodified. So the kernel pages are not migratable. There are also some other issues will cause the kernel pages not migratable. For example, the physical address may be cached somewhere and will be used. It is not to update all the caches. When doing memory hotplug in Linux, we first migrate all the pages in one memory device somewhere else, and then remove the device. But if pages are used by the kernel, they are not migratable. As a result, memory used by the kernel cannot be hot-removed. Modifying the kernel direct mapping mechanism is too difficult to do. And it may cause the kernel performance down and unstable. So we use the following way to do memory hotplug. [What we are doing] In Linux, memory in one numa node is divided into several zones. One of the zones is ZONE_MOVABLE, which the kernel won't use. In order to implement memory hotplug in Linux, we are going to arrange all hotpluggable memory in ZONE_MOVABLE so that the kernel won't use these memory. To do this, we need ACPI's help. In ACPI, SRAT(System Resource Affinity Table) contains NUMA info. The memory affinities in SRAT record every memory range in the system, and also, flags specifying if the memory range is hotpluggable. (Please refer to ACPI spec 5.0 5.2.16) With the help of SRAT, we have to do the following two things to achieve our goal: 1. When doing memory hot-add, allow the users arranging hotpluggable as ZONE_MOVABLE. (This has been done by the MOVABLE_NODE functionality in Linux.) 2. when the system is booting, prevent bootmem allocator from allocating hotpluggable memory for the kernel before the memory initialization finishes. The problem 2 is the key problem we are going to solve. But before solving it, we need some preparation. Please see below. [Preparation] Bootloader has to load the kernel image into memory. And this memory must be unhotpluggable. We cannot prevent this anyway. So in a memory hotplug system, we can assume any node the kernel resides in is not hotpluggable. Before SRAT is parsed, we don't know which memory ranges are hotpluggable. But memblock has already started to work. In the current kernel, memblock allocates the following memory before SRAT is parsed: setup_arch() |->memblock_x86_fill() /* memblock is ready */ |...... |->early_reserve_e820_mpc_new() /* allocate memory under 1MB */ |->reserve_real_mode() /* allocate memory under 1MB */ |->init_mem_mapping() /* allocate page tables, about 2MB to map 1GB memory */ |->dma_contiguous_reserve() /* specified by user, should be low */ |->setup_log_buf() /* specified by user, several mega bytes */ |->relocate_initrd() /* could be large, but will be freed after boot, should reorder */ |->acpi_initrd_override() /* several mega bytes */ |->reserve_crashkernel() /* could be large, should reorder */ |...... |->initmem_init() /* Parse SRAT */ According to Tejun's advice, before SRAT is parsed, we should try our best to allocate memory near the kernel image. Since the whole node the kernel resides in won't be hotpluggable, and for a modern server, a node may have at least 16GB memory, allocating several mega bytes memory around the kernel image won't cross to hotpluggable memory. [About this patchset] So this patchset is the preparation for the problem 2 that we want to solve. It does the following: 1. Make memblock be able to allocate memory bottom up. 1) Keep all the memblock APIs' prototype unmodified. 2) When the direction is bottom up, keep the start address greater than the end of kernel image. 2. Improve init_mem_mapping() to support allocate page tables in bottom up direction. 3. Introduce "movable_node" boot option to enable and disable this functionality. This patch (of 6): Create a new function __memblock_find_range_top_down to factor out of top-down allocation from memblock_find_in_range_node. This is a preparation because we will introduce a new bottom-up allocation mode in the following patch. Signed-off-by: Tang Chen Signed-off-by: Zhang Yanfei Acked-by: Tejun Heo Acked-by: Toshi Kani Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Wanpeng Li Cc: Thomas Renninger Cc: Yinghai Lu Cc: Jiang Liu Cc: Wen Congyang Cc: Lai Jiangshan Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Mel Gorman Cc: Michal Nazarewicz Cc: Minchan Kim Cc: Rik van Riel Cc: Johannes Weiner Cc: Kamezawa Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memblock.c b/mm/memblock.c index 0ac412a..accff10 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -83,33 +83,25 @@ static long __init_memblock memblock_overlaps_region(struct memblock_type *type, } /** - * memblock_find_in_range_node - find free area in given range and node + * __memblock_find_range_top_down - find free area utility, in top-down * @start: start of candidate range * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} * @size: size of free area to find * @align: alignment of free area to find * @nid: nid of the free area to find, %MAX_NUMNODES for any node * - * Find @size free area aligned to @align in the specified range and node. + * Utility called from memblock_find_in_range_node(), find free area top-down. * * RETURNS: * Found address on success, %0 on failure. */ -phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start, - phys_addr_t end, phys_addr_t size, - phys_addr_t align, int nid) +static phys_addr_t __init_memblock +__memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, + phys_addr_t size, phys_addr_t align, int nid) { phys_addr_t this_start, this_end, cand; u64 i; - /* pump up @end */ - if (end == MEMBLOCK_ALLOC_ACCESSIBLE) - end = memblock.current_limit; - - /* avoid allocating the first page */ - start = max_t(phys_addr_t, start, PAGE_SIZE); - end = max(start, end); - for_each_free_mem_range_reverse(i, nid, &this_start, &this_end, NULL) { this_start = clamp(this_start, start, end); this_end = clamp(this_end, start, end); @@ -121,10 +113,39 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start, if (cand >= this_start) return cand; } + return 0; } /** + * memblock_find_in_range_node - find free area in given range and node + * @start: start of candidate range + * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} + * @size: size of free area to find + * @align: alignment of free area to find + * @nid: nid of the free area to find, %MAX_NUMNODES for any node + * + * Find @size free area aligned to @align in the specified range and node. + * + * RETURNS: + * Found address on success, %0 on failure. + */ +phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start, + phys_addr_t end, phys_addr_t size, + phys_addr_t align, int nid) +{ + /* pump up @end */ + if (end == MEMBLOCK_ALLOC_ACCESSIBLE) + end = memblock.current_limit; + + /* avoid allocating the first page */ + start = max_t(phys_addr_t, start, PAGE_SIZE); + end = max(start, end); + + return __memblock_find_range_top_down(start, end, size, align, nid); +} + +/** * memblock_find_in_range - find free area in given range * @start: start of candidate range * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} -- cgit v0.10.2 From 79442ed189acb8b949662676e750eda173c06f9b Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Tue, 12 Nov 2013 15:07:59 -0800 Subject: mm/memblock.c: introduce bottom-up allocation mode The Linux kernel cannot migrate pages used by the kernel. As a result, kernel pages cannot be hot-removed. So we cannot allocate hotpluggable memory for the kernel. ACPI SRAT (System Resource Affinity Table) contains the memory hotplug info. But before SRAT is parsed, memblock has already started to allocate memory for the kernel. So we need to prevent memblock from doing this. In a memory hotplug system, any numa node the kernel resides in should be unhotpluggable. And for a modern server, each node could have at least 16GB memory. So memory around the kernel image is highly likely unhotpluggable. So the basic idea is: Allocate memory from the end of the kernel image and to the higher memory. Since memory allocation before SRAT is parsed won't be too much, it could highly likely be in the same node with kernel image. The current memblock can only allocate memory top-down. So this patch introduces a new bottom-up allocation mode to allocate memory bottom-up. And later when we use this allocation direction to allocate memory, we will limit the start address above the kernel. Signed-off-by: Tang Chen Signed-off-by: Zhang Yanfei Acked-by: Toshi Kani Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Tejun Heo Cc: Wanpeng Li Cc: Thomas Renninger Cc: Yinghai Lu Cc: Jiang Liu Cc: Wen Congyang Cc: Lai Jiangshan Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Mel Gorman Cc: Michal Nazarewicz Cc: Minchan Kim Cc: Rik van Riel Cc: Johannes Weiner Cc: Kamezawa Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 31e95ac..77c60e5 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -35,6 +35,7 @@ struct memblock_type { }; struct memblock { + bool bottom_up; /* is bottom up direction? */ phys_addr_t current_limit; struct memblock_type memory; struct memblock_type reserved; @@ -148,6 +149,29 @@ phys_addr_t memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid) phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align); +#ifdef CONFIG_MOVABLE_NODE +/* + * Set the allocation direction to bottom-up or top-down. + */ +static inline void memblock_set_bottom_up(bool enable) +{ + memblock.bottom_up = enable; +} + +/* + * Check if the allocation direction is bottom-up or not. + * if this is true, that said, memblock will allocate memory + * in bottom-up direction. + */ +static inline bool memblock_bottom_up(void) +{ + return memblock.bottom_up; +} +#else +static inline void memblock_set_bottom_up(bool enable) {} +static inline bool memblock_bottom_up(void) { return false; } +#endif + /* Flags for memblock_alloc_base() amd __memblock_alloc_base() */ #define MEMBLOCK_ALLOC_ANYWHERE (~(phys_addr_t)0) #define MEMBLOCK_ALLOC_ACCESSIBLE 0 diff --git a/include/linux/mm.h b/include/linux/mm.h index 8aa4006..42a35d9 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -50,6 +50,10 @@ extern int sysctl_legacy_va_layout; #include #include +#ifndef __pa_symbol +#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) +#endif + extern unsigned long sysctl_user_reserve_kbytes; extern unsigned long sysctl_admin_reserve_kbytes; diff --git a/mm/memblock.c b/mm/memblock.c index accff10..53e477b 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -20,6 +20,8 @@ #include #include +#include + static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; @@ -32,6 +34,7 @@ struct memblock memblock __initdata_memblock = { .reserved.cnt = 1, /* empty dummy entry */ .reserved.max = INIT_MEMBLOCK_REGIONS, + .bottom_up = false, .current_limit = MEMBLOCK_ALLOC_ANYWHERE, }; @@ -82,6 +85,38 @@ static long __init_memblock memblock_overlaps_region(struct memblock_type *type, return (i < type->cnt) ? i : -1; } +/* + * __memblock_find_range_bottom_up - find free area utility in bottom-up + * @start: start of candidate range + * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} + * @size: size of free area to find + * @align: alignment of free area to find + * @nid: nid of the free area to find, %MAX_NUMNODES for any node + * + * Utility called from memblock_find_in_range_node(), find free area bottom-up. + * + * RETURNS: + * Found address on success, 0 on failure. + */ +static phys_addr_t __init_memblock +__memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, + phys_addr_t size, phys_addr_t align, int nid) +{ + phys_addr_t this_start, this_end, cand; + u64 i; + + for_each_free_mem_range(i, nid, &this_start, &this_end, NULL) { + this_start = clamp(this_start, start, end); + this_end = clamp(this_end, start, end); + + cand = round_up(this_start, align); + if (cand < this_end && this_end - cand >= size) + return cand; + } + + return 0; +} + /** * __memblock_find_range_top_down - find free area utility, in top-down * @start: start of candidate range @@ -93,7 +128,7 @@ static long __init_memblock memblock_overlaps_region(struct memblock_type *type, * Utility called from memblock_find_in_range_node(), find free area top-down. * * RETURNS: - * Found address on success, %0 on failure. + * Found address on success, 0 on failure. */ static phys_addr_t __init_memblock __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, @@ -127,13 +162,24 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, * * Find @size free area aligned to @align in the specified range and node. * + * When allocation direction is bottom-up, the @start should be greater + * than the end of the kernel image. Otherwise, it will be trimmed. The + * reason is that we want the bottom-up allocation just near the kernel + * image so it is highly likely that the allocated memory and the kernel + * will reside in the same node. + * + * If bottom-up allocation failed, will try to allocate memory top-down. + * * RETURNS: - * Found address on success, %0 on failure. + * Found address on success, 0 on failure. */ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid) { + int ret; + phys_addr_t kernel_end; + /* pump up @end */ if (end == MEMBLOCK_ALLOC_ACCESSIBLE) end = memblock.current_limit; @@ -141,6 +187,37 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start, /* avoid allocating the first page */ start = max_t(phys_addr_t, start, PAGE_SIZE); end = max(start, end); + kernel_end = __pa_symbol(_end); + + /* + * try bottom-up allocation only when bottom-up mode + * is set and @end is above the kernel image. + */ + if (memblock_bottom_up() && end > kernel_end) { + phys_addr_t bottom_up_start; + + /* make sure we will allocate above the kernel */ + bottom_up_start = max(start, kernel_end); + + /* ok, try bottom-up allocation first */ + ret = __memblock_find_range_bottom_up(bottom_up_start, end, + size, align, nid); + if (ret) + return ret; + + /* + * we always limit bottom-up allocation above the kernel, + * but top-down allocation doesn't have the limit, so + * retrying top-down allocation may succeed when bottom-up + * allocation failed. + * + * bottom-up allocation is expected to be fail very rarely, + * so we use WARN_ONCE() here to see the stack trace if + * fail happens. + */ + WARN_ONCE(1, "memblock: bottom-up allocation failed, " + "memory hotunplug may be affected\n"); + } return __memblock_find_range_top_down(start, end, size, align, nid); } @@ -155,7 +232,7 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start, * Find @size free area aligned to @align in the specified range. * * RETURNS: - * Found address on success, %0 on failure. + * Found address on success, 0 on failure. */ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, phys_addr_t end, phys_addr_t size, -- cgit v0.10.2 From 0167d7d8b0beb4cf12076b47e4dc73897ae5acb0 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Tue, 12 Nov 2013 15:08:02 -0800 Subject: x86/mm: factor out of top-down direct mapping setup Create a new function memory_map_top_down to factor out of the top-down direct memory mapping pagetable setup. This is also a preparation for the following patch, which will introduce the bottom-up memory mapping. That said, we will put the two ways of pagetable setup into separate functions, and choose to use which way in init_mem_mapping, which makes the code more clear. Signed-off-by: Tang Chen Signed-off-by: Zhang Yanfei Acked-by: Tejun Heo Acked-by: Toshi Kani Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Wanpeng Li Cc: Thomas Renninger Cc: Yinghai Lu Cc: Jiang Liu Cc: Wen Congyang Cc: Lai Jiangshan Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Mel Gorman Cc: Michal Nazarewicz Cc: Minchan Kim Cc: Rik van Riel Cc: Johannes Weiner Cc: Kamezawa Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index ce32017..742d6d4 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -418,27 +418,27 @@ static unsigned long __init get_new_step_size(unsigned long step_size) return step_size << 5; } -void __init init_mem_mapping(void) +/** + * memory_map_top_down - Map [map_start, map_end) top down + * @map_start: start address of the target memory range + * @map_end: end address of the target memory range + * + * This function will setup direct mapping for memory range + * [map_start, map_end) in top-down. That said, the page tables + * will be allocated at the end of the memory, and we map the + * memory in top-down. + */ +static void __init memory_map_top_down(unsigned long map_start, + unsigned long map_end) { - unsigned long end, real_end, start, last_start; + unsigned long real_end, start, last_start; unsigned long step_size; unsigned long addr; unsigned long mapped_ram_size = 0; unsigned long new_mapped_ram_size; - probe_page_size_mask(); - -#ifdef CONFIG_X86_64 - end = max_pfn << PAGE_SHIFT; -#else - end = max_low_pfn << PAGE_SHIFT; -#endif - - /* the ISA range is always mapped regardless of memory holes */ - init_memory_mapping(0, ISA_END_ADDRESS); - /* xen has big range in reserved near end of ram, skip it at first.*/ - addr = memblock_find_in_range(ISA_END_ADDRESS, end, PMD_SIZE, PMD_SIZE); + addr = memblock_find_in_range(map_start, map_end, PMD_SIZE, PMD_SIZE); real_end = addr + PMD_SIZE; /* step_size need to be small so pgt_buf from BRK could cover it */ @@ -453,13 +453,13 @@ void __init init_mem_mapping(void) * end of RAM in [min_pfn_mapped, max_pfn_mapped) used as new pages * for page table. */ - while (last_start > ISA_END_ADDRESS) { + while (last_start > map_start) { if (last_start > step_size) { start = round_down(last_start - 1, step_size); - if (start < ISA_END_ADDRESS) - start = ISA_END_ADDRESS; + if (start < map_start) + start = map_start; } else - start = ISA_END_ADDRESS; + start = map_start; new_mapped_ram_size = init_range_memory_mapping(start, last_start); last_start = start; @@ -470,8 +470,27 @@ void __init init_mem_mapping(void) mapped_ram_size += new_mapped_ram_size; } - if (real_end < end) - init_range_memory_mapping(real_end, end); + if (real_end < map_end) + init_range_memory_mapping(real_end, map_end); +} + +void __init init_mem_mapping(void) +{ + unsigned long end; + + probe_page_size_mask(); + +#ifdef CONFIG_X86_64 + end = max_pfn << PAGE_SHIFT; +#else + end = max_low_pfn << PAGE_SHIFT; +#endif + + /* the ISA range is always mapped regardless of memory holes */ + init_memory_mapping(0, ISA_END_ADDRESS); + + /* setup direct mapping for range [ISA_END_ADDRESS, end) in top-down*/ + memory_map_top_down(ISA_END_ADDRESS, end); #ifdef CONFIG_X86_64 if (max_pfn > max_low_pfn) { -- cgit v0.10.2 From b959ed6c73845aebf51afb8f76bb74b9388344d2 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Tue, 12 Nov 2013 15:08:05 -0800 Subject: x86/mem-hotplug: support initialize page tables in bottom-up The Linux kernel cannot migrate pages used by the kernel. As a result, kernel pages cannot be hot-removed. So we cannot allocate hotpluggable memory for the kernel. In a memory hotplug system, any numa node the kernel resides in should be unhotpluggable. And for a modern server, each node could have at least 16GB memory. So memory around the kernel image is highly likely unhotpluggable. ACPI SRAT (System Resource Affinity Table) contains the memory hotplug info. But before SRAT is parsed, memblock has already started to allocate memory for the kernel. So we need to prevent memblock from doing this. So direct memory mapping page tables setup is the case. init_mem_mapping() is called before SRAT is parsed. To prevent page tables being allocated within hotpluggable memory, we will use bottom-up direction to allocate page tables from the end of kernel image to the higher memory. Note: As for allocating page tables in lower memory, TJ said: : This is an optional behavior which is triggered by a very specific kernel : boot param, which I suspect is gonna need to stick around to support : memory hotplug in the current setup unless we add another layer of address : translation to support memory hotplug. As for page tables may occupy too much lower memory if using 4K mapping (CONFIG_DEBUG_PAGEALLOC and CONFIG_KMEMCHECK both disable using >4k pages), TJ said: : But as I said in the same paragraph, parsing SRAT earlier doesn't solve : the problem in itself either. Ignoring the option if 4k mapping is : required and memory consumption would be prohibitive should work, no? : Something like that would be necessary if we're gonna worry about cases : like this no matter how we implement it, but, frankly, I'm not sure this : is something worth worrying about. Signed-off-by: Tang Chen Signed-off-by: Zhang Yanfei Acked-by: Tejun Heo Acked-by: Toshi Kani Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Wanpeng Li Cc: Thomas Renninger Cc: Yinghai Lu Cc: Jiang Liu Cc: Wen Congyang Cc: Lai Jiangshan Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Mel Gorman Cc: Michal Nazarewicz Cc: Minchan Kim Cc: Rik van Riel Cc: Johannes Weiner Cc: Kamezawa Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 742d6d4..91b5220 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -474,6 +474,51 @@ static void __init memory_map_top_down(unsigned long map_start, init_range_memory_mapping(real_end, map_end); } +/** + * memory_map_bottom_up - Map [map_start, map_end) bottom up + * @map_start: start address of the target memory range + * @map_end: end address of the target memory range + * + * This function will setup direct mapping for memory range + * [map_start, map_end) in bottom-up. Since we have limited the + * bottom-up allocation above the kernel, the page tables will + * be allocated just above the kernel and we map the memory + * in [map_start, map_end) in bottom-up. + */ +static void __init memory_map_bottom_up(unsigned long map_start, + unsigned long map_end) +{ + unsigned long next, new_mapped_ram_size, start; + unsigned long mapped_ram_size = 0; + /* step_size need to be small so pgt_buf from BRK could cover it */ + unsigned long step_size = PMD_SIZE; + + start = map_start; + min_pfn_mapped = start >> PAGE_SHIFT; + + /* + * We start from the bottom (@map_start) and go to the top (@map_end). + * The memblock_find_in_range() gets us a block of RAM from the + * end of RAM in [min_pfn_mapped, max_pfn_mapped) used as new pages + * for page table. + */ + while (start < map_end) { + if (map_end - start > step_size) { + next = round_up(start + 1, step_size); + if (next > map_end) + next = map_end; + } else + next = map_end; + + new_mapped_ram_size = init_range_memory_mapping(start, next); + start = next; + + if (new_mapped_ram_size > mapped_ram_size) + step_size = get_new_step_size(step_size); + mapped_ram_size += new_mapped_ram_size; + } +} + void __init init_mem_mapping(void) { unsigned long end; @@ -489,8 +534,25 @@ void __init init_mem_mapping(void) /* the ISA range is always mapped regardless of memory holes */ init_memory_mapping(0, ISA_END_ADDRESS); - /* setup direct mapping for range [ISA_END_ADDRESS, end) in top-down*/ - memory_map_top_down(ISA_END_ADDRESS, end); + /* + * If the allocation is in bottom-up direction, we setup direct mapping + * in bottom-up, otherwise we setup direct mapping in top-down. + */ + if (memblock_bottom_up()) { + unsigned long kernel_end = __pa_symbol(_end); + + /* + * we need two separate calls here. This is because we want to + * allocate page tables above the kernel. So we first map + * [kernel_end, end) to make memory above the kernel be mapped + * as soon as possible. And then use page tables allocated above + * the kernel to map [ISA_END_ADDRESS, kernel_end). + */ + memory_map_bottom_up(kernel_end, end); + memory_map_bottom_up(ISA_END_ADDRESS, kernel_end); + } else { + memory_map_top_down(ISA_END_ADDRESS, end); + } #ifdef CONFIG_X86_64 if (max_pfn > max_low_pfn) { -- cgit v0.10.2 From fa591c4ae76ecbd4d26d7e8f65429d6d454554a6 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Tue, 12 Nov 2013 15:08:07 -0800 Subject: x86, acpi, crash, kdump: do reserve_crashkernel() after SRAT is parsed. Memory reserved for crashkernel could be large. So we should not allocate this memory bottom up from the end of kernel image. When SRAT is parsed, we will be able to know which memory is hotpluggable, and we can avoid allocating this memory for the kernel. So reorder reserve_crashkernel() after SRAT is parsed. Signed-off-by: Tang Chen Signed-off-by: Zhang Yanfei Acked-by: Tejun Heo Acked-by: Toshi Kani Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Wanpeng Li Cc: Thomas Renninger Cc: Yinghai Lu Cc: Jiang Liu Cc: Wen Congyang Cc: Lai Jiangshan Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Mel Gorman Cc: Michal Nazarewicz Cc: Minchan Kim Cc: Rik van Riel Cc: Johannes Weiner Cc: Kamezawa Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 918d489..cb233bc 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1121,8 +1121,6 @@ void __init setup_arch(char **cmdline_p) acpi_initrd_override((void *)initrd_start, initrd_end - initrd_start); #endif - reserve_crashkernel(); - vsmp_init(); io_delay_init(); @@ -1135,6 +1133,13 @@ void __init setup_arch(char **cmdline_p) early_acpi_boot_init(); initmem_init(); + + /* + * Reserve memory for crash kernel after SRAT is parsed so that it + * won't consume hotpluggable memory. + */ + reserve_crashkernel(); + memblock_find_dma_reserve(); #ifdef CONFIG_KVM_GUEST -- cgit v0.10.2 From c5320926e370b4cfb8f10c2169e26f960079cf67 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Tue, 12 Nov 2013 15:08:10 -0800 Subject: mem-hotplug: introduce movable_node boot option The hot-Pluggable field in SRAT specifies which memory is hotpluggable. As we mentioned before, if hotpluggable memory is used by the kernel, it cannot be hot-removed. So memory hotplug users may want to set all hotpluggable memory in ZONE_MOVABLE so that the kernel won't use it. Memory hotplug users may also set a node as movable node, which has ZONE_MOVABLE only, so that the whole node can be hot-removed. But the kernel cannot use memory in ZONE_MOVABLE. By doing this, the kernel cannot use memory in movable nodes. This will cause NUMA performance down. And other users may be unhappy. So we need a way to allow users to enable and disable this functionality. In this patch, we introduce movable_node boot option to allow users to choose to not to consume hotpluggable memory at early boot time and later we can set it as ZONE_MOVABLE. To achieve this, the movable_node boot option will control the memblock allocation direction. That said, after memblock is ready, before SRAT is parsed, we should allocate memory near the kernel image as we explained in the previous patches. So if movable_node boot option is set, the kernel does the following: 1. After memblock is ready, make memblock allocate memory bottom up. 2. After SRAT is parsed, make memblock behave as default, allocate memory top down. Users can specify "movable_node" in kernel commandline to enable this functionality. For those who don't use memory hotplug or who don't want to lose their NUMA performance, just don't specify anything. The kernel will work as before. Signed-off-by: Tang Chen Signed-off-by: Zhang Yanfei Suggested-by: Kamezawa Hiroyuki Suggested-by: Ingo Molnar Acked-by: Tejun Heo Acked-by: Toshi Kani Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Wanpeng Li Cc: Thomas Renninger Cc: Yinghai Lu Cc: Jiang Liu Cc: Wen Congyang Cc: Lai Jiangshan Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Mel Gorman Cc: Michal Nazarewicz Cc: Minchan Kim Cc: Rik van Riel Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fd3eced..882a40d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1775,6 +1775,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. that the amount of memory usable for all allocations is not too small. + movable_node [KNL,X86] Boot-time switch to enable the effects + of CONFIG_MOVABLE_NODE=y. See mm/Kconfig for details. + MTD_Partition= [MTD] Format: ,,, diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 8bf93ba..24aec58 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -567,6 +567,17 @@ static int __init numa_init(int (*init_func)(void)) ret = init_func(); if (ret < 0) return ret; + + /* + * We reset memblock back to the top-down direction + * here because if we configured ACPI_NUMA, we have + * parsed SRAT in init_func(). It is ok to have the + * reset here even if we did't configure ACPI_NUMA + * or acpi numa init fails and fallbacks to dummy + * numa init. + */ + memblock_set_bottom_up(false); + ret = numa_cleanup_meminfo(&numa_meminfo); if (ret < 0) return ret; diff --git a/mm/Kconfig b/mm/Kconfig index 394838f..3f4ffda 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -153,11 +153,18 @@ config MOVABLE_NODE help Allow a node to have only movable memory. Pages used by the kernel, such as direct mapping pages cannot be migrated. So the corresponding - memory device cannot be hotplugged. This option allows users to - online all the memory of a node as movable memory so that the whole - node can be hotplugged. Users who don't use the memory hotplug - feature are fine with this option on since they don't online memory - as movable. + memory device cannot be hotplugged. This option allows the following + two things: + - When the system is booting, node full of hotpluggable memory can + be arranged to have only movable memory so that the whole node can + be hot-removed. (need movable_node boot option specified). + - After the system is up, the option allows users to online all the + memory of a node as movable memory so that the whole node can be + hot-removed. + + Users who don't use the memory hotplug feature are fine with this + option on since they don't specify movable_node boot option or they + don't online memory as movable. Say Y here if you want to hotplug a whole node. Say N here if you want kernel to use memory on all nodes evenly. diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 1b6fe8c..489f235 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -1422,6 +1423,36 @@ static bool can_offline_normal(struct zone *zone, unsigned long nr_pages) } #endif /* CONFIG_MOVABLE_NODE */ +static int __init cmdline_parse_movable_node(char *p) +{ +#ifdef CONFIG_MOVABLE_NODE + /* + * Memory used by the kernel cannot be hot-removed because Linux + * cannot migrate the kernel pages. When memory hotplug is + * enabled, we should prevent memblock from allocating memory + * for the kernel. + * + * ACPI SRAT records all hotpluggable memory ranges. But before + * SRAT is parsed, we don't know about it. + * + * The kernel image is loaded into memory at very early time. We + * cannot prevent this anyway. So on NUMA system, we set any + * node the kernel resides in as un-hotpluggable. + * + * Since on modern servers, one node could have double-digit + * gigabytes memory, we can assume the memory around the kernel + * image is also un-hotpluggable. So before SRAT is parsed, just + * allocate memory near the kernel image to try the best to keep + * the kernel away from hotpluggable memory. + */ + memblock_set_bottom_up(true); +#else + pr_warn("movable_node option not supported\n"); +#endif + return 0; +} +early_param("movable_node", cmdline_parse_movable_node); + /* check which state of node_states will be changed when offline memory */ static void node_states_check_changes_offline(unsigned long nr_pages, struct zone *zone, struct memory_notify *arg) -- cgit v0.10.2 From d7e0b37a87c39f5c02dd7b5d55c7a3ec2f65b943 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 12 Nov 2013 15:08:12 -0800 Subject: mm: set N_CPU to node_states during boot After a system booted, N_CPU is not set to any node as has_cpu shows an empty line. # cat /sys/devices/system/node/has_cpu (show-empty-line) setup_vmstat() registers its CPU notifier callback, vmstat_cpuup_callback(), which marks N_CPU to a node when a CPU is put into online. However, setup_vmstat() is called after all CPUs are launched in the boot sequence. Changed setup_vmstat() to mark N_CPU to the nodes with online CPUs at boot, which is consistent with other operations in vmstat_cpuup_callback(), i.e. start_cpu_timer() and refresh_zone_stat_thresholds(). Also added get_online_cpus() to protect the for_each_online_cpu() loop. Signed-off-by: Toshi Kani Acked-by: Christoph Lameter Reviewed-by: Yasuaki Ishimatsu Tested-by: Yasuaki Ishimatsu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmstat.c b/mm/vmstat.c index 9bb3145..0a1f7de 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1276,8 +1276,12 @@ static int __init setup_vmstat(void) register_cpu_notifier(&vmstat_notifier); - for_each_online_cpu(cpu) + get_online_cpus(); + for_each_online_cpu(cpu) { start_cpu_timer(cpu); + node_set_state(cpu_to_node(cpu), N_CPU); + } + put_online_cpus(); #endif #ifdef CONFIG_PROC_FS proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); -- cgit v0.10.2 From 807a1bd2b2a38845fd422b93328e7d69f13eb13a Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 12 Nov 2013 15:08:13 -0800 Subject: mm: clear N_CPU from node_states at CPU offline vmstat_cpuup_callback() is a CPU notifier callback, which marks N_CPU to a node at CPU online event. However, it does not update this N_CPU info at CPU offline event. Changed vmstat_cpuup_callback() to clear N_CPU when the last CPU in the node is put into offline, i.e. the node no longer has any online CPU. Signed-off-by: Toshi Kani Acked-by: Christoph Lameter Reviewed-by: Yasuaki Ishimatsu Tested-by: Yasuaki Ishimatsu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmstat.c b/mm/vmstat.c index 0a1f7de..b6d17ed 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1229,6 +1229,20 @@ static void start_cpu_timer(int cpu) schedule_delayed_work_on(cpu, work, __round_jiffies_relative(HZ, cpu)); } +static void vmstat_cpu_dead(int node) +{ + int cpu; + + get_online_cpus(); + for_each_online_cpu(cpu) + if (cpu_to_node(cpu) == node) + goto end; + + node_clear_state(node, N_CPU); +end: + put_online_cpus(); +} + /* * Use the cpu notifier to insure that the thresholds are recalculated * when necessary. @@ -1258,6 +1272,7 @@ static int vmstat_cpuup_callback(struct notifier_block *nfb, case CPU_DEAD: case CPU_DEAD_FROZEN: refresh_zone_stat_thresholds(); + vmstat_cpu_dead(cpu_to_node(cpu)); break; default: break; -- cgit v0.10.2 From 4a099fb4bdb9982759ce2625f50636a6fbd173bc Mon Sep 17 00:00:00 2001 From: Daeseok Youn Date: Tue, 12 Nov 2013 15:08:14 -0800 Subject: mm/bootmem.c: remove unused local `map' Signed-off-by: Daeseok Youn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/bootmem.c b/mm/bootmem.c index 95b528c..90bd350 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -172,11 +172,12 @@ void __init free_bootmem_late(unsigned long physaddr, unsigned long size) static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) { struct page *page; - unsigned long start, end, pages, count = 0; + unsigned long *map, start, end, pages, count = 0; if (!bdata->node_bootmem_map) return 0; + map = bdata->node_bootmem_map; start = bdata->node_min_pfn; end = bdata->node_low_pfn; @@ -184,10 +185,9 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) bdata - bootmem_node_data, start, end); while (start < end) { - unsigned long *map, idx, vec; + unsigned long idx, vec; unsigned shift; - map = bdata->node_bootmem_map; idx = start - bdata->node_min_pfn; shift = idx & (BITS_PER_LONG - 1); /* -- cgit v0.10.2 From c78e93630d15b5f5774213aad9bdc9f52473a89b Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Tue, 12 Nov 2013 15:08:15 -0800 Subject: mm: do not walk all of system memory during show_mem It has been reported on very large machines that show_mem is taking almost 5 minutes to display information. This is a serious problem if there is an OOM storm. The bulk of the cost is in show_mem doing a very expensive PFN walk to give us the following information Total RAM: Also available as totalram_pages Highmem pages: Also available as totalhigh_pages Reserved pages: Can be inferred from the zone structure Shared pages: PFN walk required Unshared pages: PFN walk required Quick pages: Per-cpu walk required Only the shared/unshared pages requires a full PFN walk but that information is useless. It is also inaccurate as page pins of unshared pages would be accounted for as shared. Even if the information was accurate, I'm struggling to think how the shared/unshared information could be useful for debugging OOM conditions. Maybe it was useful before rmap existed when reclaiming shared pages was costly but it is less relevant today. The PFN walk could be optimised a bit but why bother as the information is useless. This patch deletes the PFN walker and infers the total RAM, highmem and reserved pages count from struct zone. It omits the shared/unshared page usage on the grounds that it is useless. It also corrects the reporting of HighMem as HighMem/MovableOnly as ZONE_MOVABLE has similar problems to HighMem with respect to lowmem/highmem exhaustion. Signed-off-by: Mel Gorman Cc: David Rientjes Acked-by: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/show_mem.c b/lib/show_mem.c index b7c7231..5847a49 100644 --- a/lib/show_mem.c +++ b/lib/show_mem.c @@ -12,8 +12,7 @@ void show_mem(unsigned int filter) { pg_data_t *pgdat; - unsigned long total = 0, reserved = 0, shared = 0, - nonshared = 0, highmem = 0; + unsigned long total = 0, reserved = 0, highmem = 0; printk("Mem-Info:\n"); show_free_areas(filter); @@ -22,43 +21,27 @@ void show_mem(unsigned int filter) return; for_each_online_pgdat(pgdat) { - unsigned long i, flags; + unsigned long flags; + int zoneid; pgdat_resize_lock(pgdat, &flags); - for (i = 0; i < pgdat->node_spanned_pages; i++) { - struct page *page; - unsigned long pfn = pgdat->node_start_pfn + i; - - if (unlikely(!(i % MAX_ORDER_NR_PAGES))) - touch_nmi_watchdog(); - - if (!pfn_valid(pfn)) + for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) { + struct zone *zone = &pgdat->node_zones[zoneid]; + if (!populated_zone(zone)) continue; - page = pfn_to_page(pfn); - - if (PageHighMem(page)) - highmem++; + total += zone->present_pages; + reserved = zone->present_pages - zone->managed_pages; - if (PageReserved(page)) - reserved++; - else if (page_count(page) == 1) - nonshared++; - else if (page_count(page) > 1) - shared += page_count(page) - 1; - - total++; + if (is_highmem_idx(zoneid)) + highmem += zone->present_pages; } pgdat_resize_unlock(pgdat, &flags); } printk("%lu pages RAM\n", total); -#ifdef CONFIG_HIGHMEM - printk("%lu pages HighMem\n", highmem); -#endif + printk("%lu pages HighMem/MovableOnly\n", highmem); printk("%lu pages reserved\n", reserved); - printk("%lu pages shared\n", shared); - printk("%lu pages non-shared\n", nonshared); #ifdef CONFIG_QUICKLIST printk("%lu pages in pagetable cache\n", quicklist_total_size()); -- cgit v0.10.2 From af248a0c67457e5c6d2bcf288f07b4b2ed064f1f Mon Sep 17 00:00:00 2001 From: Damien Ramonda Date: Tue, 12 Nov 2013 15:08:16 -0800 Subject: readahead: fix sequential read cache miss detection The kernel's readahead algorithm sometimes interprets random read accesses as sequential and triggers unnecessary data prefecthing from storage device (impacting random read average latency). In order to identify sequential cache read misses, the readahead algorithm intends to check whether offset - previous offset == 1 (trivial sequential reads) or offset - previous offset == 0 (sequential reads not aligned on page boundary): if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL) The current offset is stored in the "offset" variable of type "pgoff_t" (unsigned long), while previous offset is stored in "ra->prev_pos" of type "loff_t" (long long). Therefore, operands of the if statement are implicitly converted to type long long. Consequently, when previous offset > current offset (which happens on random pattern), the if condition is true and access is wrongly interpeted as sequential. An unnecessary data prefetching is triggered, impacting the average random read latency. Storing the previous offset value in a "pgoff_t" variable (unsigned long) fixes the sequential read detection logic. Signed-off-by: Damien Ramonda Reviewed-by: Fengguang Wu Acked-by: Pierre Tardy Acked-by: David Cohen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/readahead.c b/mm/readahead.c index 5024183..7cdbb44 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -401,6 +401,7 @@ ondemand_readahead(struct address_space *mapping, unsigned long req_size) { unsigned long max = max_sane_readahead(ra->ra_pages); + pgoff_t prev_offset; /* * start of file @@ -452,8 +453,11 @@ ondemand_readahead(struct address_space *mapping, /* * sequential cache miss + * trivial case: (offset - prev_offset) == 1 + * unaligned reads: (offset - prev_offset) == 0 */ - if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL) + prev_offset = (unsigned long long)ra->prev_pos >> PAGE_CACHE_SHIFT; + if (offset - prev_offset <= 1UL) goto initial_readahead; /* -- cgit v0.10.2 From 5d0f3f72efb1c1968ce1f56c58f9e3e6495effa6 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 12 Nov 2013 15:08:18 -0800 Subject: mm: fix page_group_by_mobility_disabled breakage Currently, set_pageblock_migratetype() screws up MIGRATE_CMA and MIGRATE_ISOLATE if page_group_by_mobility_disabled is true. It rewrites the argument to MIGRATE_UNMOVABLE and we lost these attribute. The problem was introduced by commit 49255c619fbd ("page allocator: move check for disabled anti-fragmentation out of fastpath"). So a 4 year old issue may mean that nobody uses page_group_by_mobility_disabled. But anyway, this patch fixes the problem. Signed-off-by: KOSAKI Motohiro Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 770dbb4..5a98836 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -234,8 +234,8 @@ int page_group_by_mobility_disabled __read_mostly; void set_pageblock_migratetype(struct page *page, int migratetype) { - - if (unlikely(page_group_by_mobility_disabled)) + if (unlikely(page_group_by_mobility_disabled && + migratetype < MIGRATE_PCPTYPES)) migratetype = MIGRATE_UNMOVABLE; set_pageblock_flags_group(page, (unsigned long)migratetype, -- cgit v0.10.2 From 52c8f6a5aeb0bdd396849ecaa72d96f8175528f5 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 12 Nov 2013 15:08:19 -0800 Subject: mm: get rid of unnecessary overhead of trace_mm_page_alloc_extfrag() In general, every tracepoint should be zero overhead if it is disabled. However, trace_mm_page_alloc_extfrag() is one of exception. It evaluate "new_type == start_migratetype" even if tracepoint is disabled. However, the code can be moved into tracepoint's TP_fast_assign() and TP_fast_assign exist exactly such purpose. This patch does it. Signed-off-by: KOSAKI Motohiro Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h index d0c6134..aece134 100644 --- a/include/trace/events/kmem.h +++ b/include/trace/events/kmem.h @@ -267,14 +267,12 @@ DEFINE_EVENT_PRINT(mm_page, mm_page_pcpu_drain, TRACE_EVENT(mm_page_alloc_extfrag, TP_PROTO(struct page *page, - int alloc_order, int fallback_order, - int alloc_migratetype, int fallback_migratetype, - int change_ownership), + int alloc_order, int fallback_order, + int alloc_migratetype, int fallback_migratetype, int new_migratetype), TP_ARGS(page, alloc_order, fallback_order, - alloc_migratetype, fallback_migratetype, - change_ownership), + alloc_migratetype, fallback_migratetype, new_migratetype), TP_STRUCT__entry( __field( struct page *, page ) @@ -291,7 +289,7 @@ TRACE_EVENT(mm_page_alloc_extfrag, __entry->fallback_order = fallback_order; __entry->alloc_migratetype = alloc_migratetype; __entry->fallback_migratetype = fallback_migratetype; - __entry->change_ownership = change_ownership; + __entry->change_ownership = (new_migratetype == alloc_migratetype); ), TP_printk("page=%p pfn=%lu alloc_order=%d fallback_order=%d pageblock_order=%d alloc_migratetype=%d fallback_migratetype=%d fragmenting=%d change_ownership=%d", diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5a98836..442f129 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1103,9 +1103,8 @@ __rmqueue_fallback(struct zone *zone, int order, int start_migratetype) is_migrate_cma(migratetype) ? migratetype : start_migratetype); - trace_mm_page_alloc_extfrag(page, order, - current_order, start_migratetype, migratetype, - new_type == start_migratetype); + trace_mm_page_alloc_extfrag(page, order, current_order, + start_migratetype, migratetype, new_type); return page; } -- cgit v0.10.2 From 0cbef29a782162a3896487901eca4550bfa397ef Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 12 Nov 2013 15:08:20 -0800 Subject: mm: __rmqueue_fallback() should respect pageblock type When __rmqueue_fallback() doesn't find a free block with the required size it splits a larger page and puts the rest of the page onto the free list. But it has one serious mistake. When putting back, __rmqueue_fallback() always use start_migratetype if type is not CMA. However, __rmqueue_fallback() is only called when all of the start_migratetype queue is empty. That said, __rmqueue_fallback always puts back memory to the wrong queue except try_to_steal_freepages() changed pageblock type (i.e. requested size is smaller than half of page block). The end result is that the antifragmentation framework increases fragmenation instead of decreasing it. Mel's original anti fragmentation does the right thing. But commit 47118af076f6 ("mm: mmzone: MIGRATE_CMA migration type added") broke it. This patch restores sane and old behavior. It also removes an incorrect comment which was introduced by commit fef903efcf0c ("mm/page_alloc.c: restructure free-page stealing code and fix a bug"). Signed-off-by: KOSAKI Motohiro Cc: Mel Gorman Cc: Michal Nazarewicz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 442f129..cb17e8b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1027,6 +1027,10 @@ static int try_to_steal_freepages(struct zone *zone, struct page *page, { int current_order = page_order(page); + /* + * When borrowing from MIGRATE_CMA, we need to release the excess + * buddy pages to CMA itself. + */ if (is_migrate_cma(fallback_type)) return fallback_type; @@ -1091,17 +1095,8 @@ __rmqueue_fallback(struct zone *zone, int order, int start_migratetype) list_del(&page->lru); rmv_page_order(page); - /* - * Borrow the excess buddy pages as well, irrespective - * of whether we stole freepages, or took ownership of - * the pageblock or not. - * - * Exception: When borrowing from MIGRATE_CMA, release - * the excess buddy pages to CMA itself. - */ expand(zone, page, order, current_order, area, - is_migrate_cma(migratetype) - ? migratetype : start_migratetype); + new_type); trace_mm_page_alloc_extfrag(page, order, current_order, start_migratetype, migratetype, new_type); -- cgit v0.10.2 From 2afc745f3e3079ab16c826be4860da2529054dd2 Mon Sep 17 00:00:00 2001 From: Akira Takeuchi Date: Tue, 12 Nov 2013 15:08:21 -0800 Subject: mm: ensure get_unmapped_area() returns higher address than mmap_min_addr This patch fixes the problem that get_unmapped_area() can return illegal address and result in failing mmap(2) etc. In case that the address higher than PAGE_SIZE is set to /proc/sys/vm/mmap_min_addr, the address lower than mmap_min_addr can be returned by get_unmapped_area(), even if you do not pass any virtual address hint (i.e. the second argument). This is because the current get_unmapped_area() code does not take into account mmap_min_addr. This leads to two actual problems as follows: 1. mmap(2) can fail with EPERM on the process without CAP_SYS_RAWIO, although any illegal parameter is not passed. 2. The bottom-up search path after the top-down search might not work in arch_get_unmapped_area_topdown(). Note: The first and third chunk of my patch, which changes "len" check, are for more precise check using mmap_min_addr, and not for solving the above problem. [How to reproduce] --- test.c ------------------------------------------------- #include #include #include #include int main(int argc, char *argv[]) { void *ret = NULL, *last_map; size_t pagesize = sysconf(_SC_PAGESIZE); do { last_map = ret; ret = mmap(0, pagesize, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); // printf("ret=%p\n", ret); } while (ret != MAP_FAILED); if (errno != ENOMEM) { printf("ERR: unexpected errno: %d (last map=%p)\n", errno, last_map); } return 0; } --------------------------------------------------------------- $ gcc -m32 -o test test.c $ sudo sysctl -w vm.mmap_min_addr=65536 vm.mmap_min_addr = 65536 $ ./test (run as non-priviledge user) ERR: unexpected errno: 1 (last map=0x10000) Signed-off-by: Akira Takeuchi Signed-off-by: Kiyoshi Owada Reviewed-by: Naoya Horiguchi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mmap.c b/mm/mmap.c index fa206ab..3d3e224 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1856,7 +1856,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, struct vm_area_struct *vma; struct vm_unmapped_area_info info; - if (len > TASK_SIZE) + if (len > TASK_SIZE - mmap_min_addr) return -ENOMEM; if (flags & MAP_FIXED) @@ -1865,7 +1865,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && (!vma || addr + len <= vma->vm_start)) return addr; } @@ -1895,7 +1895,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, struct vm_unmapped_area_info info; /* requested length too big for entire address space */ - if (len > TASK_SIZE) + if (len > TASK_SIZE - mmap_min_addr) return -ENOMEM; if (flags & MAP_FIXED) @@ -1905,14 +1905,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && (!vma || addr + len <= vma->vm_start)) return addr; } info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; - info.low_limit = PAGE_SIZE; + info.low_limit = max(PAGE_SIZE, mmap_min_addr); info.high_limit = mm->mmap_base; info.align_mask = 0; addr = vm_unmapped_area(&info); -- cgit v0.10.2 From f35c3a8eed52878c2dde9c4b9a87b276127f7f8d Mon Sep 17 00:00:00 2001 From: Qiang Huang Date: Tue, 12 Nov 2013 15:08:22 -0800 Subject: memcg, kmem: use is_root_cache instead of hard code Signed-off-by: Qiang Huang Reviewed-by: Pekka Enberg Acked-by: David Rientjes Cc: Johannes Weiner Cc: Michal Hocko Cc: Glauber Costa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memcontrol.c b/mm/memcontrol.c index c890724..3d28d5a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -59,6 +59,7 @@ #include #include #include +#include "slab.h" #include @@ -3131,7 +3132,7 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups) { struct memcg_cache_params *cur_params = s->memcg_params; - VM_BUG_ON(s->memcg_params && !s->memcg_params->is_root_cache); + VM_BUG_ON(!is_root_cache(s)); if (num_groups > memcg_limited_groups_array_size) { int i; -- cgit v0.10.2 From 2ade4de871172b17dd81b336cf0488a83885ffde Mon Sep 17 00:00:00 2001 From: Qiang Huang Date: Tue, 12 Nov 2013 15:08:23 -0800 Subject: memcg, kmem: rename cache_from_memcg to cache_from_memcg_idx We can't see the relationship with memcg from the parameters, so the name with memcg_idx would be more reasonable. Signed-off-by: Qiang Huang Reviewed-by: Pekka Enberg Acked-by: David Rientjes Cc: Johannes Weiner Cc: Michal Hocko Cc: Glauber Costa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/slab.c b/mm/slab.c index 2580db0..0c8967b 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3982,7 +3982,7 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit, VM_BUG_ON(!mutex_is_locked(&slab_mutex)); for_each_memcg_cache_index(i) { - c = cache_from_memcg(cachep, i); + c = cache_from_memcg_idx(cachep, i); if (c) /* return value determined by the parent cache only */ __do_tune_cpucache(c, limit, batchcount, shared, gfp); diff --git a/mm/slab.h b/mm/slab.h index a535033..0859c42 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -160,7 +160,8 @@ static inline const char *cache_name(struct kmem_cache *s) return s->name; } -static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx) +static inline struct kmem_cache * +cache_from_memcg_idx(struct kmem_cache *s, int idx) { if (!s->memcg_params) return NULL; @@ -204,7 +205,8 @@ static inline const char *cache_name(struct kmem_cache *s) return s->name; } -static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx) +static inline struct kmem_cache * +cache_from_memcg_idx(struct kmem_cache *s, int idx) { return NULL; } diff --git a/mm/slab_common.c b/mm/slab_common.c index e2e98af..0b7bb39 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -571,7 +571,7 @@ memcg_accumulate_slabinfo(struct kmem_cache *s, struct slabinfo *info) return; for_each_memcg_cache_index(i) { - c = cache_from_memcg(s, i); + c = cache_from_memcg_idx(s, i); if (!c) continue; diff --git a/mm/slub.c b/mm/slub.c index c3eb3d3..92737a0 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -4983,7 +4983,7 @@ static ssize_t slab_attr_store(struct kobject *kobj, * through the descendants with best-effort propagation. */ for_each_memcg_cache_index(i) { - struct kmem_cache *c = cache_from_memcg(s, i); + struct kmem_cache *c = cache_from_memcg_idx(s, i); if (c) attribute->store(c, buf, len); } -- cgit v0.10.2 From 7a67d7abcc8da30a16ed64c3909d3fea004bde93 Mon Sep 17 00:00:00 2001 From: Qiang Huang Date: Tue, 12 Nov 2013 15:08:24 -0800 Subject: memcg, kmem: use cache_from_memcg_idx instead of hard code Signed-off-by: Qiang Huang Reviewed-by: Pekka Enberg Acked-by: David Rientjes Cc: Johannes Weiner Cc: Michal Hocko Cc: Glauber Costa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3d28d5a..3d4bb07 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2956,7 +2956,7 @@ static struct kmem_cache *memcg_params_to_cache(struct memcg_cache_params *p) VM_BUG_ON(p->is_root_cache); cachep = p->root_cache; - return cachep->memcg_params->memcg_caches[memcg_cache_id(p->memcg)]; + return cache_from_memcg_idx(cachep, memcg_cache_id(p->memcg)); } #ifdef CONFIG_SLABINFO @@ -3393,7 +3393,7 @@ static struct kmem_cache *memcg_create_kmem_cache(struct mem_cgroup *memcg, idx = memcg_cache_id(memcg); mutex_lock(&memcg_cache_mutex); - new_cachep = cachep->memcg_params->memcg_caches[idx]; + new_cachep = cache_from_memcg_idx(cachep, idx); if (new_cachep) { css_put(&memcg->css); goto out; @@ -3439,8 +3439,8 @@ void kmem_cache_destroy_memcg_children(struct kmem_cache *s) * we'll take the set_limit_mutex to protect ourselves against this. */ mutex_lock(&set_limit_mutex); - for (i = 0; i < memcg_limited_groups_array_size; i++) { - c = s->memcg_params->memcg_caches[i]; + for_each_memcg_cache_index(i) { + c = cache_from_memcg_idx(s, i); if (!c) continue; @@ -3573,8 +3573,8 @@ struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep, * code updating memcg_caches will issue a write barrier to match this. */ read_barrier_depends(); - if (likely(cachep->memcg_params->memcg_caches[idx])) { - cachep = cachep->memcg_params->memcg_caches[idx]; + if (likely(cache_from_memcg_idx(cachep, idx))) { + cachep = cache_from_memcg_idx(cachep, idx); goto out; } -- cgit v0.10.2 From 67d13fe846c57a54d12578e7a4518f68c5c86ad7 Mon Sep 17 00:00:00 2001 From: Weijie Yang Date: Tue, 12 Nov 2013 15:08:26 -0800 Subject: mm/zswap: bugfix: memory leak when invalidate and reclaim occur concurrently Consider the following scenario: thread 0: reclaim entry x (get refcount, but not call zswap_get_swap_cache_page) thread 1: call zswap_frontswap_invalidate_page to invalidate entry x. finished, entry x and its zbud is not freed as its refcount != 0 now, the swap_map[x] = 0 thread 0: now call zswap_get_swap_cache_page swapcache_prepare return -ENOENT because entry x is not used any more zswap_get_swap_cache_page return ZSWAP_SWAPCACHE_NOMEM zswap_writeback_entry do nothing except put refcount Now, the memory of zswap_entry x and its zpage leak. Modify: - check the refcount in fail path, free memory if it is not referenced. - use ZSWAP_SWAPCACHE_FAIL instead of ZSWAP_SWAPCACHE_NOMEM as the fail path can be not only caused by nomem but also by invalidate. Signed-off-by: Weijie Yang Reviewed-by: Bob Liu Reviewed-by: Minchan Kim Acked-by: Seth Jennings Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/zswap.c b/mm/zswap.c index 001474c..0ffcad0 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -387,7 +387,7 @@ static void zswap_free_entry(struct zswap_tree *tree, struct zswap_entry *entry) enum zswap_get_swap_ret { ZSWAP_SWAPCACHE_NEW, ZSWAP_SWAPCACHE_EXIST, - ZSWAP_SWAPCACHE_NOMEM + ZSWAP_SWAPCACHE_FAIL, }; /* @@ -401,9 +401,10 @@ enum zswap_get_swap_ret { * added to the swap cache, and returned in retpage. * * If success, the swap cache page is returned in retpage - * Returns 0 if page was already in the swap cache, page is not locked - * Returns 1 if the new page needs to be populated, page is locked - * Returns <0 on error + * Returns ZSWAP_SWAPCACHE_EXIST if page was already in the swap cache + * Returns ZSWAP_SWAPCACHE_NEW if the new page needs to be populated, + * the new page is added to swapcache and locked + * Returns ZSWAP_SWAPCACHE_FAIL on error */ static int zswap_get_swap_cache_page(swp_entry_t entry, struct page **retpage) @@ -475,7 +476,7 @@ static int zswap_get_swap_cache_page(swp_entry_t entry, if (new_page) page_cache_release(new_page); if (!found_page) - return ZSWAP_SWAPCACHE_NOMEM; + return ZSWAP_SWAPCACHE_FAIL; *retpage = found_page; return ZSWAP_SWAPCACHE_EXIST; } @@ -529,11 +530,11 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle) /* try to allocate swap cache page */ switch (zswap_get_swap_cache_page(swpentry, &page)) { - case ZSWAP_SWAPCACHE_NOMEM: /* no memory */ + case ZSWAP_SWAPCACHE_FAIL: /* no memory or invalidate happened */ ret = -ENOMEM; goto fail; - case ZSWAP_SWAPCACHE_EXIST: /* page is unlocked */ + case ZSWAP_SWAPCACHE_EXIST: /* page is already in the swap cache, ignore for now */ page_cache_release(page); ret = -EEXIST; @@ -594,7 +595,12 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle) fail: spin_lock(&tree->lock); - zswap_entry_put(entry); + refcount = zswap_entry_put(entry); + if (refcount <= 0) { + /* invalidate happened, consider writeback as success */ + zswap_free_entry(tree, entry); + ret = 0; + } spin_unlock(&tree->lock); return ret; } -- cgit v0.10.2 From 0ab0abcf511545d1fddbe72a36b3ca73388ac937 Mon Sep 17 00:00:00 2001 From: Weijie Yang Date: Tue, 12 Nov 2013 15:08:27 -0800 Subject: mm/zswap: refactor the get/put routines The refcount routine was not fit the kernel get/put semantic exactly, There were too many judgement statements on refcount and it could be minus. This patch does the following: - move refcount judgement to zswap_entry_put() to hide resource free function. - add a new function zswap_entry_find_get(), so that callers can use easily in the following pattern: zswap_entry_find_get .../* do something */ zswap_entry_put - to eliminate compile error, move some functions declaration This patch is based on Minchan Kim 's idea and suggestion. Signed-off-by: Weijie Yang Cc: Seth Jennings Acked-by: Minchan Kim Cc: Bob Liu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/zswap.c b/mm/zswap.c index 0ffcad0..5a63f78 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -217,6 +217,7 @@ static struct zswap_entry *zswap_entry_cache_alloc(gfp_t gfp) if (!entry) return NULL; entry->refcount = 1; + RB_CLEAR_NODE(&entry->rbnode); return entry; } @@ -225,19 +226,6 @@ static void zswap_entry_cache_free(struct zswap_entry *entry) kmem_cache_free(zswap_entry_cache, entry); } -/* caller must hold the tree lock */ -static void zswap_entry_get(struct zswap_entry *entry) -{ - entry->refcount++; -} - -/* caller must hold the tree lock */ -static int zswap_entry_put(struct zswap_entry *entry) -{ - entry->refcount--; - return entry->refcount; -} - /********************************* * rbtree functions **********************************/ @@ -285,6 +273,61 @@ static int zswap_rb_insert(struct rb_root *root, struct zswap_entry *entry, return 0; } +static void zswap_rb_erase(struct rb_root *root, struct zswap_entry *entry) +{ + if (!RB_EMPTY_NODE(&entry->rbnode)) { + rb_erase(&entry->rbnode, root); + RB_CLEAR_NODE(&entry->rbnode); + } +} + +/* + * Carries out the common pattern of freeing and entry's zsmalloc allocation, + * freeing the entry itself, and decrementing the number of stored pages. + */ +static void zswap_free_entry(struct zswap_tree *tree, + struct zswap_entry *entry) +{ + zbud_free(tree->pool, entry->handle); + zswap_entry_cache_free(entry); + atomic_dec(&zswap_stored_pages); + zswap_pool_pages = zbud_get_pool_size(tree->pool); +} + +/* caller must hold the tree lock */ +static void zswap_entry_get(struct zswap_entry *entry) +{ + entry->refcount++; +} + +/* caller must hold the tree lock +* remove from the tree and free it, if nobody reference the entry +*/ +static void zswap_entry_put(struct zswap_tree *tree, + struct zswap_entry *entry) +{ + int refcount = --entry->refcount; + + BUG_ON(refcount < 0); + if (refcount == 0) { + zswap_rb_erase(&tree->rbroot, entry); + zswap_free_entry(tree, entry); + } +} + +/* caller must hold the tree lock */ +static struct zswap_entry *zswap_entry_find_get(struct rb_root *root, + pgoff_t offset) +{ + struct zswap_entry *entry = NULL; + + entry = zswap_rb_search(root, offset); + if (entry) + zswap_entry_get(entry); + + return entry; +} + /********************************* * per-cpu code **********************************/ @@ -368,18 +411,6 @@ static bool zswap_is_full(void) zswap_pool_pages); } -/* - * Carries out the common pattern of freeing and entry's zsmalloc allocation, - * freeing the entry itself, and decrementing the number of stored pages. - */ -static void zswap_free_entry(struct zswap_tree *tree, struct zswap_entry *entry) -{ - zbud_free(tree->pool, entry->handle); - zswap_entry_cache_free(entry); - atomic_dec(&zswap_stored_pages); - zswap_pool_pages = zbud_get_pool_size(tree->pool); -} - /********************************* * writeback code **********************************/ @@ -503,7 +534,7 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle) struct page *page; u8 *src, *dst; unsigned int dlen; - int ret, refcount; + int ret; struct writeback_control wbc = { .sync_mode = WB_SYNC_NONE, }; @@ -518,13 +549,12 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle) /* find and ref zswap entry */ spin_lock(&tree->lock); - entry = zswap_rb_search(&tree->rbroot, offset); + entry = zswap_entry_find_get(&tree->rbroot, offset); if (!entry) { /* entry was invalidated */ spin_unlock(&tree->lock); return 0; } - zswap_entry_get(entry); spin_unlock(&tree->lock); BUG_ON(offset != entry->offset); @@ -566,42 +596,35 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle) zswap_written_back_pages++; spin_lock(&tree->lock); - /* drop local reference */ - zswap_entry_put(entry); - /* drop the initial reference from entry creation */ - refcount = zswap_entry_put(entry); + zswap_entry_put(tree, entry); /* - * There are three possible values for refcount here: - * (1) refcount is 1, load is in progress, unlink from rbtree, - * load will free - * (2) refcount is 0, (normal case) entry is valid, - * remove from rbtree and free entry - * (3) refcount is -1, invalidate happened during writeback, - * free entry - */ - if (refcount >= 0) { - /* no invalidate yet, remove from rbtree */ - rb_erase(&entry->rbnode, &tree->rbroot); - } + * There are two possible situations for entry here: + * (1) refcount is 1(normal case), entry is valid and on the tree + * (2) refcount is 0, entry is freed and not on the tree + * because invalidate happened during writeback + * search the tree and free the entry if find entry + */ + if (entry == zswap_rb_search(&tree->rbroot, offset)) + zswap_entry_put(tree, entry); spin_unlock(&tree->lock); - if (refcount <= 0) { - /* free the entry */ - zswap_free_entry(tree, entry); - return 0; - } - return -EAGAIN; + goto end; + + /* + * if we get here due to ZSWAP_SWAPCACHE_EXIST + * a load may happening concurrently + * it is safe and okay to not free the entry + * if we free the entry in the following put + * it it either okay to return !0 + */ fail: spin_lock(&tree->lock); - refcount = zswap_entry_put(entry); - if (refcount <= 0) { - /* invalidate happened, consider writeback as success */ - zswap_free_entry(tree, entry); - ret = 0; - } + zswap_entry_put(tree, entry); spin_unlock(&tree->lock); + +end: return ret; } @@ -685,11 +708,8 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, if (ret == -EEXIST) { zswap_duplicate_entry++; /* remove from rbtree */ - rb_erase(&dupentry->rbnode, &tree->rbroot); - if (!zswap_entry_put(dupentry)) { - /* free */ - zswap_free_entry(tree, dupentry); - } + zswap_rb_erase(&tree->rbroot, dupentry); + zswap_entry_put(tree, dupentry); } } while (ret == -EEXIST); spin_unlock(&tree->lock); @@ -718,17 +738,16 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset, struct zswap_entry *entry; u8 *src, *dst; unsigned int dlen; - int refcount, ret; + int ret; /* find */ spin_lock(&tree->lock); - entry = zswap_rb_search(&tree->rbroot, offset); + entry = zswap_entry_find_get(&tree->rbroot, offset); if (!entry) { /* entry was written back */ spin_unlock(&tree->lock); return -1; } - zswap_entry_get(entry); spin_unlock(&tree->lock); /* decompress */ @@ -743,22 +762,9 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset, BUG_ON(ret); spin_lock(&tree->lock); - refcount = zswap_entry_put(entry); - if (likely(refcount)) { - spin_unlock(&tree->lock); - return 0; - } + zswap_entry_put(tree, entry); spin_unlock(&tree->lock); - /* - * We don't have to unlink from the rbtree because - * zswap_writeback_entry() or zswap_frontswap_invalidate page() - * has already done this for us if we are the last reference. - */ - /* free */ - - zswap_free_entry(tree, entry); - return 0; } @@ -767,7 +773,6 @@ static void zswap_frontswap_invalidate_page(unsigned type, pgoff_t offset) { struct zswap_tree *tree = zswap_trees[type]; struct zswap_entry *entry; - int refcount; /* find */ spin_lock(&tree->lock); @@ -779,20 +784,12 @@ static void zswap_frontswap_invalidate_page(unsigned type, pgoff_t offset) } /* remove from rbtree */ - rb_erase(&entry->rbnode, &tree->rbroot); + zswap_rb_erase(&tree->rbroot, entry); /* drop the initial reference from entry creation */ - refcount = zswap_entry_put(entry); + zswap_entry_put(tree, entry); spin_unlock(&tree->lock); - - if (refcount) { - /* writeback in progress, writeback will free */ - return; - } - - /* free */ - zswap_free_entry(tree, entry); } /* frees all zswap entries for the given swap type */ @@ -806,11 +803,8 @@ static void zswap_frontswap_invalidate_area(unsigned type) /* walk the tree and free everything */ spin_lock(&tree->lock); - rbtree_postorder_for_each_entry_safe(entry, n, &tree->rbroot, rbnode) { - zbud_free(tree->pool, entry->handle); - zswap_entry_cache_free(entry); - atomic_dec(&zswap_stored_pages); - } + rbtree_postorder_for_each_entry_safe(entry, n, &tree->rbroot, rbnode) + zswap_free_entry(tree, entry); tree->rbroot = RB_ROOT; spin_unlock(&tree->lock); -- cgit v0.10.2 From d4dd100f2ebb2bc9aca5378ad3cb333b6117069c Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Tue, 12 Nov 2013 15:08:28 -0800 Subject: arch/x86/mm/init.c: fix incorrect function name in alloc_low_pages() Signed-off-by: Zhi Yong Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 91b5220..f971306 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -53,12 +53,12 @@ __ref void *alloc_low_pages(unsigned int num) if ((pgt_buf_end + num) > pgt_buf_top || !can_use_brk_pgt) { unsigned long ret; if (min_pfn_mapped >= max_pfn_mapped) - panic("alloc_low_page: ran out of memory"); + panic("alloc_low_pages: ran out of memory"); ret = memblock_find_in_range(min_pfn_mapped << PAGE_SHIFT, max_pfn_mapped << PAGE_SHIFT, PAGE_SIZE * num , PAGE_SIZE); if (!ret) - panic("alloc_low_page: can not alloc memory"); + panic("alloc_low_pages: can not alloc memory"); memblock_reserve(ret, PAGE_SIZE * num); pfn = ret >> PAGE_SHIFT; } else { -- cgit v0.10.2 From a1aeb65a4c80d8e97eca8bcde02a5aeae11f6201 Mon Sep 17 00:00:00 2001 From: Zhi Yong Wu Date: Tue, 12 Nov 2013 15:08:29 -0800 Subject: mm/page_alloc.c: fix comment in zlc_setup() Signed-off-by: Zhi Yong Wu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index cb17e8b..580a5f0 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1705,7 +1705,7 @@ bool zone_watermark_ok_safe(struct zone *z, int order, unsigned long mark, * comments in mmzone.h. Reduces cache footprint of zonelist scans * that have to skip over a lot of full or unallowed zones. * - * If the zonelist cache is present in the passed in zonelist, then + * If the zonelist cache is present in the passed zonelist, then * returns a pointer to the allowed node mask (either the current * tasks mems_allowed, or node_states[N_MEMORY].) * -- cgit v0.10.2 From 715ea41e60277f28f84d6c937737350e00955d56 Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Tue, 12 Nov 2013 15:08:30 -0800 Subject: mm: improve the description for dirty_background_ratio/dirty_ratio sysctl Now dirty_background_ratio/dirty_ratio contains a percentage of total avaiable memory, which contains free pages and reclaimable pages. The number of these pages is not equal to the number of total system memory. But they are described as a percentage of total system memory in Documentation/sysctl/vm.txt. So we need to fix them to avoid misunderstanding. Signed-off-by: Zheng Liu Cc: Rob Landley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 79a797e..1fbd4eb 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -119,8 +119,11 @@ other appears as 0 when read. dirty_background_ratio -Contains, as a percentage of total system memory, the number of pages at which -the background kernel flusher threads will start writing out dirty data. +Contains, as a percentage of total available memory that contains free pages +and reclaimable pages, the number of pages at which the background kernel +flusher threads will start writing out dirty data. + +The total avaiable memory is not equal to total system memory. ============================================================== @@ -151,9 +154,11 @@ interval will be written out next time a flusher thread wakes up. dirty_ratio -Contains, as a percentage of total system memory, the number of pages at which -a process which is generating disk writes will itself start writing out dirty -data. +Contains, as a percentage of total available memory that contains free pages +and reclaimable pages, the number of pages at which a process which is +generating disk writes will itself start writing out dirty data. + +The total avaiable memory is not equal to total system memory. ============================================================== -- cgit v0.10.2 From 00619bcc44d6b779aa366130b354153c222e4380 Mon Sep 17 00:00:00 2001 From: Jerome Marchand Date: Tue, 12 Nov 2013 15:08:31 -0800 Subject: mm: factor commit limit calculation The same calculation is currently done in three differents places. Factor that code so future changes has to be made at only one place. [akpm@linux-foundation.org: uninline vm_commit_limit()] Signed-off-by: Jerome Marchand Cc: Dave Hansen Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index 59d85d6..c805d5b 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c @@ -24,7 +24,6 @@ static int meminfo_proc_show(struct seq_file *m, void *v) { struct sysinfo i; unsigned long committed; - unsigned long allowed; struct vmalloc_info vmi; long cached; unsigned long pages[NR_LRU_LISTS]; @@ -37,8 +36,6 @@ static int meminfo_proc_show(struct seq_file *m, void *v) si_meminfo(&i); si_swapinfo(&i); committed = percpu_counter_read_positive(&vm_committed_as); - allowed = ((totalram_pages - hugetlb_total_pages()) - * sysctl_overcommit_ratio / 100) + total_swap_pages; cached = global_page_state(NR_FILE_PAGES) - total_swapcache_pages() - i.bufferram; @@ -147,7 +144,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) K(global_page_state(NR_UNSTABLE_NFS)), K(global_page_state(NR_BOUNCE)), K(global_page_state(NR_WRITEBACK_TEMP)), - K(allowed), + K(vm_commit_limit()), K(committed), (unsigned long)VMALLOC_TOTAL >> 10, vmi.used >> 10, diff --git a/include/linux/mman.h b/include/linux/mman.h index 92dc257..7f7f8da 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -87,4 +87,6 @@ calc_vm_flag_bits(unsigned long flags) _calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) | _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ); } + +unsigned long vm_commit_limit(void); #endif /* _LINUX_MMAN_H */ diff --git a/mm/mmap.c b/mm/mmap.c index 3d3e224..803048e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -179,14 +179,12 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) goto error; } - allowed = (totalram_pages - hugetlb_total_pages()) - * sysctl_overcommit_ratio / 100; + allowed = vm_commit_limit(); /* * Reserve some for root */ if (!cap_sys_admin) allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10); - allowed += total_swap_pages; /* * Don't let a single process grow so big a user can't recover diff --git a/mm/nommu.c b/mm/nommu.c index ecd1f15..d8a957b 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1948,13 +1948,12 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) goto error; } - allowed = totalram_pages * sysctl_overcommit_ratio / 100; + allowed = vm_commit_limit(); /* * Reserve some 3% for root */ if (!cap_sys_admin) allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10); - allowed += total_swap_pages; /* * Don't let a single process grow so big a user can't recover diff --git a/mm/util.c b/mm/util.c index eaf63fc2..f7bc209 100644 --- a/mm/util.c +++ b/mm/util.c @@ -7,6 +7,9 @@ #include #include #include +#include +#include + #include #include "internal.h" @@ -398,6 +401,16 @@ struct address_space *page_mapping(struct page *page) return mapping; } +/* + * Committed memory limit enforced when OVERCOMMIT_NEVER policy is used + */ +unsigned long vm_commit_limit(void) +{ + return ((totalram_pages - hugetlb_total_pages()) + * sysctl_overcommit_ratio / 100) + total_swap_pages; +} + + /* Tracepoints definitions. */ EXPORT_TRACEPOINT_SYMBOL(kmalloc); EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc); -- cgit v0.10.2 From 72403b4a0fbdf433c1fe0127e49864658f6f6468 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Tue, 12 Nov 2013 15:08:32 -0800 Subject: mm: numa: return the number of base pages altered by protection changes Commit 0255d4918480 ("mm: Account for a THP NUMA hinting update as one PTE update") was added to account for the number of PTE updates when marking pages prot_numa. task_numa_work was using the old return value to track how much address space had been updated. Altering the return value causes the scanner to do more work than it is configured or documented to in a single unit of work. This patch reverts that commit and accounts for the number of THP updates separately in vmstat. It is up to the administrator to interpret the pair of values correctly. This is a straight-forward operation and likely to only be of interest when actively debugging NUMA balancing problems. The impact of this patch is that the NUMA PTE scanner will scan slower when THP is enabled and workloads may converge slower as a result. On the flip size system CPU usage should be lower than recent tests reported. This is an illustrative example of a short single JVM specjbb test specjbb 3.12.0 3.12.0 vanilla acctupdates TPut 1 26143.00 ( 0.00%) 25747.00 ( -1.51%) TPut 7 185257.00 ( 0.00%) 183202.00 ( -1.11%) TPut 13 329760.00 ( 0.00%) 346577.00 ( 5.10%) TPut 19 442502.00 ( 0.00%) 460146.00 ( 3.99%) TPut 25 540634.00 ( 0.00%) 549053.00 ( 1.56%) TPut 31 512098.00 ( 0.00%) 519611.00 ( 1.47%) TPut 37 461276.00 ( 0.00%) 474973.00 ( 2.97%) TPut 43 403089.00 ( 0.00%) 414172.00 ( 2.75%) 3.12.0 3.12.0 vanillaacctupdates User 5169.64 5184.14 System 100.45 80.02 Elapsed 252.75 251.85 Performance is similar but note the reduction in system CPU time. While this showed a performance gain, it will not be universal but at least it'll be behaving as documented. The vmstats are obviously different but here is an obvious interpretation of them from mmtests. 3.12.0 3.12.0 vanillaacctupdates NUMA page range updates 1408326 11043064 NUMA huge PMD updates 0 21040 NUMA PTE updates 1408326 291624 "NUMA page range updates" == nr_pte_updates and is the value returned to the NUMA pte scanner. NUMA huge PMD updates were the number of THP updates which in combination can be used to calculate how many ptes were updated from userspace. Signed-off-by: Mel Gorman Reported-by: Alex Thorlton Reviewed-by: Rik van Riel Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h index 1855f0a..c557c6d 100644 --- a/include/linux/vm_event_item.h +++ b/include/linux/vm_event_item.h @@ -39,6 +39,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT, PAGEOUTRUN, ALLOCSTALL, PGROTATED, #ifdef CONFIG_NUMA_BALANCING NUMA_PTE_UPDATES, + NUMA_HUGE_PTE_UPDATES, NUMA_HINT_FAULTS, NUMA_HINT_FAULTS_LOCAL, NUMA_PAGE_MIGRATE, diff --git a/mm/mprotect.c b/mm/mprotect.c index a597f2f..2666797 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -112,6 +112,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, pmd_t *pmd; unsigned long next; unsigned long pages = 0; + unsigned long nr_huge_updates = 0; pmd = pmd_offset(pud, addr); do { @@ -126,9 +127,10 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, newprot, prot_numa); if (nr_ptes) { - if (nr_ptes == HPAGE_PMD_NR) - pages++; - + if (nr_ptes == HPAGE_PMD_NR) { + pages += HPAGE_PMD_NR; + nr_huge_updates++; + } continue; } } @@ -141,6 +143,8 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, pages += this_pages; } while (pmd++, addr = next, addr != end); + if (nr_huge_updates) + count_vm_numa_events(NUMA_HUGE_PTE_UPDATES, nr_huge_updates); return pages; } diff --git a/mm/vmstat.c b/mm/vmstat.c index b6d17ed..7249614 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -812,6 +812,7 @@ const char * const vmstat_text[] = { #ifdef CONFIG_NUMA_BALANCING "numa_pte_updates", + "numa_huge_pte_updates", "numa_hint_faults", "numa_hint_faults_local", "numa_pages_migrated", -- cgit v0.10.2 From 3d035f580699feba352f8703cced127fc203f0dd Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Tue, 12 Nov 2013 15:08:33 -0800 Subject: drivers/char/hpet.c: allow user controlled mmap for user processes The CONFIG_HPET_MMAP Kconfig option exposes the memory map of the HPET registers to userspace. The Kconfig help points out that in some cases this can be a security risk as some systems may erroneously configure the map such that additional data is exposed to userspace. This is a problem for distributions -- some users want the MMAP functionality but it comes with a significant security risk. In an effort to mitigate this risk, and due to the low number of users of the MMAP functionality, I've introduced a kernel parameter, hpet_mmap_enable, that is required in order to actually have the HPET MMAP exposed. Signed-off-by: Prarit Bhargava Acked-by: Matt Wilson Signed-off-by: Clemens Ladisch Cc: Randy Dunlap Cc: Tomas Winkler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 882a40d..9ca3e74 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1070,6 +1070,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. VIA, nVidia) verbose: show contents of HPET registers during setup + hpet_mmap= [X86, HPET_MMAP] Allow userspace to mmap HPET + registers. Default set by CONFIG_HPET_MMAP_DEFAULT. + hugepages= [HW,X86-32,IA-64] HugeTLB pages to allocate at boot. hugepagesz= [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages. On x86-64 and powerpc, this option can be specified diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 1421997..fa3243d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -522,10 +522,16 @@ config HPET_MMAP If you say Y here, user applications will be able to mmap the HPET registers. +config HPET_MMAP_DEFAULT + bool "Enable HPET MMAP access by default" + default y + depends on HPET_MMAP + help In some hardware implementations, the page containing HPET registers may also contain other things that shouldn't be - exposed to the user. If this applies to your hardware, - say N here. + exposed to the user. This option selects the default (if + kernel parameter hpet_mmap is not set) user access to the + registers for applications that require it. config HANGCHECK_TIMER tristate "Hangcheck timer" diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index dca5834..5d9c31d 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -367,12 +367,29 @@ static unsigned int hpet_poll(struct file *file, poll_table * wait) return 0; } +#ifdef CONFIG_HPET_MMAP +#ifdef CONFIG_HPET_MMAP_DEFAULT +static int hpet_mmap_enabled = 1; +#else +static int hpet_mmap_enabled = 0; +#endif + +static __init int hpet_mmap_enable(char *str) +{ + get_option(&str, &hpet_mmap_enabled); + pr_info("HPET mmap %s\n", hpet_mmap_enabled ? "enabled" : "disabled"); + return 1; +} +__setup("hpet_mmap", hpet_mmap_enable); + static int hpet_mmap(struct file *file, struct vm_area_struct *vma) { -#ifdef CONFIG_HPET_MMAP struct hpet_dev *devp; unsigned long addr; + if (!hpet_mmap_enabled) + return -EACCES; + devp = file->private_data; addr = devp->hd_hpets->hp_hpet_phys; @@ -381,10 +398,13 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); return vm_iomap_memory(vma, addr, PAGE_SIZE); +} #else +static int hpet_mmap(struct file *file, struct vm_area_struct *vma) +{ return -ENOSYS; -#endif } +#endif static int hpet_fasync(int fd, struct file *file, int on) { -- cgit v0.10.2 From 623fd8072c7c4d77a184bc9e35192acf480c18e4 Mon Sep 17 00:00:00 2001 From: Greg Thelen Date: Tue, 12 Nov 2013 15:08:34 -0800 Subject: percpu: add test module for various percpu operations Tests various percpu operations. Enable with CONFIG_PERCPU_TEST=m. Signed-off-by: Greg Thelen Acked-by: Tejun Heo Acked-by: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index ebef88f..db25707 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1481,6 +1481,15 @@ config INTERVAL_TREE_TEST help A benchmark measuring the performance of the interval tree library +config PERCPU_TEST + tristate "Per cpu operations test" + depends on m && DEBUG_KERNEL + help + Enable this option to build test module which validates per-cpu + operations. + + If unsure, say N. + config ATOMIC64_SELFTEST bool "Perform an atomic64_t self-test at boot" help diff --git a/lib/Makefile b/lib/Makefile index f3bb2cb..bb016e1 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -157,6 +157,8 @@ obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o interval_tree_test-objs := interval_tree_test_main.o interval_tree.o +obj-$(CONFIG_PERCPU_TEST) += percpu_test.o + obj-$(CONFIG_ASN1) += asn1_decoder.o obj-$(CONFIG_FONT_SUPPORT) += fonts/ diff --git a/lib/percpu_test.c b/lib/percpu_test.c new file mode 100644 index 0000000..0b5d14d --- /dev/null +++ b/lib/percpu_test.c @@ -0,0 +1,138 @@ +#include + +/* validate @native and @pcp counter values match @expected */ +#define CHECK(native, pcp, expected) \ + do { \ + WARN((native) != (expected), \ + "raw %ld (0x%lx) != expected %lld (0x%llx)", \ + (native), (native), \ + (long long)(expected), (long long)(expected)); \ + WARN(__this_cpu_read(pcp) != (expected), \ + "pcp %ld (0x%lx) != expected %lld (0x%llx)", \ + __this_cpu_read(pcp), __this_cpu_read(pcp), \ + (long long)(expected), (long long)(expected)); \ + } while (0) + +static DEFINE_PER_CPU(long, long_counter); +static DEFINE_PER_CPU(unsigned long, ulong_counter); + +static int __init percpu_test_init(void) +{ + /* + * volatile prevents compiler from optimizing it uses, otherwise the + * +ul_one/-ul_one below would replace with inc/dec instructions. + */ + volatile unsigned int ui_one = 1; + long l = 0; + unsigned long ul = 0; + + pr_info("percpu test start\n"); + + preempt_disable(); + + l += -1; + __this_cpu_add(long_counter, -1); + CHECK(l, long_counter, -1); + + l += 1; + __this_cpu_add(long_counter, 1); + CHECK(l, long_counter, 0); + + ul = 0; + __this_cpu_write(ulong_counter, 0); + + ul += 1UL; + __this_cpu_add(ulong_counter, 1UL); + CHECK(ul, ulong_counter, 1); + + ul += -1UL; + __this_cpu_add(ulong_counter, -1UL); + CHECK(ul, ulong_counter, 0); + + ul += -(unsigned long)1; + __this_cpu_add(ulong_counter, -(unsigned long)1); + CHECK(ul, ulong_counter, -1); + + ul = 0; + __this_cpu_write(ulong_counter, 0); + + ul -= 1; + __this_cpu_dec(ulong_counter); + CHECK(ul, ulong_counter, -1); + CHECK(ul, ulong_counter, ULONG_MAX); + + l += -ui_one; + __this_cpu_add(long_counter, -ui_one); + CHECK(l, long_counter, 0xffffffff); + + l += ui_one; + __this_cpu_add(long_counter, ui_one); + CHECK(l, long_counter, (long)0x100000000LL); + + + l = 0; + __this_cpu_write(long_counter, 0); + + l -= ui_one; + __this_cpu_sub(long_counter, ui_one); + CHECK(l, long_counter, -1); + + l = 0; + __this_cpu_write(long_counter, 0); + + l += ui_one; + __this_cpu_add(long_counter, ui_one); + CHECK(l, long_counter, 1); + + l += -ui_one; + __this_cpu_add(long_counter, -ui_one); + CHECK(l, long_counter, (long)0x100000000LL); + + l = 0; + __this_cpu_write(long_counter, 0); + + l -= ui_one; + this_cpu_sub(long_counter, ui_one); + CHECK(l, long_counter, -1); + CHECK(l, long_counter, ULONG_MAX); + + ul = 0; + __this_cpu_write(ulong_counter, 0); + + ul += ui_one; + __this_cpu_add(ulong_counter, ui_one); + CHECK(ul, ulong_counter, 1); + + ul = 0; + __this_cpu_write(ulong_counter, 0); + + ul -= ui_one; + __this_cpu_sub(ulong_counter, ui_one); + CHECK(ul, ulong_counter, -1); + CHECK(ul, ulong_counter, ULONG_MAX); + + ul = 3; + __this_cpu_write(ulong_counter, 3); + + ul = this_cpu_sub_return(ulong_counter, ui_one); + CHECK(ul, ulong_counter, 2); + + ul = __this_cpu_sub_return(ulong_counter, ui_one); + CHECK(ul, ulong_counter, 1); + + preempt_enable(); + + pr_info("percpu test done\n"); + return -EAGAIN; /* Fail will directly unload the module */ +} + +static void __exit percpu_test_exit(void) +{ +} + +module_init(percpu_test_init) +module_exit(percpu_test_exit) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Thelen"); +MODULE_DESCRIPTION("percpu operations test"); -- cgit v0.10.2 From 54886a7153353ea2bf21ebfc1b8e030e71d151d7 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 12 Nov 2013 15:08:35 -0800 Subject: cramfs: mark as obsolete Who needs cramfs when you have squashfs? At least, we should warn people that cramfs is obsolete. Signed-off-by: Michael Opdenacker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index 051e4dc..f5867f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2373,7 +2373,7 @@ F: kernel/cpuset.c CRAMFS FILESYSTEM W: http://sourceforge.net/projects/cramfs/ -S: Orphan +S: Orphan / Obsolete F: Documentation/filesystems/cramfs.txt F: fs/cramfs/ diff --git a/fs/cramfs/Kconfig b/fs/cramfs/Kconfig index cd06466..11b29d4 100644 --- a/fs/cramfs/Kconfig +++ b/fs/cramfs/Kconfig @@ -1,5 +1,5 @@ config CRAMFS - tristate "Compressed ROM file system support (cramfs)" + tristate "Compressed ROM file system support (cramfs) (OBSOLETE)" depends on BLOCK select ZLIB_INFLATE help @@ -16,4 +16,7 @@ config CRAMFS cramfs. Note that the root file system (the one containing the directory /) cannot be compiled as a module. + This filesystem is obsoleted by SquashFS, which is much better + in terms of performance and features. + If unsure, say N. -- cgit v0.10.2 From 83460ec8dcac14142e7860a01fa59c267ac4657c Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 12 Nov 2013 15:08:36 -0800 Subject: syscalls.h: use gcc alias instead of assembler aliases for syscalls Use standard gcc __attribute__((alias(foo))) to define the syscall aliases instead of custom assembler macros. This is far cleaner, and also fixes my LTO kernel build. Signed-off-by: Andi Kleen Cc: Al Viro Cc: Geert Uytterhoeven Cc: Tetsuo Handa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/compat.h b/include/linux/compat.h index 345da00..ada34c9 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -41,14 +41,14 @@ COMPAT_SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) #define COMPAT_SYSCALL_DEFINEx(x, name, ...) \ - asmlinkage long compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + asmlinkage long compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))\ + __attribute__((alias(__stringify(compat_SyS##name)))); \ static inline long C_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ asmlinkage long compat_SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));\ asmlinkage long compat_SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))\ { \ return C_SYSC##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__)); \ } \ - SYSCALL_ALIAS(compat_sys##name, compat_SyS##name); \ static inline long C_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) #ifndef compat_user_stack_pointer diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 7fac04e..c27f846 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -184,7 +184,8 @@ extern struct trace_event_functions exit_syscall_print_funcs; #define __PROTECT(...) asmlinkage_protect(__VA_ARGS__) #define __SYSCALL_DEFINEx(x, name, ...) \ - asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ + asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ + __attribute__((alias(__stringify(SyS##name)))); \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ @@ -194,7 +195,6 @@ extern struct trace_event_functions exit_syscall_print_funcs; __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ return ret; \ } \ - SYSCALL_ALIAS(sys##name, SyS##name); \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) asmlinkage long sys_time(time_t __user *tloc); -- cgit v0.10.2 From b5064654c538ad9a2eb1195d80e7593b2e1c1452 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 12 Nov 2013 15:08:38 -0800 Subject: scripts/mod/modpost.c: handle non ABS crc symbols For some reason I managed to trick gcc into create CRC symbols that are not absolute anymore, but weak. Make modpost handle this case. Signed-off-by: Andi Kleen Cc: Al Viro Cc: Geert Uytterhoeven Cc: Tetsuo Handa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 8247979..bfcea5d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -599,18 +599,17 @@ static void handle_modversions(struct module *mod, struct elf_info *info, else export = export_from_sec(info, get_secindex(info, sym)); + /* CRC'd symbol */ + if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { + crc = (unsigned int) sym->st_value; + sym_update_crc(symname + strlen(CRC_PFX), mod, crc, + export); + } + switch (sym->st_shndx) { case SHN_COMMON: warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); break; - case SHN_ABS: - /* CRC'd symbol */ - if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { - crc = (unsigned int) sym->st_value; - sym_update_crc(symname + strlen(CRC_PFX), mod, crc, - export); - } - break; case SHN_UNDEF: /* undefined symbol */ if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && -- cgit v0.10.2 From 6c251611ce68d80e0067aab80a0a3b6bc652d5f5 Mon Sep 17 00:00:00 2001 From: Sebastian Capella Date: Tue, 12 Nov 2013 15:08:39 -0800 Subject: init/do_mounts.c: add maj:min syntax comment The name_to_dev_t function has a comment block which lists the supported syntaxes for the device name. Add a bullet for the : syntax, which is already supported in the code Signed-off-by: Sebastian Capella Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/init/do_mounts.c b/init/do_mounts.c index a51cddc..8e5addc 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -197,6 +197,8 @@ done: * is a zero-filled hex representation of the 1-based partition number. * 7) PARTUUID=/PARTNROFF= to select a partition in relation to * a partition with a known unique id. + * 8) : major and minor number of the device separated by + * a colon. * * If name doesn't have fall into the categories above, we return (0,0). * block_class is used to check if something is a disk name. If the disk -- cgit v0.10.2 From 0ca43435188b9f911c8efcdf10731f726142dda1 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 12 Nov 2013 15:08:40 -0800 Subject: errno.h: remove "NFS" from descriptions in comments glibc recently changed the error string for ESTALE to remove "NFS" - https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=96945714ec61951cc748da2b4b8a80cf02127ee9 from: [ERR_REMAP (ESTALE)] = N_("Stale NFS file handle"), to: [ERR_REMAP (ESTALE)] = N_("Stale file handle"), And some have expressed concern that the kernel's errno.h comments still refer to NFS. So make that change... note that this is a comment-only change, and has no functional difference. Signed-off-by: Eric Sandeen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h index e5f29ca..17f92aa 100644 --- a/arch/alpha/include/uapi/asm/errno.h +++ b/arch/alpha/include/uapi/asm/errno.h @@ -43,7 +43,7 @@ #define EUSERS 68 /* Too many users */ #define EDQUOT 69 /* Quota exceeded */ -#define ESTALE 70 /* Stale NFS file handle */ +#define ESTALE 70 /* Stale file handle */ #define EREMOTE 71 /* Object is remote */ #define ENOLCK 77 /* No record locks available */ diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h index 31575e2f..02d645d 100644 --- a/arch/mips/include/uapi/asm/errno.h +++ b/arch/mips/include/uapi/asm/errno.h @@ -102,7 +102,7 @@ #define EWOULDBLOCK EAGAIN /* Operation would block */ #define EALREADY 149 /* Operation already in progress */ #define EINPROGRESS 150 /* Operation now in progress */ -#define ESTALE 151 /* Stale NFS file handle */ +#define ESTALE 151 /* Stale file handle */ #define ECANCELED 158 /* AIO operation canceled */ /* diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h index 135ad60..f3a8aa5 100644 --- a/arch/parisc/include/uapi/asm/errno.h +++ b/arch/parisc/include/uapi/asm/errno.h @@ -37,7 +37,7 @@ #define EBADMSG 67 /* Not a data message */ #define EUSERS 68 /* Too many users */ #define EDQUOT 69 /* Quota exceeded */ -#define ESTALE 70 /* Stale NFS file handle */ +#define ESTALE 70 /* Stale file handle */ #define EREMOTE 71 /* Object is remote */ #define EOVERFLOW 72 /* Value too large for defined data type */ diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h index c351aba..20423e17 100644 --- a/arch/sparc/include/uapi/asm/errno.h +++ b/arch/sparc/include/uapi/asm/errno.h @@ -40,7 +40,7 @@ #define EPROCLIM 67 /* SUNOS: Too many processes */ #define EUSERS 68 /* Too many users */ #define EDQUOT 69 /* Quota exceeded */ -#define ESTALE 70 /* Stale NFS file handle */ +#define ESTALE 70 /* Stale file handle */ #define EREMOTE 71 /* Object is remote */ #define ENOSTR 72 /* Device not a stream */ #define ETIME 73 /* Timer expired */ diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h b/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h index 2870487..35aefa2 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h @@ -165,7 +165,7 @@ #define LUSTRE_EHOSTUNREACH 113 /* No route to host */ #define LUSTRE_EALREADY 114 /* Operation already in progress */ #define LUSTRE_EINPROGRESS 115 /* Operation now in progress */ -#define LUSTRE_ESTALE 116 /* Stale NFS file handle */ +#define LUSTRE_ESTALE 116 /* Stale file handle */ #define LUSTRE_EUCLEAN 117 /* Structure needs cleaning */ #define LUSTRE_ENOTNAM 118 /* Not a XENIX named type file */ #define LUSTRE_ENAVAIL 119 /* No XENIX semaphores available */ diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h index a1331ce..1e1ea6e 100644 --- a/include/uapi/asm-generic/errno.h +++ b/include/uapi/asm-generic/errno.h @@ -86,7 +86,7 @@ #define EHOSTUNREACH 113 /* No route to host */ #define EALREADY 114 /* Operation already in progress */ #define EINPROGRESS 115 /* Operation now in progress */ -#define ESTALE 116 /* Stale NFS file handle */ +#define ESTALE 116 /* Stale file handle */ #define EUCLEAN 117 /* Structure needs cleaning */ #define ENOTNAM 118 /* Not a XENIX named type file */ #define ENAVAIL 119 /* No XENIX semaphores available */ -- cgit v0.10.2 From c725ee54c30b34427cb8fa68d1fe8804aca6d400 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 12 Nov 2013 15:08:41 -0800 Subject: gen_init_cpio: avoid NULL pointer dereference and rework env expanding getenv() may return NULL if given environment variable does not exist which leads to NULL dereference when calling strncat. Besides that, the environment variable name was copied to a temporary env_var buffer, but this copying can be avoided by simply using the input string. Lastly, the whole loop can be greatly simplified by using the snprintf function instead of the playing with strncat. By the way, the current implementation allows a recursive variable expansion, as in: $ echo 'out ${A} out ' | A='a ${B} a' B=b /tmp/a out a b a out I'm assuming this is just a side effect and not a conscious decision (especially as this may lead to infinite loop), but I didn't want to change this behaviour without consulting. If the current behaviour is deamed incorrect, I'll be happy to send a patch without recursive processing. Signed-off-by: Michal Nazarewicz Cc: Kees Cook Cc: Jiri Kosina Cc: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index af8c925..225ad24 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -382,24 +382,15 @@ error: static char *cpio_replace_env(char *new_location) { char expanded[PATH_MAX + 1]; - char env_var[PATH_MAX + 1]; - char *start; - char *end; - - for (start = NULL; (start = strstr(new_location, "${")); ) { - end = strchr(start, '}'); - if (start < end) { - *env_var = *expanded = '\0'; - strncat(env_var, start + 2, end - start - 2); - strncat(expanded, new_location, start - new_location); - strncat(expanded, getenv(env_var), - PATH_MAX - strlen(expanded)); - strncat(expanded, end + 1, - PATH_MAX - strlen(expanded)); - strncpy(new_location, expanded, PATH_MAX); - new_location[PATH_MAX] = 0; - } else - break; + char *start, *end, *var; + + while ((start = strstr(new_location, "${")) && + (end = strchr(start + 2, '}'))) { + *start = *end = 0; + var = getenv(start + 2); + snprintf(expanded, sizeof expanded, "%s%s%s", + new_location, var ? var : "", end + 1); + strcpy(new_location, expanded); } return new_location; -- cgit v0.10.2 From 324d666a5378946dd271c71036792235ef360204 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 12 Nov 2013 15:08:42 -0800 Subject: kernel/delayacct.c: remove redundant checking in __delayacct_add_tsk() The wrapper function delayacct_add_tsk() already checked 'tsk->delays', and __delayacct_add_tsk() has no another direct callers, so can remove the redundancy checking code. And the label 'done' is also useless, so remove it, too. Signed-off-by: Chen Gang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/delayacct.c b/kernel/delayacct.c index d473988..54996b7 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -108,12 +108,6 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) struct timespec ts; cputime_t utime, stime, stimescaled, utimescaled; - /* Though tsk->delays accessed later, early exit avoids - * unnecessary returning of other data - */ - if (!tsk->delays) - goto done; - tmp = (s64)d->cpu_run_real_total; task_cputime(tsk, &utime, &stime); cputime_to_timespec(utime + stime, &ts); @@ -158,7 +152,6 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) d->freepages_count += tsk->delays->freepages_count; spin_unlock_irqrestore(&tsk->delays->lock, flags); -done: return 0; } -- cgit v0.10.2 From 81e41ea25b52ca8175ceb209438f14182a600d6d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Nov 2013 15:08:43 -0800 Subject: kernel/sys.c: remove obsolete #include Commit 15d94b82565e ("reboot: move shutdown/reboot related functions to kernel/reboot.c") moved all kexec-related functionality to kernel/reboot.c, so kernel/sys.c no longer needs to include . Signed-off-by: Geert Uytterhoeven Cc: Robin Holt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/sys.c b/kernel/sys.c index c18ecca..c723113 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 261adc9a609dbfde815337889b9e2c8728959ab8 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 12 Nov 2013 15:08:44 -0800 Subject: jump_label: unlikely(x) > 0 if (unlikely(x) > 0) doesn't seem to help branch prediction Signed-off-by: Roel Kluin Cc: Raghavendra K T Cc: Konrad Rzeszutek Wilk Cc: "H. Peter Anvin" Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index a507907..cf08540 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -132,14 +132,14 @@ static __always_inline void jump_label_init(void) static __always_inline bool static_key_false(struct static_key *key) { - if (unlikely(atomic_read(&key->enabled)) > 0) + if (unlikely(atomic_read(&key->enabled) > 0)) return true; return false; } static __always_inline bool static_key_true(struct static_key *key) { - if (likely(atomic_read(&key->enabled)) > 0) + if (likely(atomic_read(&key->enabled) > 0)) return true; return false; } -- cgit v0.10.2 From 616c05d110bb4ef8203f49c9d2476874077c2f6a Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 12 Nov 2013 15:08:45 -0800 Subject: sh: move fpu_counter into ARCH specific thread_struct Only a couple of arches (sh/x86) use fpu_counter in task_struct so it can be moved out into ARCH specific thread_struct, reducing the size of task_struct for other arches. Compile tested sh defconfig + sh4-linux-gcc (4.6.3) Signed-off-by: Vineet Gupta Cc: Paul Mundt Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h index 06c4281..09fc2bc 100644 --- a/arch/sh/include/asm/fpu.h +++ b/arch/sh/include/asm/fpu.h @@ -46,7 +46,7 @@ static inline void __unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) save_fpu(tsk); release_fpu(regs); } else - tsk->fpu_counter = 0; + tsk->thread.fpu_counter = 0; } static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index e699a12..18e0377 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -111,6 +111,16 @@ struct thread_struct { /* Extended processor state */ union thread_xstate *xstate; + + /* + * fpu_counter contains the number of consecutive context switches + * that the FPU is used. If this is over a threshold, the lazy fpu + * saving becomes unlazy to save the trap. This is an unsigned char + * so that after 256 times the counter wraps and the behavior turns + * lazy again; this to deal with bursty apps that only use FPU for + * a short time + */ + unsigned char fpu_counter; }; #define INIT_THREAD { \ diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h index 1cc7d31..eedd4f6 100644 --- a/arch/sh/include/asm/processor_64.h +++ b/arch/sh/include/asm/processor_64.h @@ -126,6 +126,16 @@ struct thread_struct { /* floating point info */ union thread_xstate *xstate; + + /* + * fpu_counter contains the number of consecutive context switches + * that the FPU is used. If this is over a threshold, the lazy fpu + * saving becomes unlazy to save the trap. This is an unsigned char + * so that after 256 times the counter wraps and the behavior turns + * lazy again; this to deal with bursty apps that only use FPU for + * a short time + */ + unsigned char fpu_counter; }; #define INIT_MMAP \ diff --git a/arch/sh/kernel/cpu/fpu.c b/arch/sh/kernel/cpu/fpu.c index f8f7af5..4e33224 100644 --- a/arch/sh/kernel/cpu/fpu.c +++ b/arch/sh/kernel/cpu/fpu.c @@ -44,7 +44,7 @@ void __fpu_state_restore(void) restore_fpu(tsk); task_thread_info(tsk)->status |= TS_USEDFPU; - tsk->fpu_counter++; + tsk->thread.fpu_counter++; } void fpu_state_restore(struct pt_regs *regs) diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index ebd3933..2885fc9 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -156,7 +156,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, #endif ti->addr_limit = KERNEL_DS; ti->status &= ~TS_USEDFPU; - p->fpu_counter = 0; + p->thread.fpu_counter = 0; return 0; } *childregs = *current_pt_regs(); @@ -189,7 +189,7 @@ __switch_to(struct task_struct *prev, struct task_struct *next) unlazy_fpu(prev, task_pt_regs(prev)); /* we're going to use this soon, after a few expensive things */ - if (next->fpu_counter > 5) + if (next->thread.fpu_counter > 5) prefetch(next_t->xstate); #ifdef CONFIG_MMU @@ -207,7 +207,7 @@ __switch_to(struct task_struct *prev, struct task_struct *next) * restore of the math state immediately to avoid the trap; the * chances of needing FPU soon are obviously high now */ - if (next->fpu_counter > 5) + if (next->thread.fpu_counter > 5) __fpu_state_restore(); return prev; -- cgit v0.10.2 From c375f15a434db1867cb004bafba92aba739e4e39 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 12 Nov 2013 15:08:46 -0800 Subject: x86: move fpu_counter into ARCH specific thread_struct Only a couple of arches (sh/x86) use fpu_counter in task_struct so it can be moved out into ARCH specific thread_struct, reducing the size of task_struct for other arches. Compile tested i386_defconfig + gcc 4.7.3 Signed-off-by: Vineet Gupta Acked-by: Ingo Molnar Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index 4d0bda7..c49a613 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -365,7 +365,7 @@ static inline void drop_fpu(struct task_struct *tsk) * Forget coprocessor state.. */ preempt_disable(); - tsk->fpu_counter = 0; + tsk->thread.fpu_counter = 0; __drop_fpu(tsk); clear_used_math(); preempt_enable(); @@ -424,7 +424,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta * or if the past 5 consecutive context-switches used math. */ fpu.preload = tsk_used_math(new) && (use_eager_fpu() || - new->fpu_counter > 5); + new->thread.fpu_counter > 5); if (__thread_has_fpu(old)) { if (!__save_init_fpu(old)) cpu = ~0; @@ -433,16 +433,16 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta /* Don't change CR0.TS if we just switch! */ if (fpu.preload) { - new->fpu_counter++; + new->thread.fpu_counter++; __thread_set_has_fpu(new); prefetch(new->thread.fpu.state); } else if (!use_eager_fpu()) stts(); } else { - old->fpu_counter = 0; + old->thread.fpu_counter = 0; old->thread.fpu.last_cpu = ~0; if (fpu.preload) { - new->fpu_counter++; + new->thread.fpu_counter++; if (!use_eager_fpu() && fpu_lazy_restore(new, cpu)) fpu.preload = 0; else diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 987c75e..7b034a4 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -488,6 +488,15 @@ struct thread_struct { unsigned long iopl; /* Max allowed port in the bitmap, in bytes: */ unsigned io_bitmap_max; + /* + * fpu_counter contains the number of consecutive context switches + * that the FPU is used. If this is over a threshold, the lazy fpu + * saving becomes unlazy to save the trap. This is an unsigned char + * so that after 256 times the counter wraps and the behavior turns + * lazy again; this to deal with bursty apps that only use FPU for + * a short time + */ + unsigned char fpu_counter; }; /* diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 5d576ab..e8368c6 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -100,7 +100,7 @@ void unlazy_fpu(struct task_struct *tsk) __save_init_fpu(tsk); __thread_fpu_end(tsk); } else - tsk->fpu_counter = 0; + tsk->thread.fpu_counter = 0; preempt_enable(); } EXPORT_SYMBOL(unlazy_fpu); diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index c2ec1aa..6f1236c 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -153,7 +153,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, childregs->orig_ax = -1; childregs->cs = __KERNEL_CS | get_kernel_rpl(); childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED; - p->fpu_counter = 0; + p->thread.fpu_counter = 0; p->thread.io_bitmap_ptr = NULL; memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); return 0; @@ -166,7 +166,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, p->thread.ip = (unsigned long) ret_from_fork; task_user_gs(p) = get_user_gs(current_pt_regs()); - p->fpu_counter = 0; + p->thread.fpu_counter = 0; p->thread.io_bitmap_ptr = NULL; tsk = current; err = -ENOMEM; diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 45ab4d6..10fe4c1 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -163,7 +163,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, p->thread.sp = (unsigned long) childregs; p->thread.usersp = me->thread.usersp; set_tsk_thread_flag(p, TIF_FORK); - p->fpu_counter = 0; + p->thread.fpu_counter = 0; p->thread.io_bitmap_ptr = NULL; savesegment(gs, p->thread.gsindex); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 729aa77..996ce23 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -653,7 +653,7 @@ void math_state_restore(void) return; } - tsk->fpu_counter++; + tsk->thread.fpu_counter++; } EXPORT_SYMBOL_GPL(math_state_restore); -- cgit v0.10.2 From 27f69e68a5e534412faebc53a4e04acc9ce7fd7e Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 12 Nov 2013 15:08:47 -0800 Subject: sched: remove ARCH specific fpu_counter from task_struct fpu_counter in task_struct was used only by sh/x86. Both of these now carry it in ARCH specific thread_struct, hence this can now be removed from generic task_struct, shrinking it slightly for other arches. Signed-off-by: Vineet Gupta Cc: Ingo Molnar Cc: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/sched.h b/include/linux/sched.h index 045b0d2..5e226fe 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1062,15 +1062,6 @@ struct task_struct { struct hlist_head preempt_notifiers; #endif - /* - * fpu_counter contains the number of consecutive context switches - * that the FPU is used. If this is over a threshold, the lazy fpu - * saving becomes unlazy to save the trap. This is an unsigned char - * so that after 256 times the counter wraps and the behavior turns - * lazy again; this to deal with bursty apps that only use FPU for - * a short time - */ - unsigned char fpu_counter; #ifdef CONFIG_BLK_DEV_IO_TRACE unsigned int btrace_seq; #endif -- cgit v0.10.2 From 8f6b2ae49a84841c4bcf00cff35752b223c3f8d6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Nov 2013 15:08:48 -0800 Subject: init/main.c: remove prototype for softirq_init() It's already available in Signed-off-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/init/main.c b/init/main.c index 379090f..aa061ef 100644 --- a/init/main.c +++ b/init/main.c @@ -124,7 +124,6 @@ EXPORT_SYMBOL(system_state); extern void time_init(void); /* Default late time init is NULL. archs can override this later. */ void (*__initdata late_time_init)(void); -extern void softirq_init(void); /* Untouched command line saved by arch-specific code. */ char __initdata boot_command_line[COMMAND_LINE_SIZE]; -- cgit v0.10.2 From 6b80239447f6785b719345e8913af420d8ec0818 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 12 Nov 2013 15:08:49 -0800 Subject: printk: report console names during cut-over This reports the names of consoles as they're being disabled to help identify which is which during cut-over. Helps answer the question "which boot console actually got activated?" once the regular console is running, mostly when debugging boot console failures. Signed-off-by: Kees Cook Acked-by: Frederic Weisbecker Cc: Joe Perches Cc: Tejun Heo Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index b4e8500..555ad2d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2358,21 +2358,18 @@ void register_console(struct console *newcon) * users know there might be something in the kernel's log buffer that * went to the bootconsole (that they do not see on the real console) */ + printk(KERN_INFO "%sconsole [%s%d] enabled\n", + (newcon->flags & CON_BOOT) ? "boot" : "" , + newcon->name, newcon->index); if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) && !keep_bootcon) { - /* we need to iterate through twice, to make sure we print - * everything out, before we unregister the console(s) + /* We need to iterate through all boot consoles, to make + * sure we print everything out, before we unregister them. */ - printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n", - newcon->name, newcon->index); for_each_console(bcon) if (bcon->flags & CON_BOOT) unregister_console(bcon); - } else { - printk(KERN_INFO "%sconsole [%s%d] enabled\n", - (newcon->flags & CON_BOOT) ? "boot" : "" , - newcon->name, newcon->index); } } EXPORT_SYMBOL(register_console); @@ -2382,6 +2379,10 @@ int unregister_console(struct console *console) struct console *a, *b; int res; + printk(KERN_INFO "%sconsole [%s%d] disabled\n", + (console->flags & CON_BOOT) ? "boot" : "" , + console->name, console->index); + res = _braille_unregister_console(console); if (res) return res; @@ -2421,8 +2422,6 @@ static int __init printk_late_init(void) for_each_console(con) { if (!keep_bootcon && con->flags & CON_BOOT) { - printk(KERN_INFO "turn off boot console %s%d\n", - con->name, con->index); unregister_console(con); } } -- cgit v0.10.2 From 27083baca51358fe0fba8cf40b7df9bb696c931a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 12 Nov 2013 15:08:50 -0800 Subject: kernel/printk/printk.c: convert to pr_foo() It was half-and-half. Cc: Frederic Weisbecker Cc: Greg Kroah-Hartman Cc: Joe Perches Cc: Kees Cook Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 555ad2d..78b7c0f 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -791,7 +791,7 @@ static bool __read_mostly ignore_loglevel; static int __init ignore_loglevel_setup(char *str) { ignore_loglevel = 1; - printk(KERN_INFO "debug: ignoring loglevel setting.\n"); + pr_info("debug: ignoring loglevel setting.\n"); return 0; } @@ -2193,7 +2193,7 @@ static int __read_mostly keep_bootcon; static int __init keep_bootcon_setup(char *str) { keep_bootcon = 1; - printk(KERN_INFO "debug: skip boot console de-registration.\n"); + pr_info("debug: skip boot console de-registration.\n"); return 0; } @@ -2241,7 +2241,7 @@ void register_console(struct console *newcon) /* find the last or real console */ for_each_console(bcon) { if (!(bcon->flags & CON_BOOT)) { - printk(KERN_INFO "Too late to register bootconsole %s%d\n", + pr_info("Too late to register bootconsole %s%d\n", newcon->name, newcon->index); return; } @@ -2358,7 +2358,7 @@ void register_console(struct console *newcon) * users know there might be something in the kernel's log buffer that * went to the bootconsole (that they do not see on the real console) */ - printk(KERN_INFO "%sconsole [%s%d] enabled\n", + pr_info("%sconsole [%s%d] enabled\n", (newcon->flags & CON_BOOT) ? "boot" : "" , newcon->name, newcon->index); if (bcon && @@ -2379,7 +2379,7 @@ int unregister_console(struct console *console) struct console *a, *b; int res; - printk(KERN_INFO "%sconsole [%s%d] disabled\n", + pr_info("%sconsole [%s%d] disabled\n", (console->flags & CON_BOOT) ? "boot" : "" , console->name, console->index); @@ -2448,7 +2448,7 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work) if (pending & PRINTK_PENDING_SCHED) { char *buf = __get_cpu_var(printk_sched_buf); - printk(KERN_WARNING "[sched_delayed] %s", buf); + pr_warn("[sched_delayed] %s", buf); } if (pending & PRINTK_PENDING_WAKEUP) -- cgit v0.10.2 From 312b4e226951f707e120b95b118cbc14f3d162b2 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Tue, 12 Nov 2013 15:08:51 -0800 Subject: vsprintf: check real user/group id for %pK Some setuid binaries will allow reading of files which have read permission by the real user id. This is problematic with files which use %pK because the file access permission is checked at open() time, but the kptr_restrict setting is checked at read() time. If a setuid binary opens a %pK file as an unprivileged user, and then elevates permissions before reading the file, then kernel pointer values may be leaked. This happens for example with the setuid pppd application on Ubuntu 12.04: $ head -1 /proc/kallsyms 00000000 T startup_32 $ pppd file /proc/kallsyms pppd: In file /proc/kallsyms: unrecognized option 'c1000000' This will only leak the pointer value from the first line, but other setuid binaries may leak more information. Fix this by adding a check that in addition to the current process having CAP_SYSLOG, that effective user and group ids are equal to the real ids. If a setuid binary reads the contents of a file which uses %pK then the pointer values will be printed as NULL if the real user is unprivileged. Update the sysctl documentation to reflect the changes, and also correct the documentation to state the kptr_restrict=0 is the default. This is a only temporary solution to the issue. The correct solution is to do the permission check at open() time on files, and to replace %pK with a function which checks the open() time permission. %pK uses in printk should be removed since no sane permission check can be done, and instead protected by using dmesg_restrict. Signed-off-by: Ryan Mallon Cc: Kees Cook Cc: Alexander Viro Cc: Joe Perches Cc: "Eric W. Biederman" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 4273b2d..26b7ee4 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -290,13 +290,24 @@ Default value is "/sbin/hotplug". kptr_restrict: This toggle indicates whether restrictions are placed on -exposing kernel addresses via /proc and other interfaces. When -kptr_restrict is set to (0), there are no restrictions. When -kptr_restrict is set to (1), the default, kernel pointers -printed using the %pK format specifier will be replaced with 0's -unless the user has CAP_SYSLOG. When kptr_restrict is set to -(2), kernel pointers printed using %pK will be replaced with 0's -regardless of privileges. +exposing kernel addresses via /proc and other interfaces. + +When kptr_restrict is set to (0), the default, there are no restrictions. + +When kptr_restrict is set to (1), kernel pointers printed using the %pK +format specifier will be replaced with 0's unless the user has CAP_SYSLOG +and effective user and group ids are equal to the real ids. This is +because %pK checks are done at read() time rather than open() time, so +if permissions are elevated between the open() and the read() (e.g via +a setuid binary) then %pK will not leak kernel pointers to unprivileged +users. Note, this is a temporary solution only. The correct long-term +solution is to do the permission checks at open() time. Consider removing +world read permissions from files that use %pK, and using dmesg_restrict +to protect against uses of %pK in dmesg(8) if leaking kernel pointer +values to unprivileged users is a concern. + +When kptr_restrict is set to (2), kernel pointers printed using +%pK will be replaced with 0's regardless of privileges. ============================================================== diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 26559bd..d76555c 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include /* for PAGE_SIZE */ @@ -1312,11 +1313,37 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, spec.field_width = default_width; return string(buf, end, "pK-error", spec); } - if (!((kptr_restrict == 0) || - (kptr_restrict == 1 && - has_capability_noaudit(current, CAP_SYSLOG)))) + + switch (kptr_restrict) { + case 0: + /* Always print %pK values */ + break; + case 1: { + /* + * Only print the real pointer value if the current + * process has CAP_SYSLOG and is running with the + * same credentials it started with. This is because + * access to files is checked at open() time, but %pK + * checks permission at read() time. We don't want to + * leak pointer values if a binary opens a file using + * %pK and then elevates privileges before reading it. + */ + const struct cred *cred = current_cred(); + + if (!has_capability_noaudit(current, CAP_SYSLOG) || + !uid_eq(cred->euid, cred->uid) || + !gid_eq(cred->egid, cred->gid)) + ptr = NULL; + break; + } + case 2: + default: + /* Always print 0's for %pK */ ptr = NULL; + break; + } break; + case 'N': switch (fmt[1]) { case 'F': -- cgit v0.10.2 From 29e9d22559065af169bba6f99166eb9ab64c01c6 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Tue, 12 Nov 2013 15:08:53 -0800 Subject: kernel/printk/printk.c: enable boot delay for earlyprintk boot_delay does not work for earlyprintk because the kernel cmdline parsing is late. Change to use early_param so early kernel messages can also be delayed. Signed-off-by: Dave Young Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 78b7c0f..9b527d4 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -820,9 +820,9 @@ static int __init boot_delay_setup(char *str) pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, " "HZ: %d, loops_per_msec: %llu\n", boot_delay, preset_lpj, lpj, HZ, loops_per_msec); - return 1; + return 0; } -__setup("boot_delay=", boot_delay_setup); +early_param("boot_delay", boot_delay_setup); static void boot_delay_msec(int level) { -- cgit v0.10.2 From 4c1ace6408c83797117621f4c324dfa76259d16e Mon Sep 17 00:00:00 2001 From: Dirk Gouders Date: Tue, 12 Nov 2013 15:08:54 -0800 Subject: printk.c: comments should refer to /proc/vmcore instead of /proc/vmcoreinfo In one of those comments a typo was fixed, too. Signed-off-by: Dirk Gouders Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 9b527d4..be7c86b 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -705,9 +705,9 @@ const struct file_operations kmsg_fops = { #ifdef CONFIG_KEXEC /* - * This appends the listed symbols to /proc/vmcoreinfo + * This appends the listed symbols to /proc/vmcore * - * /proc/vmcoreinfo is used by various utiilties, like crash and makedumpfile to + * /proc/vmcore is used by various utilities, like crash and makedumpfile to * obtain access to symbols that are otherwise very difficult to locate. These * symbols are specifically used so that utilities can access and extract the * dmesg log from a vmcore file after a crash. -- cgit v0.10.2 From 07eb6597c059d9276c8dc7cd0401083ed66ad714 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:08:55 -0800 Subject: MAINTAINERS: remove Richard Purdie as backlight maintainer Remove Richard Purdie as backlight subsystem maintainer, akpm: Richard is still responsive and is reviewing some of the patches, but appears to agree that listing him as the maintainer is no longer appropriate. [akpm@linux-foundation.org: s/USA/UK/] Signed-off-by: Jingoo Han Acked-by: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/CREDITS b/CREDITS index b928516..dc04d8f 100644 --- a/CREDITS +++ b/CREDITS @@ -2895,6 +2895,11 @@ S: Framewood Road S: Wexham SL3 6PJ S: United Kingdom +N: Richard Purdie +E: rpurdie@rpsys.net +D: Backlight subsystem maintainer +S: United Kingdom + N: Daniel Quinlan E: quinlan@pathname.com W: http://www.pathname.com/~quinlan/ diff --git a/MAINTAINERS b/MAINTAINERS index f5867f4..30c1e39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1661,7 +1661,6 @@ S: Maintained F: drivers/net/wireless/b43legacy/ BACKLIGHT CLASS/SUBSYSTEM -M: Richard Purdie M: Jingoo Han S: Maintained F: drivers/video/backlight/ -- cgit v0.10.2 From b300645aec9a5d71f6d85d5138215a9d6d7fe5e6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 12 Nov 2013 15:08:56 -0800 Subject: MAINTAINERS: update Zwane Mwaikambo's e-mail address Zwane Mwaikambo's @arm.linux.org.uk address no longer works. In February 2013 he asked for his gmail address to be used instead [1] so let's just do that. [1] http://marc.info/?l=linux-kernel&m=136079068903214&w=2 Signed-off-by: Jean Delvare Cc: Russell King Cc: Zwane Mwaikambo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/CREDITS b/CREDITS index dc04d8f..4fc997d 100644 --- a/CREDITS +++ b/CREDITS @@ -2576,7 +2576,7 @@ S: Toronto, Ontario S: Canada N: Zwane Mwaikambo -E: zwane@arm.linux.org.uk +E: zwanem@gmail.com D: Various driver hacking D: Lowlevel x86 kernel hacking D: General debugging diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt index 786dc82..8cb9938 100644 --- a/Documentation/cpu-hotplug.txt +++ b/Documentation/cpu-hotplug.txt @@ -5,7 +5,7 @@ Rusty Russell Srivatsa Vaddagiri i386: - Zwane Mwaikambo + Zwane Mwaikambo ppc64: Nathan Lynch Joel Schopp diff --git a/MAINTAINERS b/MAINTAINERS index 30c1e39..5cfa91b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7319,7 +7319,7 @@ S: Odd Fixes F: drivers/media/usb/tlg2300/ SC1200 WDT DRIVER -M: Zwane Mwaikambo +M: Zwane Mwaikambo S: Maintained F: drivers/watchdog/sc1200wdt.c -- cgit v0.10.2 From 5812c13a4e636da4bd7f7cabbbbc59d9dbf3c86c Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Tue, 12 Nov 2013 15:08:57 -0800 Subject: backlight: lp855x_bl: support new LP8555 device LP8555 is one of the LP855x family devices. This device needs pre_init_device() and post_init_device() driver structure. It's same as LP8557, so the device configuration code is shared with LP8557. Backlight outputs are generated from dual DC-DC boost converters. It's configurable EPROM settings which are defined in the platform data. Driver documentation and device tree bindings are updated. Signed-off-by: Milo Kim Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/backlight/lp855x-driver.txt b/Documentation/backlight/lp855x-driver.txt index 1c732f0..01bce24 100644 --- a/Documentation/backlight/lp855x-driver.txt +++ b/Documentation/backlight/lp855x-driver.txt @@ -4,7 +4,8 @@ Kernel driver lp855x Backlight driver for LP855x ICs Supported chips: - Texas Instruments LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557 + Texas Instruments LP8550, LP8551, LP8552, LP8553, LP8555, LP8556 and + LP8557 Author: Milo(Woogyom) Kim @@ -24,7 +25,7 @@ Value : pwm based or register based 2) chip_id The lp855x chip id. -Value : lp8550/lp8551/lp8552/lp8553/lp8556/lp8557 +Value : lp8550/lp8551/lp8552/lp8553/lp8555/lp8556/lp8557 Platform data for lp855x ------------------------ diff --git a/Documentation/devicetree/bindings/video/backlight/lp855x.txt b/Documentation/devicetree/bindings/video/backlight/lp855x.txt index 1482103..96e83a5 100644 --- a/Documentation/devicetree/bindings/video/backlight/lp855x.txt +++ b/Documentation/devicetree/bindings/video/backlight/lp855x.txt @@ -2,7 +2,7 @@ lp855x bindings Required properties: - compatible: "ti,lp8550", "ti,lp8551", "ti,lp8552", "ti,lp8553", - "ti,lp8556", "ti,lp8557" + "ti,lp8555", "ti,lp8556", "ti,lp8557" - reg: I2C slave address (u8) - dev-ctrl: Value of DEVICE CONTROL register (u8). It depends on the device. @@ -15,6 +15,33 @@ Optional properties: Example: + /* LP8555 */ + backlight@2c { + compatible = "ti,lp8555"; + reg = <0x2c>; + + dev-ctrl = /bits/ 8 <0x00>; + pwm-period = <10000>; + + /* 4V OV, 4 output LED0 string enabled */ + rom_14h { + rom-addr = /bits/ 8 <0x14>; + rom-val = /bits/ 8 <0xcf>; + }; + + /* Heavy smoothing, 24ms ramp time step */ + rom_15h { + rom-addr = /bits/ 8 <0x15>; + rom-val = /bits/ 8 <0xc7>; + }; + + /* 4 output LED1 string enabled */ + rom_19h { + rom-addr = /bits/ 8 <0x19>; + rom-val = /bits/ 8 <0x0f>; + }; + }; + /* LP8556 */ backlight@2c { compatible = "ti,lp8556"; diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index d4a7a35..a65dd06 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -388,8 +388,8 @@ config BACKLIGHT_LP855X tristate "Backlight driver for TI LP855X" depends on BACKLIGHT_CLASS_DEVICE && I2C help - This supports TI LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557 - backlight driver. + This supports TI LP8550, LP8551, LP8552, LP8553, LP8555, LP8556 and + LP8557 backlight driver. config BACKLIGHT_LP8788 tristate "Backlight driver for TI LP8788 MFD" diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index c0b41f1..c952175 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -26,13 +26,15 @@ #define LP8556_EPROM_START 0xA0 #define LP8556_EPROM_END 0xAF -/* LP8557 Registers */ +/* LP8555/7 Registers */ #define LP8557_BL_CMD 0x00 #define LP8557_BL_MASK 0x01 #define LP8557_BL_ON 0x01 #define LP8557_BL_OFF 0x00 #define LP8557_BRIGHTNESS_CTRL 0x04 #define LP8557_CONFIG 0x10 +#define LP8555_EPROM_START 0x10 +#define LP8555_EPROM_END 0x7A #define LP8557_EPROM_START 0x10 #define LP8557_EPROM_END 0x1E @@ -111,6 +113,10 @@ static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr) start = LP8556_EPROM_START; end = LP8556_EPROM_END; break; + case LP8555: + start = LP8555_EPROM_START; + end = LP8555_EPROM_END; + break; case LP8557: start = LP8557_EPROM_START; end = LP8557_EPROM_END; @@ -165,9 +171,14 @@ static int lp855x_configure(struct lp855x *lp) struct lp855x_platform_data *pd = lp->pdata; switch (lp->chip_id) { - case LP8550 ... LP8556: + case LP8550: + case LP8551: + case LP8552: + case LP8553: + case LP8556: lp->cfg = &lp855x_dev_cfg; break; + case LP8555: case LP8557: lp->cfg = &lp8557_dev_cfg; break; @@ -470,6 +481,7 @@ static const struct of_device_id lp855x_dt_ids[] = { { .compatible = "ti,lp8551", }, { .compatible = "ti,lp8552", }, { .compatible = "ti,lp8553", }, + { .compatible = "ti,lp8555", }, { .compatible = "ti,lp8556", }, { .compatible = "ti,lp8557", }, { } @@ -481,6 +493,7 @@ static const struct i2c_device_id lp855x_ids[] = { {"lp8551", LP8551}, {"lp8552", LP8552}, {"lp8553", LP8553}, + {"lp8555", LP8555}, {"lp8556", LP8556}, {"lp8557", LP8557}, { } diff --git a/include/linux/platform_data/lp855x.h b/include/linux/platform_data/lp855x.h index ea32005..1b2ba24 100644 --- a/include/linux/platform_data/lp855x.h +++ b/include/linux/platform_data/lp855x.h @@ -40,6 +40,17 @@ #define LP8553_PWM_CONFIG LP8550_PWM_CONFIG #define LP8553_I2C_CONFIG LP8550_I2C_CONFIG +/* CONFIG register - LP8555 */ +#define LP8555_PWM_STANDBY BIT(7) +#define LP8555_PWM_FILTER BIT(6) +#define LP8555_RELOAD_EPROM BIT(3) /* use it if EPROMs should be reset + when the backlight turns on */ +#define LP8555_OFF_OPENLEDS BIT(2) +#define LP8555_PWM_CONFIG LP8555_PWM_ONLY +#define LP8555_I2C_CONFIG LP8555_I2C_ONLY +#define LP8555_COMB1_CONFIG LP8555_COMBINED1 +#define LP8555_COMB2_CONFIG LP8555_COMBINED2 + /* DEVICE CONTROL register - LP8556 */ #define LP8556_PWM_CONFIG (LP8556_PWM_ONLY << BRT_MODE_SHFT) #define LP8556_COMB1_CONFIG (LP8556_COMBINED1 << BRT_MODE_SHFT) @@ -65,6 +76,7 @@ enum lp855x_chip_id { LP8551, LP8552, LP8553, + LP8555, LP8556, LP8557, }; @@ -89,6 +101,13 @@ enum lp8553_brighntess_source { LP8553_I2C_ONLY = LP8550_I2C_ONLY, }; +enum lp8555_brightness_source { + LP8555_PWM_ONLY, + LP8555_I2C_ONLY, + LP8555_COMBINED1, /* Brightness register with shaped PWM */ + LP8555_COMBINED2, /* PWM with shaped brightness register */ +}; + enum lp8556_brightness_source { LP8556_PWM_ONLY, LP8556_COMBINED1, /* pwm + i2c before the shaper block */ -- cgit v0.10.2 From 28e64a68a2ef1c48f30e8b6803725199929069fc Mon Sep 17 00:00:00 2001 From: Daniel Jeong Date: Tue, 12 Nov 2013 15:08:58 -0800 Subject: backlight: lm3630: apply chip revision The LM3630 chip was revised by TI and chip name was also changed to LM3630A. And register map, default values and initial sequences are changed. The files, lm3630_bl.{c,h} are replaced by lm3630a_bl.{c,h} You can find more information about LM3630A(datasheet, evm etc) at http://www.ti.com/product/lm3630a Signed-off-by: Daniel Jeong Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index a65dd06..5a3eb2e 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -368,12 +368,12 @@ config BACKLIGHT_AAT2870 If you have a AnalogicTech AAT2870 say Y to enable the backlight driver. -config BACKLIGHT_LM3630 - tristate "Backlight Driver for LM3630" +config BACKLIGHT_LM3630A + tristate "Backlight Driver for LM3630A" depends on BACKLIGHT_CLASS_DEVICE && I2C select REGMAP_I2C help - This supports TI LM3630 Backlight Driver + This supports TI LM3630A Backlight Driver config BACKLIGHT_LM3639 tristate "Backlight Driver for LM3639" diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 38e1bab..bb82002 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -37,7 +37,7 @@ obj-$(CONFIG_BACKLIGHT_GPIO) += gpio_backlight.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o -obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o +obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o diff --git a/drivers/video/backlight/lm3630_bl.c b/drivers/video/backlight/lm3630_bl.c deleted file mode 100644 index 76a62e9..0000000 --- a/drivers/video/backlight/lm3630_bl.c +++ /dev/null @@ -1,475 +0,0 @@ -/* -* Simple driver for Texas Instruments LM3630 Backlight driver chip -* Copyright (C) 2012 Texas Instruments -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REG_CTRL 0x00 -#define REG_CONFIG 0x01 -#define REG_BRT_A 0x03 -#define REG_BRT_B 0x04 -#define REG_INT_STATUS 0x09 -#define REG_INT_EN 0x0A -#define REG_FAULT 0x0B -#define REG_PWM_OUTLOW 0x12 -#define REG_PWM_OUTHIGH 0x13 -#define REG_MAX 0x1F - -#define INT_DEBOUNCE_MSEC 10 - -enum lm3630_leds { - BLED_ALL = 0, - BLED_1, - BLED_2 -}; - -static const char * const bled_name[] = { - [BLED_ALL] = "lm3630_bled", /*Bank1 controls all string */ - [BLED_1] = "lm3630_bled1", /*Bank1 controls bled1 */ - [BLED_2] = "lm3630_bled2", /*Bank1 or 2 controls bled2 */ -}; - -struct lm3630_chip_data { - struct device *dev; - struct delayed_work work; - int irq; - struct workqueue_struct *irqthread; - struct lm3630_platform_data *pdata; - struct backlight_device *bled1; - struct backlight_device *bled2; - struct regmap *regmap; -}; - -/* initialize chip */ -static int lm3630_chip_init(struct lm3630_chip_data *pchip) -{ - int ret; - unsigned int reg_val; - struct lm3630_platform_data *pdata = pchip->pdata; - - /*pwm control */ - reg_val = ((pdata->pwm_active & 0x01) << 2) | (pdata->pwm_ctrl & 0x03); - ret = regmap_update_bits(pchip->regmap, REG_CONFIG, 0x07, reg_val); - if (ret < 0) - goto out; - - /* bank control */ - reg_val = ((pdata->bank_b_ctrl & 0x01) << 1) | - (pdata->bank_a_ctrl & 0x07); - ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x07, reg_val); - if (ret < 0) - goto out; - - ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); - if (ret < 0) - goto out; - - /* set initial brightness */ - if (pdata->bank_a_ctrl != BANK_A_CTRL_DISABLE) { - ret = regmap_write(pchip->regmap, - REG_BRT_A, pdata->init_brt_led1); - if (ret < 0) - goto out; - } - - if (pdata->bank_b_ctrl != BANK_B_CTRL_DISABLE) { - ret = regmap_write(pchip->regmap, - REG_BRT_B, pdata->init_brt_led2); - if (ret < 0) - goto out; - } - return ret; - -out: - dev_err(pchip->dev, "i2c failed to access register\n"); - return ret; -} - -/* interrupt handling */ -static void lm3630_delayed_func(struct work_struct *work) -{ - int ret; - unsigned int reg_val; - struct lm3630_chip_data *pchip; - - pchip = container_of(work, struct lm3630_chip_data, work.work); - - ret = regmap_read(pchip->regmap, REG_INT_STATUS, ®_val); - if (ret < 0) { - dev_err(pchip->dev, - "i2c failed to access REG_INT_STATUS Register\n"); - return; - } - - dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", reg_val); -} - -static irqreturn_t lm3630_isr_func(int irq, void *chip) -{ - int ret; - struct lm3630_chip_data *pchip = chip; - unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); - - queue_delayed_work(pchip->irqthread, &pchip->work, delay); - - ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); - if (ret < 0) - goto out; - - return IRQ_HANDLED; -out: - dev_err(pchip->dev, "i2c failed to access register\n"); - return IRQ_HANDLED; -} - -static int lm3630_intr_config(struct lm3630_chip_data *pchip) -{ - INIT_DELAYED_WORK(&pchip->work, lm3630_delayed_func); - pchip->irqthread = create_singlethread_workqueue("lm3630-irqthd"); - if (!pchip->irqthread) { - dev_err(pchip->dev, "create irq thread fail...\n"); - return -1; - } - if (request_threaded_irq - (pchip->irq, NULL, lm3630_isr_func, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630_irq", pchip)) { - dev_err(pchip->dev, "request threaded irq fail..\n"); - return -1; - } - return 0; -} - -static bool -set_intensity(struct backlight_device *bl, struct lm3630_chip_data *pchip) -{ - if (!pchip->pdata->pwm_set_intensity) - return false; - pchip->pdata->pwm_set_intensity(bl->props.brightness - 1, - pchip->pdata->pwm_period); - return true; -} - -/* update and get brightness */ -static int lm3630_bank_a_update_status(struct backlight_device *bl) -{ - int ret; - struct lm3630_chip_data *pchip = bl_get_data(bl); - enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; - - /* brightness 0 means disable */ - if (!bl->props.brightness) { - ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x04, 0x00); - if (ret < 0) - goto out; - return bl->props.brightness; - } - - /* pwm control */ - if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) { - if (!set_intensity(bl, pchip)) - dev_err(pchip->dev, "No pwm control func. in plat-data\n"); - } else { - - /* i2c control */ - ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); - if (ret < 0) - goto out; - mdelay(1); - ret = regmap_write(pchip->regmap, - REG_BRT_A, bl->props.brightness - 1); - if (ret < 0) - goto out; - } - return bl->props.brightness; -out: - dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); - return bl->props.brightness; -} - -static int lm3630_bank_a_get_brightness(struct backlight_device *bl) -{ - unsigned int reg_val; - int brightness, ret; - struct lm3630_chip_data *pchip = bl_get_data(bl); - enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; - - if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) { - ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, ®_val); - if (ret < 0) - goto out; - brightness = reg_val & 0x01; - ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, ®_val); - if (ret < 0) - goto out; - brightness = ((brightness << 8) | reg_val) + 1; - } else { - ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); - if (ret < 0) - goto out; - mdelay(1); - ret = regmap_read(pchip->regmap, REG_BRT_A, ®_val); - if (ret < 0) - goto out; - brightness = reg_val + 1; - } - bl->props.brightness = brightness; - return bl->props.brightness; -out: - dev_err(pchip->dev, "i2c failed to access register\n"); - return 0; -} - -static const struct backlight_ops lm3630_bank_a_ops = { - .options = BL_CORE_SUSPENDRESUME, - .update_status = lm3630_bank_a_update_status, - .get_brightness = lm3630_bank_a_get_brightness, -}; - -static int lm3630_bank_b_update_status(struct backlight_device *bl) -{ - int ret; - struct lm3630_chip_data *pchip = bl_get_data(bl); - enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; - - if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) { - if (!set_intensity(bl, pchip)) - dev_err(pchip->dev, - "no pwm control func. in plat-data\n"); - } else { - ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); - if (ret < 0) - goto out; - mdelay(1); - ret = regmap_write(pchip->regmap, - REG_BRT_B, bl->props.brightness - 1); - } - return bl->props.brightness; -out: - dev_err(pchip->dev, "i2c failed to access register\n"); - return bl->props.brightness; -} - -static int lm3630_bank_b_get_brightness(struct backlight_device *bl) -{ - unsigned int reg_val; - int brightness, ret; - struct lm3630_chip_data *pchip = bl_get_data(bl); - enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; - - if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) { - ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, ®_val); - if (ret < 0) - goto out; - brightness = reg_val & 0x01; - ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, ®_val); - if (ret < 0) - goto out; - brightness = ((brightness << 8) | reg_val) + 1; - } else { - ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); - if (ret < 0) - goto out; - mdelay(1); - ret = regmap_read(pchip->regmap, REG_BRT_B, ®_val); - if (ret < 0) - goto out; - brightness = reg_val + 1; - } - bl->props.brightness = brightness; - - return bl->props.brightness; -out: - dev_err(pchip->dev, "i2c failed to access register\n"); - return bl->props.brightness; -} - -static const struct backlight_ops lm3630_bank_b_ops = { - .options = BL_CORE_SUSPENDRESUME, - .update_status = lm3630_bank_b_update_status, - .get_brightness = lm3630_bank_b_get_brightness, -}; - -static int lm3630_backlight_register(struct lm3630_chip_data *pchip, - enum lm3630_leds ledno) -{ - const char *name = bled_name[ledno]; - struct backlight_properties props; - struct lm3630_platform_data *pdata = pchip->pdata; - - props.type = BACKLIGHT_RAW; - switch (ledno) { - case BLED_1: - case BLED_ALL: - props.brightness = pdata->init_brt_led1; - props.max_brightness = pdata->max_brt_led1; - pchip->bled1 = - backlight_device_register(name, pchip->dev, pchip, - &lm3630_bank_a_ops, &props); - if (IS_ERR(pchip->bled1)) - return PTR_ERR(pchip->bled1); - break; - case BLED_2: - props.brightness = pdata->init_brt_led2; - props.max_brightness = pdata->max_brt_led2; - pchip->bled2 = - backlight_device_register(name, pchip->dev, pchip, - &lm3630_bank_b_ops, &props); - if (IS_ERR(pchip->bled2)) - return PTR_ERR(pchip->bled2); - break; - } - return 0; -} - -static void lm3630_backlight_unregister(struct lm3630_chip_data *pchip) -{ - if (pchip->bled1) - backlight_device_unregister(pchip->bled1); - if (pchip->bled2) - backlight_device_unregister(pchip->bled2); -} - -static const struct regmap_config lm3630_regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = REG_MAX, -}; - -static int lm3630_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct lm3630_platform_data *pdata = client->dev.platform_data; - struct lm3630_chip_data *pchip; - int ret; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "fail : i2c functionality check...\n"); - return -EOPNOTSUPP; - } - - if (pdata == NULL) { - dev_err(&client->dev, "fail : no platform data.\n"); - return -ENODATA; - } - - pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630_chip_data), - GFP_KERNEL); - if (!pchip) - return -ENOMEM; - pchip->pdata = pdata; - pchip->dev = &client->dev; - - pchip->regmap = devm_regmap_init_i2c(client, &lm3630_regmap); - if (IS_ERR(pchip->regmap)) { - ret = PTR_ERR(pchip->regmap); - dev_err(&client->dev, "fail : allocate register map: %d\n", - ret); - return ret; - } - i2c_set_clientdata(client, pchip); - - /* chip initialize */ - ret = lm3630_chip_init(pchip); - if (ret < 0) { - dev_err(&client->dev, "fail : init chip\n"); - goto err_chip_init; - } - - switch (pdata->bank_a_ctrl) { - case BANK_A_CTRL_ALL: - ret = lm3630_backlight_register(pchip, BLED_ALL); - pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE; - break; - case BANK_A_CTRL_LED1: - ret = lm3630_backlight_register(pchip, BLED_1); - break; - case BANK_A_CTRL_LED2: - ret = lm3630_backlight_register(pchip, BLED_2); - pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE; - break; - default: - break; - } - - if (ret < 0) - goto err_bl_reg; - - if (pdata->bank_b_ctrl && pchip->bled2 == NULL) { - ret = lm3630_backlight_register(pchip, BLED_2); - if (ret < 0) - goto err_bl_reg; - } - - /* interrupt enable : irq 0 is not allowed for lm3630 */ - pchip->irq = client->irq; - if (pchip->irq) - lm3630_intr_config(pchip); - - dev_info(&client->dev, "LM3630 backlight register OK.\n"); - return 0; - -err_bl_reg: - dev_err(&client->dev, "fail : backlight register.\n"); - lm3630_backlight_unregister(pchip); -err_chip_init: - return ret; -} - -static int lm3630_remove(struct i2c_client *client) -{ - int ret; - struct lm3630_chip_data *pchip = i2c_get_clientdata(client); - - ret = regmap_write(pchip->regmap, REG_BRT_A, 0); - if (ret < 0) - dev_err(pchip->dev, "i2c failed to access register\n"); - - ret = regmap_write(pchip->regmap, REG_BRT_B, 0); - if (ret < 0) - dev_err(pchip->dev, "i2c failed to access register\n"); - - lm3630_backlight_unregister(pchip); - if (pchip->irq) { - free_irq(pchip->irq, pchip); - flush_workqueue(pchip->irqthread); - destroy_workqueue(pchip->irqthread); - } - return 0; -} - -static const struct i2c_device_id lm3630_id[] = { - {LM3630_NAME, 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, lm3630_id); - -static struct i2c_driver lm3630_i2c_driver = { - .driver = { - .name = LM3630_NAME, - }, - .probe = lm3630_probe, - .remove = lm3630_remove, - .id_table = lm3630_id, -}; - -module_i2c_driver(lm3630_i2c_driver); - -MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630"); -MODULE_AUTHOR("G.Shark Jeong "); -MODULE_AUTHOR("Daniel Jeong "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c new file mode 100644 index 0000000..cf40cc8 --- /dev/null +++ b/drivers/video/backlight/lm3630a_bl.c @@ -0,0 +1,483 @@ +/* +* Simple driver for Texas Instruments LM3630A Backlight driver chip +* Copyright (C) 2012 Texas Instruments +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_CTRL 0x00 +#define REG_BOOST 0x02 +#define REG_CONFIG 0x01 +#define REG_BRT_A 0x03 +#define REG_BRT_B 0x04 +#define REG_I_A 0x05 +#define REG_I_B 0x06 +#define REG_INT_STATUS 0x09 +#define REG_INT_EN 0x0A +#define REG_FAULT 0x0B +#define REG_PWM_OUTLOW 0x12 +#define REG_PWM_OUTHIGH 0x13 +#define REG_MAX 0x1F + +#define INT_DEBOUNCE_MSEC 10 +struct lm3630a_chip { + struct device *dev; + struct delayed_work work; + + int irq; + struct workqueue_struct *irqthread; + struct lm3630a_platform_data *pdata; + struct backlight_device *bleda; + struct backlight_device *bledb; + struct regmap *regmap; + struct pwm_device *pwmd; +}; + +/* i2c access */ +static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg) +{ + int rval; + unsigned int reg_val; + + rval = regmap_read(pchip->regmap, reg, ®_val); + if (rval < 0) + return rval; + return reg_val & 0xFF; +} + +static int lm3630a_write(struct lm3630a_chip *pchip, + unsigned int reg, unsigned int data) +{ + return regmap_write(pchip->regmap, reg, data); +} + +static int lm3630a_update(struct lm3630a_chip *pchip, + unsigned int reg, unsigned int mask, + unsigned int data) +{ + return regmap_update_bits(pchip->regmap, reg, mask, data); +} + +/* initialize chip */ +static int lm3630a_chip_init(struct lm3630a_chip *pchip) +{ + int rval; + struct lm3630a_platform_data *pdata = pchip->pdata; + + usleep_range(1000, 2000); + /* set Filter Strength Register */ + rval = lm3630a_write(pchip, 0x50, 0x03); + /* set Cofig. register */ + rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl); + /* set boost control */ + rval |= lm3630a_write(pchip, REG_BOOST, 0x38); + /* set current A */ + rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F); + /* set current B */ + rval |= lm3630a_write(pchip, REG_I_B, 0x1F); + /* set control */ + rval |= + lm3630a_write(pchip, REG_CTRL, pdata->leda_ctrl | pdata->ledb_ctrl); + usleep_range(1000, 2000); + /* set brightness A and B */ + rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt); + rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt); + + if (rval < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + return rval; +} + +/* interrupt handling */ +static void lm3630a_delayed_func(struct work_struct *work) +{ + unsigned int rval; + struct lm3630a_chip *pchip; + + pchip = container_of(work, struct lm3630a_chip, work.work); + + rval = lm3630a_read(pchip, REG_INT_STATUS); + if (rval < 0) { + dev_err(pchip->dev, + "i2c failed to access REG_INT_STATUS Register\n"); + return; + } + + dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval); +} + +static irqreturn_t lm3630a_isr_func(int irq, void *chip) +{ + int rval; + struct lm3630a_chip *pchip = chip; + unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); + + queue_delayed_work(pchip->irqthread, &pchip->work, delay); + + rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (rval < 0) { + dev_err(pchip->dev, "i2c failed to access register\n"); + return IRQ_NONE; + } + return IRQ_HANDLED; +} + +static int lm3630a_intr_config(struct lm3630a_chip *pchip) +{ + int rval; + + rval = lm3630a_write(pchip, REG_INT_EN, 0x87); + if (rval < 0) + return rval; + + INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func); + pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd"); + if (!pchip->irqthread) { + dev_err(pchip->dev, "create irq thread fail\n"); + return -ENOMEM; + } + if (request_threaded_irq + (pchip->irq, NULL, lm3630a_isr_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) { + dev_err(pchip->dev, "request threaded irq fail\n"); + return -ENOMEM; + } + return rval; +} + +static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) +{ + unsigned int period = pwm_get_period(pchip->pwmd); + unsigned int duty = br * period / br_max; + + pwm_config(pchip->pwmd, duty, period); + if (duty) + pwm_enable(pchip->pwmd); + else + pwm_disable(pchip->pwmd); +} + +/* update and get brightness */ +static int lm3630a_bank_a_update_status(struct backlight_device *bl) +{ + int ret; + struct lm3630a_chip *pchip = bl_get_data(bl); + enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + /* pwm control */ + if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { + lm3630a_pwm_ctrl(pchip, bl->props.brightness, + bl->props.max_brightness); + return bl->props.brightness; + } + + /* disable sleep */ + ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out_i2c_err; + usleep_range(1000, 2000); + /* minimum brightness is 0x04 */ + ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness); + if (bl->props.brightness < 0x4) + ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0); + else + ret |= lm3630a_update(pchip, REG_CTRL, + LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE); + if (ret < 0) + goto out_i2c_err; + return bl->props.brightness; + +out_i2c_err: + dev_err(pchip->dev, "i2c failed to access\n"); + return bl->props.brightness; +} + +static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) +{ + int brightness, rval; + struct lm3630a_chip *pchip = bl_get_data(bl); + enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { + rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); + if (rval < 0) + goto out_i2c_err; + brightness = (rval & 0x01) << 8; + rval = lm3630a_read(pchip, REG_PWM_OUTLOW); + if (rval < 0) + goto out_i2c_err; + brightness |= rval; + goto out; + } + + /* disable sleep */ + rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (rval < 0) + goto out_i2c_err; + usleep_range(1000, 2000); + rval = lm3630a_read(pchip, REG_BRT_A); + if (rval < 0) + goto out_i2c_err; + brightness = rval; + +out: + bl->props.brightness = brightness; + return bl->props.brightness; +out_i2c_err: + dev_err(pchip->dev, "i2c failed to access register\n"); + return 0; +} + +static const struct backlight_ops lm3630a_bank_a_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3630a_bank_a_update_status, + .get_brightness = lm3630a_bank_a_get_brightness, +}; + +/* update and get brightness */ +static int lm3630a_bank_b_update_status(struct backlight_device *bl) +{ + int ret; + struct lm3630a_chip *pchip = bl_get_data(bl); + enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + /* pwm control */ + if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { + lm3630a_pwm_ctrl(pchip, bl->props.brightness, + bl->props.max_brightness); + return bl->props.brightness; + } + + /* disable sleep */ + ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out_i2c_err; + usleep_range(1000, 2000); + /* minimum brightness is 0x04 */ + ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness); + if (bl->props.brightness < 0x4) + ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0); + else + ret |= lm3630a_update(pchip, REG_CTRL, + LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE); + if (ret < 0) + goto out_i2c_err; + return bl->props.brightness; + +out_i2c_err: + dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); + return bl->props.brightness; +} + +static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) +{ + int brightness, rval; + struct lm3630a_chip *pchip = bl_get_data(bl); + enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { + rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); + if (rval < 0) + goto out_i2c_err; + brightness = (rval & 0x01) << 8; + rval = lm3630a_read(pchip, REG_PWM_OUTLOW); + if (rval < 0) + goto out_i2c_err; + brightness |= rval; + goto out; + } + + /* disable sleep */ + rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); + if (rval < 0) + goto out_i2c_err; + usleep_range(1000, 2000); + rval = lm3630a_read(pchip, REG_BRT_B); + if (rval < 0) + goto out_i2c_err; + brightness = rval; + +out: + bl->props.brightness = brightness; + return bl->props.brightness; +out_i2c_err: + dev_err(pchip->dev, "i2c failed to access register\n"); + return 0; +} + +static const struct backlight_ops lm3630a_bank_b_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3630a_bank_b_update_status, + .get_brightness = lm3630a_bank_b_get_brightness, +}; + +static int lm3630a_backlight_register(struct lm3630a_chip *pchip) +{ + struct backlight_properties props; + struct lm3630a_platform_data *pdata = pchip->pdata; + + props.type = BACKLIGHT_RAW; + if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) { + props.brightness = pdata->leda_init_brt; + props.max_brightness = pdata->leda_max_brt; + pchip->bleda = + devm_backlight_device_register(pchip->dev, "lm3630a_leda", + pchip->dev, pchip, + &lm3630a_bank_a_ops, &props); + if (IS_ERR(pchip->bleda)) + return PTR_ERR(pchip->bleda); + } + + if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) && + (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) { + props.brightness = pdata->ledb_init_brt; + props.max_brightness = pdata->ledb_max_brt; + pchip->bledb = + devm_backlight_device_register(pchip->dev, "lm3630a_ledb", + pchip->dev, pchip, + &lm3630a_bank_b_ops, &props); + if (IS_ERR(pchip->bledb)) + return PTR_ERR(pchip->bledb); + } + return 0; +} + +static const struct regmap_config lm3630a_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, +}; + +static int lm3630a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm3630a_platform_data *pdata = client->dev.platform_data; + struct lm3630a_chip *pchip; + int rval; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "fail : i2c functionality check\n"); + return -EOPNOTSUPP; + } + + pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip), + GFP_KERNEL); + if (!pchip) + return -ENOMEM; + pchip->dev = &client->dev; + + pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap); + if (IS_ERR(pchip->regmap)) { + rval = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval); + return rval; + } + + i2c_set_clientdata(client, pchip); + if (pdata == NULL) { + pchip->pdata = devm_kzalloc(pchip->dev, + sizeof(struct + lm3630a_platform_data), + GFP_KERNEL); + if (pchip->pdata == NULL) + return -ENOMEM; + /* default values */ + pchip->pdata->leda_ctrl = LM3630A_LEDA_ENABLE; + pchip->pdata->ledb_ctrl = LM3630A_LEDB_ENABLE; + pchip->pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS; + pchip->pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS; + pchip->pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS; + pchip->pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS; + } else { + pchip->pdata = pdata; + } + /* chip initialize */ + rval = lm3630a_chip_init(pchip); + if (rval < 0) { + dev_err(&client->dev, "fail : init chip\n"); + return rval; + } + /* backlight register */ + rval = lm3630a_backlight_register(pchip); + if (rval < 0) { + dev_err(&client->dev, "fail : backlight register.\n"); + return rval; + } + /* pwm */ + if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) { + pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm"); + if (IS_ERR(pchip->pwmd)) { + dev_err(&client->dev, "fail : get pwm device\n"); + return PTR_ERR(pchip->pwmd); + } + } + pchip->pwmd->period = pdata->pwm_period; + + /* interrupt enable : irq 0 is not allowed */ + pchip->irq = client->irq; + if (pchip->irq) { + rval = lm3630a_intr_config(pchip); + if (rval < 0) + return rval; + } + dev_info(&client->dev, "LM3630A backlight register OK.\n"); + return 0; +} + +static int lm3630a_remove(struct i2c_client *client) +{ + int rval; + struct lm3630a_chip *pchip = i2c_get_clientdata(client); + + rval = lm3630a_write(pchip, REG_BRT_A, 0); + if (rval < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + + rval = lm3630a_write(pchip, REG_BRT_B, 0); + if (rval < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + + if (pchip->irq) { + free_irq(pchip->irq, pchip); + flush_workqueue(pchip->irqthread); + destroy_workqueue(pchip->irqthread); + } + return 0; +} + +static const struct i2c_device_id lm3630a_id[] = { + {LM3630A_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lm3630a_id); + +static struct i2c_driver lm3630a_i2c_driver = { + .driver = { + .name = LM3630A_NAME, + }, + .probe = lm3630a_probe, + .remove = lm3630a_remove, + .id_table = lm3630a_id, +}; + +module_i2c_driver(lm3630a_i2c_driver); + +MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A"); +MODULE_AUTHOR("Daniel Jeong "); +MODULE_AUTHOR("LDD MLP "); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform_data/lm3630_bl.h b/include/linux/platform_data/lm3630_bl.h deleted file mode 100644 index 9176dd3..0000000 --- a/include/linux/platform_data/lm3630_bl.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Simple driver for Texas Instruments LM3630 LED Flash driver chip -* Copyright (C) 2012 Texas Instruments -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -*/ - -#ifndef __LINUX_LM3630_H -#define __LINUX_LM3630_H - -#define LM3630_NAME "lm3630_bl" - -enum lm3630_pwm_ctrl { - PWM_CTRL_DISABLE = 0, - PWM_CTRL_BANK_A, - PWM_CTRL_BANK_B, - PWM_CTRL_BANK_ALL, -}; - -enum lm3630_pwm_active { - PWM_ACTIVE_HIGH = 0, - PWM_ACTIVE_LOW, -}; - -enum lm3630_bank_a_ctrl { - BANK_A_CTRL_DISABLE = 0x0, - BANK_A_CTRL_LED1 = 0x4, - BANK_A_CTRL_LED2 = 0x1, - BANK_A_CTRL_ALL = 0x5, -}; - -enum lm3630_bank_b_ctrl { - BANK_B_CTRL_DISABLE = 0, - BANK_B_CTRL_LED2, -}; - -struct lm3630_platform_data { - - /* maximum brightness */ - int max_brt_led1; - int max_brt_led2; - - /* initial on brightness */ - int init_brt_led1; - int init_brt_led2; - enum lm3630_pwm_ctrl pwm_ctrl; - enum lm3630_pwm_active pwm_active; - enum lm3630_bank_a_ctrl bank_a_ctrl; - enum lm3630_bank_b_ctrl bank_b_ctrl; - unsigned int pwm_period; - void (*pwm_set_intensity) (int brightness, int max_brightness); -}; - -#endif /* __LINUX_LM3630_H */ diff --git a/include/linux/platform_data/lm3630a_bl.h b/include/linux/platform_data/lm3630a_bl.h new file mode 100644 index 0000000..7538e38 --- /dev/null +++ b/include/linux/platform_data/lm3630a_bl.h @@ -0,0 +1,65 @@ +/* +* Simple driver for Texas Instruments LM3630A LED Flash driver chip +* Copyright (C) 2012 Texas Instruments +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ + +#ifndef __LINUX_LM3630A_H +#define __LINUX_LM3630A_H + +#define LM3630A_NAME "lm3630a_bl" + +enum lm3630a_pwm_ctrl { + LM3630A_PWM_DISABLE = 0x00, + LM3630A_PWM_BANK_A, + LM3630A_PWM_BANK_B, + LM3630A_PWM_BANK_ALL, + LM3630A_PWM_BANK_A_ACT_LOW = 0x05, + LM3630A_PWM_BANK_B_ACT_LOW, + LM3630A_PWM_BANK_ALL_ACT_LOW, +}; + +enum lm3630a_leda_ctrl { + LM3630A_LEDA_DISABLE = 0x00, + LM3630A_LEDA_ENABLE = 0x04, + LM3630A_LEDA_ENABLE_LINEAR = 0x14, +}; + +enum lm3630a_ledb_ctrl { + LM3630A_LEDB_DISABLE = 0x00, + LM3630A_LEDB_ON_A = 0x01, + LM3630A_LEDB_ENABLE = 0x02, + LM3630A_LEDB_ENABLE_LINEAR = 0x0A, +}; + +#define LM3630A_MAX_BRIGHTNESS 255 +/* + *@leda_init_brt : led a init brightness. 4~255 + *@leda_max_brt : led a max brightness. 4~255 + *@leda_ctrl : led a disable, enable linear, enable exponential + *@ledb_init_brt : led b init brightness. 4~255 + *@ledb_max_brt : led b max brightness. 4~255 + *@ledb_ctrl : led b disable, enable linear, enable exponential + *@pwm_period : pwm period + *@pwm_ctrl : pwm disable, bank a or b, active high or low + */ +struct lm3630a_platform_data { + + /* led a config. */ + int leda_init_brt; + int leda_max_brt; + enum lm3630a_leda_ctrl leda_ctrl; + /* led b config. */ + int ledb_init_brt; + int ledb_max_brt; + enum lm3630a_ledb_ctrl ledb_ctrl; + /* pwm config. */ + unsigned int pwm_period; + enum lm3630a_pwm_ctrl pwm_ctrl; +}; + +#endif /* __LINUX_LM3630A_H */ -- cgit v0.10.2 From 2a0c316bf3ccd910dc58ec62465ff620c664b5e4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 12 Nov 2013 15:08:59 -0800 Subject: drivers/video/backlight/lm3630a_bl.c: fix signedness bug in lm3630a_chip_init() "rval" needs to be signed for the error handling to work. Signed-off-by: Dan Carpenter Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index cf40cc8..200dca0 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -105,7 +105,7 @@ static int lm3630a_chip_init(struct lm3630a_chip *pchip) /* interrupt handling */ static void lm3630a_delayed_func(struct work_struct *work) { - unsigned int rval; + int rval; struct lm3630a_chip *pchip; pchip = container_of(work, struct lm3630a_chip, work.work); -- cgit v0.10.2 From e19493c1f29a3ac48db8797a79532b62a03442b8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 12 Nov 2013 15:09:00 -0800 Subject: drivers/video/backlight/lm3630a_bl.c: potential NULL deref in probe() We dereference "pdata" later in the function so we can't leave it as NULL. Signed-off-by: Dan Carpenter Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index 200dca0..d719a89 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -389,22 +389,21 @@ static int lm3630a_probe(struct i2c_client *client, i2c_set_clientdata(client, pchip); if (pdata == NULL) { - pchip->pdata = devm_kzalloc(pchip->dev, - sizeof(struct - lm3630a_platform_data), - GFP_KERNEL); - if (pchip->pdata == NULL) + pdata = devm_kzalloc(pchip->dev, + sizeof(struct lm3630a_platform_data), + GFP_KERNEL); + if (pdata == NULL) return -ENOMEM; /* default values */ - pchip->pdata->leda_ctrl = LM3630A_LEDA_ENABLE; - pchip->pdata->ledb_ctrl = LM3630A_LEDB_ENABLE; - pchip->pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS; - pchip->pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS; - pchip->pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS; - pchip->pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS; - } else { - pchip->pdata = pdata; + pdata->leda_ctrl = LM3630A_LEDA_ENABLE; + pdata->ledb_ctrl = LM3630A_LEDB_ENABLE; + pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS; + pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS; + pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS; + pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS; } + pchip->pdata = pdata; + /* chip initialize */ rval = lm3630a_chip_init(pchip); if (rval < 0) { -- cgit v0.10.2 From 4c4d2a3a064c893324ad3daca5c097dc7f06bbe3 Mon Sep 17 00:00:00 2001 From: Daniel Jeong Date: Tue, 12 Nov 2013 15:09:01 -0800 Subject: backlight: lm3630: fix sparse warning This patch is to fix sparse warning due to mixing different enum type. Signed-off-by: Daniel Jeong Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index d719a89..1128a02 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -90,8 +90,8 @@ static int lm3630a_chip_init(struct lm3630a_chip *pchip) /* set current B */ rval |= lm3630a_write(pchip, REG_I_B, 0x1F); /* set control */ - rval |= - lm3630a_write(pchip, REG_CTRL, pdata->leda_ctrl | pdata->ledb_ctrl); + rval |= lm3630a_update(pchip, REG_CTRL, 0x14, pdata->leda_ctrl); + rval |= lm3630a_update(pchip, REG_CTRL, 0x0B, pdata->ledb_ctrl); usleep_range(1000, 2000); /* set brightness A and B */ rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt); -- cgit v0.10.2 From 86b15d5d3bae0b4a64bd2bf834fc1d876285dbf0 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:01 -0800 Subject: backlight: ld9040: Staticize local variable gamma_table Fix the following sparse warnings: drivers/video/backlight/ld9040_gamma.h:172:3: warning: symbol 'gamma_table' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backlight/ld9040_gamma.h index 038d9c8..c5e586d 100644 --- a/drivers/video/backlight/ld9040_gamma.h +++ b/drivers/video/backlight/ld9040_gamma.h @@ -169,7 +169,9 @@ static const unsigned int ld9040_22_50[] = { struct ld9040_gamma { unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; -} gamma_table = { +}; + +static struct ld9040_gamma gamma_table = { .gamma_22_table[0] = (unsigned int *)&ld9040_22_50, .gamma_22_table[1] = (unsigned int *)&ld9040_22_70, .gamma_22_table[2] = (unsigned int *)&ld9040_22_80, -- cgit v0.10.2 From 0ab7b20fa011f25f900b04e8f6f6e8221864eefd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:02 -0800 Subject: backlight: lm3639: don't mix different enum types Don't mix different enum types to fix the sparse warnings. drivers/video/backlight/lm3639_bl.c:80:51: warning: mixing different enum types drivers/video/backlight/lm3639_bl.c:80:51: int enum lm3639_fleds versus drivers/video/backlight/lm3639_bl.c:80:51: int enum lm3639_bleds drivers/video/backlight/lm3639_bl.c:82:51: warning: mixing different enum types drivers/video/backlight/lm3639_bl.c:82:51: int enum lm3639_fleds versus drivers/video/backlight/lm3639_bl.c:82:51: int enum lm3639_bleds Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c index 053964d..6c888e3 100644 --- a/drivers/video/backlight/lm3639_bl.c +++ b/drivers/video/backlight/lm3639_bl.c @@ -76,10 +76,13 @@ static int lm3639_chip_init(struct lm3639_chip_data *pchip) goto out; /* output pins config. */ - if (!pdata->init_brt_led) - reg_val = pdata->fled_pins | pdata->bled_pins; - else - reg_val = pdata->fled_pins | pdata->bled_pins | 0x01; + if (!pdata->init_brt_led) { + reg_val = pdata->fled_pins; + reg_val |= pdata->bled_pins; + } else { + reg_val = pdata->fled_pins; + reg_val |= pdata->bled_pins | 0x01; + } ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val); if (ret < 0) -- cgit v0.10.2 From 1f299997b460d08356006945345a8962f7ecd719 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:03 -0800 Subject: backlight: lp8788: staticize 'default_bl_config' Fix the following sparse warning: drivers/video/backlight/lp8788_bl.c:55:25: warning: symbol 'default_bl_config' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c index 980855e..e49905d 100644 --- a/drivers/video/backlight/lp8788_bl.c +++ b/drivers/video/backlight/lp8788_bl.c @@ -52,7 +52,7 @@ struct lp8788_bl { struct pwm_device *pwm; }; -struct lp8788_bl_config default_bl_config = { +static struct lp8788_bl_config default_bl_config = { .bl_mode = LP8788_BL_REGISTER_ONLY, .dim_mode = LP8788_DIM_EXPONENTIAL, .full_scale = LP8788_FULLSCALE_1900uA, -- cgit v0.10.2 From c512794cada491e008eeca822af7e4ad5db72a56 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:04 -0800 Subject: backlight: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 2cd6350..a84a12a 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -196,7 +196,7 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev, static int pm860x_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_backlight_pdata *pdata = pdev->dev.platform_data; + struct pm860x_backlight_pdata *pdata = dev_get_platdata(&pdev->dev); struct pm860x_backlight_data *data; struct backlight_device *bl; struct resource *res; diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index c6fc668..c68232b 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -127,7 +127,7 @@ static const struct backlight_ops aat2870_bl_ops = { static int aat2870_bl_probe(struct platform_device *pdev) { - struct aat2870_bl_platform_data *pdata = pdev->dev.platform_data; + struct aat2870_bl_platform_data *pdata = dev_get_platdata(&pdev->dev); struct aat2870_bl_driver_data *aat2870_bl; struct backlight_device *bd; struct backlight_properties props; diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index c84701b..fe8e3d1 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -297,7 +297,7 @@ static int adp5520_bl_probe(struct platform_device *pdev) return -ENOMEM; data->master = pdev->dev.parent; - data->pdata = pdev->dev.platform_data; + data->pdata = dev_get_platdata(&pdev->dev); if (data->pdata == NULL) { dev_err(&pdev->dev, "missing platform data\n"); diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 75b10f8..2f77f37 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -216,7 +216,7 @@ static int adp8860_led_setup(struct adp8860_led *led) static int adp8860_led_probe(struct i2c_client *client) { struct adp8860_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct adp8860_bl *data = i2c_get_clientdata(client); struct adp8860_led *led, *led_dat; struct led_info *cur_led; @@ -300,7 +300,7 @@ static int adp8860_led_probe(struct i2c_client *client) static int adp8860_led_remove(struct i2c_client *client) { struct adp8860_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct adp8860_bl *data = i2c_get_clientdata(client); int i; @@ -658,7 +658,7 @@ static int adp8860_probe(struct i2c_client *client, struct backlight_device *bl; struct adp8860_bl *data; struct adp8860_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct backlight_properties props; uint8_t reg_val; int ret; diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 90049d7..9eee69f 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -238,7 +238,7 @@ static int adp8870_led_setup(struct adp8870_led *led) static int adp8870_led_probe(struct i2c_client *client) { struct adp8870_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct adp8870_bl *data = i2c_get_clientdata(client); struct adp8870_led *led, *led_dat; struct led_info *cur_led; @@ -325,7 +325,7 @@ static int adp8870_led_probe(struct i2c_client *client) static int adp8870_led_remove(struct i2c_client *client) { struct adp8870_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); struct adp8870_bl *data = i2c_get_clientdata(client); int i; @@ -848,7 +848,7 @@ static int adp8870_probe(struct i2c_client *client, struct backlight_device *bl; struct adp8870_bl *data; struct adp8870_backlight_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); uint8_t reg_val; int ret; diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index 319fef6..df5507b 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -471,7 +471,7 @@ static int ams369fg06_probe(struct spi_device *spi) lcd->spi = spi; lcd->dev = &spi->dev; - lcd->lcd_pd = spi->dev.platform_data; + lcd->lcd_pd = dev_get_platdata(&spi->dev); if (!lcd->lcd_pd) { dev_err(&spi->dev, "platform data is NULL\n"); return -EINVAL; diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index f7447f7..c11121e 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -133,7 +133,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) pwmbl->pdev = pdev; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { retval = -ENODEV; goto err_free_mem; diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c index 15e3294..43c434e 100644 --- a/drivers/video/backlight/bd6107.c +++ b/drivers/video/backlight/bd6107.c @@ -128,7 +128,7 @@ static const struct backlight_ops bd6107_backlight_ops = { static int bd6107_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct bd6107_platform_data *pdata = client->dev.platform_data; + struct bd6107_platform_data *pdata = dev_get_platdata(&client->dev); struct backlight_device *backlight; struct backlight_properties props; struct bd6107 *bd; diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index c97867a..be56cfe 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -533,7 +533,7 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd, static int corgi_lcd_probe(struct spi_device *spi) { struct backlight_properties props; - struct corgi_lcd_platform_data *pdata = spi->dev.platform_data; + struct corgi_lcd_platform_data *pdata = dev_get_platdata(&spi->dev); struct corgi_lcd *lcd; int ret = 0; diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index 67cadd3..bbad5c2 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -109,7 +109,7 @@ static const struct backlight_ops da903x_backlight_ops = { static int da903x_backlight_probe(struct platform_device *pdev) { - struct da9034_backlight_pdata *pdata = pdev->dev.platform_data; + struct da9034_backlight_pdata *pdata = dev_get_platdata(&pdev->dev); struct da903x_backlight_data *data; struct backlight_device *bl; struct backlight_properties props; diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 19e393b..48fa914 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -79,7 +79,7 @@ static const struct backlight_ops genericbl_ops = { static int genericbl_probe(struct platform_device *pdev) { struct backlight_properties props; - struct generic_bl_info *machinfo = pdev->dev.platform_data; + struct generic_bl_info *machinfo = dev_get_platdata(&pdev->dev); const char *name = "generic-bl"; struct backlight_device *bd; diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c index 5fa217f..118da0c 100644 --- a/drivers/video/backlight/gpio_backlight.c +++ b/drivers/video/backlight/gpio_backlight.c @@ -62,7 +62,8 @@ static const struct backlight_ops gpio_backlight_ops = { static int gpio_backlight_probe(struct platform_device *pdev) { - struct gpio_backlight_platform_data *pdata = pdev->dev.platform_data; + struct gpio_backlight_platform_data *pdata = + dev_get_platdata(&pdev->dev); struct backlight_properties props; struct backlight_device *bl; struct gpio_backlight *gbl; diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c index f8be90c..4dd43e0 100644 --- a/drivers/video/backlight/ili9320.c +++ b/drivers/video/backlight/ili9320.c @@ -198,7 +198,7 @@ static void ili9320_setup_spi(struct ili9320 *ili, int ili9320_probe_spi(struct spi_device *spi, struct ili9320_client *client) { - struct ili9320_platdata *cfg = spi->dev.platform_data; + struct ili9320_platdata *cfg = dev_get_platdata(&spi->dev); struct device *dev = &spi->dev; struct ili9320 *ili; struct lcd_device *lcd; diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index bca6ccc..5bacabb 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -141,7 +141,7 @@ static const struct backlight_ops kb3886bl_ops = { static int kb3886bl_probe(struct platform_device *pdev) { struct backlight_properties props; - struct kb3886bl_machinfo *machinfo = pdev->dev.platform_data; + struct kb3886bl_machinfo *machinfo = dev_get_platdata(&pdev->dev); bl_machinfo = machinfo; if (!machinfo->limit_mask) diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index a35a38c..923eae2 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -48,7 +48,7 @@ static void l4f00242t03_reset(unsigned int gpio) static void l4f00242t03_lcd_init(struct spi_device *spi) { - struct l4f00242t03_pdata *pdata = spi->dev.platform_data; + struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); struct l4f00242t03_priv *priv = spi_get_drvdata(spi); const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) }; int ret; @@ -88,7 +88,7 @@ static void l4f00242t03_lcd_init(struct spi_device *spi) static void l4f00242t03_lcd_powerdown(struct spi_device *spi) { - struct l4f00242t03_pdata *pdata = spi->dev.platform_data; + struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); struct l4f00242t03_priv *priv = spi_get_drvdata(spi); dev_dbg(&spi->dev, "Powering down LCD\n"); @@ -171,7 +171,7 @@ static struct lcd_ops l4f_ops = { static int l4f00242t03_probe(struct spi_device *spi) { struct l4f00242t03_priv *priv; - struct l4f00242t03_pdata *pdata = spi->dev.platform_data; + struct l4f00242t03_pdata *pdata = dev_get_platdata(&spi->dev); int ret; if (pdata == NULL) { diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c index 1e0a309..26d5139 100644 --- a/drivers/video/backlight/ld9040.c +++ b/drivers/video/backlight/ld9040.c @@ -702,7 +702,7 @@ static int ld9040_probe(struct spi_device *spi) lcd->spi = spi; lcd->dev = &spi->dev; - lcd->lcd_pd = spi->dev.platform_data; + lcd->lcd_pd = dev_get_platdata(&spi->dev); if (!lcd->lcd_pd) { dev_err(&spi->dev, "platform data is NULL.\n"); return -EINVAL; diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c index 1d1dbfb..93eea65 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -284,7 +284,7 @@ static int lm3533_bl_probe(struct platform_device *pdev) if (!lm3533) return -EINVAL; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "no platform data\n"); return -EINVAL; diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index 1128a02..999075a 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -365,7 +365,7 @@ static const struct regmap_config lm3630a_regmap = { static int lm3630a_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct lm3630a_platform_data *pdata = client->dev.platform_data; + struct lm3630a_platform_data *pdata = dev_get_platdata(&client->dev); struct lm3630a_chip *pchip; int rval; diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c index 6c888e3..6fd60ad 100644 --- a/drivers/video/backlight/lm3639_bl.c +++ b/drivers/video/backlight/lm3639_bl.c @@ -307,7 +307,7 @@ static int lm3639_probe(struct i2c_client *client, { int ret; struct lm3639_chip_data *pchip; - struct lm3639_platform_data *pdata = client->dev.platform_data; + struct lm3639_platform_data *pdata = dev_get_platdata(&client->dev); struct backlight_properties props; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index 4eec472..80b5929 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -128,7 +128,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power) { struct lms283gf05_state *st = lcd_get_data(ld); struct spi_device *spi = st->spi; - struct lms283gf05_pdata *pdata = spi->dev.platform_data; + struct lms283gf05_pdata *pdata = dev_get_platdata(&spi->dev); if (power <= FB_BLANK_NORMAL) { if (pdata) @@ -153,7 +153,7 @@ static struct lcd_ops lms_ops = { static int lms283gf05_probe(struct spi_device *spi) { struct lms283gf05_state *st; - struct lms283gf05_pdata *pdata = spi->dev.platform_data; + struct lms283gf05_pdata *pdata = dev_get_platdata(&spi->dev); struct lcd_device *ld; int ret = 0; diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c index cf01b9a..ff46e19 100644 --- a/drivers/video/backlight/lms501kf03.c +++ b/drivers/video/backlight/lms501kf03.c @@ -344,7 +344,7 @@ static int lms501kf03_probe(struct spi_device *spi) lcd->spi = spi; lcd->dev = &spi->dev; - lcd->lcd_pd = spi->dev.platform_data; + lcd->lcd_pd = dev_get_platdata(&spi->dev); if (!lcd->lcd_pd) { dev_err(&spi->dev, "platform data is NULL\n"); return -EINVAL; diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index c952175..57f005a 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -405,7 +405,7 @@ static int lp855x_parse_dt(struct device *dev, struct device_node *node) static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) { struct lp855x *lp; - struct lp855x_platform_data *pdata = cl->dev.platform_data; + struct lp855x_platform_data *pdata = dev_get_platdata(&cl->dev); struct device_node *node = cl->dev.of_node; int ret; @@ -414,7 +414,7 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) if (ret < 0) return ret; - pdata = cl->dev.platform_data; + pdata = dev_get_platdata(&cl->dev); } if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c index 498fd73..8091a28 100644 --- a/drivers/video/backlight/lv5207lp.c +++ b/drivers/video/backlight/lv5207lp.c @@ -93,7 +93,7 @@ static const struct backlight_ops lv5207lp_backlight_ops = { static int lv5207lp_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct lv5207lp_platform_data *pdata = client->dev.platform_data; + struct lv5207lp_platform_data *pdata = dev_get_platdata(&client->dev); struct backlight_device *backlight; struct backlight_properties props; struct lv5207lp *lv; diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index 812e22e..ac11a46 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -133,7 +133,7 @@ static int omapbl_probe(struct platform_device *pdev) struct backlight_properties props; struct backlight_device *dev; struct omap_backlight *bl; - struct omap_backlight_config *pdata = pdev->dev.platform_data; + struct omap_backlight_config *pdata = dev_get_platdata(&pdev->dev); if (!pdata) return -ENXIO; diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c index 6ed76be..b2184cf 100644 --- a/drivers/video/backlight/pcf50633-backlight.c +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -103,7 +103,7 @@ static int pcf50633_bl_probe(struct platform_device *pdev) { struct pcf50633_bl *pcf_bl; struct device *parent = pdev->dev.parent; - struct pcf50633_platform_data *pcf50633_data = parent->platform_data; + struct pcf50633_platform_data *pcf50633_data = dev_get_platdata(parent); struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data; struct backlight_properties bl_props; diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index 0568367..cc0f067 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -80,7 +80,7 @@ static int platform_lcd_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int err; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(dev, "no platform data supplied\n"); return -EINVAL; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 1fea627..36db5d9 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -163,7 +163,7 @@ static int pwm_backlight_parse_dt(struct device *dev, static int pwm_backlight_probe(struct platform_device *pdev) { - struct platform_pwm_backlight_data *data = pdev->dev.platform_data; + struct platform_pwm_backlight_data *data = dev_get_platdata(&pdev->dev); struct platform_pwm_backlight_data defdata; struct backlight_properties props; struct backlight_device *bl; diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index b37bb18..4e339ad 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -735,7 +735,7 @@ static int s6e63m0_probe(struct spi_device *spi) lcd->spi = spi; lcd->dev = &spi->dev; - lcd->lcd_pd = spi->dev.platform_data; + lcd->lcd_pd = dev_get_platdata(&spi->dev); if (!lcd->lcd_pd) { dev_err(&spi->dev, "platform data is NULL.\n"); return -EINVAL; diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 18cdf46..2ccfa46 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -338,7 +338,7 @@ static int tdo24m_probe(struct spi_device *spi) enum tdo24m_model model; int err; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (pdata) model = pdata->model; else diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 9df66ac..b8db933 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -38,7 +38,7 @@ struct tosa_bl_data { static void tosa_bl_set_backlight(struct tosa_bl_data *data, int brightness) { - struct spi_device *spi = data->i2c->dev.platform_data; + struct spi_device *spi = dev_get_platdata(&data->i2c->dev); i2c_smbus_write_byte_data(data->i2c, DAC_CH1, data->comadj); diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 0578231..4ea2039 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -287,12 +287,11 @@ static int tps65217_bl_probe(struct platform_device *pdev) if (IS_ERR(pdata)) return PTR_ERR(pdata); } else { - if (!pdev->dev.platform_data) { + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { dev_err(&pdev->dev, "no platform data provided\n"); return -EINVAL; } - - pdata = pdev->dev.platform_data; } tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 9e5517a..2ccf320 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -123,7 +123,7 @@ static const struct backlight_ops wm831x_backlight_ops = { static int wm831x_backlight_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); - struct wm831x_pdata *wm831x_pdata; + struct wm831x_pdata *wm831x_pdata = dev_get_platdata(pdev->dev.parent); struct wm831x_backlight_pdata *pdata; struct wm831x_backlight_data *data; struct backlight_device *bl; @@ -131,12 +131,10 @@ static int wm831x_backlight_probe(struct platform_device *pdev) int ret, i, max_isel, isink_reg, dcdc_cfg; /* We need platform data */ - if (pdev->dev.parent->platform_data) { - wm831x_pdata = pdev->dev.parent->platform_data; + if (wm831x_pdata) pdata = wm831x_pdata->backlight; - } else { + else pdata = NULL; - } if (!pdata) { dev_err(&pdev->dev, "No platform data supplied\n"); -- cgit v0.10.2 From f829c9ef826a4247ac2e6017632be266df0b13ae Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:05 -0800 Subject: backlight: 88pm860x_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index a84a12a..7db5234 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -243,7 +243,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bl = backlight_device_register(name, &pdev->dev, data, + bl = devm_backlight_device_register(&pdev->dev, name, &pdev->dev, data, &pm860x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); @@ -256,21 +256,10 @@ static int pm860x_backlight_probe(struct platform_device *pdev) /* read current backlight */ ret = pm860x_backlight_get_brightness(bl); if (ret < 0) - goto out_brt; + return ret; backlight_update_status(bl); return 0; -out_brt: - backlight_device_unregister(bl); - return ret; -} - -static int pm860x_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; } static struct platform_driver pm860x_backlight_driver = { @@ -279,7 +268,6 @@ static struct platform_driver pm860x_backlight_driver = { .owner = THIS_MODULE, }, .probe = pm860x_backlight_probe, - .remove = pm860x_backlight_remove, }; module_platform_driver(pm860x_backlight_driver); -- cgit v0.10.2 From c7a2bf3b217869f277c5cce229e482ef3bf5ad16 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:06 -0800 Subject: backlight: aat2870: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index c68232b..ee0c0a9 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -158,8 +158,9 @@ static int aat2870_bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; - bd = backlight_device_register("aat2870-backlight", &pdev->dev, - aat2870_bl, &aat2870_bl_ops, &props); + bd = devm_backlight_device_register(&pdev->dev, "aat2870-backlight", + &pdev->dev, aat2870_bl, &aat2870_bl_ops, + &props); if (IS_ERR(bd)) { dev_err(&pdev->dev, "Failed allocate memory for backlight device\n"); @@ -194,13 +195,11 @@ static int aat2870_bl_probe(struct platform_device *pdev) ret = aat2870_bl_update_status(bd); if (ret < 0) { dev_err(&pdev->dev, "Failed to initialize\n"); - goto out_bl_dev_unregister; + return ret; } return 0; -out_bl_dev_unregister: - backlight_device_unregister(bd); out: return ret; } @@ -214,8 +213,6 @@ static int aat2870_bl_remove(struct platform_device *pdev) bd->props.brightness = 0; backlight_update_status(bd); - backlight_device_unregister(bd); - return 0; } -- cgit v0.10.2 From 5f652c710d0aa7a4b97b4a55a2d035187eb0efcf Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:07 -0800 Subject: backlight: adp5520: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index fe8e3d1..f37097a 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -312,8 +312,9 @@ static int adp5520_bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = ADP5020_MAX_BRIGHTNESS; - bl = backlight_device_register(pdev->name, data->master, data, - &adp5520_bl_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, pdev->name, + data->master, data, &adp5520_bl_ops, + &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -326,7 +327,7 @@ static int adp5520_bl_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to register sysfs\n"); - backlight_device_unregister(bl); + return ret; } platform_set_drvdata(pdev, bl); @@ -347,8 +348,6 @@ static int adp5520_bl_remove(struct platform_device *pdev) sysfs_remove_group(&bl->dev.kobj, &adp5520_bl_attr_group); - backlight_device_unregister(bl); - return 0; } -- cgit v0.10.2 From 91fa4ee8f4c77e7ab87a42d795d6589ef3478094 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:08 -0800 Subject: backlight: adp8860: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 2f77f37..9d65671 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -711,8 +711,9 @@ static int adp8860_probe(struct i2c_client *client, mutex_init(&data->lock); - bl = backlight_device_register(dev_driver_string(&client->dev), - &client->dev, data, &adp8860_bl_ops, &props); + bl = devm_backlight_device_register(&client->dev, + dev_driver_string(&client->dev), + &client->dev, data, &adp8860_bl_ops, &props); if (IS_ERR(bl)) { dev_err(&client->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -728,7 +729,7 @@ static int adp8860_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, "failed to register sysfs\n"); - goto out1; + return ret; } ret = adp8860_bl_setup(bl); @@ -751,8 +752,6 @@ out: if (data->en_ambl_sens) sysfs_remove_group(&data->bl->dev.kobj, &adp8860_bl_attr_group); -out1: - backlight_device_unregister(bl); return ret; } @@ -770,8 +769,6 @@ static int adp8860_remove(struct i2c_client *client) sysfs_remove_group(&data->bl->dev.kobj, &adp8860_bl_attr_group); - backlight_device_unregister(data->bl); - return 0; } -- cgit v0.10.2 From 568ee6c3c852610a3951da31519aa28cc9f1927e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:09 -0800 Subject: backlight: adp8870: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 9eee69f..6370720 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -888,8 +888,9 @@ static int adp8870_probe(struct i2c_client *client, memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = props.brightness = ADP8870_MAX_BRIGHTNESS; - bl = backlight_device_register(dev_driver_string(&client->dev), - &client->dev, data, &adp8870_bl_ops, &props); + bl = devm_backlight_device_register(&client->dev, + dev_driver_string(&client->dev), + &client->dev, data, &adp8870_bl_ops, &props); if (IS_ERR(bl)) { dev_err(&client->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -902,7 +903,7 @@ static int adp8870_probe(struct i2c_client *client, &adp8870_bl_attr_group); if (ret) { dev_err(&client->dev, "failed to register sysfs\n"); - goto out1; + return ret; } } @@ -925,8 +926,6 @@ out: if (data->pdata->en_ambl_sens) sysfs_remove_group(&data->bl->dev.kobj, &adp8870_bl_attr_group); -out1: - backlight_device_unregister(bl); return ret; } @@ -944,8 +943,6 @@ static int adp8870_remove(struct i2c_client *client) sysfs_remove_group(&data->bl->dev.kobj, &adp8870_bl_attr_group); - backlight_device_unregister(data->bl); - return 0; } -- cgit v0.10.2 From 83dedc056b61bcfc693d1085b76aa32cc242db6f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:10 -0800 Subject: backlight: as3711_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c index 123887c..bb1fc45 100644 --- a/drivers/video/backlight/as3711_bl.c +++ b/drivers/video/backlight/as3711_bl.c @@ -240,7 +240,8 @@ static int as3711_bl_register(struct platform_device *pdev, /* max tuning I = 31uA for voltage- and 38250uA for current-feedback */ props.max_brightness = max_brightness; - bl = backlight_device_register(su->type == AS3711_BL_SU1 ? + bl = devm_backlight_device_register(&pdev->dev, + su->type == AS3711_BL_SU1 ? "as3711-su1" : "as3711-su2", &pdev->dev, su, &as3711_bl_ops, &props); @@ -432,8 +433,7 @@ static int as3711_backlight_probe(struct platform_device *pdev) case AS3711_SU2_LX_SD4: break; default: - ret = -EINVAL; - goto esu2; + return -EINVAL; } switch (pdata->su2_feedback) { @@ -447,8 +447,7 @@ static int as3711_backlight_probe(struct platform_device *pdev) max_brightness = min(pdata->su2_max_uA / 150, 255); break; default: - ret = -EINVAL; - goto esu2; + return -EINVAL; } ret = as3711_bl_init_su2(supply); @@ -457,26 +456,12 @@ static int as3711_backlight_probe(struct platform_device *pdev) ret = as3711_bl_register(pdev, max_brightness, su); if (ret < 0) - goto esu2; + return ret; } platform_set_drvdata(pdev, supply); return 0; - -esu2: - backlight_device_unregister(supply->su1.bl); - return ret; -} - -static int as3711_backlight_remove(struct platform_device *pdev) -{ - struct as3711_bl_supply *supply = platform_get_drvdata(pdev); - - backlight_device_unregister(supply->su1.bl); - backlight_device_unregister(supply->su2.bl); - - return 0; } static struct platform_driver as3711_backlight_driver = { @@ -485,7 +470,6 @@ static struct platform_driver as3711_backlight_driver = { .owner = THIS_MODULE, }, .probe = as3711_backlight_probe, - .remove = as3711_backlight_remove, }; module_platform_driver(as3711_backlight_driver); -- cgit v0.10.2 From 3e61c73c52443b98a587a0db70a7ebf417de34f6 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:11 -0800 Subject: backlight: atmel-pwm-bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index c11121e..66885fb 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -171,8 +171,9 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min; - bldev = backlight_device_register("atmel-pwm-bl", &pdev->dev, pwmbl, - &atmel_pwm_bl_ops, &props); + bldev = devm_backlight_device_register(&pdev->dev, "atmel-pwm-bl", + &pdev->dev, pwmbl, &atmel_pwm_bl_ops, + &props); if (IS_ERR(bldev)) { retval = PTR_ERR(bldev); goto err_free_pwm; @@ -188,14 +189,12 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) retval = atmel_pwm_bl_init_pwm(pwmbl); if (retval) - goto err_free_bl_dev; + goto err_free_pwm; atmel_pwm_bl_set_intensity(bldev); return 0; -err_free_bl_dev: - backlight_device_unregister(bldev); err_free_pwm: pwm_channel_free(&pwmbl->pwmc); err_free_mem: @@ -210,7 +209,6 @@ static int atmel_pwm_bl_remove(struct platform_device *pdev) gpio_set_value(pwmbl->gpio_on, 0); pwm_channel_disable(&pwmbl->pwmc); pwm_channel_free(&pwmbl->pwmc); - backlight_device_unregister(pwmbl->bldev); return 0; } -- cgit v0.10.2 From 26faf15cc650c6f30687c3e3c22d480bb1e3542b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:12 -0800 Subject: backlight: bd6107: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c index 43c434e..16dd9bc 100644 --- a/drivers/video/backlight/bd6107.c +++ b/drivers/video/backlight/bd6107.c @@ -166,7 +166,8 @@ static int bd6107_probe(struct i2c_client *client, props.brightness = clamp_t(unsigned int, pdata->def_value, 0, props.max_brightness); - backlight = backlight_device_register(dev_name(&client->dev), + backlight = devm_backlight_device_register(&client->dev, + dev_name(&client->dev), &bd->client->dev, bd, &bd6107_backlight_ops, &props); if (IS_ERR(backlight)) { @@ -186,7 +187,6 @@ static int bd6107_remove(struct i2c_client *client) backlight->props.brightness = 0; backlight_update_status(backlight); - backlight_device_unregister(backlight); return 0; } -- cgit v0.10.2 From 564452938311c81194fb9da8fc51f2a12c9a3afd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:12 -0800 Subject: backlight: da903x_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index bbad5c2..12c5d84 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -144,8 +144,9 @@ static int da903x_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = max_brightness; - bl = backlight_device_register(pdev->name, data->da903x_dev, data, - &da903x_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, pdev->name, + data->da903x_dev, data, + &da903x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -158,21 +159,12 @@ static int da903x_backlight_probe(struct platform_device *pdev) return 0; } -static int da903x_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; -} - static struct platform_driver da903x_backlight_driver = { .driver = { .name = "da903x-backlight", .owner = THIS_MODULE, }, .probe = da903x_backlight_probe, - .remove = da903x_backlight_remove, }; module_platform_driver(da903x_backlight_driver); -- cgit v0.10.2 From 02f0092cb37669fd9c68770365a18168b8cd5f60 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:13 -0800 Subject: backlight: da9052_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c index 842da5a..20d55be 100644 --- a/drivers/video/backlight/da9052_bl.c +++ b/drivers/video/backlight/da9052_bl.c @@ -125,8 +125,9 @@ static int da9052_backlight_probe(struct platform_device *pdev) props.type = BACKLIGHT_RAW; props.max_brightness = DA9052_MAX_BRIGHTNESS; - bl = backlight_device_register(pdev->name, wleds->da9052->dev, wleds, - &da9052_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, pdev->name, + wleds->da9052->dev, wleds, + &da9052_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "Failed to register backlight\n"); return PTR_ERR(bl); @@ -147,7 +148,6 @@ static int da9052_backlight_remove(struct platform_device *pdev) wleds->brightness = 0; wleds->state = DA9052_WLEDS_OFF; da9052_adjust_wled_brightness(wleds); - backlight_device_unregister(bl); return 0; } -- cgit v0.10.2 From 23741ada20103cda6a39fad9eb0171757ef997ff Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:14 -0800 Subject: backlight: ep93xx: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c index 018368b..0d1f633 100644 --- a/drivers/video/backlight/ep93xx_bl.c +++ b/drivers/video/backlight/ep93xx_bl.c @@ -92,8 +92,8 @@ static int ep93xxbl_probe(struct platform_device *dev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = EP93XX_MAX_BRIGHT; - bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl, - &ep93xxbl_ops, &props); + bl = devm_backlight_device_register(&dev->dev, dev->name, &dev->dev, + ep93xxbl, &ep93xxbl_ops, &props); if (IS_ERR(bl)) return PTR_ERR(bl); @@ -106,14 +106,6 @@ static int ep93xxbl_probe(struct platform_device *dev) return 0; } -static int ep93xxbl_remove(struct platform_device *dev) -{ - struct backlight_device *bl = platform_get_drvdata(dev); - - backlight_device_unregister(bl); - return 0; -} - #ifdef CONFIG_PM_SLEEP static int ep93xxbl_suspend(struct device *dev) { @@ -140,7 +132,6 @@ static struct platform_driver ep93xxbl_driver = { .pm = &ep93xxbl_pm_ops, }, .probe = ep93xxbl_probe, - .remove = ep93xxbl_remove, }; module_platform_driver(ep93xxbl_driver); -- cgit v0.10.2 From de2efd2a9ffba56eb0c00a48346685baa377c370 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:15 -0800 Subject: backlight: generic_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 48fa914..5d8d652 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -93,8 +93,8 @@ static int genericbl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = machinfo->max_intensity; - bd = backlight_device_register(name, &pdev->dev, NULL, &genericbl_ops, - &props); + bd = devm_backlight_device_register(&pdev->dev, name, &pdev->dev, + NULL, &genericbl_ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); @@ -118,8 +118,6 @@ static int genericbl_remove(struct platform_device *pdev) bd->props.brightness = 0; backlight_update_status(bd); - backlight_device_unregister(bd); - dev_info(&pdev->dev, "Generic Backlight Driver Unloaded\n"); return 0; } -- cgit v0.10.2 From ff47201582a5bbe6d14d2004e637351c41f78214 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:16 -0800 Subject: backlight: gpio_backlight: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c index 118da0c..81fb127 100644 --- a/drivers/video/backlight/gpio_backlight.c +++ b/drivers/video/backlight/gpio_backlight.c @@ -95,8 +95,9 @@ static int gpio_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = 1; - bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, gbl, - &gpio_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev), + &pdev->dev, gbl, &gpio_backlight_ops, + &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -109,21 +110,12 @@ static int gpio_backlight_probe(struct platform_device *pdev) return 0; } -static int gpio_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; -} - static struct platform_driver gpio_backlight_driver = { .driver = { .name = "gpio-backlight", .owner = THIS_MODULE, }, .probe = gpio_backlight_probe, - .remove = gpio_backlight_remove, }; module_platform_driver(gpio_backlight_driver); -- cgit v0.10.2 From da6537850eb0d54eed44ba686be0f5f83c5c6559 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:17 -0800 Subject: backlight: kb3886_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index 5bacabb..7592cc2 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -150,10 +150,10 @@ static int kb3886bl_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = machinfo->max_intensity; - kb3886_backlight_device = backlight_device_register("kb3886-bl", - &pdev->dev, NULL, - &kb3886bl_ops, - &props); + kb3886_backlight_device = devm_backlight_device_register(&pdev->dev, + "kb3886-bl", &pdev->dev, + NULL, &kb3886bl_ops, + &props); if (IS_ERR(kb3886_backlight_device)) return PTR_ERR(kb3886_backlight_device); @@ -166,18 +166,8 @@ static int kb3886bl_probe(struct platform_device *pdev) return 0; } -static int kb3886bl_remove(struct platform_device *pdev) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - - backlight_device_unregister(bd); - - return 0; -} - static struct platform_driver kb3886bl_driver = { .probe = kb3886bl_probe, - .remove = kb3886bl_remove, .driver = { .name = "kb3886-bl", .pm = &kb3886bl_pm_ops, -- cgit v0.10.2 From e86c7098942d6446004ccf89a81c93328d93446a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:18 -0800 Subject: backlight: lm3533_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c index 93eea65..187d1c2 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -313,8 +313,9 @@ static int lm3533_bl_probe(struct platform_device *pdev) props.type = BACKLIGHT_RAW; props.max_brightness = LM3533_BL_MAX_BRIGHTNESS; props.brightness = pdata->default_brightness; - bd = backlight_device_register(pdata->name, pdev->dev.parent, bl, - &lm3533_bl_ops, &props); + bd = devm_backlight_device_register(&pdev->dev, pdata->name, + pdev->dev.parent, bl, &lm3533_bl_ops, + &props); if (IS_ERR(bd)) { dev_err(&pdev->dev, "failed to register backlight device\n"); return PTR_ERR(bd); @@ -328,7 +329,7 @@ static int lm3533_bl_probe(struct platform_device *pdev) ret = sysfs_create_group(&bd->dev.kobj, &lm3533_bl_attribute_group); if (ret < 0) { dev_err(&pdev->dev, "failed to create sysfs attributes\n"); - goto err_unregister; + return ret; } backlight_update_status(bd); @@ -345,8 +346,6 @@ static int lm3533_bl_probe(struct platform_device *pdev) err_sysfs_remove: sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); -err_unregister: - backlight_device_unregister(bd); return ret; } @@ -363,7 +362,6 @@ static int lm3533_bl_remove(struct platform_device *pdev) lm3533_ctrlbank_disable(&bl->cb); sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); - backlight_device_unregister(bd); return 0; } -- cgit v0.10.2 From 6255e8e9849767bcc9c9074aff7c0ec4f6e06c88 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:19 -0800 Subject: backlight: lp855x: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Also, unnecessary lp855x_backlight_unregister() is removed. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 57f005a..cae80d5 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -300,7 +300,7 @@ static int lp855x_backlight_register(struct lp855x *lp) props.brightness = pdata->initial_brightness; - bl = backlight_device_register(name, lp->dev, lp, + bl = devm_backlight_device_register(lp->dev, name, lp->dev, lp, &lp855x_bl_ops, &props); if (IS_ERR(bl)) return PTR_ERR(bl); @@ -310,12 +310,6 @@ static int lp855x_backlight_register(struct lp855x *lp) return 0; } -static void lp855x_backlight_unregister(struct lp855x *lp) -{ - if (lp->bl) - backlight_device_unregister(lp->bl); -} - static ssize_t lp855x_get_chip_id(struct device *dev, struct device_attribute *attr, char *buf) { @@ -439,29 +433,24 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) ret = lp855x_configure(lp); if (ret) { dev_err(lp->dev, "device config err: %d", ret); - goto err_dev; + return ret; } ret = lp855x_backlight_register(lp); if (ret) { dev_err(lp->dev, "failed to register backlight. err: %d\n", ret); - goto err_dev; + return ret; } ret = sysfs_create_group(&lp->dev->kobj, &lp855x_attr_group); if (ret) { dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret); - goto err_sysfs; + return ret; } backlight_update_status(lp->bl); return 0; - -err_sysfs: - lp855x_backlight_unregister(lp); -err_dev: - return ret; } static int lp855x_remove(struct i2c_client *cl) @@ -471,7 +460,6 @@ static int lp855x_remove(struct i2c_client *cl) lp->bl->props.brightness = 0; backlight_update_status(lp->bl); sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group); - lp855x_backlight_unregister(lp); return 0; } -- cgit v0.10.2 From e924c2aadfbd18a38bcc805f32e5ffc1bdad4ad7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:20 -0800 Subject: backlight: lv5207lp: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c index 8091a28..1802b2d 100644 --- a/drivers/video/backlight/lv5207lp.c +++ b/drivers/video/backlight/lv5207lp.c @@ -124,9 +124,9 @@ static int lv5207lp_probe(struct i2c_client *client, props.brightness = clamp_t(unsigned int, pdata->def_value, 0, props.max_brightness); - backlight = backlight_device_register(dev_name(&client->dev), - &lv->client->dev, lv, - &lv5207lp_backlight_ops, &props); + backlight = devm_backlight_device_register(&client->dev, + dev_name(&client->dev), &lv->client->dev, + lv, &lv5207lp_backlight_ops, &props); if (IS_ERR(backlight)) { dev_err(&client->dev, "failed to register backlight\n"); return PTR_ERR(backlight); @@ -144,7 +144,6 @@ static int lv5207lp_remove(struct i2c_client *client) backlight->props.brightness = 0; backlight_update_status(backlight); - backlight_device_unregister(backlight); return 0; } -- cgit v0.10.2 From 18d9dbce468135c07ab57d2a53b406b9d1e05f18 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:21 -0800 Subject: backlight: max8925_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 886e797..66fa08c 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -163,7 +163,8 @@ static int max8925_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bl = backlight_device_register("max8925-backlight", &pdev->dev, data, + bl = devm_backlight_device_register(&pdev->dev, "max8925-backlight", + &pdev->dev, data, &max8925_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); @@ -188,20 +189,9 @@ static int max8925_backlight_probe(struct platform_device *pdev) } ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value); if (ret < 0) - goto out_brt; + return ret; backlight_update_status(bl); return 0; -out_brt: - backlight_device_unregister(bl); - return ret; -} - -static int max8925_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; } static struct platform_driver max8925_backlight_driver = { @@ -210,7 +200,6 @@ static struct platform_driver max8925_backlight_driver = { .owner = THIS_MODULE, }, .probe = max8925_backlight_probe, - .remove = max8925_backlight_remove, }; module_platform_driver(max8925_backlight_driver); -- cgit v0.10.2 From 75d4baec9becbf1ed9c8804bd94004622f38cb11 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:22 -0800 Subject: backlight: pandora_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c index 633b0a2..2098c5d 100644 --- a/drivers/video/backlight/pandora_bl.c +++ b/drivers/video/backlight/pandora_bl.c @@ -120,8 +120,8 @@ static int pandora_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(props)); props.max_brightness = MAX_USER_VALUE; props.type = BACKLIGHT_RAW; - bl = backlight_device_register(pdev->name, &pdev->dev, - NULL, &pandora_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev, + NULL, &pandora_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -145,20 +145,12 @@ static int pandora_backlight_probe(struct platform_device *pdev) return 0; } -static int pandora_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - backlight_device_unregister(bl); - return 0; -} - static struct platform_driver pandora_backlight_driver = { .driver = { .name = "pandora-backlight", .owner = THIS_MODULE, }, .probe = pandora_backlight_probe, - .remove = pandora_backlight_remove, }; module_platform_driver(pandora_backlight_driver); -- cgit v0.10.2 From c423a7712170f2ce51a71cc117cd2d588664bebe Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:23 -0800 Subject: backlight: pcf50633: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c index b2184cf..b95d3b0 100644 --- a/drivers/video/backlight/pcf50633-backlight.c +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -126,7 +126,8 @@ static int pcf50633_bl_probe(struct platform_device *pdev) pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent); - pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl, + pcf_bl->bl = devm_backlight_device_register(&pdev->dev, pdev->name, + &pdev->dev, pcf_bl, &pcf50633_bl_ops, &bl_props); if (IS_ERR(pcf_bl->bl)) @@ -147,18 +148,8 @@ static int pcf50633_bl_probe(struct platform_device *pdev) return 0; } -static int pcf50633_bl_remove(struct platform_device *pdev) -{ - struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev); - - backlight_device_unregister(pcf_bl->bl); - - return 0; -} - static struct platform_driver pcf50633_bl_driver = { .probe = pcf50633_bl_probe, - .remove = pcf50633_bl_remove, .driver = { .name = "pcf50633-backlight", }, -- cgit v0.10.2 From 626d09089f350f876f965c1e6fa4621498213b1e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:24 -0800 Subject: backlight: tps65217_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 4ea2039..cbba37e 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -313,7 +313,7 @@ static int tps65217_bl_probe(struct platform_device *pdev) bl_props.type = BACKLIGHT_RAW; bl_props.max_brightness = 100; - tps65217_bl->bl = backlight_device_register(pdev->name, + tps65217_bl->bl = devm_backlight_device_register(&pdev->dev, pdev->name, tps65217_bl->dev, tps65217_bl, &tps65217_bl_ops, &bl_props); if (IS_ERR(tps65217_bl->bl)) { @@ -329,18 +329,8 @@ static int tps65217_bl_probe(struct platform_device *pdev) return 0; } -static int tps65217_bl_remove(struct platform_device *pdev) -{ - struct tps65217_bl *tps65217_bl = platform_get_drvdata(pdev); - - backlight_device_unregister(tps65217_bl->bl); - - return 0; -} - static struct platform_driver tps65217_bl_driver = { .probe = tps65217_bl_probe, - .remove = tps65217_bl_remove, .driver = { .owner = THIS_MODULE, .name = "tps65217-bl", -- cgit v0.10.2 From f369e664498c8e73f24d137f5356bb3492917bc2 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:25 -0800 Subject: backlight: wm831x_bl: use devm_backlight_device_register() Use devm_backlight_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 2ccf320..8b9455e 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -195,8 +195,8 @@ static int wm831x_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = max_isel; - bl = backlight_device_register("wm831x", &pdev->dev, data, - &wm831x_backlight_ops, &props); + bl = devm_backlight_device_register(&pdev->dev, "wm831x", &pdev->dev, + data, &wm831x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -214,21 +214,12 @@ static int wm831x_backlight_probe(struct platform_device *pdev) return 0; } -static int wm831x_backlight_remove(struct platform_device *pdev) -{ - struct backlight_device *bl = platform_get_drvdata(pdev); - - backlight_device_unregister(bl); - return 0; -} - static struct platform_driver wm831x_backlight_driver = { .driver = { .name = "wm831x-backlight", .owner = THIS_MODULE, }, .probe = wm831x_backlight_probe, - .remove = wm831x_backlight_remove, }; module_platform_driver(wm831x_backlight_driver); -- cgit v0.10.2 From ea5092c890ed093297554e0216188543ee445068 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:25 -0800 Subject: backlight: hx8357: use devm_lcd_device_register() Use devm_lcd_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c index c7af8c4..0d252e7 100644 --- a/drivers/video/backlight/hx8357.c +++ b/drivers/video/backlight/hx8357.c @@ -648,7 +648,8 @@ static int hx8357_probe(struct spi_device *spi) lcd->use_im_pins = 0; } - lcdev = lcd_device_register("mxsfb", &spi->dev, lcd, &hx8357_ops); + lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd, + &hx8357_ops); if (IS_ERR(lcdev)) { ret = PTR_ERR(lcdev); return ret; @@ -660,29 +661,16 @@ static int hx8357_probe(struct spi_device *spi) ret = ((int (*)(struct lcd_device *))match->data)(lcdev); if (ret) { dev_err(&spi->dev, "Couldn't initialize panel\n"); - goto init_error; + return ret; } dev_info(&spi->dev, "Panel probed\n"); return 0; - -init_error: - lcd_device_unregister(lcdev); - return ret; -} - -static int hx8357_remove(struct spi_device *spi) -{ - struct lcd_device *lcdev = spi_get_drvdata(spi); - - lcd_device_unregister(lcdev); - return 0; } static struct spi_driver hx8357_driver = { .probe = hx8357_probe, - .remove = hx8357_remove, .driver = { .name = "hx8357", .of_match_table = of_match_ptr(hx8357_dt_ids), -- cgit v0.10.2 From a7e9e3ffd7e80db0d5eb181bc5b3054604db7811 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:26 -0800 Subject: backlight: ili922x: use devm_lcd_device_register() Use devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c index d9f65c2..73464e4 100644 --- a/drivers/video/backlight/ili922x.c +++ b/drivers/video/backlight/ili922x.c @@ -513,8 +513,8 @@ static int ili922x_probe(struct spi_device *spi) ili->power = FB_BLANK_POWERDOWN; - lcd = lcd_device_register("ili922xlcd", &spi->dev, ili, - &ili922x_ops); + lcd = devm_lcd_device_register(&spi->dev, "ili922xlcd", &spi->dev, ili, + &ili922x_ops); if (IS_ERR(lcd)) { dev_err(&spi->dev, "cannot register LCD\n"); return PTR_ERR(lcd); @@ -530,10 +530,7 @@ static int ili922x_probe(struct spi_device *spi) static int ili922x_remove(struct spi_device *spi) { - struct ili922x *ili = spi_get_drvdata(spi); - ili922x_poweroff(spi); - lcd_device_unregister(ili->ld); return 0; } -- cgit v0.10.2 From 5690378efa8b232161d4cae5d9650da85c88ab1f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:27 -0800 Subject: backlight: ili9320: use devm_lcd_device_register() Use devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c index 4dd43e0..e2b8b40 100644 --- a/drivers/video/backlight/ili9320.c +++ b/drivers/video/backlight/ili9320.c @@ -235,7 +235,8 @@ int ili9320_probe_spi(struct spi_device *spi, ili9320_setup_spi(ili, spi); - lcd = lcd_device_register("ili9320", dev, ili, &ili9320_ops); + lcd = devm_lcd_device_register(&spi->dev, "ili9320", dev, ili, + &ili9320_ops); if (IS_ERR(lcd)) { dev_err(dev, "failed to register lcd device\n"); return PTR_ERR(lcd); @@ -248,24 +249,16 @@ int ili9320_probe_spi(struct spi_device *spi, ret = ili9320_power(ili, FB_BLANK_UNBLANK); if (ret != 0) { dev_err(dev, "failed to set lcd power state\n"); - goto err_unregister; + return ret; } return 0; - - err_unregister: - lcd_device_unregister(lcd); - - return ret; } EXPORT_SYMBOL_GPL(ili9320_probe_spi); int ili9320_remove(struct ili9320 *ili) { ili9320_power(ili, FB_BLANK_POWERDOWN); - - lcd_device_unregister(ili->lcd); - return 0; } EXPORT_SYMBOL_GPL(ili9320_remove); -- cgit v0.10.2 From 0a1c55d0212661a582e9b4688410ccf9d4b163e8 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:28 -0800 Subject: backlight: lms283gf05: use devm_lcd_device_register() Use devm_lcd_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index 80b5929..de88325 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -173,7 +173,8 @@ static int lms283gf05_probe(struct spi_device *spi) return -ENOMEM; } - ld = lcd_device_register("lms283gf05", &spi->dev, st, &lms_ops); + ld = devm_lcd_device_register(&spi->dev, "lms283gf05", &spi->dev, st, + &lms_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -190,22 +191,12 @@ static int lms283gf05_probe(struct spi_device *spi) return 0; } -static int lms283gf05_remove(struct spi_device *spi) -{ - struct lms283gf05_state *st = spi_get_drvdata(spi); - - lcd_device_unregister(st->ld); - - return 0; -} - static struct spi_driver lms283gf05_driver = { .driver = { .name = "lms283gf05", .owner = THIS_MODULE, }, .probe = lms283gf05_probe, - .remove = lms283gf05_remove, }; module_spi_driver(lms283gf05_driver); -- cgit v0.10.2 From 8358741ab72a6a15165d1a855304c81beee74240 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:29 -0800 Subject: backlight: lms501kf03: use devm_lcd_device_register() Use devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c index ff46e19..77258b7 100644 --- a/drivers/video/backlight/lms501kf03.c +++ b/drivers/video/backlight/lms501kf03.c @@ -350,8 +350,8 @@ static int lms501kf03_probe(struct spi_device *spi) return -EINVAL; } - ld = lcd_device_register("lms501kf03", &spi->dev, lcd, - &lms501kf03_lcd_ops); + ld = devm_lcd_device_register(&spi->dev, "lms501kf03", &spi->dev, lcd, + &lms501kf03_lcd_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -382,8 +382,6 @@ static int lms501kf03_remove(struct spi_device *spi) struct lms501kf03 *lcd = spi_get_drvdata(spi); lms501kf03_power(lcd, FB_BLANK_POWERDOWN); - lcd_device_unregister(lcd->ld); - return 0; } -- cgit v0.10.2 From e8796d9f4fde228478ccf953c3f97a58f8e34e48 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:30 -0800 Subject: backlight: ltv350qv: use devm_lcd_device_register() Use devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index ed1b392..383f550 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -242,7 +242,8 @@ static int ltv350qv_probe(struct spi_device *spi) if (!lcd->buffer) return -ENOMEM; - ld = lcd_device_register("ltv350qv", &spi->dev, lcd, <v_ops); + ld = devm_lcd_device_register(&spi->dev, "ltv350qv", &spi->dev, lcd, + <v_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -250,15 +251,11 @@ static int ltv350qv_probe(struct spi_device *spi) ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK); if (ret) - goto out_unregister; + return ret; spi_set_drvdata(spi, lcd); return 0; - -out_unregister: - lcd_device_unregister(ld); - return ret; } static int ltv350qv_remove(struct spi_device *spi) @@ -266,8 +263,6 @@ static int ltv350qv_remove(struct spi_device *spi) struct ltv350qv *lcd = spi_get_drvdata(spi); ltv350qv_power(lcd, FB_BLANK_POWERDOWN); - lcd_device_unregister(lcd->ld); - return 0; } -- cgit v0.10.2 From 1f9ca1eee8e93cacf1bff11dc3fdd01b7fd80cd7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:31 -0800 Subject: backlight: platform_lcd: use devm_lcd_device_register() Use devm_lcd_device_register() to make cleanup paths simpler, and remove unnecessary remove(). Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index cc0f067..d01884d 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -101,30 +101,17 @@ static int platform_lcd_probe(struct platform_device *pdev) plcd->us = dev; plcd->pdata = pdata; - plcd->lcd = lcd_device_register(dev_name(dev), dev, - plcd, &platform_lcd_ops); + plcd->lcd = devm_lcd_device_register(&pdev->dev, dev_name(dev), dev, + plcd, &platform_lcd_ops); if (IS_ERR(plcd->lcd)) { dev_err(dev, "cannot register lcd device\n"); - err = PTR_ERR(plcd->lcd); - goto err; + return PTR_ERR(plcd->lcd); } platform_set_drvdata(pdev, plcd); platform_lcd_set_power(plcd->lcd, FB_BLANK_NORMAL); return 0; - - err: - return err; -} - -static int platform_lcd_remove(struct platform_device *pdev) -{ - struct platform_lcd *plcd = platform_get_drvdata(pdev); - - lcd_device_unregister(plcd->lcd); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -168,7 +155,6 @@ static struct platform_driver platform_lcd_driver = { .of_match_table = of_match_ptr(platform_lcd_of_match), }, .probe = platform_lcd_probe, - .remove = platform_lcd_remove, }; module_platform_driver(platform_lcd_driver); -- cgit v0.10.2 From 0524fc5194e548a4fe32d87850b976e0ec4e9007 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:32 -0800 Subject: backlight: tdo24m: use devm_lcd_device_register() Use devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 2ccfa46..908016f 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -385,21 +385,17 @@ static int tdo24m_probe(struct spi_device *spi) return -EINVAL; } - lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev, - lcd, &tdo24m_ops); + lcd->lcd_dev = devm_lcd_device_register(&spi->dev, "tdo24m", &spi->dev, + lcd, &tdo24m_ops); if (IS_ERR(lcd->lcd_dev)) return PTR_ERR(lcd->lcd_dev); spi_set_drvdata(spi, lcd); err = tdo24m_power(lcd, FB_BLANK_UNBLANK); if (err) - goto out_unregister; + return err; return 0; - -out_unregister: - lcd_device_unregister(lcd->lcd_dev); - return err; } static int tdo24m_remove(struct spi_device *spi) @@ -407,8 +403,6 @@ static int tdo24m_remove(struct spi_device *spi) struct tdo24m *lcd = spi_get_drvdata(spi); tdo24m_power(lcd, FB_BLANK_POWERDOWN); - lcd_device_unregister(lcd->lcd_dev); - return 0; } -- cgit v0.10.2 From ebc41e43b2b72e236019580490044604a48824e5 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:32 -0800 Subject: backlight: ams369fg06: use devm_{backlight,lcd}_device_register() Use devm_backlight_device_register() and devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index df5507b..d8952c4 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -477,8 +477,8 @@ static int ams369fg06_probe(struct spi_device *spi) return -EINVAL; } - ld = lcd_device_register("ams369fg06", &spi->dev, lcd, - &ams369fg06_lcd_ops); + ld = devm_lcd_device_register(&spi->dev, "ams369fg06", &spi->dev, lcd, + &ams369fg06_lcd_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -488,12 +488,11 @@ static int ams369fg06_probe(struct spi_device *spi) props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bd = backlight_device_register("ams369fg06-bl", &spi->dev, lcd, - &ams369fg06_backlight_ops, &props); - if (IS_ERR(bd)) { - ret = PTR_ERR(bd); - goto out_lcd_unregister; - } + bd = devm_backlight_device_register(&spi->dev, "ams369fg06-bl", + &spi->dev, lcd, + &ams369fg06_backlight_ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); bd->props.brightness = DEFAULT_BRIGHTNESS; lcd->bd = bd; @@ -516,10 +515,6 @@ static int ams369fg06_probe(struct spi_device *spi) dev_info(&spi->dev, "ams369fg06 panel driver has been probed.\n"); return 0; - -out_lcd_unregister: - lcd_device_unregister(ld); - return ret; } static int ams369fg06_remove(struct spi_device *spi) @@ -527,9 +522,6 @@ static int ams369fg06_remove(struct spi_device *spi) struct ams369fg06 *lcd = spi_get_drvdata(spi); ams369fg06_power(lcd, FB_BLANK_POWERDOWN); - backlight_device_unregister(lcd->bd); - lcd_device_unregister(lcd->ld); - return 0; } -- cgit v0.10.2 From 7a78e1b24b993b3af257d4d4f10fa7bd0913deaa Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:33 -0800 Subject: backlight: ld9040: use devm_{backlight,lcd}_device_register() Use devm_backlight_device_register() and devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c index 26d5139..506a6c2 100644 --- a/drivers/video/backlight/ld9040.c +++ b/drivers/video/backlight/ld9040.c @@ -716,7 +716,8 @@ static int ld9040_probe(struct spi_device *spi) return ret; } - ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops); + ld = devm_lcd_device_register(&spi->dev, "ld9040", &spi->dev, lcd, + &ld9040_lcd_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -726,12 +727,10 @@ static int ld9040_probe(struct spi_device *spi) props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bd = backlight_device_register("ld9040-bl", &spi->dev, - lcd, &ld9040_backlight_ops, &props); - if (IS_ERR(bd)) { - ret = PTR_ERR(bd); - goto out_unregister_lcd; - } + bd = devm_backlight_device_register(&spi->dev, "ld9040-bl", &spi->dev, + lcd, &ld9040_backlight_ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); bd->props.brightness = MAX_BRIGHTNESS; lcd->bd = bd; @@ -757,11 +756,6 @@ static int ld9040_probe(struct spi_device *spi) dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); return 0; - -out_unregister_lcd: - lcd_device_unregister(lcd->ld); - - return ret; } static int ld9040_remove(struct spi_device *spi) @@ -769,9 +763,6 @@ static int ld9040_remove(struct spi_device *spi) struct ld9040 *lcd = spi_get_drvdata(spi); ld9040_power(lcd, FB_BLANK_POWERDOWN); - backlight_device_unregister(lcd->bd); - lcd_device_unregister(lcd->ld); - return 0; } -- cgit v0.10.2 From 10645a1d1878cf4c1dde0398a6d6e82aed06ab4a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:34 -0800 Subject: backlight: corgi_lcd: use devm_{backlight,lcd}_device_register() Use devm_backlight_device_register() and devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index be56cfe..db8db5f 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -550,8 +550,8 @@ static int corgi_lcd_probe(struct spi_device *spi) lcd->spi_dev = spi; - lcd->lcd_dev = lcd_device_register("corgi_lcd", &spi->dev, - lcd, &corgi_lcd_ops); + lcd->lcd_dev = devm_lcd_device_register(&spi->dev, "corgi_lcd", + &spi->dev, lcd, &corgi_lcd_ops); if (IS_ERR(lcd->lcd_dev)) return PTR_ERR(lcd->lcd_dev); @@ -561,18 +561,18 @@ static int corgi_lcd_probe(struct spi_device *spi) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = pdata->max_intensity; - lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, lcd, - &corgi_bl_ops, &props); - if (IS_ERR(lcd->bl_dev)) { - ret = PTR_ERR(lcd->bl_dev); - goto err_unregister_lcd; - } + lcd->bl_dev = devm_backlight_device_register(&spi->dev, "corgi_bl", + &spi->dev, lcd, &corgi_bl_ops, + &props); + if (IS_ERR(lcd->bl_dev)) + return PTR_ERR(lcd->bl_dev); + lcd->bl_dev->props.brightness = pdata->default_intensity; lcd->bl_dev->props.power = FB_BLANK_UNBLANK; ret = setup_gpio_backlight(lcd, pdata); if (ret) - goto err_unregister_bl; + return ret; lcd->kick_battery = pdata->kick_battery; @@ -583,12 +583,6 @@ static int corgi_lcd_probe(struct spi_device *spi) lcd->limit_mask = pdata->limit_mask; the_corgi_lcd = lcd; return 0; - -err_unregister_bl: - backlight_device_unregister(lcd->bl_dev); -err_unregister_lcd: - lcd_device_unregister(lcd->lcd_dev); - return ret; } static int corgi_lcd_remove(struct spi_device *spi) @@ -598,11 +592,7 @@ static int corgi_lcd_remove(struct spi_device *spi) lcd->bl_dev->props.power = FB_BLANK_UNBLANK; lcd->bl_dev->props.brightness = 0; backlight_update_status(lcd->bl_dev); - backlight_device_unregister(lcd->bl_dev); - corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN); - lcd_device_unregister(lcd->lcd_dev); - return 0; } -- cgit v0.10.2 From 289a65e46b0eb57a5c8f54b4881b93d6ebed9f4e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:35 -0800 Subject: backlight: cr_bllcd: use devm_{backlight,lcd}_device_register() Use devm_backlight_device_register() and devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 37bae80..f3fed9e 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -195,16 +195,17 @@ static int cr_backlight_probe(struct platform_device *pdev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; - bdp = backlight_device_register("cr-backlight", &pdev->dev, NULL, - &cr_backlight_ops, &props); + bdp = devm_backlight_device_register(&pdev->dev, "cr-backlight", + &pdev->dev, NULL, &cr_backlight_ops, + &props); if (IS_ERR(bdp)) { pci_dev_put(lpc_dev); return PTR_ERR(bdp); } - ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops); + ldp = devm_lcd_device_register(&pdev->dev, "cr-lcd", &pdev->dev, NULL, + &cr_lcd_ops); if (IS_ERR(ldp)) { - backlight_device_unregister(bdp); pci_dev_put(lpc_dev); return PTR_ERR(ldp); } @@ -215,8 +216,6 @@ static int cr_backlight_probe(struct platform_device *pdev) crp = devm_kzalloc(&pdev->dev, sizeof(*crp), GFP_KERNEL); if (!crp) { - lcd_device_unregister(ldp); - backlight_device_unregister(bdp); pci_dev_put(lpc_dev); return -ENOMEM; } @@ -241,8 +240,6 @@ static int cr_backlight_remove(struct platform_device *pdev) crp->cr_backlight_device->props.max_brightness = 0; cr_backlight_set_intensity(crp->cr_backlight_device); cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN); - backlight_device_unregister(crp->cr_backlight_device); - lcd_device_unregister(crp->cr_lcd_device); pci_dev_put(lpc_dev); return 0; -- cgit v0.10.2 From a18863f5e83881e3ed1f4ee92496898045e1f5c3 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:09:36 -0800 Subject: backlight: s6e63m0: use devm_{backlight,lcd}_device_register() Use devm_backlight_device_register() and devm_lcd_device_register() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index 4e339ad..510a1bc 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -741,7 +741,8 @@ static int s6e63m0_probe(struct spi_device *spi) return -EINVAL; } - ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops); + ld = devm_lcd_device_register(&spi->dev, "s6e63m0", &spi->dev, lcd, + &s6e63m0_lcd_ops); if (IS_ERR(ld)) return PTR_ERR(ld); @@ -751,12 +752,11 @@ static int s6e63m0_probe(struct spi_device *spi) props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd, - &s6e63m0_backlight_ops, &props); - if (IS_ERR(bd)) { - ret = PTR_ERR(bd); - goto out_lcd_unregister; - } + bd = devm_backlight_device_register(&spi->dev, "s6e63m0bl-bl", + &spi->dev, lcd, &s6e63m0_backlight_ops, + &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); bd->props.brightness = MAX_BRIGHTNESS; lcd->bd = bd; @@ -798,10 +798,6 @@ static int s6e63m0_probe(struct spi_device *spi) dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n"); return 0; - -out_lcd_unregister: - lcd_device_unregister(ld); - return ret; } static int s6e63m0_remove(struct spi_device *spi) @@ -811,8 +807,6 @@ static int s6e63m0_remove(struct spi_device *spi) s6e63m0_power(lcd, FB_BLANK_POWERDOWN); device_remove_file(&spi->dev, &dev_attr_gamma_table); device_remove_file(&spi->dev, &dev_attr_gamma_mode); - backlight_device_unregister(lcd->bd); - lcd_device_unregister(lcd->ld); return 0; } -- cgit v0.10.2 From bcd5b4165645eb44c781bca456c11c0478546161 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 Nov 2013 15:09:37 -0800 Subject: drivers/video/backlight/lm3630a_bl.c: add missing destroy_workqueue() on error in lm3630a_intr_config() Add the missing destroy_workqueue() before return from lm3630a_intr_config() in the error handling case. Signed-off-by: Wei Yongjun Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index 999075a..35fe482 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -154,6 +154,7 @@ static int lm3630a_intr_config(struct lm3630a_chip *pchip) (pchip->irq, NULL, lm3630a_isr_func, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) { dev_err(pchip->dev, "request threaded irq fail\n"); + destroy_workqueue(pchip->irqthread); return -ENOMEM; } return rval; -- cgit v0.10.2 From 185d91442550110db67a7dc794a32efcea455a36 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:38 -0800 Subject: backlight: atmel-pwm-bl: fix reported brightness The driver supports 16-bit brightness values, but the value returned from get_brightness was truncated to eight bits. Signed-off-by: Johan Hovold Cc: Jingoo Han Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index 66885fb..0971a8e 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -70,7 +70,7 @@ static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) static int atmel_pwm_bl_get_intensity(struct backlight_device *bd) { struct atmel_pwm_bl *pwmbl = bl_get_data(bd); - u8 intensity; + u32 intensity; if (pwmbl->pdata->pwm_active_low) { intensity = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY) - @@ -80,7 +80,7 @@ static int atmel_pwm_bl_get_intensity(struct backlight_device *bd) pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY); } - return intensity; + return intensity & 0xffff; } static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl) -- cgit v0.10.2 From ad5066d4c2b1d696749f8d7816357c23b648c4d3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:39 -0800 Subject: backlight: atmel-pwm-bl: fix gpio polarity in remove Make sure to honour gpio polarity also at remove so that the backlight is actually disabled on boards with active-low enable pin. Signed-off-by: Johan Hovold Acked-by: Jingoo Han Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index 0971a8e..e21beb6 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -205,8 +205,10 @@ static int atmel_pwm_bl_remove(struct platform_device *pdev) { struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev); - if (pwmbl->gpio_on != -1) - gpio_set_value(pwmbl->gpio_on, 0); + if (pwmbl->gpio_on != -1) { + gpio_set_value(pwmbl->gpio_on, + 0 ^ pwmbl->pdata->on_active_low); + } pwm_channel_disable(&pwmbl->pwmc); pwm_channel_free(&pwmbl->pwmc); -- cgit v0.10.2 From 5c057e5570f18b9d0f4eea99e0a0d55ad5f30e36 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:40 -0800 Subject: backlight: atmel-pwm-bl: fix module autoload Add missing module alias which is needed for module autoloading. Signed-off-by: Johan Hovold Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index e21beb6..4886028 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -229,3 +229,4 @@ module_platform_driver(atmel_pwm_bl_driver); MODULE_AUTHOR("Hans-Christian egtvedt "); MODULE_DESCRIPTION("Atmel PWM backlight driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:atmel-pwm-bl"); -- cgit v0.10.2 From ce726c9738a27ee32a00136cc512b1058044a0fe Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:41 -0800 Subject: backlight: atmel-pwm-bl: clean up probe error handling Clean up probe error handling by checking parameters before any allocations and removing an obsolete error label. Also remove unnecessary reset of private gpio number. Signed-off-by: Johan Hovold Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index 4886028..01af5c2 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -126,40 +126,33 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) struct atmel_pwm_bl *pwmbl; int retval; + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) + return -ENODEV; + + if (pdata->pwm_compare_max < pdata->pwm_duty_max || + pdata->pwm_duty_min > pdata->pwm_duty_max || + pdata->pwm_frequency == 0) + return -EINVAL; + pwmbl = devm_kzalloc(&pdev->dev, sizeof(struct atmel_pwm_bl), GFP_KERNEL); if (!pwmbl) return -ENOMEM; pwmbl->pdev = pdev; - - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - retval = -ENODEV; - goto err_free_mem; - } - - if (pdata->pwm_compare_max < pdata->pwm_duty_max || - pdata->pwm_duty_min > pdata->pwm_duty_max || - pdata->pwm_frequency == 0) { - retval = -EINVAL; - goto err_free_mem; - } - pwmbl->pdata = pdata; pwmbl->gpio_on = pdata->gpio_on; retval = pwm_channel_alloc(pdata->pwm_channel, &pwmbl->pwmc); if (retval) - goto err_free_mem; + return retval; if (pwmbl->gpio_on != -1) { retval = devm_gpio_request(&pdev->dev, pwmbl->gpio_on, "gpio_atmel_pwm_bl"); - if (retval) { - pwmbl->gpio_on = -1; + if (retval) goto err_free_pwm; - } /* Turn display off by default. */ retval = gpio_direction_output(pwmbl->gpio_on, @@ -197,7 +190,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) err_free_pwm: pwm_channel_free(&pwmbl->pwmc); -err_free_mem: + return retval; } -- cgit v0.10.2 From 9a26a84e3f77850ab80dbb9fb7f9821109f38f12 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:42 -0800 Subject: backlight: atmel-pwm-bl: clean up get_intensity Clean up get_intensity to increase readability. Signed-off-by: Johan Hovold Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index 01af5c2..abfaada 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -70,15 +70,14 @@ static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) static int atmel_pwm_bl_get_intensity(struct backlight_device *bd) { struct atmel_pwm_bl *pwmbl = bl_get_data(bd); + u32 cdty; u32 intensity; - if (pwmbl->pdata->pwm_active_low) { - intensity = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY) - - pwmbl->pdata->pwm_duty_min; - } else { - intensity = pwmbl->pdata->pwm_duty_max - - pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY); - } + cdty = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY); + if (pwmbl->pdata->pwm_active_low) + intensity = cdty - pwmbl->pdata->pwm_duty_min; + else + intensity = pwmbl->pdata->pwm_duty_max - cdty; return intensity & 0xffff; } -- cgit v0.10.2 From 7bb8abe6ed58835c58153d59e4b13513b7306802 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:43 -0800 Subject: backlight: atmel-pwm-bl: remove unused include Remove unused include of clk.h. Signed-off-by: Johan Hovold Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index abfaada..bfd6a96 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 5ada4550e86b081b889bced50e5ab6c510f9cdd7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:44 -0800 Subject: backlight: atmel-pwm-bl: use gpio_is_valid Use gpio_is_valid rather than open coding the more restrictive != -1 test. Signed-off-by: Johan Hovold Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index bfd6a96..c254209 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -48,7 +48,7 @@ static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) pwm_duty = pwmbl->pdata->pwm_duty_min; if (!intensity) { - if (pwmbl->gpio_on != -1) { + if (gpio_is_valid(pwmbl->gpio_on)) { gpio_set_value(pwmbl->gpio_on, 0 ^ pwmbl->pdata->on_active_low); } @@ -57,7 +57,7 @@ static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) } else { pwm_channel_enable(&pwmbl->pwmc); pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty); - if (pwmbl->gpio_on != -1) { + if (gpio_is_valid(pwmbl->gpio_on)) { gpio_set_value(pwmbl->gpio_on, 1 ^ pwmbl->pdata->on_active_low); } @@ -146,7 +146,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) if (retval) return retval; - if (pwmbl->gpio_on != -1) { + if (gpio_is_valid(pwmbl->gpio_on)) { retval = devm_gpio_request(&pdev->dev, pwmbl->gpio_on, "gpio_atmel_pwm_bl"); if (retval) @@ -196,7 +196,7 @@ static int atmel_pwm_bl_remove(struct platform_device *pdev) { struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev); - if (pwmbl->gpio_on != -1) { + if (gpio_is_valid(pwmbl->gpio_on)) { gpio_set_value(pwmbl->gpio_on, 0 ^ pwmbl->pdata->on_active_low); } -- cgit v0.10.2 From 81b62db56dbdfef8f3b596dc2845df7ee3ab2165 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:45 -0800 Subject: backlight: atmel-pwm-bl: refactor gpio_on handling Add helper function to control the gpio_on signal. Signed-off-by: Johan Hovold Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index c254209..bd1ed34 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -26,6 +26,14 @@ struct atmel_pwm_bl { int gpio_on; }; +static void atmel_pwm_bl_set_gpio_on(struct atmel_pwm_bl *pwmbl, int on) +{ + if (!gpio_is_valid(pwmbl->gpio_on)) + return; + + gpio_set_value(pwmbl->gpio_on, on ^ pwmbl->pdata->on_active_low); +} + static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) { struct atmel_pwm_bl *pwmbl = bl_get_data(bd); @@ -48,19 +56,13 @@ static int atmel_pwm_bl_set_intensity(struct backlight_device *bd) pwm_duty = pwmbl->pdata->pwm_duty_min; if (!intensity) { - if (gpio_is_valid(pwmbl->gpio_on)) { - gpio_set_value(pwmbl->gpio_on, - 0 ^ pwmbl->pdata->on_active_low); - } + atmel_pwm_bl_set_gpio_on(pwmbl, 0); pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty); pwm_channel_disable(&pwmbl->pwmc); } else { pwm_channel_enable(&pwmbl->pwmc); pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty); - if (gpio_is_valid(pwmbl->gpio_on)) { - gpio_set_value(pwmbl->gpio_on, - 1 ^ pwmbl->pdata->on_active_low); - } + atmel_pwm_bl_set_gpio_on(pwmbl, 1); } return 0; @@ -196,10 +198,7 @@ static int atmel_pwm_bl_remove(struct platform_device *pdev) { struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev); - if (gpio_is_valid(pwmbl->gpio_on)) { - gpio_set_value(pwmbl->gpio_on, - 0 ^ pwmbl->pdata->on_active_low); - } + atmel_pwm_bl_set_gpio_on(pwmbl, 0); pwm_channel_disable(&pwmbl->pwmc); pwm_channel_free(&pwmbl->pwmc); -- cgit v0.10.2 From 9b3521ee8f35faa73459cda9a8b9b6e0a08a8d30 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 12 Nov 2013 15:09:46 -0800 Subject: backlight: atmel-pwm-bl: use gpio_request_one Use devm_gpio_request_one rather than requesting and setting direction in two calls. Signed-off-by: Johan Hovold Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index bd1ed34..261b1a4 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -124,6 +124,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) const struct atmel_pwm_bl_platform_data *pdata; struct backlight_device *bldev; struct atmel_pwm_bl *pwmbl; + unsigned long flags; int retval; pdata = dev_get_platdata(&pdev->dev); @@ -149,14 +150,14 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) return retval; if (gpio_is_valid(pwmbl->gpio_on)) { - retval = devm_gpio_request(&pdev->dev, pwmbl->gpio_on, - "gpio_atmel_pwm_bl"); - if (retval) - goto err_free_pwm; - /* Turn display off by default. */ - retval = gpio_direction_output(pwmbl->gpio_on, - 0 ^ pdata->on_active_low); + if (pdata->on_active_low) + flags = GPIOF_OUT_INIT_HIGH; + else + flags = GPIOF_OUT_INIT_LOW; + + retval = devm_gpio_request_one(&pdev->dev, pwmbl->gpio_on, + flags, "gpio_atmel_pwm_bl"); if (retval) goto err_free_pwm; } -- cgit v0.10.2 From c962f7b95c98d2b42019cc9cb074886d177ee3a3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:09:47 -0800 Subject: drivers/video/backlight/hx8357.c: remove redundant of_match_ptr 'hx8357_dt_ids' is always compiled in. Hence of_match_ptr is not needed. Signed-off-by: Sachin Kamat Acked-by: Maxime Ripard Acked-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c index 0d252e7..985e854 100644 --- a/drivers/video/backlight/hx8357.c +++ b/drivers/video/backlight/hx8357.c @@ -673,7 +673,7 @@ static struct spi_driver hx8357_driver = { .probe = hx8357_probe, .driver = { .name = "hx8357", - .of_match_table = of_match_ptr(hx8357_dt_ids), + .of_match_table = hx8357_dt_ids, }, }; -- cgit v0.10.2 From ec778edf97dcaa517e5b0eea6f1a9ba9d476e4a8 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Tue, 12 Nov 2013 15:09:48 -0800 Subject: bitops/find: clarify and extend documentation Add return value documentation and clarify the units of the @size parameter. Signed-off-by: Cody P Schafer Cc: Arnd Bergmann Cc: Cody P Schafer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-generic/bitops/find.h b/include/asm-generic/bitops/find.h index 71c7780..998d4d5 100644 --- a/include/asm-generic/bitops/find.h +++ b/include/asm-generic/bitops/find.h @@ -7,6 +7,9 @@ * @addr: The address to base the search on * @offset: The bitnumber to start searching at * @size: The bitmap size in bits + * + * Returns the bit number for the next set bit + * If no bits are set, returns @size. */ extern unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset); @@ -18,6 +21,9 @@ extern unsigned long find_next_bit(const unsigned long *addr, unsigned long * @addr: The address to base the search on * @offset: The bitnumber to start searching at * @size: The bitmap size in bits + * + * Returns the bit number of the next zero bit + * If no bits are zero, returns @size. */ extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset); @@ -28,9 +34,10 @@ extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned /** * find_first_bit - find the first set bit in a memory region * @addr: The address to start the search at - * @size: The maximum size to search + * @size: The maximum number of bits to search * * Returns the bit number of the first set bit. + * If no bits are set, returns @size. */ extern unsigned long find_first_bit(const unsigned long *addr, unsigned long size); @@ -38,9 +45,10 @@ extern unsigned long find_first_bit(const unsigned long *addr, /** * find_first_zero_bit - find the first cleared bit in a memory region * @addr: The address to start the search at - * @size: The maximum size to search + * @size: The maximum number of bits to search * * Returns the bit number of the first cleared bit. + * If no bits are zero, returns @size. */ extern unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size); -- cgit v0.10.2 From d3773ba13c8ca63a4ee9e7926813f6e82be27a6c Mon Sep 17 00:00:00 2001 From: Xie XiuQi Date: Tue, 12 Nov 2013 15:09:49 -0800 Subject: lib/debugobjects.c: remove unnecessary work pending test Remove unnecessary work pending test before calling schedule_work(). It has been tested in queue_work_on() already. No functional changed. Signed-off-by: Xie XiuQi Reviewed-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/debugobjects.c b/lib/debugobjects.c index bf2c8b1..e0731c3 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c @@ -196,7 +196,7 @@ static void free_object(struct debug_obj *obj) * initialized: */ if (obj_pool_free > ODEBUG_POOL_SIZE && obj_cache) - sched = keventd_up() && !work_pending(&debug_obj_work); + sched = keventd_up(); hlist_add_head(&obj->node, &obj_pool); obj_pool_free++; obj_pool_used--; -- cgit v0.10.2 From c0d92a57a88586586b8cb9c7ac149bd10bc40d11 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 12 Nov 2013 15:09:50 -0800 Subject: lib/vsprintf.c: document formats for dentry and struct file Looks like these were added to Documentation/printk-formats.txt but not the in-file table. Signed-off-by: Olof Johansson Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d76555c..48586ac 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1219,6 +1219,8 @@ int kptr_restrict __read_mostly; * The maximum supported length is 64 bytes of the input. Consider * to use print_hex_dump() for the larger input. * - 'a' For a phys_addr_t type and its derivative types (passed by reference) + * - 'd[234]' For a dentry name (optionally 2-4 last components) + * - 'D[234]' Same as 'd' but for a struct file * * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 * function pointers are really function descriptors, which contain a -- cgit v0.10.2 From ff6092a8a413f3db1938b4606e078fa751ed6cdb Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Tue, 12 Nov 2013 15:09:51 -0800 Subject: lib/digsig.c: use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...)) Signed-off-by: Duan Jiong Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/lib/digsig.c b/lib/digsig.c index 2f31e6a..8793aed 100644 --- a/lib/digsig.c +++ b/lib/digsig.c @@ -209,7 +209,7 @@ int digsig_verify(struct key *keyring, const char *sig, int siglen, kref = keyring_search(make_key_ref(keyring, 1UL), &key_type_user, name); if (IS_ERR(kref)) - key = ERR_PTR(PTR_ERR(kref)); + key = ERR_CAST(kref); else key = key_ref_to_ptr(kref); } else { -- cgit v0.10.2 From 684f0d3d14f2744ae7ad79063b21909e32bf444e Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 12 Nov 2013 15:09:52 -0800 Subject: lib/genalloc: add a helper function for DMA buffer allocation When using pool space for DMA buffer, there might be duplicated calling of gen_pool_alloc() and gen_pool_virt_to_phys() in each implementation. Thus it's better to add a simple helper function, a compatible one to the common dma_alloc_coherent(), to save some code. Signed-off-by: Nicolin Chen Cc: "Hans J. Koch" Cc: Dan Williams Cc: Eric Miao Cc: Grant Likely Cc: Greg Kroah-Hartman Cc: Haojian Zhuang Cc: Jaroslav Kysela Cc: Kevin Hilman Cc: Liam Girdwood Cc: Mark Brown Cc: Mauro Carvalho Chehab Cc: Rob Herring Cc: Russell King Cc: Sekhar Nori Cc: Takashi Iwai Cc: Vinod Koul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index f8d41cb..1eda33d 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h @@ -94,6 +94,8 @@ static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr, } extern void gen_pool_destroy(struct gen_pool *); extern unsigned long gen_pool_alloc(struct gen_pool *, size_t); +extern void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, + dma_addr_t *dma); extern void gen_pool_free(struct gen_pool *, unsigned long, size_t); extern void gen_pool_for_each_chunk(struct gen_pool *, void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *); diff --git a/lib/genalloc.c b/lib/genalloc.c index 26cf20b..dda3116 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -313,6 +313,34 @@ retry: EXPORT_SYMBOL(gen_pool_alloc); /** + * gen_pool_dma_alloc - allocate special memory from the pool for DMA usage + * @pool: pool to allocate from + * @size: number of bytes to allocate from the pool + * @dma: dma-view physical address + * + * Allocate the requested number of bytes from the specified pool. + * Uses the pool allocation function (with first-fit algorithm by default). + * Can not be used in NMI handler on architectures without + * NMI-safe cmpxchg implementation. + */ +void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma) +{ + unsigned long vaddr; + + if (!pool) + return NULL; + + vaddr = gen_pool_alloc(pool, size); + if (!vaddr) + return NULL; + + *dma = gen_pool_virt_to_phys(pool, vaddr); + + return (void *)vaddr; +} +EXPORT_SYMBOL(gen_pool_dma_alloc); + +/** * gen_pool_free - free allocated special memory back to the pool * @pool: pool to free to * @addr: starting address of memory to free back to pool -- cgit v0.10.2 From 66f119695bcccc2b03b354152f6d65a0b129cef9 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 12 Nov 2013 15:09:54 -0800 Subject: arch/arm/mach-davinci/sram.c: use gen_pool_dma_alloc() to sram.c Since gen_pool_dma_alloc() is introduced, we implement it to simplify code. Signed-off-by: Nicolin Chen Cc: Sekhar Nori Cc: Kevin Hilman Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/arm/mach-davinci/sram.c b/arch/arm/mach-davinci/sram.c index f18928b..8540ddd 100644 --- a/arch/arm/mach-davinci/sram.c +++ b/arch/arm/mach-davinci/sram.c @@ -25,7 +25,6 @@ struct gen_pool *sram_get_gen_pool(void) void *sram_alloc(size_t len, dma_addr_t *dma) { - unsigned long vaddr; dma_addr_t dma_base = davinci_soc_info.sram_dma; if (dma) @@ -33,13 +32,7 @@ void *sram_alloc(size_t len, dma_addr_t *dma) if (!sram_pool || (dma && !dma_base)) return NULL; - vaddr = gen_pool_alloc(sram_pool, len); - if (!vaddr) - return NULL; - - if (dma) - *dma = gen_pool_virt_to_phys(sram_pool, vaddr); - return (void *)vaddr; + return gen_pool_dma_alloc(sram_pool, len, dma); } EXPORT_SYMBOL(sram_alloc); -- cgit v0.10.2 From a6dd30e2bc88b3816341534c3cd0ebbecdda3ec6 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 12 Nov 2013 15:09:55 -0800 Subject: drivers/dma/mmp_tdma.c: use gen_pool_dma_alloc() to allocate descriptor Since gen_pool_dma_alloc() is introduced, we implement it to simplify code. Signed-off-by: Nicolin Chen Cc: Dan Williams Cc: Vinod Koul Cc: Grant Likely Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 38cb517..d3b6358 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -350,12 +350,7 @@ struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac) if (!gpool) return NULL; - tdmac->desc_arr = (void *)gen_pool_alloc(gpool, size); - if (!tdmac->desc_arr) - return NULL; - - tdmac->desc_arr_phys = gen_pool_virt_to_phys(gpool, - (unsigned long)tdmac->desc_arr); + tdmac->desc_arr = gen_pool_dma_alloc(gpool, size, &tdmac->desc_arr_phys); return tdmac->desc_arr; } -- cgit v0.10.2 From 43f950f454815cca2c39244c7441f9288d7389e0 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 12 Nov 2013 15:09:56 -0800 Subject: drivers/media/platform/coda.c: use gen_pool_dma_alloc() to allocate iram buffer Since gen_pool_dma_alloc() is introduced, we implement it to simplify code. Signed-off-by: Nicolin Chen Acked-by: Mauro Carvalho Chehab Cc: Grant Likely Cc: Rob Herring Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 449d2fe..4993610 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -3232,13 +3232,12 @@ static int coda_probe(struct platform_device *pdev) dev->iram_size = CODA7_IRAM_SIZE; break; } - dev->iram_vaddr = gen_pool_alloc(dev->iram_pool, dev->iram_size); + dev->iram_vaddr = (unsigned long)gen_pool_dma_alloc(dev->iram_pool, + dev->iram_size, (dma_addr_t *)&dev->iram_paddr); if (!dev->iram_vaddr) { dev_err(&pdev->dev, "unable to alloc iram\n"); return -ENOMEM; } - dev->iram_paddr = gen_pool_virt_to_phys(dev->iram_pool, - dev->iram_vaddr); platform_set_drvdata(pdev, dev); -- cgit v0.10.2 From 288342e9cc867421d20f940d0c06b7aa4bf39096 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 12 Nov 2013 15:09:57 -0800 Subject: drivers/uio/uio_pruss.c: use gen_pool_dma_alloc() to allocate sram memory Since gen_pool_dma_alloc() is introduced, we implement it to simplify code. Signed-off-by: Nicolin Chen Cc: "Hans J. Koch" Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index f519da9..96c4a19 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -158,14 +158,12 @@ static int pruss_probe(struct platform_device *dev) if (pdata->sram_pool) { gdev->sram_pool = pdata->sram_pool; gdev->sram_vaddr = - gen_pool_alloc(gdev->sram_pool, sram_pool_sz); + (unsigned long)gen_pool_dma_alloc(gdev->sram_pool, + sram_pool_sz, &gdev->sram_paddr); if (!gdev->sram_vaddr) { dev_err(&dev->dev, "Could not allocate SRAM pool\n"); goto out_free; } - gdev->sram_paddr = - gen_pool_virt_to_phys(gdev->sram_pool, - gdev->sram_vaddr); } gdev->ddr_vaddr = dma_alloc_coherent(&dev->dev, extram_pool_sz, -- cgit v0.10.2 From 1112b9e2c9c8ae10551a7d34667a6189f971cdba Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 12 Nov 2013 15:09:58 -0800 Subject: sound/soc/davinci/davinci-pcm.c: use gen_pool_dma_alloc() in davinci-pcm.c Since gen_pool_dma_alloc() is introduced, we implement it to simplify code. Signed-off-by: Nicolin Chen Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 8460edc..443e9e5 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -267,10 +267,9 @@ static int allocate_sram(struct snd_pcm_substream *substream, return 0; ppcm->period_bytes_max = size; - iram_virt = (void *)gen_pool_alloc(sram_pool, size); + iram_virt = gen_pool_dma_alloc(sram_pool, size, &iram_phys); if (!iram_virt) goto exit1; - iram_phys = gen_pool_virt_to_phys(sram_pool, (unsigned)iram_virt); iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL); if (!iram_dma) goto exit2; -- cgit v0.10.2 From 92a2e1cb53ba649e620b7f02a15ad1fb949c6355 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 12 Nov 2013 15:10:00 -0800 Subject: sound/soc/pxa/mmp-pcm.c: use gen_pool_dma_alloc() to allocate dma buffer Since gen_pool_dma_alloc() is introduced, we implement it to simplify code. Signed-off-by: Nicolin Chen Cc: Eric Miao Cc: Russell King Cc: Haojian Zhuang Cc: Liam Girdwood Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 8235e23..7929e19 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -201,10 +201,9 @@ static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream, if (!gpool) return -ENOMEM; - buf->area = (unsigned char *)gen_pool_alloc(gpool, size); + buf->area = gen_pool_dma_alloc(gpool, size, &buf->addr); if (!buf->area) return -ENOMEM; - buf->addr = gen_pool_virt_to_phys(gpool, (unsigned long)buf->area); buf->bytes = size; return 0; } -- cgit v0.10.2 From 008208c6b26f21c2648c250a09c55e737c02c5f8 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 12 Nov 2013 15:10:01 -0800 Subject: list: introduce list_next_entry() and list_prev_entry() Add two trivial helpers list_next_entry() and list_prev_entry(), they can have a lot of users including list.h itself. In fact the 1st one is already defined in events/core.c and bnx2x_sp.c, so the patch simply moves the definition to list.h. Signed-off-by: Oleg Nesterov Cc: Eilon Greenstein Cc: Greg Kroah-Hartman Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 9fbeee5..32c92ab 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -1217,9 +1217,6 @@ static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp, ETH_VLAN_FILTER_CLASSIFY, config); } -#define list_next_entry(pos, member) \ - list_entry((pos)->member.next, typeof(*(pos)), member) - /** * bnx2x_vlan_mac_restore - reconfigure next MAC/VLAN/VLAN-MAC element * diff --git a/include/linux/list.h b/include/linux/list.h index f4d8a2f..2ece638 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -373,6 +373,22 @@ static inline void list_splice_tail_init(struct list_head *list, (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) /** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_struct within the struct. + */ +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +/** + * list_prev_entry - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the list_struct within the struct. + */ +#define list_prev_entry(pos, member) \ + list_entry((pos)->member.prev, typeof(*(pos)), member) + +/** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. diff --git a/kernel/events/core.c b/kernel/events/core.c index 8c875ef..d724e77 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2234,9 +2234,6 @@ static void __perf_event_sync_stat(struct perf_event *event, perf_event_update_userpage(next_event); } -#define list_next_entry(pos, member) \ - list_entry(pos->member.next, typeof(*pos), member) - static void perf_event_sync_stat(struct perf_event_context *ctx, struct perf_event_context *next_ctx) { -- cgit v0.10.2 From 8120e2e5141a420edee725ff28f18aa264795f7a Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 12 Nov 2013 15:10:02 -0800 Subject: list: change list_for_each_entry*() to use list_*_entry() Now that we have list_{next,prev}_entry() we can change list_for_each_entry*() and list_safe_reset_next() to use the new helpers to improve the readability. Signed-off-by: Oleg Nesterov Cc: Eilon Greenstein Cc: Greg Kroah-Hartman Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/list.h b/include/linux/list.h index 2ece638..c88a591 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -433,8 +433,8 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) + &pos->member != (head); \ + pos = list_next_entry(pos, member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. @@ -444,8 +444,8 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() @@ -468,9 +468,9 @@ static inline void list_splice_tail_init(struct list_head *list, * the current position. */ #define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) + for (pos = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) /** * list_for_each_entry_continue_reverse - iterate backwards from the given point @@ -482,9 +482,9 @@ static inline void list_splice_tail_init(struct list_head *list, * the current position. */ #define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) + for (pos = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) /** * list_for_each_entry_from - iterate over list of given type from the current point @@ -495,8 +495,8 @@ static inline void list_splice_tail_init(struct list_head *list, * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ - for (; &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) + for (; &pos->member != (head); \ + pos = list_next_entry(pos, member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry @@ -507,9 +507,9 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ + n = list_next_entry(pos, member); \ &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) + pos = n, n = list_next_entry(n, member)) /** * list_for_each_entry_safe_continue - continue list iteration safe against removal @@ -522,10 +522,10 @@ static inline void list_splice_tail_init(struct list_head *list, * safe against removal of list entry. */ #define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ + for (pos = list_next_entry(pos, member), \ + n = list_next_entry(pos, member); \ &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) + pos = n, n = list_next_entry(n, member)) /** * list_for_each_entry_safe_from - iterate over list from current point safe against removal @@ -538,9 +538,9 @@ static inline void list_splice_tail_init(struct list_head *list, * removal of list entry. */ #define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ + for (n = list_next_entry(pos, member); \ &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) + pos = n, n = list_next_entry(n, member)) /** * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal @@ -554,9 +554,9 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_entry_safe_reverse(pos, n, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ + n = list_prev_entry(pos, member); \ &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + pos = n, n = list_prev_entry(n, member)) /** * list_safe_reset_next - reset a stale list_for_each_entry_safe loop @@ -571,7 +571,7 @@ static inline void list_splice_tail_init(struct list_head *list, * completing the current iteration of the loop body. */ #define list_safe_reset_next(pos, n, member) \ - n = list_entry(pos->member.next, typeof(*pos), member) + n = list_next_entry(pos, member) /* * Double linked lists with a single pointer list head. -- cgit v0.10.2 From 93be3c2eb3371f022ad88acf1ab6bee8e3c38378 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 12 Nov 2013 15:10:03 -0800 Subject: list: introduce list_last_entry(), use list_{first,last}_entry() We already have list_first_entry(), it makes sense to also add list_last_entry() for consistency. And we use both helpers in list_for_each_*(). Signed-off-by: Oleg Nesterov Cc: Eilon Greenstein Cc: Greg Kroah-Hartman Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/list.h b/include/linux/list.h index c88a591..ef95941 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -362,6 +362,17 @@ static inline void list_splice_tail_init(struct list_head *list, list_entry((ptr)->next, type, member) /** + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +/** * list_first_entry_or_null - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. @@ -432,7 +443,7 @@ static inline void list_splice_tail_init(struct list_head *list, * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ + for (pos = list_first_entry(head, typeof(*pos), member); \ &pos->member != (head); \ pos = list_next_entry(pos, member)) @@ -443,7 +454,7 @@ static inline void list_splice_tail_init(struct list_head *list, * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ + for (pos = list_last_entry(head, typeof(*pos), member); \ &pos->member != (head); \ pos = list_prev_entry(pos, member)) @@ -506,7 +517,7 @@ static inline void list_splice_tail_init(struct list_head *list, * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ + for (pos = list_first_entry(head, typeof(*pos), member), \ n = list_next_entry(pos, member); \ &pos->member != (head); \ pos = n, n = list_next_entry(n, member)) @@ -553,7 +564,7 @@ static inline void list_splice_tail_init(struct list_head *list, * of list entry. */ #define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ + for (pos = list_last_entry(head, typeof(*pos), member), \ n = list_prev_entry(pos, member); \ &pos->member != (head); \ pos = n, n = list_prev_entry(n, member)) -- cgit v0.10.2 From 6bc080d8fdae33f4463203a400cfaa01e91701e2 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 12 Nov 2013 15:10:04 -0800 Subject: debugfs: use list_next_entry() in debugfs_remove_recursive() Change debugfs_remove_recursive() to use list_next_entry(child), no changes in generated code. Signed-off-by: Oleg Nesterov Cc: Eilon Greenstein Cc: Greg Kroah-Hartman Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index c7c83ff..9c0444c 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -566,8 +566,7 @@ void debugfs_remove_recursive(struct dentry *dentry) mutex_lock(&parent->d_inode->i_mutex); if (child != dentry) { - next = list_entry(child->d_u.d_child.next, struct dentry, - d_u.d_child); + next = list_next_entry(child, d_u.d_child); goto up; } -- cgit v0.10.2 From 847316231c2f89918a2872e3d5fa3f5de11c39b6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:05 -0800 Subject: checkpatch: report missing spaces around trigraphs with --strict Spaces around trigraphs are specified by CodingStyle but checkpatch is currently silent about them because there are many current instances without them. Make missing spaces around trigraphs a --strict message. Signed-off-by: Joe Perches Reviewed-by: Josh Triplett Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 66cad50..42103a0 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2838,7 +2838,7 @@ sub process { \+=|-=|\*=|\/=|%=|\^=|\|=|&=| =>|->|<<|>>|<|>|=|!|~| &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| - \?|: + \?:|\?|: }x; my @elements = split(/($ops|;)/, $opline); @@ -3061,15 +3061,13 @@ sub process { $ok = 1; } - # Ignore ?: - if (($opv eq ':O' && $ca =~ /\?$/) || - ($op eq '?' && $cc =~ /^:/)) { - $ok = 1; - } - + # messages are ERROR, but ?: are CHK if ($ok == 0) { - if (ERROR("SPACING", - "spaces required around that '$op' $at\n" . $hereptr)) { + my $msg_type = \&ERROR; + $msg_type = \&CHK if (($op eq '?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/); + + if (&{$msg_type}("SPACING", + "spaces required around that '$op' $at\n" . $hereptr)) { $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; if (defined $fix_elements[$n + 2]) { $fix_elements[$n + 2] =~ s/^\s+//; -- cgit v0.10.2 From d8b077101bcfbd36701c18bfda04fd74648d5d35 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:06 -0800 Subject: checkpatch: extend CamelCase types and ignore existing CamelCase uses in a patch Extend the CamelCase words found to include structure members. In https://lkml.org/lkml/2013/9/3/318 Sarah Sharp (mostly) wrote: "In general, if checkpatch.pl complains about a variable a patch introduces that's CamelCase, you should pay attention to it. Otherwise, [] ignore it." So, if checking a patch, scan the original patched file if it's available and add any preexisting CamelCase types so reuses do not generate CamelCase messages. That also means Andrew's not so cruelly spurned anymore. https://lkml.org/lkml/2013/2/22/426 Signed-off-by: Joe Perches Suggested-by: Sarah Sharp Suggested-by: Andrew Morton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 42103a0..c03e427 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -443,7 +443,7 @@ sub seed_camelcase_file { if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) { $camelcase{$1} = 1; } - elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*\(/) { + elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) { $camelcase{$1} = 1; } } @@ -1612,6 +1612,8 @@ sub process { my @setup_docs = (); my $setup_docs = 0; + my $camelcase_file_seeded = 0; + sanitise_line_reset(); my $line; foreach my $rawline (@rawlines) { @@ -3394,7 +3396,13 @@ sub process { while ($var =~ m{($Ident)}g) { my $word = $1; next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/); - seed_camelcase_includes() if ($check); + if ($check) { + seed_camelcase_includes(); + if (!$file && !$camelcase_file_seeded) { + seed_camelcase_file($realfile); + $camelcase_file_seeded = 1; + } + } if (!defined $camelcase{$word}) { $camelcase{$word} = 1; CHK("CAMELCASE", -- cgit v0.10.2 From 066687279ccf5e9e935f7780c4b311d18ebaf977 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:07 -0800 Subject: checkpatch: update seq_ tests seq_vprintf, seq_printf and seq_puts are logging functions and should be allowed to exceed the maximium line length. Add maximum line length exceptions for these functions. Also, suggesting seq_printf conversions to seq_puts should be tested for arguments after the format. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index c03e427..42567bc 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -323,7 +323,8 @@ our $logFunctions = qr{(?x: (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| WARN(?:_RATELIMIT|_ONCE|)| panic| - MODULE_[A-Z_]+ + MODULE_[A-Z_]+| + seq_vprintf|seq_printf|seq_puts )}; our $signature_tags = qr{(?xi: @@ -3909,9 +3910,9 @@ sub string_find_replace { } # check for seq_printf uses that could be seq_puts - if ($line =~ /\bseq_printf\s*\(/) { + if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) { my $fmt = get_quoted_string($line, $rawline); - if ($fmt !~ /[^\\]\%/) { + if ($fmt ne "" && $fmt !~ /[^\\]\%/) { if (WARN("PREFER_SEQ_PUTS", "Prefer seq_puts to seq_printf\n" . $herecurr) && $fix) { -- cgit v0.10.2 From 11ea516a6c578564a65a352abb08ef558d365946 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:08 -0800 Subject: checkpatch: find CamelCase definitions of struct/union/enum Checkpatch doesn't currently find CamelCase definitions of structs, unions or enums. Add that ability. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 42567bc..fcc74fe7 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -443,8 +443,9 @@ sub seed_camelcase_file { next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/); if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) { $camelcase{$1} = 1; - } - elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) { + } elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) { $camelcase{$1} = 1; } } -- cgit v0.10.2 From 52ea85061d188031c827ecef9bce47ae93f1e52e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:09 -0800 Subject: checkpatch: add test for #defines of ARCH_HAS_ Add a test for these #defines Additionally, moved string_find_replace sub as it screws up subsequent formatting when placed inside another sub. Signed-off-by: Joe Perches Suggested-by: Andrew Morton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index fcc74fe7..8489c35 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1514,6 +1514,14 @@ sub rtrim { return $string; } +sub string_find_replace { + my ($string, $find, $replace) = @_; + + $string =~ s/$find/$replace/g; + + return $string; +} + sub tabify { my ($leading) = @_; @@ -3733,14 +3741,6 @@ sub process { } } -sub string_find_replace { - my ($string, $find, $replace) = @_; - - $string =~ s/$find/$replace/g; - - return $string; -} - # check for bad placement of section $InitAttribute (e.g.: __initdata) if ($line =~ /(\b$InitAttribute\b)/) { my $attr = $1; @@ -4198,6 +4198,12 @@ sub string_find_replace { "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); } +# Use of __ARCH_HAS_ or ARCH_HAVE_ is wrong. + if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) { + ERROR("DEFINE_ARCH_HAS", + "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr); + } + # check for %L{u,d,i} in strings my $string; while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { -- cgit v0.10.2 From e970b8846ae4763e64be3c93dc06b4eaebf9ad63 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:10 -0800 Subject: checkpatch: add rules to check init attribute and const defects People get this regularly wrong and it breaks the LTO builds, as it causes a section attribute conflict. Add --fix capability too. Based on a patch from Andi Kleen. Signed-off-by: Joe Perches Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 8489c35..23d55bf 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -241,8 +241,11 @@ our $Sparse = qr{ __ref| __rcu }x; - -our $InitAttribute = qr{__(?:mem|cpu|dev|net_|)(?:initdata|initconst|init\b)}; +our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)}; +our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)}; +our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)}; +our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)}; +our $InitAttribute = qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit}; # Notes to $Attribute: # We need \b after 'init' otherwise 'initconst' will cause a false positive in a check @@ -3759,6 +3762,35 @@ sub process { } } +# check for $InitAttributeData (ie: __initdata) with const + if ($line =~ /\bconst\b/ && $line =~ /($InitAttributeData)/) { + my $attr = $1; + $attr =~ /($InitAttributePrefix)(.*)/; + my $attr_prefix = $1; + my $attr_type = $2; + if (ERROR("INIT_ATTRIBUTE", + "Use of const init definition must use ${attr_prefix}initconst\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ + s/$InitAttributeData/${attr_prefix}initconst/; + } + } + +# check for $InitAttributeConst (ie: __initconst) without const + if ($line !~ /\bconst\b/ && $line =~ /($InitAttributeConst)/) { + my $attr = $1; + if (ERROR("INIT_ATTRIBUTE", + "Use of $attr requires a separate use of const\n" . $herecurr) && + $fix) { + my $lead = $fixed[$linenr - 1] =~ + /(^\+\s*(?:static\s+))/; + $lead = rtrim($1); + $lead = "$lead " if ($lead !~ /^\+$/); + $lead = "${lead}const "; + $fixed[$linenr - 1] =~ s/(^\+\s*(?:static\s+))/$lead/; + } + } + # prefer usleep_range over udelay if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) { # ignore udelay's < 10, however -- cgit v0.10.2 From c1fd7bb99637e69994d26df5f6e33192319d3866 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:11 -0800 Subject: checkpatch: make the memory barrier test noisier Peter Zijlstra prefers that comments be required near uses of memory barriers. Change the message level for memory barrier uses from a --strict test only to a normal WARN so it's always emitted. This might produce false positives around insertions of memory barriers when a comment is outside the patch context block. And checkpatch is still stupid, it only looks for existence of any comment, not at the comment content. Signed-off-by: Joe Perches Suggested-by: Peter Zijlstra Acked-by: Peter Zijlstra Acked-by: Paul E. McKenney Cc: Oliver Neukum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 23d55bf..2e40f64 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3850,8 +3850,8 @@ sub process { # check for memory barriers without a comment. if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) { if (!ctx_has_comment($first_line, $linenr)) { - CHK("MEMORY_BARRIER", - "memory barrier without comment\n" . $herecurr); + WARN("MEMORY_BARRIER", + "memory barrier without comment\n" . $herecurr); } } # check of hardware specific defines -- cgit v0.10.2 From 4783f894d0f3bfb107cf3b1d9aed1f1a0672ee1d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 12 Nov 2013 15:10:12 -0800 Subject: checkpatch.pl: check for the FSF mailing address Kernel maintainers reject new instances of the GPL boilerplate paragraph directing people to write to the FSF for a copy of the GPL, since the FSF has moved in the past and may do so again. Make this an error for new code, but just a --strict CHK in --file mode; anyone interested in doing tree-wide cleanups of this form can enable this test explicitly. Signed-off-by: Josh Triplett Acked-by: Greg Kroah-Hartman Acked-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 2e40f64..ec9bbf8 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1962,6 +1962,18 @@ sub process { $rpt_cleaners = 1; } +# Check for FSF mailing addresses. + if ($rawline =~ /You should have received a copy/ || + $rawline =~ /write to the Free Software/ || + $rawline =~ /59 Temple Place/ || + $rawline =~ /51 Franklin Street/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + my $msg_type = \&ERROR; + $msg_type = \&CHK if ($file); + &{$msg_type}("FSF_MAILING_ADDRESS", + "Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.\n" . $herevet) + } + # check for Kconfig help text having a real description # Only applies when adding the entry originally, after that we do not have # sufficient context to determine whether it is indeed long enough. -- cgit v0.10.2 From 507e51418ca0c98640310aa02450720825b2b6b1 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:13 -0800 Subject: checkpatch: improve "return is not a function" test Find a few more cases where parentheses are used around the value of a return statement. This now uses the "$balanced_parens" test and also makes the test depend on perl v5.10 and higher. This now finds return with parenthesis uses the old code did not find like: ERROR: return is not a function, parentheses are not required #211: FILE: arch/m68k/include/asm/sun3xflop.h:211: + return ((error == 0) ? 0 : -1); Signed-off-by: Joe Perches Tested-by: David Cohen Acked-by: David Cohen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ec9bbf8..6e0f1ec 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3233,21 +3233,10 @@ sub process { } # Return is not a function. - if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) { + if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) { my $spacing = $1; - my $value = $2; - - # Flatten any parentheses - $value =~ s/\(/ \(/g; - $value =~ s/\)/\) /g; - while ($value =~ s/\[[^\[\]]*\]/1/ || - $value !~ /(?:$Ident|-?$Constant)\s* - $Compare\s* - (?:$Ident|-?$Constant)/x && - $value =~ s/\([^\(\)]*\)/1/) { - } -#print "value<$value>\n"; - if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) { + if ($^V && $^V ge 5.10.0 && + $stat =~ /^.\s*return\s*$balanced_parens\s*;\s*$/) { ERROR("RETURN_PARENTHESES", "return is not a function, parentheses are not required\n" . $herecurr); @@ -3256,6 +3245,7 @@ sub process { "space required before the open parenthesis '('\n" . $herecurr); } } + # Return of what appears to be an errno should normally be -'ve if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { my $name = $1; -- cgit v0.10.2 From 2b7ab45395dc4d91ef30985f76d90a8f28f58c27 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:14 -0800 Subject: checkpatch: don't require kernel style __attribute__ shortcuts in uapi paths Avoid prescribing kernel styled shortcuts for gcc extensions of __attribute__((foo)) in the uapi include paths. Fix $realfile filename when using -f/--file to not remove first level directory as if the filename was used in a -P1 patch. Only strip the first level directory (typically a or b) for P1 patches. Signed-off-by: Joe Perches Cc: "Dixit, Ashutosh" Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 6e0f1ec..1eb5d2f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1769,11 +1769,11 @@ sub process { # extract the filename as it passes if ($line =~ /^diff --git.*?(\S+)$/) { $realfile = $1; - $realfile =~ s@^([^/]*)/@@; + $realfile =~ s@^([^/]*)/@@ if (!$file); $in_commit_log = 0; } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; - $realfile =~ s@^([^/]*)/@@; + $realfile =~ s@^([^/]*)/@@ if (!$file); $in_commit_log = 0; $p1_prefix = $1; @@ -3877,7 +3877,8 @@ sub process { } # Check for __inline__ and __inline, prefer inline - if ($line =~ /\b(__inline__|__inline)\b/) { + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b(__inline__|__inline)\b/) { if (WARN("INLINE", "plain inline is preferred over $1\n" . $herecurr) && $fix) { @@ -3887,19 +3888,22 @@ sub process { } # Check for __attribute__ packed, prefer __packed - if ($line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { WARN("PREFER_PACKED", "__packed is preferred over __attribute__((packed))\n" . $herecurr); } # Check for __attribute__ aligned, prefer __aligned - if ($line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { WARN("PREFER_ALIGNED", "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); } # Check for __attribute__ format(printf, prefer __printf - if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { if (WARN("PREFER_PRINTF", "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr) && $fix) { @@ -3909,7 +3913,8 @@ sub process { } # Check for __attribute__ format(scanf, prefer __scanf - if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) { + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) { if (WARN("PREFER_SCANF", "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr) && $fix) { -- cgit v0.10.2 From 823b794ce176bcf135a062075737be71a78629dd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 12 Nov 2013 15:10:15 -0800 Subject: checkpatch: add check for sscanf without return use Naked use sscanf can be troublesome because the pointed to variables may not have been set. Add a warning when the sscanf return value is not used. For now, do not add __must_check to the sscanf prototype because that will cause a couple of hundred new warnings when compiling a kernel. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 1eb5d2f..61090e0 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -4019,6 +4019,23 @@ sub process { } } +# check for naked sscanf + if ($^V && $^V ge 5.10.0 && + defined $stat && + $stat =~ /\bsscanf\b/ && + ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ && + $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ && + $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + WARN("NAKED_SSCANF", + "unchecked sscanf return value\n" . "$here\n$stat_real\n"); + } + # check for new externs in .h files. if ($realfile =~ /\.h$/ && $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) { -- cgit v0.10.2 From ae10b2b4eb01bedc91d29d5c5bb9e416fd806c40 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Tue, 12 Nov 2013 15:10:16 -0800 Subject: epoll: optimize EPOLL_CTL_DEL using rcu Nathan Zimmer found that once we get over 10+ cpus, the scalability of SPECjbb falls over due to the contention on the global 'epmutex', which is taken in on EPOLL_CTL_ADD and EPOLL_CTL_DEL operations. Patch #1 removes the 'epmutex' lock completely from the EPOLL_CTL_DEL path by using rcu to guard against any concurrent traversals. Patch #2 remove the 'epmutex' lock from EPOLL_CTL_ADD operations for simple topologies. IE when adding a link from an epoll file descriptor to a wakeup source, where the epoll file descriptor is not nested. This patch (of 2): Optimize EPOLL_CTL_DEL such that it does not require the 'epmutex' by converting the file->f_ep_links list into an rcu one. In this way, we can traverse the epoll network on the add path in parallel with deletes. Since deletes can't create loops or worse wakeup paths, this is safe. This patch in combination with the patch "epoll: Do not take global 'epmutex' for simple topologies", shows a dramatic performance improvement in scalability for SPECjbb. Signed-off-by: Jason Baron Tested-by: Nathan Zimmer Cc: Eric Wong Cc: Nelson Elhage Cc: Al Viro Cc: Davide Libenzi Cc: "Paul E. McKenney" CC: Wu Fengguang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 810c28f..5842494 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -41,6 +41,7 @@ #include #include #include +#include /* * LOCKING: @@ -133,8 +134,12 @@ struct nested_calls { * of these on a server and we do not want this to take another cache line. */ struct epitem { - /* RB tree node used to link this structure to the eventpoll RB tree */ - struct rb_node rbn; + union { + /* RB tree node links this structure to the eventpoll RB tree */ + struct rb_node rbn; + /* Used to free the struct epitem */ + struct rcu_head rcu; + }; /* List header used to link this structure to the eventpoll ready list */ struct list_head rdllink; @@ -671,6 +676,12 @@ static int ep_scan_ready_list(struct eventpoll *ep, return error; } +static void epi_rcu_free(struct rcu_head *head) +{ + struct epitem *epi = container_of(head, struct epitem, rcu); + kmem_cache_free(epi_cache, epi); +} + /* * Removes a "struct epitem" from the eventpoll RB tree and deallocates * all the associated resources. Must be called with "mtx" held. @@ -692,8 +703,7 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) /* Remove the current item from the list of epoll hooks */ spin_lock(&file->f_lock); - if (ep_is_linked(&epi->fllink)) - list_del_init(&epi->fllink); + list_del_rcu(&epi->fllink); spin_unlock(&file->f_lock); rb_erase(&epi->rbn, &ep->rbr); @@ -704,9 +714,14 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) spin_unlock_irqrestore(&ep->lock, flags); wakeup_source_unregister(ep_wakeup_source(epi)); - - /* At this point it is safe to free the eventpoll item */ - kmem_cache_free(epi_cache, epi); + /* + * At this point it is safe to free the eventpoll item. Use the union + * field epi->rcu, since we are trying to minimize the size of + * 'struct epitem'. The 'rbn' field is no longer in use. Protected by + * ep->mtx. The rcu read side, reverse_path_check_proc(), does not make + * use of the rbn field. + */ + call_rcu(&epi->rcu, epi_rcu_free); atomic_long_dec(&ep->user->epoll_watches); @@ -872,7 +887,6 @@ static const struct file_operations eventpoll_fops = { */ void eventpoll_release_file(struct file *file) { - struct list_head *lsthead = &file->f_ep_links; struct eventpoll *ep; struct epitem *epi; @@ -890,17 +904,12 @@ void eventpoll_release_file(struct file *file) * Besides, ep_remove() acquires the lock, so we can't hold it here. */ mutex_lock(&epmutex); - - while (!list_empty(lsthead)) { - epi = list_first_entry(lsthead, struct epitem, fllink); - + list_for_each_entry_rcu(epi, &file->f_ep_links, fllink) { ep = epi->ep; - list_del_init(&epi->fllink); mutex_lock_nested(&ep->mtx, 0); ep_remove(ep, epi); mutex_unlock(&ep->mtx); } - mutex_unlock(&epmutex); } @@ -1138,7 +1147,9 @@ static int reverse_path_check_proc(void *priv, void *cookie, int call_nests) struct file *child_file; struct epitem *epi; - list_for_each_entry(epi, &file->f_ep_links, fllink) { + /* CTL_DEL can remove links here, but that can't increase our count */ + rcu_read_lock(); + list_for_each_entry_rcu(epi, &file->f_ep_links, fllink) { child_file = epi->ep->file; if (is_file_epoll(child_file)) { if (list_empty(&child_file->f_ep_links)) { @@ -1160,6 +1171,7 @@ static int reverse_path_check_proc(void *priv, void *cookie, int call_nests) "file is not an ep!\n"); } } + rcu_read_unlock(); return error; } @@ -1286,7 +1298,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, /* Add the current item to the list of active epoll hook for this file */ spin_lock(&tfile->f_lock); - list_add_tail(&epi->fllink, &tfile->f_ep_links); + list_add_tail_rcu(&epi->fllink, &tfile->f_ep_links); spin_unlock(&tfile->f_lock); /* @@ -1327,8 +1339,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, error_remove_epi: spin_lock(&tfile->f_lock); - if (ep_is_linked(&epi->fllink)) - list_del_init(&epi->fllink); + list_del_rcu(&epi->fllink); spin_unlock(&tfile->f_lock); rb_erase(&epi->rbn, &ep->rbr); @@ -1844,15 +1855,12 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, * and hang them on the tfile_check_list, so we can check that we * haven't created too many possible wakeup paths. * - * We need to hold the epmutex across both ep_insert and ep_remove - * b/c we want to make sure we are looking at a coherent view of - * epoll network. + * We need to hold the epmutex across ep_insert to prevent + * multple adds from creating loops in parallel. */ - if (op == EPOLL_CTL_ADD || op == EPOLL_CTL_DEL) { + if (op == EPOLL_CTL_ADD) { mutex_lock(&epmutex); did_lock_epmutex = 1; - } - if (op == EPOLL_CTL_ADD) { if (is_file_epoll(tf.file)) { error = -ELOOP; if (ep_loop_check(ep, tf.file) != 0) { -- cgit v0.10.2 From 67347fe4e6326338ee217d7eb826bedf30b2e155 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Tue, 12 Nov 2013 15:10:18 -0800 Subject: epoll: do not take global 'epmutex' for simple topologies When calling EPOLL_CTL_ADD for an epoll file descriptor that is attached directly to a wakeup source, we do not need to take the global 'epmutex', unless the epoll file descriptor is nested. The purpose of taking the 'epmutex' on add is to prevent complex topologies such as loops and deep wakeup paths from forming in parallel through multiple EPOLL_CTL_ADD operations. However, for the simple case of an epoll file descriptor attached directly to a wakeup source (with no nesting), we do not need to hold the 'epmutex'. This patch along with 'epoll: optimize EPOLL_CTL_DEL using rcu' improves scalability on larger systems. Quoting Nathan Zimmer's mail on SPECjbb performance: "On the 16 socket run the performance went from 35k jOPS to 125k jOPS. In addition the benchmark when from scaling well on 10 sockets to scaling well on just over 40 sockets. ... Currently the benchmark stops scaling at around 40-44 sockets but it seems like I found a second unrelated bottleneck." [akpm@linux-foundation.org: use `bool' for boolean variables, remove unneeded/undesirable cast of void*, add missed ep_scan_ready_list() kerneldoc] Signed-off-by: Jason Baron Tested-by: Nathan Zimmer Cc: Eric Wong Cc: Nelson Elhage Cc: Al Viro Cc: Davide Libenzi Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 5842494..f7fe7e3 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -585,14 +585,14 @@ static inline void ep_pm_stay_awake_rcu(struct epitem *epi) * @sproc: Pointer to the scan callback. * @priv: Private opaque data passed to the @sproc callback. * @depth: The current depth of recursive f_op->poll calls. + * @ep_locked: caller already holds ep->mtx * * Returns: The same integer error code returned by the @sproc callback. */ static int ep_scan_ready_list(struct eventpoll *ep, int (*sproc)(struct eventpoll *, struct list_head *, void *), - void *priv, - int depth) + void *priv, int depth, bool ep_locked) { int error, pwake = 0; unsigned long flags; @@ -603,7 +603,9 @@ static int ep_scan_ready_list(struct eventpoll *ep, * We need to lock this because we could be hit by * eventpoll_release_file() and epoll_ctl(). */ - mutex_lock_nested(&ep->mtx, depth); + + if (!ep_locked) + mutex_lock_nested(&ep->mtx, depth); /* * Steal the ready list, and re-init the original one to the @@ -667,7 +669,8 @@ static int ep_scan_ready_list(struct eventpoll *ep, } spin_unlock_irqrestore(&ep->lock, flags); - mutex_unlock(&ep->mtx); + if (!ep_locked) + mutex_unlock(&ep->mtx); /* We have to call this outside the lock */ if (pwake) @@ -822,15 +825,34 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, return 0; } +static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, + poll_table *pt); + +struct readyevents_arg { + struct eventpoll *ep; + bool locked; +}; + static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests) { - return ep_scan_ready_list(priv, ep_read_events_proc, NULL, call_nests + 1); + struct readyevents_arg *arg = priv; + + return ep_scan_ready_list(arg->ep, ep_read_events_proc, NULL, + call_nests + 1, arg->locked); } static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) { int pollflags; struct eventpoll *ep = file->private_data; + struct readyevents_arg arg; + + /* + * During ep_insert() we already hold the ep->mtx for the tfile. + * Prevent re-aquisition. + */ + arg.locked = wait && (wait->_qproc == ep_ptable_queue_proc); + arg.ep = ep; /* Insert inside our poll wait queue */ poll_wait(file, &ep->poll_wait, wait); @@ -842,7 +864,7 @@ static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) * could re-enter here. */ pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS, - ep_poll_readyevents_proc, ep, ep, current); + ep_poll_readyevents_proc, &arg, ep, current); return pollflags != -1 ? pollflags : 0; } @@ -1243,7 +1265,7 @@ static noinline void ep_destroy_wakeup_source(struct epitem *epi) * Must be called with "mtx" held. */ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, - struct file *tfile, int fd) + struct file *tfile, int fd, int full_check) { int error, revents, pwake = 0; unsigned long flags; @@ -1309,7 +1331,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, /* now check if we've created too many backpaths */ error = -EINVAL; - if (reverse_path_check()) + if (full_check && reverse_path_check()) goto error_remove_epi; /* We have to drop the new item inside our item list to keep track of it */ @@ -1532,7 +1554,7 @@ static int ep_send_events(struct eventpoll *ep, esed.maxevents = maxevents; esed.events = events; - return ep_scan_ready_list(ep, ep_send_events_proc, &esed, 0); + return ep_scan_ready_list(ep, ep_send_events_proc, &esed, 0, false); } static inline struct timespec ep_set_mstimeout(long ms) @@ -1802,11 +1824,12 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event __user *, event) { int error; - int did_lock_epmutex = 0; + int full_check = 0; struct fd f, tf; struct eventpoll *ep; struct epitem *epi; struct epoll_event epds; + struct eventpoll *tep = NULL; error = -EFAULT; if (ep_op_has_event(op) && @@ -1855,23 +1878,40 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, * and hang them on the tfile_check_list, so we can check that we * haven't created too many possible wakeup paths. * - * We need to hold the epmutex across ep_insert to prevent - * multple adds from creating loops in parallel. + * We do not need to take the global 'epumutex' on EPOLL_CTL_ADD when + * the epoll file descriptor is attaching directly to a wakeup source, + * unless the epoll file descriptor is nested. The purpose of taking the + * 'epmutex' on add is to prevent complex toplogies such as loops and + * deep wakeup paths from forming in parallel through multiple + * EPOLL_CTL_ADD operations. */ + mutex_lock_nested(&ep->mtx, 0); if (op == EPOLL_CTL_ADD) { - mutex_lock(&epmutex); - did_lock_epmutex = 1; - if (is_file_epoll(tf.file)) { - error = -ELOOP; - if (ep_loop_check(ep, tf.file) != 0) { - clear_tfile_check_list(); - goto error_tgt_fput; + if (!list_empty(&f.file->f_ep_links) || + is_file_epoll(tf.file)) { + full_check = 1; + mutex_unlock(&ep->mtx); + mutex_lock(&epmutex); + if (is_file_epoll(tf.file)) { + error = -ELOOP; + if (ep_loop_check(ep, tf.file) != 0) { + clear_tfile_check_list(); + goto error_tgt_fput; + } + } else + list_add(&tf.file->f_tfile_llink, + &tfile_check_list); + mutex_lock_nested(&ep->mtx, 0); + if (is_file_epoll(tf.file)) { + tep = tf.file->private_data; + mutex_lock_nested(&tep->mtx, 1); } - } else - list_add(&tf.file->f_tfile_llink, &tfile_check_list); + } + } + if (op == EPOLL_CTL_DEL && is_file_epoll(tf.file)) { + tep = tf.file->private_data; + mutex_lock_nested(&tep->mtx, 1); } - - mutex_lock_nested(&ep->mtx, 0); /* * Try to lookup the file inside our RB tree, Since we grabbed "mtx" @@ -1885,10 +1925,11 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, case EPOLL_CTL_ADD: if (!epi) { epds.events |= POLLERR | POLLHUP; - error = ep_insert(ep, &epds, tf.file, fd); + error = ep_insert(ep, &epds, tf.file, fd, full_check); } else error = -EEXIST; - clear_tfile_check_list(); + if (full_check) + clear_tfile_check_list(); break; case EPOLL_CTL_DEL: if (epi) @@ -1904,10 +1945,12 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, error = -ENOENT; break; } + if (tep != NULL) + mutex_unlock(&tep->mtx); mutex_unlock(&ep->mtx); error_tgt_fput: - if (did_lock_epmutex) + if (full_check) mutex_unlock(&epmutex); fdput(tf); -- cgit v0.10.2 From 65321547c8be5b00427ac8de23fd15801b68de1f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Nov 2013 15:10:19 -0800 Subject: init.h: document the existence of __initconst Initdata can be const since more than 5 years, using the __initconst keyword. Signed-off-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/init.h b/include/linux/init.h index f1c27a7..8e68a64 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -26,8 +26,8 @@ * extern int initialize_foobar_device(int, int, int) __init; * * For initialized data: - * You should insert __initdata between the variable name and equal - * sign followed by value, e.g.: + * You should insert __initdata or __initconst between the variable name + * and equal sign followed by value, e.g.: * * static int init_variable __initdata = 0; * static const char linux_logo[] __initconst = { 0x32, 0x36, ... }; @@ -35,8 +35,6 @@ * Don't forget to initialize data not at file scope, i.e. within a function, * as gcc otherwise puts the data into the bss section and not into the init * section. - * - * Also note, that this data cannot be "const". */ /* These are for everybody (although not all archs will actually -- cgit v0.10.2 From df3ef3af503e131f7848652af8be21747fd57419 Mon Sep 17 00:00:00 2001 From: P J P Date: Tue, 12 Nov 2013 15:10:20 -0800 Subject: init/do_mounts_rd.c: fix NULL pointer dereference while loading initramfs Make menuconfig allows one to choose compression format of an initial ramdisk image. But this choice does not result in duly compressed initial ramdisk image. Because - $ make install - does not pass on the selected compression choice to the dracut(8) tool, which creates the initramfs file. dracut(8) generates the image with the default compression, ie. gzip(1). If a user chose any other compression instead of gzip(1), it leads to a crash due to NULL pointer dereference in crd_load(), caused by a NULL function pointer returned by the 'decompress_method()' routine. Because the initramfs image is gzip(1) compressed, whereas the kernel knows only to decompress the chosen format and not gzip(1). This patch replaces the crash by an explicit panic() call with an appropriate error message. This shall prevent the kernel from eventually panicking in: init/do_mounts.c: mount_block_root() with -> panic("VFS: Unable to mount root fs on %s", b); [akpm@linux-foundation.org: mention that the problem is with the ramdisk, don't print known-to-be-NULL value] Signed-off-by: P J P Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c index 6be2879..143e98d 100644 --- a/init/do_mounts_rd.c +++ b/init/do_mounts_rd.c @@ -342,6 +342,13 @@ static int __init crd_load(int in_fd, int out_fd, decompress_fn deco) int result; crd_infd = in_fd; crd_outfd = out_fd; + + if (!deco) { + pr_emerg("Invalid ramdisk decompression routine. " + "Select appropriate config option.\n"); + panic("Could not decompress initial ramdisk image."); + } + result = deco(NULL, 0, compr_fill, compr_flush, NULL, NULL, error); if (decompress_error) result = 1; -- cgit v0.10.2 From ba24762bd53faaf39cc8b991175636954b7ef4be Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 12 Nov 2013 15:10:21 -0800 Subject: init: make init failures more explicit This patch proposes to make init failures more explicit. Before this, the "No init found" message didn't help much. It could sometimes be misleading and actually mean "No *working* init found". This message could hide many different issues: - no init program candidates found at all - some init program candidates exist but can't be executed (missing execute permissions, failed to load shared libraries, executable compiled for an unknown architecture...) This patch notifies the kernel user when a candidate init program is found but can't be executed. In each failure situation, the error code is displayed, to quickly find the root cause. "No init found" is also replaced by "No working init found", which is more correct. This will help embedded Linux developers (especially the newcomers), regularly making and debugging new root filesystems. Credits to Geert Uytterhoeven and Janne Karhunen for their improvement suggestions. Signed-off-by: Michael Opdenacker Cc: Geert Uytterhoeven Tested-by: Janne Karhunen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/init/main.c b/init/main.c index aa061ef..67ee8ef 100644 --- a/init/main.c +++ b/init/main.c @@ -810,10 +810,26 @@ static int run_init_process(const char *init_filename) (const char __user *const __user *)envp_init); } +static int try_to_run_init_process(const char *init_filename) +{ + int ret; + + ret = run_init_process(init_filename); + + if (ret && ret != -ENOENT) { + pr_err("Starting init: %s exists but couldn't execute it (error %d)\n", + init_filename, ret); + } + + return ret; +} + static noinline void __init kernel_init_freeable(void); static int __ref kernel_init(void *unused) { + int ret; + kernel_init_freeable(); /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); @@ -825,9 +841,11 @@ static int __ref kernel_init(void *unused) flush_delayed_fput(); if (ramdisk_execute_command) { - if (!run_init_process(ramdisk_execute_command)) + ret = run_init_process(ramdisk_execute_command); + if (!ret) return 0; - pr_err("Failed to execute %s\n", ramdisk_execute_command); + pr_err("Failed to execute %s (error %d)\n", + ramdisk_execute_command, ret); } /* @@ -837,18 +855,19 @@ static int __ref kernel_init(void *unused) * trying to recover a really broken machine. */ if (execute_command) { - if (!run_init_process(execute_command)) + ret = run_init_process(execute_command); + if (!ret) return 0; - pr_err("Failed to execute %s. Attempting defaults...\n", - execute_command); + pr_err("Failed to execute %s (error %d). Attempting defaults...\n", + execute_command, ret); } - if (!run_init_process("/sbin/init") || - !run_init_process("/etc/init") || - !run_init_process("/bin/init") || - !run_init_process("/bin/sh")) + if (!try_to_run_init_process("/sbin/init") || + !try_to_run_init_process("/etc/init") || + !try_to_run_init_process("/bin/init") || + !try_to_run_init_process("/bin/sh")) return 0; - panic("No init found. Try passing init= option to kernel. " + panic("No working init found. Try passing init= option to kernel. " "See Linux Documentation/init.txt for guidance."); } -- cgit v0.10.2 From 9ba4bcb645898d562498ea66a0df958ef0e7a68c Mon Sep 17 00:00:00 2001 From: P J P Date: Tue, 12 Nov 2013 15:10:22 -0800 Subject: initramfs: read CONFIG_RD_ variables for initramfs compression When expert configuration option(CONFIG_EXPERT) is enabled, menuconfig offers a choice of compression algorithm to compress initial ramfs image; This choice is stored into CONFIG_RD_* variables. But usr/Makefile uses earlier INITRAMFS_COMPRESSION_* macros to build initial ramfs file. Since none of them is defined, resulting 'initramfs_data.cpio' file remains un-compressed. This patch updates the Makefile to use CONFIG_RD_* variables and adds support for LZ4 compression algorithm. Also updates the 'gen_initramfs_list.sh' script to check whether a selected compression command is accessible or not. And fall-back to default gzip(1) compression when it is not. Signed-off-by: P J P Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index b482f16..ef47409 100644 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -240,12 +240,24 @@ case "$arg" in output_file="$1" cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)" output=${cpio_list} - echo "$output_file" | grep -q "\.gz$" && compr="gzip -n -9 -f" - echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f" - echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f" - echo "$output_file" | grep -q "\.xz$" && \ - compr="xz --check=crc32 --lzma2=dict=1MiB" - echo "$output_file" | grep -q "\.lzo$" && compr="lzop -9 -f" + echo "$output_file" | grep -q "\.gz$" \ + && [ -x "`which gzip 2> /dev/null`" ] \ + && compr="gzip -n -9 -f" + echo "$output_file" | grep -q "\.bz2$" \ + && [ -x "`which bzip2 2> /dev/null`" ] \ + && compr="bzip2 -9 -f" + echo "$output_file" | grep -q "\.lzma$" \ + && [ -x "`which lzma 2> /dev/null`" ] \ + && compr="lzma -9 -f" + echo "$output_file" | grep -q "\.xz$" \ + && [ -x "`which xz 2> /dev/null`" ] \ + && compr="xz --check=crc32 --lzma2=dict=1MiB" + echo "$output_file" | grep -q "\.lzo$" \ + && [ -x "`which lzop 2> /dev/null`" ] \ + && compr="lzop -9 -f" + echo "$output_file" | grep -q "\.lz4$" \ + && [ -x "`which lz4 2> /dev/null`" ] \ + && compr="lz4 -9 -f" echo "$output_file" | grep -q "\.cpio$" && compr="cat" shift ;; diff --git a/usr/Makefile b/usr/Makefile index 029ffe6..e767f01 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -6,20 +6,23 @@ klibcdirs:; PHONY += klibcdirs -# Gzip -suffix_$(CONFIG_INITRAMFS_COMPRESSION_GZIP) = .gz - # Bzip2 -suffix_$(CONFIG_INITRAMFS_COMPRESSION_BZIP2) = .bz2 +suffix_$(CONFIG_RD_BZIP2) = .bz2 # Lzma -suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZMA) = .lzma +suffix_$(CONFIG_RD_LZMA) = .lzma # XZ -suffix_$(CONFIG_INITRAMFS_COMPRESSION_XZ) = .xz +suffix_$(CONFIG_RD_XZ) = .xz # Lzo -suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZO) = .lzo +suffix_$(CONFIG_RD_LZO) = .lzo + +# Lz4 +suffix_$(CONFIG_RD_LZ4) = .lz4 + +# Gzip +suffix_$(CONFIG_RD_GZIP) = .gz AFLAGS_initramfs_data.o += -DINITRAMFS_IMAGE="usr/initramfs_data.cpio$(suffix_y)" @@ -53,7 +56,10 @@ endif quiet_cmd_initfs = GEN $@ cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) -targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 initramfs_data.cpio.lzma initramfs_data.cpio.xz initramfs_data.cpio.lzo initramfs_data.cpio +targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 \ + initramfs_data.cpio.lzma initramfs_data.cpio.xz \ + initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \ + initramfs_data.cpio # do not try to update files included in initramfs $(deps_initramfs): ; @@ -66,4 +72,3 @@ $(deps_initramfs): klibcdirs $(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d $(call if_changed,initfs) - -- cgit v0.10.2 From ab76786561e0fa1c6d45d6963ab87bb6d628d4cb Mon Sep 17 00:00:00 2001 From: Joe Mario Date: Tue, 12 Nov 2013 15:10:23 -0800 Subject: kprobes: use KSYM_NAME_LEN to size identifier buffers Use KSYM_NAME_LEN to size identifier buffers, so that it can be easier increased. Signed-off-by: Joe Mario Signed-off-by: Andi Kleen Acked-by: Ananth N Mavinakayanahalli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/kprobes.c b/kernel/kprobes.c index a0d367a..ceeadfc 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -2066,7 +2066,7 @@ static int __init init_kprobes(void) { int i, err = 0; unsigned long offset = 0, size = 0; - char *modname, namebuf[128]; + char *modname, namebuf[KSYM_NAME_LEN]; const char *symbol_name; void *addr; struct kprobe_blackpoint *kb; @@ -2192,7 +2192,7 @@ static int __kprobes show_kprobe_addr(struct seq_file *pi, void *v) const char *sym = NULL; unsigned int i = *(loff_t *) v; unsigned long offset = 0; - char *modname, namebuf[128]; + char *modname, namebuf[KSYM_NAME_LEN]; head = &kprobe_table[i]; preempt_disable(); -- cgit v0.10.2 From 10992435b30eb470e6b91d2415abfb79680d00b6 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 Nov 2013 15:10:24 -0800 Subject: drivers/message/i2o/driver.c: add missing destroy_workqueue() on error in i2o_driver_register() Add the missing destroy_workqueue() before return from i2o_driver_register() in the error handling case. Signed-off-by: Wei Yongjun Acked-by: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index b6b92d7..1b18a0d 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -105,7 +105,8 @@ int i2o_driver_register(struct i2o_driver *drv) osm_err("too many drivers registered, increase " "max_drivers\n"); spin_unlock_irqrestore(&i2o_drivers_lock, flags); - return -EFAULT; + rc = -EFAULT; + goto out; } drv->context = i; @@ -124,11 +125,14 @@ int i2o_driver_register(struct i2o_driver *drv) } rc = driver_register(&drv->driver); - if (rc) { - if (drv->event) { - destroy_workqueue(drv->event_queue); - drv->event_queue = NULL; - } + if (rc) + goto out; + + return 0; +out: + if (drv->event_queue) { + destroy_workqueue(drv->event_queue); + drv->event_queue = NULL; } return rc; -- cgit v0.10.2 From 50ccf0455e51eba51e645b3724c8e932c75774b1 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:25 -0800 Subject: drivers/rtc/rtc-ds1307.c: release irq on error 'client->irq' was not released on error. Fix it. Signed-off-by: Sachin Kamat Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index ca18fd1..e8ac439 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -956,7 +956,7 @@ read_rtc: GFP_KERNEL); if (!ds1307->nvram) { err = -ENOMEM; - goto exit; + goto err_irq; } ds1307->nvram->attr.name = "nvram"; ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; @@ -967,13 +967,15 @@ read_rtc: ds1307->nvram_offset = chip->nvram_offset; err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram); if (err) - goto exit; + goto err_irq; set_bit(HAS_NVRAM, &ds1307->flags); dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size); } return 0; +err_irq: + free_irq(client->irq, client); exit: return err; } -- cgit v0.10.2 From c91fd91d686654f8afbbbca18f5ff0a6ebc9c7a2 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:26 -0800 Subject: drivers/rtc/rtc-isl1208.c: remove redundant checks i2c_smbus_read_byte_data() returns negative errno on failure. Return the value obtained from it directly. Signed-off-by: Sachin Kamat Cc: Herbert Valerio Riedel Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index c016ad8..5a0bf7c 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -144,11 +144,7 @@ isl1208_i2c_validate_client(struct i2c_client *client) static int isl1208_i2c_get_sr(struct i2c_client *client) { - int sr = i2c_smbus_read_byte_data(client, ISL1208_REG_SR); - if (sr < 0) - return -EIO; - - return sr; + return i2c_smbus_read_byte_data(client, ISL1208_REG_SR); } static int -- cgit v0.10.2 From f16189aca0e2c6395e7fd6593c3a3063764c628d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:27 -0800 Subject: drivers/rtc/rtc-max6900.c: remove redundant checks i2c_smbus_write_byte_data() returns negative errno on failure or 0 on success. Return the value obtained from it directly. Signed-off-by: Sachin Kamat Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index 55969b1..4804985 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c @@ -164,14 +164,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) static int max6900_i2c_clear_write_protect(struct i2c_client *client) { - int rc; - rc = i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0); - if (rc < 0) { - dev_err(&client->dev, "%s: control register write failed\n", - __func__); - return -EIO; - } - return 0; + return i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0); } static int -- cgit v0.10.2 From 58f27d7d061b47f57c84cad7d9af239c6bc6977e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:28 -0800 Subject: drivers/rtc/rtc-vt8500.c: fix return value Propagate the return value from platform_get_irq() instead of hardcoding. Signed-off-by: Sachin Kamat Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index c2d6331..5be217d 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -228,7 +228,7 @@ static int vt8500_rtc_probe(struct platform_device *pdev) vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0); if (vt8500_rtc->irq_alarm < 0) { dev_err(&pdev->dev, "No alarm IRQ resource defined\n"); - return -ENXIO; + return vt8500_rtc->irq_alarm; } vt8500_rtc->res = devm_request_mem_region(&pdev->dev, -- cgit v0.10.2 From f3766250b2e9f2920c3c9ef9821827ac82fa7a84 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:29 -0800 Subject: drivers/rtc/rtc-at91rm9200.c: use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 7418926..8b2cd8a 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -376,7 +376,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev) return -ENXIO; } - at91_rtc_regs = ioremap(regs->start, resource_size(regs)); + at91_rtc_regs = devm_ioremap(&pdev->dev, regs->start, + resource_size(regs)); if (!at91_rtc_regs) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); return -ENOMEM; @@ -390,12 +391,12 @@ static int __init at91_rtc_probe(struct platform_device *pdev) AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); - ret = request_irq(irq, at91_rtc_interrupt, + ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt, IRQF_SHARED, "at91_rtc", pdev); if (ret) { dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); - goto err_unmap; + return ret; } /* cpu init code should really have flagged this device as @@ -404,23 +405,14 @@ static int __init at91_rtc_probe(struct platform_device *pdev) if (!device_can_wakeup(&pdev->dev)) device_init_wakeup(&pdev->dev, 1); - rtc = rtc_device_register(pdev->name, &pdev->dev, + rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &at91_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - goto err_free_irq; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); platform_set_drvdata(pdev, rtc); dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n"); return 0; - -err_free_irq: - free_irq(irq, pdev); -err_unmap: - iounmap(at91_rtc_regs); - - return ret; } /* @@ -428,16 +420,10 @@ err_unmap: */ static int __exit at91_rtc_remove(struct platform_device *pdev) { - struct rtc_device *rtc = platform_get_drvdata(pdev); - /* Disable all interrupts */ at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM | AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); - free_irq(irq, pdev); - - rtc_device_unregister(rtc); - iounmap(at91_rtc_regs); return 0; } -- cgit v0.10.2 From adce8c14c9eaf8e184d9410f4a0bdfa8be07ee6f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:30 -0800 Subject: drivers/rtc/rtc-isl1208.c: use devm_* APIs devm_* APIs are device managed and make code simpler. Signed-off-by: Sachin Kamat Cc: Herbert Valerio Riedel Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 5a0bf7c..c3c549d 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -643,10 +643,11 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) "chip found, driver version " DRV_VERSION "\n"); if (client->irq > 0) { - rc = request_threaded_irq(client->irq, NULL, - isl1208_rtc_interrupt, - IRQF_SHARED, - isl1208_driver.driver.name, client); + rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, + isl1208_rtc_interrupt, + IRQF_SHARED, + isl1208_driver.driver.name, + client); if (!rc) { device_init_wakeup(&client->dev, 1); enable_irq_wake(client->irq); @@ -658,20 +659,18 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) } } - rtc = rtc_device_register(isl1208_driver.driver.name, - &client->dev, &isl1208_rtc_ops, + rtc = devm_rtc_device_register(&client->dev, isl1208_driver.driver.name, + &isl1208_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - rc = PTR_ERR(rtc); - goto exit_free_irq; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); i2c_set_clientdata(client, rtc); rc = isl1208_i2c_get_sr(client); if (rc < 0) { dev_err(&client->dev, "reading status failed\n"); - goto exit_unregister; + return rc; } if (rc & ISL1208_REG_SR_RTCF) @@ -680,28 +679,15 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); if (rc) - goto exit_unregister; + return rc; return 0; - -exit_unregister: - rtc_device_unregister(rtc); -exit_free_irq: - if (client->irq) - free_irq(client->irq, client); - - return rc; } static int isl1208_remove(struct i2c_client *client) { - struct rtc_device *rtc = i2c_get_clientdata(client); - sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); - rtc_device_unregister(rtc); - if (client->irq) - free_irq(client->irq, client); return 0; } -- cgit v0.10.2 From 3d09162e9976d1ae79dd737849ca63ab6cff6df6 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:31 -0800 Subject: drivers/rtc/rtc-sirfsoc.c: use devm_rtc_device_register devm_rtc_device_register simplifies the code. Signed-off-by: Sachin Kamat Cc: Xianglong Du Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index 63460cf..1775265 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -274,7 +274,7 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base); if (err) { dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n"); - goto error; + return err; } platform_set_drvdata(pdev, rtcdrv); @@ -290,7 +290,7 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) rtc_div = ((32768 / RTC_HZ) / 2) - 1; sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); - rtcdrv->rtc = rtc_device_register(pdev->name, &(pdev->dev), + rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sirfsoc_rtc_ops, THIS_MODULE); if (IS_ERR(rtcdrv->rtc)) { err = PTR_ERR(rtcdrv->rtc); @@ -322,24 +322,15 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) rtcdrv); if (err) { dev_err(&pdev->dev, "Unable to register for the SiRF SOC RTC IRQ\n"); - goto error; + return err; } return 0; - -error: - if (rtcdrv->rtc) - rtc_device_unregister(rtcdrv->rtc); - - return err; } static int sirfsoc_rtc_remove(struct platform_device *pdev) { - struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev); - device_init_wakeup(&pdev->dev, 0); - rtc_device_unregister(rtcdrv->rtc); return 0; } -- cgit v0.10.2 From d7d954acb7eb204eeed10cd4494812e9f2e48bd8 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:32 -0800 Subject: drivers/rtc/rtc-cmos.c: remove redundant dev_set_drvdata Driver core sets the driver data to NULL upon device_release or on probe failure. Signed-off-by: Sachin Kamat Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 24e733c..79680b1 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -789,7 +789,6 @@ static void __exit cmos_do_remove(struct device *dev) cmos->iomem = NULL; cmos->dev = NULL; - dev_set_drvdata(dev, NULL); } #ifdef CONFIG_PM -- cgit v0.10.2 From 8e3dd0d8e9217e5076538e7232e206e024a04b3c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:33 -0800 Subject: drivers/rtc/rtc-mrst.c: remove redundant dev_set_drvdata Driver core sets the driver data to NULL upon device_release or on probe failure. Signed-off-by: Sachin Kamat Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index 315209d9..e2436d1 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -380,7 +380,6 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, cleanup1: rtc_device_unregister(mrst_rtc.rtc); cleanup0: - dev_set_drvdata(dev, NULL); mrst_rtc.dev = NULL; release_mem_region(iomem->start, resource_size(iomem)); dev_err(dev, "rtc-mrst: unable to initialise\n"); @@ -412,7 +411,6 @@ static void rtc_mrst_do_remove(struct device *dev) mrst->iomem = NULL; mrst->dev = NULL; - dev_set_drvdata(dev, NULL); } #ifdef CONFIG_PM -- cgit v0.10.2 From 4271e7ff1a9fc49efeff8496d1e21878e7de74eb Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:34 -0800 Subject: drivers/rtc/rtc-vr41xx.c: fix checkpatch warnings Fixes the following warnings: WARNING: Use #include instead of WARNING: Use #include instead of Signed-off-by: Sachin Kamat Cc: Yoichi Yuasa Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 54e104e..aabc22c 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -27,11 +28,10 @@ #include #include #include +#include #include #include -#include -#include MODULE_AUTHOR("Yoichi Yuasa "); MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); -- cgit v0.10.2 From b7efdf3b1be423d21fa3106aede5a8bcb9c4d152 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:35 -0800 Subject: drivers/rtc/rtc-sirfsoc.c: remove unneeded casts of void* Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index 1775265..de132b4 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -59,7 +59,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, unsigned long rtc_alarm, rtc_count; struct sirfsoc_rtc_drv *rtcdrv; - rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); + rtcdrv = dev_get_drvdata(dev); local_irq_disable(); @@ -94,7 +94,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, { unsigned long rtc_status_reg, rtc_alarm; struct sirfsoc_rtc_drv *rtcdrv; - rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); + rtcdrv = dev_get_drvdata(dev); if (alrm->enabled) { rtc_tm_to_time(&(alrm->time), &rtc_alarm); @@ -157,7 +157,7 @@ static int sirfsoc_rtc_read_time(struct device *dev, { unsigned long tmp_rtc = 0; struct sirfsoc_rtc_drv *rtcdrv; - rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); + rtcdrv = dev_get_drvdata(dev); /* * This patch is taken from WinCE - Need to validate this for * correctness. To work around sirfsoc RTC counter double sync logic @@ -178,7 +178,7 @@ static int sirfsoc_rtc_set_time(struct device *dev, { unsigned long rtc_time; struct sirfsoc_rtc_drv *rtcdrv; - rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); + rtcdrv = dev_get_drvdata(dev); rtc_tm_to_time(tm, &rtc_time); @@ -364,7 +364,7 @@ static int sirfsoc_rtc_thaw(struct device *dev) { u32 tmp; struct sirfsoc_rtc_drv *rtcdrv; - rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); + rtcdrv = dev_get_drvdata(dev); /* * if resume from snapshot and the rtc power is losed, -- cgit v0.10.2 From b5ebf0780da1846d985998565a51935d10b807da Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:36 -0800 Subject: drivers/rtc/rtc-88pm80x.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 354c937..0916089 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -251,14 +251,15 @@ static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume); static int pm80x_rtc_probe(struct platform_device *pdev) { struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm80x_platform_data *pm80x_pdata; + struct pm80x_platform_data *pm80x_pdata = + dev_get_platdata(pdev->dev.parent); struct pm80x_rtc_pdata *pdata = NULL; struct pm80x_rtc_info *info; struct rtc_time tm; unsigned long ticks = 0; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (pdata == NULL) dev_warn(&pdev->dev, "No platform data!\n"); @@ -326,8 +327,7 @@ static int pm80x_rtc_probe(struct platform_device *pdev) regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO, PM800_RTC1_USE_XO); - if (pdev->dev.parent->platform_data) { - pm80x_pdata = pdev->dev.parent->platform_data; + if (pm80x_pdata) { pdata = pm80x_pdata->rtc; if (pdata) info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; -- cgit v0.10.2 From 82df0b28557a3e4cad4b8258b19bb61d097da9df Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:37 -0800 Subject: drivers/rtc/rtc-88pm860x.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Acked-by: Haojian Zhuang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 4e30c85..81650484 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -316,7 +316,7 @@ static int pm860x_rtc_probe(struct platform_device *pdev) unsigned long ticks = 0; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_rtc_info), GFP_KERNEL); -- cgit v0.10.2 From 97a92e77ca5d3d899619282e3f4cbb94e3162251 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:38 -0800 Subject: drivers/rtc/rtc-cmos.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 79680b1..f148762 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -595,7 +595,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p) static int INITSECTION cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) { - struct cmos_rtc_board_info *info = dev->platform_data; + struct cmos_rtc_board_info *info = dev_get_platdata(dev); int retval = 0; unsigned char rtc_control; unsigned address_space; -- cgit v0.10.2 From d1fa24524899b342690f565a3dbf190fb65cc145 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:39 -0800 Subject: drivers/rtc/rtc-da9055.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c index e00642b..48cb2ac3 100644 --- a/drivers/rtc/rtc-da9055.c +++ b/drivers/rtc/rtc-da9055.c @@ -278,7 +278,7 @@ static int da9055_rtc_probe(struct platform_device *pdev) return -ENOMEM; rtc->da9055 = dev_get_drvdata(pdev->dev.parent); - pdata = rtc->da9055->dev->platform_data; + pdata = dev_get_platdata(rtc->da9055->dev); platform_set_drvdata(pdev, rtc); ret = da9055_rtc_device_init(rtc->da9055, pdata); -- cgit v0.10.2 From cfa13b249ed5f63db55df6ff123fc8856b48ff9f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:40 -0800 Subject: drivers/rtc/rtc-ds1305.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index dd6170a..80f3237 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -606,7 +606,7 @@ static int ds1305_probe(struct spi_device *spi) struct ds1305 *ds1305; int status; u8 addr, value; - struct ds1305_platform_data *pdata = spi->dev.platform_data; + struct ds1305_platform_data *pdata = dev_get_platdata(&spi->dev); bool write_ctrl = false; /* Sanity check board setup data. This may be hooked up -- cgit v0.10.2 From 01ce893d37f053a9f76dd461adf4a4715ac388f1 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:41 -0800 Subject: drivers/rtc/rtc-ds1307.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e8ac439..bd94920 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -672,7 +672,7 @@ static int ds1307_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int want_irq = false; unsigned char *buf; - struct ds1307_platform_data *pdata = client->dev.platform_data; + struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); static const int bbsqi_bitpos[] = { [ds_1337] = 0, [ds_1339] = DS1339_BIT_BBSQI, -- cgit v0.10.2 From 77bf38223c0bf51bb303bc074881b403be3c09b4 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:42 -0800 Subject: drivers/rtc/rtc-ds2404.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 2ca5a23..fc209dc 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -224,7 +224,7 @@ static const struct rtc_class_ops ds2404_rtc_ops = { static int rtc_probe(struct platform_device *pdev) { - struct ds2404_platform_data *pdata = pdev->dev.platform_data; + struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev); struct ds2404 *chip; int retval = -EBUSY; -- cgit v0.10.2 From 28dc5f803899c14f3096b36b643424717ba2b271 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:43 -0800 Subject: drivers/rtc/rtc-ep93xx.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 580e7b5..5e4f5dc 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -42,7 +42,7 @@ struct ep93xx_rtc { static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, unsigned short *delete) { - struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); unsigned long comp; comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP); @@ -60,7 +60,7 @@ static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); unsigned long time; time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); @@ -71,7 +71,7 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) { - struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); __raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD); return 0; -- cgit v0.10.2 From 8136032ba50c9e1efdc93b047543fadfc691e884 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:44 -0800 Subject: drivers/rtc/rtc-m48t59.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index fcb0329..11880c1 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -68,7 +68,7 @@ m48t59_mem_readb(struct device *dev, u32 ofs) static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; u8 val; @@ -111,7 +111,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; u8 val = 0; @@ -158,7 +158,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); struct rtc_time *tm = &alrm->time; unsigned long flags; @@ -205,7 +205,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); struct rtc_time *tm = &alrm->time; u8 mday, hour, min, sec; @@ -266,7 +266,7 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; @@ -283,7 +283,7 @@ static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; u8 val; @@ -304,7 +304,7 @@ static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id) { struct device *dev = (struct device *)dev_id; struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); u8 event; @@ -340,7 +340,7 @@ static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); ssize_t cnt = 0; unsigned long flags; @@ -360,7 +360,7 @@ static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); ssize_t cnt = 0; unsigned long flags; @@ -385,7 +385,7 @@ static struct bin_attribute m48t59_nvram_attr = { static int m48t59_rtc_probe(struct platform_device *pdev) { - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = NULL; struct resource *res; int ret = -ENOMEM; -- cgit v0.10.2 From b5f0902dcdb5e6f8f1eb8dd083ae56dc8245ab53 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:44 -0800 Subject: drivers/rtc/rtc-m48t86.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 2d30314..32f64c9 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -46,7 +46,7 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) { unsigned char reg; struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; + struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); reg = ops->readbyte(M48T86_REG_B); @@ -84,7 +84,7 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned char reg; struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; + struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); reg = ops->readbyte(M48T86_REG_B); @@ -123,7 +123,7 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) { unsigned char reg; struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; + struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); reg = ops->readbyte(M48T86_REG_B); @@ -147,7 +147,7 @@ static const struct rtc_class_ops m48t86_rtc_ops = { static int m48t86_rtc_probe(struct platform_device *dev) { unsigned char reg; - struct m48t86_ops *ops = dev->dev.platform_data; + struct m48t86_ops *ops = dev_get_platdata(&dev->dev); struct rtc_device *rtc; rtc = devm_rtc_device_register(&dev->dev, "m48t86", -- cgit v0.10.2 From ffc75bb8f240b65ecd4e23d7f87863d9f7aeeeff Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:50 -0800 Subject: drivers/rtc/rtc-pcf2123.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 1725b50..d1953bb 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -327,7 +327,7 @@ kfree_exit: static int pcf2123_remove(struct spi_device *spi) { - struct pcf2123_plat_data *pdata = spi->dev.platform_data; + struct pcf2123_plat_data *pdata = dev_get_platdata(&spi->dev); int i; if (pdata) { -- cgit v0.10.2 From f6405afe238f9f16362dd64a814b0381113da67e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:51 -0800 Subject: drivers/rtc/rtc-rs5c348.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index f7a90a1..090a101 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -64,7 +64,7 @@ static int rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct spi_device *spi = to_spi_device(dev); - struct rs5c348_plat_data *pdata = spi->dev.platform_data; + struct rs5c348_plat_data *pdata = dev_get_platdata(&spi->dev); u8 txbuf[5+7], *txp; int ret; @@ -100,7 +100,7 @@ static int rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct spi_device *spi = to_spi_device(dev); - struct rs5c348_plat_data *pdata = spi->dev.platform_data; + struct rs5c348_plat_data *pdata = dev_get_platdata(&spi->dev); u8 txbuf[5], rxbuf[7]; int ret; -- cgit v0.10.2 From e58c18d434a44d0d4402ea08f08c6ed0f4c4ff72 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:52 -0800 Subject: drivers/rtc/rtc-sh.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 6d87e26..d0d2b04 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -649,8 +649,9 @@ static int __init sh_rtc_probe(struct platform_device *pdev) clk_enable(rtc->clk); rtc->capabilities = RTC_DEF_CAPABILITIES; - if (pdev->dev.platform_data) { - struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; + if (dev_get_platdata(&pdev->dev)) { + struct sh_rtc_platform_info *pinfo = + dev_get_platdata(&pdev->dev); /* * Some CPUs have special capabilities in addition to the -- cgit v0.10.2 From a65ddcebabe3e824ab63669e6e14a3352bae4948 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:10:53 -0800 Subject: drivers/rtc/rtc-v3020.c: use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index d07d898..25222cd 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -303,7 +303,7 @@ static const struct rtc_class_ops v3020_rtc_ops = { static int rtc_probe(struct platform_device *pdev) { - struct v3020_platform_data *pdata = pdev->dev.platform_data; + struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev); struct v3020 *chip; int retval = -EBUSY; int i; -- cgit v0.10.2 From ce6bafdf94d827bea25bae59bb1abc23d52e5ff7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:54 -0800 Subject: drivers/rtc/rtc-vt8500.c: remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Cc: Tony Prisk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 5be217d..df2ef3e 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -296,7 +296,7 @@ static struct platform_driver vt8500_rtc_driver = { .driver = { .name = "vt8500-rtc", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(wmt_dt_ids), + .of_match_table = wmt_dt_ids, }, }; -- cgit v0.10.2 From 616b734130af858e9e9dce57c9f49ebc75b19869 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:55 -0800 Subject: drivers/rtc/rtc-omap.c: remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index c7d97ee..26de5f8 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -553,7 +553,7 @@ static struct platform_driver omap_rtc_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .pm = &omap_rtc_pm_ops, - .of_match_table = of_match_ptr(omap_rtc_of_match), + .of_match_table = omap_rtc_of_match, }, .id_table = omap_rtc_devtype, }; -- cgit v0.10.2 From d149632e037e1d84a058c1e70666d4ced10ae156 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:56 -0800 Subject: drivers/rtc/rtc-sirfsoc.c: remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index de132b4..3eb3642 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -458,7 +458,7 @@ static struct platform_driver sirfsoc_rtc_driver = { #ifdef CONFIG_PM .pm = &sirfsoc_rtc_pm_ops, #endif - .of_match_table = of_match_ptr(sirfsoc_rtc_of_match), + .of_match_table = sirfsoc_rtc_of_match, }, .probe = sirfsoc_rtc_probe, .remove = sirfsoc_rtc_remove, -- cgit v0.10.2 From c39b3717b869a0b74e1951416819cc2ec1da629c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:57 -0800 Subject: drivers/rtc/rtc-snvs.c: remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 316a342..fa384fe 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -329,7 +329,7 @@ static struct platform_driver snvs_rtc_driver = { .name = "snvs_rtc", .owner = THIS_MODULE, .pm = &snvs_rtc_pm_ops, - .of_match_table = of_match_ptr(snvs_dt_ids), + .of_match_table = snvs_dt_ids, }, .probe = snvs_rtc_probe, }; -- cgit v0.10.2 From 462a465be2c4cb376875fe8511e3c2c23aae2227 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:10:58 -0800 Subject: drivers/rtc/rtc-stmp3xxx.c: remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 2601953..ea96492 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -343,7 +343,7 @@ static struct platform_driver stmp3xxx_rtcdrv = { .name = "stmp3xxx-rtc", .owner = THIS_MODULE, .pm = &stmp3xxx_rtc_pm_ops, - .of_match_table = of_match_ptr(rtc_dt_ids), + .of_match_table = rtc_dt_ids, }, }; -- cgit v0.10.2 From c8b18da7769af46455180a61e7c292ec514e47e7 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Tue, 12 Nov 2013 15:10:59 -0800 Subject: drivers/rtc/rtc-ds1307.c: change variable type to bool The variable want_irq is only assigned the values true and false. Change its type to bool. The simplified semantic patch that find this problem is as follows (http://coccinelle.lip6.fr/): @exists@ type T; identifier b; @@ - T + bool b = ...; ... when any b = \(true\|false\) Signed-off-by: Peter Senna Tschudin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index bd94920..4e75345 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -670,7 +670,7 @@ static int ds1307_probe(struct i2c_client *client, int tmp; const struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - int want_irq = false; + bool want_irq = false; unsigned char *buf; struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); static const int bbsqi_bitpos[] = { -- cgit v0.10.2 From a2726061920f43f594e03236d694c71f77adc6a2 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 12 Nov 2013 15:11:00 -0800 Subject: drivers/rtc/rtc-pl03x.c: remove unnecessary amba_set_drvdata() Driver core clears the driver data to NULL after device_release or on probe failure, so just remove it from here. The relevant driver core change was commit 0998d0631001 ("device-core: Ensure drvdata = NULL when no driver is bound"). Signed-off-by: Michal Simek Cc: Linus Walleij Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index 22bacdb..a804f75 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -153,8 +153,6 @@ static int pl030_remove(struct amba_device *dev) { struct pl030_rtc *rtc = amba_get_drvdata(dev); - amba_set_drvdata(dev, NULL); - writel(0, rtc->base + RTC_CR); free_irq(dev->irq[0], rtc); diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index e3b2571..99181fff 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -305,7 +305,6 @@ static int pl031_remove(struct amba_device *adev) { struct pl031_local *ldata = dev_get_drvdata(&adev->dev); - amba_set_drvdata(adev, NULL); free_irq(adev->irq[0], ldata); rtc_device_unregister(ldata->rtc); iounmap(ldata->base); @@ -391,7 +390,6 @@ out_no_irq: rtc_device_unregister(ldata->rtc); out_no_rtc: iounmap(ldata->base); - amba_set_drvdata(adev, NULL); out_no_remap: kfree(ldata); out: -- cgit v0.10.2 From 1fbc4c4d79e63709b919bc1a72e991c29ea13f4c Mon Sep 17 00:00:00 2001 From: Sangjung Woo Date: Tue, 12 Nov 2013 15:11:00 -0800 Subject: drivers/rtc/rtc-puv3.c: use dev_dbg() instead of pr_debug() Because dev_*() are used along with pr_debug() function in this code, the debug message is not tidy. This patch converts from pr_debug() to dev_dbg() since dev_*() are encouraged to use in device driver code. Signed-off-by: Sangjung Woo Cc: Guan Xuetao Cc: Alessandro Zummo Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 402732c..1ecfe3b 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -53,11 +53,11 @@ static irqreturn_t puv3_rtc_tickirq(int irq, void *id) } /* Update control registers */ -static void puv3_rtc_setaie(int to) +static void puv3_rtc_setaie(struct device *dev, int to) { unsigned int tmp; - pr_debug("%s: aie=%d\n", __func__, to); + dev_dbg(dev, "%s: aie=%d\n", __func__, to); tmp = readl(RTC_RTSR) & ~RTC_RTSR_ALE; @@ -71,7 +71,7 @@ static int puv3_rtc_setpie(struct device *dev, int enabled) { unsigned int tmp; - pr_debug("%s: pie=%d\n", __func__, enabled); + dev_debug(dev, "%s: pie=%d\n", __func__, enabled); spin_lock_irq(&puv3_rtc_pie_lock); tmp = readl(RTC_RTSR) & ~RTC_RTSR_HZE; @@ -90,7 +90,7 @@ static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); - pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", + dev_dbg(dev, "read time %02x.%02x.%02x %02x/%02x/%02x\n", rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); @@ -101,7 +101,7 @@ static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long rtc_count = 0; - pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", + dev_dbg(dev, "set time %02d.%02d.%02d %02d/%02d/%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -119,7 +119,7 @@ static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; - pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", + dev_dbg(dev, "read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", alrm->enabled, alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); @@ -132,7 +132,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; unsigned long rtcalarm_count = 0; - pr_debug("puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", + dev_dbg(dev, "puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", alrm->enabled, tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); @@ -140,7 +140,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) rtc_tm_to_time(tm, &rtcalarm_count); writel(rtcalarm_count, RTC_RTAR); - puv3_rtc_setaie(alrm->enabled); + puv3_rtc_setaie(&dev->dev, alrm->enabled); if (alrm->enabled) enable_irq_wake(puv3_rtc_alarmno); @@ -227,7 +227,7 @@ static int puv3_rtc_remove(struct platform_device *dev) rtc_device_unregister(rtc); puv3_rtc_setpie(&dev->dev, 0); - puv3_rtc_setaie(0); + puv3_rtc_setaie(&dev->dev, 0); release_resource(puv3_rtc_mem); kfree(puv3_rtc_mem); @@ -241,7 +241,7 @@ static int puv3_rtc_probe(struct platform_device *pdev) struct resource *res; int ret; - pr_debug("%s: probe=%p\n", __func__, pdev); + dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev); /* find the IRQs */ puv3_rtc_tickno = platform_get_irq(pdev, 1); @@ -256,7 +256,7 @@ static int puv3_rtc_probe(struct platform_device *pdev) return -ENOENT; } - pr_debug("PKUnity_rtc: tick irq %d, alarm irq %d\n", + dev_dbg(&pdev->dev, "PKUnity_rtc: tick irq %d, alarm irq %d\n", puv3_rtc_tickno, puv3_rtc_alarmno); /* get the memory region */ -- cgit v0.10.2 From 58c181c8255b8f23c5772b4c4d2328450a95081f Mon Sep 17 00:00:00 2001 From: Sangjung Woo Date: Tue, 12 Nov 2013 15:11:02 -0800 Subject: drivers/rtc/rtc-pl030.c: use devm_kzalloc() instead of kmalloc() In order to be free automatically and make the cleanup paths more simple, use devm_kzalloc() instead of kmalloc(). Signed-off-by: Sangjung Woo Cc: Joe Perches Cc: Alessandro Zummo Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index a804f75..f85a1a9 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -106,7 +106,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id) if (ret) goto err_req; - rtc = kmalloc(sizeof(*rtc), GFP_KERNEL); + rtc = devm_kzalloc(&dev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) { ret = -ENOMEM; goto err_rtc; @@ -115,7 +115,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id) rtc->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!rtc->base) { ret = -ENOMEM; - goto err_map; + goto err_rtc; } __raw_writel(0, rtc->base + RTC_CR); @@ -141,8 +141,6 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id) free_irq(dev->irq[0], rtc); err_irq: iounmap(rtc->base); - err_map: - kfree(rtc); err_rtc: amba_release_regions(dev); err_req: @@ -158,7 +156,6 @@ static int pl030_remove(struct amba_device *dev) free_irq(dev->irq[0], rtc); rtc_device_unregister(rtc->rtc); iounmap(rtc->base); - kfree(rtc); amba_release_regions(dev); return 0; -- cgit v0.10.2 From 5e0d12142e1cf5dc7a8a276fc1fe60b8a5ecb1d3 Mon Sep 17 00:00:00 2001 From: Manish Badarkhe Date: Tue, 12 Nov 2013 15:11:03 -0800 Subject: drivers/rtc/rtc-tps65910.c: remove unnecessary include Currently, driver includes 'pm_runtime.h' which is not used anywhere in code hence remove this unnecessory inclusion. Signed-off-by: Manish Badarkhe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index a9caf04..7af0020 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From 5bccae6ec4587044779f0b8e6fcb8f87db4181f0 Mon Sep 17 00:00:00 2001 From: Sangbeom Kim Date: Tue, 12 Nov 2013 15:11:04 -0800 Subject: rtc: s5m-rtc: add real-time clock driver for s5m8767 Add real-time clock driver for s5m8767. Signed-off-by: Sangbeom Kim Signed-off-by: Sachin Kamat Cc: Todd Broch Cc: Mark Brown Acked-by: Lee Jones [mfd parts] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9654aa3..4f48b9a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -497,6 +497,16 @@ config RTC_DRV_RV3029C2 This driver can also be built as a module. If so, the module will be called rtc-rv3029c2. +config RTC_DRV_S5M + tristate "Samsung S5M series" + depends on MFD_SEC_CORE + help + If you say yes here you will get support for the + RTC of Samsung S5M PMIC series. + + This driver can also be built as a module. If so, the module + will be called rtc-s5m. + endif # I2C comment "SPI RTC drivers" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2dff3d2..9312e79 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o +obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c new file mode 100644 index 0000000..b7fd02b --- /dev/null +++ b/drivers/rtc/rtc-s5m.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd + * http://www.samsung.com + * + * Copyright (C) 2013 Google, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct s5m_rtc_info { + struct device *dev; + struct sec_pmic_dev *s5m87xx; + struct regmap *rtc; + struct rtc_device *rtc_dev; + int irq; + int device_type; + int rtc_24hr_mode; + bool wtsr_smpl; +}; + +static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, + int rtc_24hr_mode) +{ + tm->tm_sec = data[RTC_SEC] & 0x7f; + tm->tm_min = data[RTC_MIN] & 0x7f; + if (rtc_24hr_mode) { + tm->tm_hour = data[RTC_HOUR] & 0x1f; + } else { + tm->tm_hour = data[RTC_HOUR] & 0x0f; + if (data[RTC_HOUR] & HOUR_PM_MASK) + tm->tm_hour += 12; + } + + tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f); + tm->tm_mday = data[RTC_DATE] & 0x1f; + tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; + tm->tm_year = (data[RTC_YEAR1] & 0x7f) + 100; + tm->tm_yday = 0; + tm->tm_isdst = 0; +} + +static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = tm->tm_sec; + data[RTC_MIN] = tm->tm_min; + + if (tm->tm_hour >= 12) + data[RTC_HOUR] = tm->tm_hour | HOUR_PM_MASK; + else + data[RTC_HOUR] = tm->tm_hour & ~HOUR_PM_MASK; + + data[RTC_WEEKDAY] = 1 << tm->tm_wday; + data[RTC_DATE] = tm->tm_mday; + data[RTC_MONTH] = tm->tm_mon + 1; + data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; + + if (tm->tm_year < 100) { + pr_err("s5m8767 RTC cannot handle the year %d.\n", + 1900 + tm->tm_year); + return -EINVAL; + } else { + return 0; + } +} + +static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) +{ + int ret; + unsigned int data; + + ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data); + if (ret < 0) { + dev_err(info->dev, "failed to read update reg(%d)\n", ret); + return ret; + } + + data |= RTC_TIME_EN_MASK; + data |= RTC_UDR_MASK; + + ret = regmap_write(info->rtc, SEC_RTC_UDR_CON, data); + if (ret < 0) { + dev_err(info->dev, "failed to write update reg(%d)\n", ret); + return ret; + } + + do { + ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data); + } while ((data & RTC_UDR_MASK) && !ret); + + return ret; +} + +static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) +{ + int ret; + unsigned int data; + + ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read update reg(%d)\n", + __func__, ret); + return ret; + } + + data &= ~RTC_TIME_EN_MASK; + data |= RTC_UDR_MASK; + + ret = regmap_write(info->rtc, SEC_RTC_UDR_CON, data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write update reg(%d)\n", + __func__, ret); + return ret; + } + + do { + ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data); + } while ((data & RTC_UDR_MASK) && !ret); + + return ret; +} + +static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(data[RTC_SEC]); + tm->tm_min = bcd2bin(data[RTC_MIN]); + + if (data[RTC_HOUR] & HOUR_12) { + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f); + if (data[RTC_HOUR] & HOUR_PM) + tm->tm_hour += 12; + } else { + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); + } + + tm->tm_wday = data[RTC_WEEKDAY] & 0x07; + tm->tm_mday = bcd2bin(data[RTC_DATE]); + tm->tm_mon = bcd2bin(data[RTC_MONTH]); + tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100; + tm->tm_year -= 1900; +} + +static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = bin2bcd(tm->tm_sec); + data[RTC_MIN] = bin2bcd(tm->tm_min); + data[RTC_HOUR] = bin2bcd(tm->tm_hour); + data[RTC_WEEKDAY] = tm->tm_wday; + data[RTC_DATE] = bin2bcd(tm->tm_mday); + data[RTC_MONTH] = bin2bcd(tm->tm_mon); + data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100); + data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100); +} + +static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + int ret; + + ret = regmap_bulk_read(info->rtc, SEC_RTC_SEC, data, 8); + if (ret < 0) + return ret; + + switch (info->device_type) { + case S5M8763X: + s5m8763_data_to_tm(data, tm); + break; + + case S5M8767X: + s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); + break; + + default: + return -EINVAL; + } + + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + + return rtc_valid_tm(tm); +} + +static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + int ret = 0; + + switch (info->device_type) { + case S5M8763X: + s5m8763_tm_to_data(tm, data); + break; + case S5M8767X: + ret = s5m8767_tm_to_data(tm, data); + break; + default: + return -EINVAL; + } + + if (ret < 0) + return ret; + + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + + ret = regmap_raw_write(info->rtc, SEC_RTC_SEC, data, 8); + if (ret < 0) + return ret; + + ret = s5m8767_rtc_set_time_reg(info); + + return ret; +} + +static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + unsigned int val; + int ret, i; + + ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8); + if (ret < 0) + return ret; + + switch (info->device_type) { + case S5M8763X: + s5m8763_data_to_tm(data, &alrm->time); + ret = regmap_read(info->rtc, SEC_ALARM0_CONF, &val); + if (ret < 0) + return ret; + + alrm->enabled = !!val; + + ret = regmap_read(info->rtc, SEC_RTC_STATUS, &val); + if (ret < 0) + return ret; + + break; + + case S5M8767X: + s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, + alrm->time.tm_mday, alrm->time.tm_hour, + alrm->time.tm_min, alrm->time.tm_sec, + alrm->time.tm_wday); + + alrm->enabled = 0; + for (i = 0; i < 7; i++) { + if (data[i] & ALARM_ENABLE_MASK) { + alrm->enabled = 1; + break; + } + } + + alrm->pending = 0; + ret = regmap_read(info->rtc, SEC_RTC_STATUS, &val); + if (ret < 0) + return ret; + break; + + default: + return -EINVAL; + } + + if (val & ALARM0_STATUS) + alrm->pending = 1; + else + alrm->pending = 0; + + return 0; +} + +static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) +{ + u8 data[8]; + int ret, i; + struct rtc_time tm; + + ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8); + if (ret < 0) + return ret; + + s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); + dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + + switch (info->device_type) { + case S5M8763X: + ret = regmap_write(info->rtc, SEC_ALARM0_CONF, 0); + break; + + case S5M8767X: + for (i = 0; i < 7; i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8); + if (ret < 0) + return ret; + + ret = s5m8767_rtc_set_alarm_reg(info); + + break; + + default: + return -EINVAL; + } + + return ret; +} + +static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) +{ + int ret; + u8 data[8]; + u8 alarm0_conf; + struct rtc_time tm; + + ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8); + if (ret < 0) + return ret; + + s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); + dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + + switch (info->device_type) { + case S5M8763X: + alarm0_conf = 0x77; + ret = regmap_write(info->rtc, SEC_ALARM0_CONF, alarm0_conf); + break; + + case S5M8767X: + data[RTC_SEC] |= ALARM_ENABLE_MASK; + data[RTC_MIN] |= ALARM_ENABLE_MASK; + data[RTC_HOUR] |= ALARM_ENABLE_MASK; + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; + if (data[RTC_DATE] & 0x1f) + data[RTC_DATE] |= ALARM_ENABLE_MASK; + if (data[RTC_MONTH] & 0xf) + data[RTC_MONTH] |= ALARM_ENABLE_MASK; + if (data[RTC_YEAR1] & 0x7f) + data[RTC_YEAR1] |= ALARM_ENABLE_MASK; + + ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8); + if (ret < 0) + return ret; + ret = s5m8767_rtc_set_alarm_reg(info); + + break; + + default: + return -EINVAL; + } + + return ret; +} + +static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + u8 data[8]; + int ret; + + switch (info->device_type) { + case S5M8763X: + s5m8763_tm_to_data(&alrm->time, data); + break; + + case S5M8767X: + s5m8767_tm_to_data(&alrm->time, data); + break; + + default: + return -EINVAL; + } + + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, + alrm->time.tm_mday, alrm->time.tm_hour, alrm->time.tm_min, + alrm->time.tm_sec, alrm->time.tm_wday); + + ret = s5m_rtc_stop_alarm(info); + if (ret < 0) + return ret; + + ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8); + if (ret < 0) + return ret; + + ret = s5m8767_rtc_set_alarm_reg(info); + if (ret < 0) + return ret; + + if (alrm->enabled) + ret = s5m_rtc_start_alarm(info); + + return ret; +} + +static int s5m_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + + if (enabled) + return s5m_rtc_start_alarm(info); + else + return s5m_rtc_stop_alarm(info); +} + +static irqreturn_t s5m_rtc_alarm_irq(int irq, void *data) +{ + struct s5m_rtc_info *info = data; + + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops s5m_rtc_ops = { + .read_time = s5m_rtc_read_time, + .set_time = s5m_rtc_set_time, + .read_alarm = s5m_rtc_read_alarm, + .set_alarm = s5m_rtc_set_alarm, + .alarm_irq_enable = s5m_rtc_alarm_irq_enable, +}; + +static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) +{ + int ret; + ret = regmap_update_bits(info->rtc, SEC_WTSR_SMPL_CNTL, + WTSR_ENABLE_MASK, + enable ? WTSR_ENABLE_MASK : 0); + if (ret < 0) + dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", + __func__, ret); +} + +static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable) +{ + int ret; + ret = regmap_update_bits(info->rtc, SEC_WTSR_SMPL_CNTL, + SMPL_ENABLE_MASK, + enable ? SMPL_ENABLE_MASK : 0); + if (ret < 0) + dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", + __func__, ret); +} + +static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) +{ + u8 data[2]; + unsigned int tp_read; + int ret; + struct rtc_time tm; + + ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &tp_read); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read control reg(%d)\n", + __func__, ret); + return ret; + } + + /* Set RTC control register : Binary mode, 24hour mode */ + data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + + info->rtc_24hr_mode = 1; + ret = regmap_raw_write(info->rtc, SEC_ALARM0_CONF, data, 2); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", + __func__, ret); + return ret; + } + + /* In first boot time, Set rtc time to 1/1/2012 00:00:00(SUN) */ + if ((tp_read & RTC_TCON_MASK) == 0) { + dev_dbg(info->dev, "rtc init\n"); + tm.tm_sec = 0; + tm.tm_min = 0; + tm.tm_hour = 0; + tm.tm_wday = 0; + tm.tm_mday = 1; + tm.tm_mon = 0; + tm.tm_year = 112; + tm.tm_yday = 0; + tm.tm_isdst = 0; + ret = s5m_rtc_set_time(info->dev, &tm); + } + + ret = regmap_update_bits(info->rtc, SEC_RTC_UDR_CON, + RTC_TCON_MASK, tp_read | RTC_TCON_MASK); + if (ret < 0) + dev_err(info->dev, "%s: fail to update TCON reg(%d)\n", + __func__, ret); + + return ret; +} + +static int s5m_rtc_probe(struct platform_device *pdev) +{ + struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent); + struct sec_platform_data *pdata = s5m87xx->pdata; + struct s5m_rtc_info *info; + int ret; + + if (!pdata) { + dev_err(pdev->dev.parent, "Platform data not supplied\n"); + return -ENODEV; + } + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = &pdev->dev; + info->s5m87xx = s5m87xx; + info->rtc = s5m87xx->rtc; + info->device_type = s5m87xx->device_type; + info->wtsr_smpl = s5m87xx->wtsr_smpl; + + switch (pdata->device_type) { + case S5M8763X: + info->irq = s5m87xx->irq_base + S5M8763_IRQ_ALARM0; + break; + + case S5M8767X: + info->irq = s5m87xx->irq_base + S5M8767_IRQ_RTCA1; + break; + + default: + ret = -EINVAL; + dev_err(&pdev->dev, "Unsupported device type: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, info); + + ret = s5m8767_rtc_init_reg(info); + + if (info->wtsr_smpl) { + s5m_rtc_enable_wtsr(info, true); + s5m_rtc_enable_smpl(info, true); + } + + device_init_wakeup(&pdev->dev, 1); + + info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", + &s5m_rtc_ops, THIS_MODULE); + + if (IS_ERR(info->rtc_dev)) + return PTR_ERR(info->rtc_dev); + + ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, + s5m_rtc_alarm_irq, 0, "rtc-alarm0", + info); + if (ret < 0) + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->irq, ret); + + return ret; +} + +static void s5m_rtc_shutdown(struct platform_device *pdev) +{ + struct s5m_rtc_info *info = platform_get_drvdata(pdev); + int i; + unsigned int val = 0; + if (info->wtsr_smpl) { + for (i = 0; i < 3; i++) { + s5m_rtc_enable_wtsr(info, false); + regmap_read(info->rtc, SEC_WTSR_SMPL_CNTL, &val); + pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); + if (val & WTSR_ENABLE_MASK) + pr_emerg("%s: fail to disable WTSR\n", + __func__); + else { + pr_info("%s: success to disable WTSR\n", + __func__); + break; + } + } + } + /* Disable SMPL when power off */ + s5m_rtc_enable_smpl(info, false); +} + +static const struct platform_device_id s5m_rtc_id[] = { + { "s5m-rtc", 0 }, +}; + +static struct platform_driver s5m_rtc_driver = { + .driver = { + .name = "s5m-rtc", + .owner = THIS_MODULE, + }, + .probe = s5m_rtc_probe, + .shutdown = s5m_rtc_shutdown, + .id_table = s5m_rtc_id, +}; + +module_platform_driver(s5m_rtc_driver); + +/* Module information */ +MODULE_AUTHOR("Sangbeom Kim "); +MODULE_DESCRIPTION("Samsung S5M RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s5m-rtc"); diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 378ae8a..2d0c907 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -51,6 +51,7 @@ struct sec_pmic_dev { int ono; int type; bool wakeup; + bool wtsr_smpl; }; int sec_irq_init(struct sec_pmic_dev *sec_pmic); diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h index 71597e2..94b7cd6 100644 --- a/include/linux/mfd/samsung/rtc.h +++ b/include/linux/mfd/samsung/rtc.h @@ -62,6 +62,11 @@ enum sec_rtc_reg { /* RTC Update Register1 */ #define RTC_UDR_SHIFT 0 #define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +#define RTC_TCON_SHIFT 1 +#define RTC_TCON_MASK (1 << RTC_TCON_SHIFT) +#define RTC_TIME_EN_SHIFT 3 +#define RTC_TIME_EN_MASK (1 << RTC_TIME_EN_SHIFT) + /* RTC Hour register */ #define HOUR_PM_SHIFT 6 #define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) @@ -69,6 +74,12 @@ enum sec_rtc_reg { #define ALARM_ENABLE_SHIFT 7 #define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) +#define SMPL_ENABLE_SHIFT 7 +#define SMPL_ENABLE_MASK (1 << SMPL_ENABLE_SHIFT) + +#define WTSR_ENABLE_SHIFT 6 +#define WTSR_ENABLE_MASK (1 << WTSR_ENABLE_SHIFT) + enum { RTC_SEC = 0, RTC_MIN, -- cgit v0.10.2 From b45062619840a56c090bab57df7b0fb36a30c2af Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 12 Nov 2013 15:11:05 -0800 Subject: drivers/rtc/rtc-as3722: add RTC driver The ams AS3722 is a compact system PMU suitable for mobile phones, tablets etc. Add a driver to support accessing the RTC found on the ams AS3722 PMIC using RTC framework. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Laxman Dewangan Signed-off-by: Florian Lobmaier Cc: Mark Brown Cc: Linus Walleij Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4f48b9a..15f166a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -153,6 +153,16 @@ config RTC_DRV_88PM80X This driver can also be built as a module. If so, the module will be called rtc-88pm80x. +config RTC_DRV_AS3722 + tristate "ams AS3722 RTC driver" + depends on MFD_AS3722 + help + If you say yes here you get support for the RTC of ams AS3722 PMIC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-as3722. + config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 9312e79..27b4bd8 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o +obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c new file mode 100644 index 0000000..9cfa817 --- /dev/null +++ b/drivers/rtc/rtc-as3722.c @@ -0,0 +1,275 @@ +/* + * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs + * + * Copyright (C) 2013 ams AG + * Copyright (c) 2013, NVIDIA Corporation. All rights reserved. + * + * Author: Florian Lobmaier + * Author: Laxman Dewangan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AS3722_RTC_START_YEAR 2000 +struct as3722_rtc { + struct rtc_device *rtc; + struct device *dev; + struct as3722 *as3722; + int alarm_irq; + bool irq_enable; +}; + +static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm) +{ + rbuff[0] = bin2bcd(tm->tm_sec); + rbuff[1] = bin2bcd(tm->tm_min); + rbuff[2] = bin2bcd(tm->tm_hour); + rbuff[3] = bin2bcd(tm->tm_mday); + rbuff[4] = bin2bcd(tm->tm_mon); + rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900)); +} + +static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(rbuff[0] & 0x7F); + tm->tm_min = bcd2bin(rbuff[1] & 0x7F); + tm->tm_hour = bcd2bin(rbuff[2] & 0x3F); + tm->tm_mday = bcd2bin(rbuff[3] & 0x3F); + tm->tm_mon = bcd2bin(rbuff[4] & 0x1F); + tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F); + return; +} + +static int as3722_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + struct as3722 *as3722 = as3722_rtc->as3722; + u8 as_time_array[6]; + int ret; + + ret = as3722_block_read(as3722, AS3722_RTC_SECOND_REG, + 6, as_time_array); + if (ret < 0) { + dev_err(dev, "RTC_SECOND reg block read failed %d\n", ret); + return ret; + } + as3722_reg_to_time(as_time_array, tm); + return 0; +} + +static int as3722_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + struct as3722 *as3722 = as3722_rtc->as3722; + u8 as_time_array[6]; + int ret; + + if (tm->tm_year < (AS3722_RTC_START_YEAR - 1900)) + return -EINVAL; + + as3722_time_to_reg(as_time_array, tm); + ret = as3722_block_write(as3722, AS3722_RTC_SECOND_REG, 6, + as_time_array); + if (ret < 0) + dev_err(dev, "RTC_SECOND reg block write failed %d\n", ret); + return ret; +} + +static int as3722_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + + if (enabled && !as3722_rtc->irq_enable) { + enable_irq(as3722_rtc->alarm_irq); + as3722_rtc->irq_enable = true; + } else if (!enabled && as3722_rtc->irq_enable) { + disable_irq(as3722_rtc->alarm_irq); + as3722_rtc->irq_enable = false; + } + return 0; +} + +static int as3722_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + struct as3722 *as3722 = as3722_rtc->as3722; + u8 as_time_array[6]; + int ret; + + ret = as3722_block_read(as3722, AS3722_RTC_ALARM_SECOND_REG, 6, + as_time_array); + if (ret < 0) { + dev_err(dev, "RTC_ALARM_SECOND block read failed %d\n", ret); + return ret; + } + + as3722_reg_to_time(as_time_array, &alrm->time); + return 0; +} + +static int as3722_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + struct as3722 *as3722 = as3722_rtc->as3722; + u8 as_time_array[6]; + int ret; + + if (alrm->time.tm_year < (AS3722_RTC_START_YEAR - 1900)) + return -EINVAL; + + ret = as3722_rtc_alarm_irq_enable(dev, 0); + if (ret < 0) { + dev_err(dev, "Disable RTC alarm failed\n"); + return ret; + } + + as3722_time_to_reg(as_time_array, &alrm->time); + ret = as3722_block_write(as3722, AS3722_RTC_ALARM_SECOND_REG, 6, + as_time_array); + if (ret < 0) { + dev_err(dev, "RTC_ALARM_SECOND block write failed %d\n", ret); + return ret; + } + + if (alrm->enabled) + ret = as3722_rtc_alarm_irq_enable(dev, alrm->enabled); + return ret; +} + +static irqreturn_t as3722_alarm_irq(int irq, void *data) +{ + struct as3722_rtc *as3722_rtc = data; + + rtc_update_irq(as3722_rtc->rtc, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; +} + +static const struct rtc_class_ops as3722_rtc_ops = { + .read_time = as3722_rtc_read_time, + .set_time = as3722_rtc_set_time, + .read_alarm = as3722_rtc_read_alarm, + .set_alarm = as3722_rtc_set_alarm, + .alarm_irq_enable = as3722_rtc_alarm_irq_enable, +}; + +static int as3722_rtc_probe(struct platform_device *pdev) +{ + struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent); + struct as3722_rtc *as3722_rtc; + int ret; + + as3722_rtc = devm_kzalloc(&pdev->dev, sizeof(*as3722_rtc), GFP_KERNEL); + if (!as3722_rtc) + return -ENOMEM; + + as3722_rtc->as3722 = as3722; + as3722_rtc->dev = &pdev->dev; + platform_set_drvdata(pdev, as3722_rtc); + + /* Enable the RTC to make sure it is running. */ + ret = as3722_update_bits(as3722, AS3722_RTC_CONTROL_REG, + AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN, + AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN); + if (ret < 0) { + dev_err(&pdev->dev, "RTC_CONTROL reg write failed: %d\n", ret); + return ret; + } + + device_init_wakeup(&pdev->dev, 1); + + as3722_rtc->rtc = rtc_device_register("as3722", &pdev->dev, + &as3722_rtc_ops, THIS_MODULE); + if (IS_ERR(as3722_rtc->rtc)) { + ret = PTR_ERR(as3722_rtc->rtc); + dev_err(&pdev->dev, "RTC register failed: %d\n", ret); + return ret; + } + + as3722_rtc->alarm_irq = platform_get_irq(pdev, 0); + dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq); + + ret = request_threaded_irq(as3722_rtc->alarm_irq, NULL, + as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME, + "rtc-alarm", as3722_rtc); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", + as3722_rtc->alarm_irq, ret); + goto scrub; + } + disable_irq(as3722_rtc->alarm_irq); + return 0; +scrub: + rtc_device_unregister(as3722_rtc->rtc); + return ret; +} + +static int as3722_rtc_remove(struct platform_device *pdev) +{ + struct as3722_rtc *as3722_rtc = platform_get_drvdata(pdev); + + free_irq(as3722_rtc->alarm_irq, as3722_rtc); + rtc_device_unregister(as3722_rtc->rtc); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int as3722_rtc_suspend(struct device *dev) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(as3722_rtc->alarm_irq); + + return 0; +} + +static int as3722_rtc_resume(struct device *dev) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(as3722_rtc->alarm_irq); + return 0; +} +#endif + +static const struct dev_pm_ops as3722_rtc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(as3722_rtc_suspend, as3722_rtc_resume) +}; + +static struct platform_driver as3722_rtc_driver = { + .probe = as3722_rtc_probe, + .remove = as3722_rtc_remove, + .driver = { + .name = "as3722-rtc", + .pm = &as3722_rtc_pm_ops, + }, +}; +module_platform_driver(as3722_rtc_driver); + +MODULE_DESCRIPTION("RTC driver for AS3722 PMICs"); +MODULE_ALIAS("platform:as3722-rtc"); +MODULE_AUTHOR("Florian Lobmaier "); +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 74a797d99a9fa4871ca978ac65e0f3a90dcf84d8 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Tue, 12 Nov 2013 15:11:06 -0800 Subject: fs/hfs/btree.h: remove duplicate defines This patch removes duplicate defines from fs/hfs/btree.h [akpm@linux-foundation.org: retain the comments] Signed-off-by: Michael Opdenacker Reviewed-by: Vyacheslav Dubeyko Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/hfs/btree.h b/fs/hfs/btree.h index 2a1d712..f6bd266 100644 --- a/fs/hfs/btree.h +++ b/fs/hfs/btree.h @@ -153,11 +153,6 @@ struct hfs_btree_header_rec { u32 reserved3[16]; } __packed; -#define HFS_NODE_INDEX 0x00 /* An internal (index) node */ -#define HFS_NODE_HEADER 0x01 /* The tree header node (node 0) */ -#define HFS_NODE_MAP 0x02 /* Holds part of the bitmap of used nodes */ -#define HFS_NODE_LEAF 0xFF /* A leaf (ndNHeight==1) node */ - #define BTREE_ATTR_BADCLOSE 0x00000001 /* b-tree not closed properly. not used by hfsplus. */ #define HFS_TREE_BIGKEYS 0x00000002 /* key length is u16 instead of u8. diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index 452ede0..2c54dd8 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h @@ -156,10 +156,10 @@ struct hfs_bnode_desc { } __packed; /* HFS+ BTree node types */ -#define HFS_NODE_INDEX 0x00 -#define HFS_NODE_HEADER 0x01 -#define HFS_NODE_MAP 0x02 -#define HFS_NODE_LEAF 0xFF +#define HFS_NODE_INDEX 0x00 /* An internal (index) node */ +#define HFS_NODE_HEADER 0x01 /* The tree header node (node 0) */ +#define HFS_NODE_MAP 0x02 /* Holds part of the bitmap of used nodes */ +#define HFS_NODE_LEAF 0xFF /* A leaf (ndNHeight==1) node */ /* HFS+ BTree header */ struct hfs_btree_header_rec { -- cgit v0.10.2 From b3b5b0f03cc4ea074ed0ac110d0afd17e0ccdf9e Mon Sep 17 00:00:00 2001 From: Vyacheslav Dubeyko Date: Tue, 12 Nov 2013 15:11:07 -0800 Subject: hfsplus: add metadata file's clump size calculation functionality There are situation when HFS+ volume had been created without AttributesFile. Such situation can take place because of using old mkfs.hfs utility or creation HFS+ volume without taking in mind necessity to use xattrs. For example, Mac OS X 10.4 (Tiger) doesn't create AttributesFile during mkfs phase. Also it is a very frequent situation for the case of users that created HFS+ volumes under Linux. As a result, xattrs and POSIX ACLs on HFS+ volume are unavailable for such users. This patchset implements functionality of AttributesFile creation on HFS+ volume in the case of this metadata file absence during operation of xattr creation. This patch: Add functionality of metadata file's clump size calculation. Operation of AttributesFile creation needs in clump size setting. This value will be used when AttributesFile will be extended. This code is adopted from code of newfs_hfs utility of diskdev_cmds packet http://opensource.apple.com/tarballs/diskdev_cmds/. Signed-off-by: Vyacheslav Dubeyko Cc: Al Viro Cc: Christoph Hellwig Cc: Hin-Tak Leung Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 0c6540c..0fcec8b 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c @@ -15,6 +15,118 @@ #include "hfsplus_fs.h" #include "hfsplus_raw.h" +/* + * Initial source code of clump size calculation is gotten + * from http://opensource.apple.com/tarballs/diskdev_cmds/ + */ +#define CLUMP_ENTRIES 15 + +static short clumptbl[CLUMP_ENTRIES * 3] = { +/* + * Volume Attributes Catalog Extents + * Size Clump (MB) Clump (MB) Clump (MB) + */ + /* 1GB */ 4, 4, 4, + /* 2GB */ 6, 6, 4, + /* 4GB */ 8, 8, 4, + /* 8GB */ 11, 11, 5, + /* + * For volumes 16GB and larger, we want to make sure that a full OS + * install won't require fragmentation of the Catalog or Attributes + * B-trees. We do this by making the clump sizes sufficiently large, + * and by leaving a gap after the B-trees for them to grow into. + * + * For SnowLeopard 10A298, a FullNetInstall with all packages selected + * results in: + * Catalog B-tree Header + * nodeSize: 8192 + * totalNodes: 31616 + * freeNodes: 1978 + * (used = 231.55 MB) + * Attributes B-tree Header + * nodeSize: 8192 + * totalNodes: 63232 + * freeNodes: 958 + * (used = 486.52 MB) + * + * We also want Time Machine backup volumes to have a sufficiently + * large clump size to reduce fragmentation. + * + * The series of numbers for Catalog and Attribute form a geometric + * series. For Catalog (16GB to 512GB), each term is 8**(1/5) times + * the previous term. For Attributes (16GB to 512GB), each term is + * 4**(1/5) times the previous term. For 1TB to 16TB, each term is + * 2**(1/5) times the previous term. + */ + /* 16GB */ 64, 32, 5, + /* 32GB */ 84, 49, 6, + /* 64GB */ 111, 74, 7, + /* 128GB */ 147, 111, 8, + /* 256GB */ 194, 169, 9, + /* 512GB */ 256, 256, 11, + /* 1TB */ 294, 294, 14, + /* 2TB */ 338, 338, 16, + /* 4TB */ 388, 388, 20, + /* 8TB */ 446, 446, 25, + /* 16TB */ 512, 512, 32 +}; + +u32 hfsplus_calc_btree_clump_size(u32 block_size, u32 node_size, + u64 sectors, int file_id) +{ + u32 mod = max(node_size, block_size); + u32 clump_size; + int column; + int i; + + /* Figure out which column of the above table to use for this file. */ + switch (file_id) { + case HFSPLUS_ATTR_CNID: + column = 0; + break; + case HFSPLUS_CAT_CNID: + column = 1; + break; + default: + column = 2; + break; + } + + /* + * The default clump size is 0.8% of the volume size. And + * it must also be a multiple of the node and block size. + */ + if (sectors < 0x200000) { + clump_size = sectors << 2; /* 0.8 % */ + if (clump_size < (8 * node_size)) + clump_size = 8 * node_size; + } else { + /* turn exponent into table index... */ + for (i = 0, sectors = sectors >> 22; + sectors && (i < CLUMP_ENTRIES - 1); + ++i, sectors = sectors >> 1) { + /* empty body */ + } + + clump_size = clumptbl[column + (i) * 3] * 1024 * 1024; + } + + /* + * Round the clump size to a multiple of node and block size. + * NOTE: This rounds down. + */ + clump_size /= mod; + clump_size *= mod; + + /* + * Rounding down could have rounded down to 0 if the block size was + * greater than the clump size. If so, just use one block or node. + */ + if (clump_size == 0) + clump_size = mod; + + return clump_size; +} /* Get a reference to a B*Tree and do some initial checks */ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 2b9cd01..1e36f18 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -380,6 +380,7 @@ int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *); int hfsplus_block_free(struct super_block *, u32, u32); /* btree.c */ +u32 hfsplus_calc_btree_clump_size(u32, u32, u64, int); struct hfs_btree *hfs_btree_open(struct super_block *, u32); void hfs_btree_close(struct hfs_btree *); int hfs_btree_write(struct hfs_btree *); -- cgit v0.10.2 From 099e9245e04d50bb12ed621b4fa61df0a4c9dba9 Mon Sep 17 00:00:00 2001 From: Vyacheslav Dubeyko Date: Tue, 12 Nov 2013 15:11:08 -0800 Subject: hfsplus: implement attributes file's header node initialization code Implement functionality of AttributesFile's header node initialization. Signed-off-by: Vyacheslav Dubeyko Cc: Al Viro Cc: Christoph Hellwig Cc: Hin-Tak Leung Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index 2c54dd8..8ffb3a8 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h @@ -187,6 +187,9 @@ struct hfs_btree_header_rec { /* HFS+ BTree misc info */ #define HFSPLUS_TREE_HEAD 0 #define HFSPLUS_NODE_MXSZ 32768 +#define HFSPLUS_ATTR_TREE_NODE_SIZE 8192 +#define HFSPLUS_BTREE_HDR_NODE_RECS_COUNT 3 +#define HFSPLUS_BTREE_HDR_USER_BYTES 128 /* Some special File ID numbers (stolen from hfs.h) */ #define HFSPLUS_POR_CNID 1 /* Parent Of the Root */ diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index bd8471f..568a45c 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -127,6 +127,71 @@ static int can_set_xattr(struct inode *inode, const char *name, return 0; } +static void hfsplus_init_header_node(struct inode *attr_file, + u32 clump_size, + char *buf, size_t node_size) +{ + struct hfs_bnode_desc *desc; + struct hfs_btree_header_rec *head; + u16 offset; + __be16 *rec_offsets; + u32 hdr_node_map_rec_bits; + char *bmp; + u32 used_nodes; + u32 used_bmp_bytes; + + hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %zu\n", + clump_size, node_size); + + /* The end of the node contains list of record offsets */ + rec_offsets = (__be16 *)(buf + node_size); + + desc = (struct hfs_bnode_desc *)buf; + desc->type = HFS_NODE_HEADER; + desc->num_recs = cpu_to_be16(HFSPLUS_BTREE_HDR_NODE_RECS_COUNT); + offset = sizeof(struct hfs_bnode_desc); + *--rec_offsets = cpu_to_be16(offset); + + head = (struct hfs_btree_header_rec *)(buf + offset); + head->node_size = cpu_to_be16(node_size); + head->node_count = cpu_to_be32(i_size_read(attr_file) / node_size); + head->free_nodes = cpu_to_be32(be32_to_cpu(head->node_count) - 1); + head->clump_size = cpu_to_be32(clump_size); + head->attributes |= cpu_to_be32(HFS_TREE_BIGKEYS | HFS_TREE_VARIDXKEYS); + head->max_key_len = cpu_to_be16(HFSPLUS_ATTR_KEYLEN - sizeof(u16)); + offset += sizeof(struct hfs_btree_header_rec); + *--rec_offsets = cpu_to_be16(offset); + offset += HFSPLUS_BTREE_HDR_USER_BYTES; + *--rec_offsets = cpu_to_be16(offset); + + hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16))); + if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) { + u32 map_node_bits; + u32 map_nodes; + + desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1); + map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) - + (2 * sizeof(u16)) - 2); + map_nodes = (be32_to_cpu(head->node_count) - + hdr_node_map_rec_bits + + (map_node_bits - 1)) / map_node_bits; + be32_add_cpu(&head->free_nodes, 0 - map_nodes); + } + + bmp = buf + offset; + used_nodes = + be32_to_cpu(head->node_count) - be32_to_cpu(head->free_nodes); + used_bmp_bytes = used_nodes / 8; + if (used_bmp_bytes) { + memset(bmp, 0xFF, used_bmp_bytes); + bmp += used_bmp_bytes; + used_nodes %= 8; + } + *bmp = ~(0xFF >> used_nodes); + offset += hdr_node_map_rec_bits / 8; + *--rec_offsets = cpu_to_be16(offset); +} + int __hfsplus_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags) { -- cgit v0.10.2 From 95e0d7dbb9b28ab0dfad7c7316066b05e1f1d4cd Mon Sep 17 00:00:00 2001 From: Vyacheslav Dubeyko Date: Tue, 12 Nov 2013 15:11:09 -0800 Subject: hfsplus: implement attributes file creation functionality Implement functionality of creation AttributesFile metadata file on HFS+ volume in the case of absence of it. It makes trying to open AttributesFile's B-tree during mount of HFS+ volume. If HFS+ volume hasn't AttributesFile then a pointer on AttributesFile's B-tree keeps as NULL. Thereby, when it is discovered absence of AttributesFile on HFS+ volume in the begin of xattr creation operation then AttributesFile will be created. The creation of AttributesFile will have success in the case of availability (2 * clump) free blocks on HFS+ volume. Otherwise, creation operation is ended with error (-ENOSPC). Signed-off-by: Vyacheslav Dubeyko Cc: Al Viro Cc: Christoph Hellwig Acked-by: Hin-Tak Leung Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 1e36f18..08846425b 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -127,6 +127,14 @@ struct hfs_bnode { #define HFS_BNODE_DELETED 4 /* + * Attributes file states + */ +#define HFSPLUS_EMPTY_ATTR_TREE 0 +#define HFSPLUS_CREATING_ATTR_TREE 1 +#define HFSPLUS_VALID_ATTR_TREE 2 +#define HFSPLUS_FAILED_ATTR_TREE 3 + +/* * HFS+ superblock info (built from Volume Header on disk) */ @@ -141,6 +149,7 @@ struct hfsplus_sb_info { struct hfs_btree *ext_tree; struct hfs_btree *cat_tree; struct hfs_btree *attr_tree; + atomic_t attr_tree_state; struct inode *alloc_file; struct inode *hidden_dir; struct nls_table *nls; diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 4c4d142..80875aa 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -474,12 +474,14 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) pr_err("failed to load catalog file\n"); goto out_close_ext_tree; } + atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE); if (vhdr->attr_file.total_blocks != 0) { sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); if (!sbi->attr_tree) { pr_err("failed to load attributes file\n"); goto out_close_cat_tree; } + atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE); } sb->s_xattr = hfsplus_xattr_handlers; diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index 568a45c..efc85b1 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -192,6 +192,143 @@ static void hfsplus_init_header_node(struct inode *attr_file, *--rec_offsets = cpu_to_be16(offset); } +static int hfsplus_create_attributes_file(struct super_block *sb) +{ + int err = 0; + struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); + struct inode *attr_file; + struct hfsplus_inode_info *hip; + u32 clump_size; + u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE; + char *buf; + int index, written; + struct address_space *mapping; + struct page *page; + int old_state = HFSPLUS_EMPTY_ATTR_TREE; + + hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID); + +check_attr_tree_state_again: + switch (atomic_read(&sbi->attr_tree_state)) { + case HFSPLUS_EMPTY_ATTR_TREE: + if (old_state != atomic_cmpxchg(&sbi->attr_tree_state, + old_state, + HFSPLUS_CREATING_ATTR_TREE)) + goto check_attr_tree_state_again; + break; + case HFSPLUS_CREATING_ATTR_TREE: + /* + * This state means that another thread is in process + * of AttributesFile creation. Theoretically, it is + * possible to be here. But really __setxattr() method + * first of all calls hfs_find_init() for lookup in + * B-tree of CatalogFile. This method locks mutex of + * CatalogFile's B-tree. As a result, if some thread + * is inside AttributedFile creation operation then + * another threads will be waiting unlocking of + * CatalogFile's B-tree's mutex. However, if code will + * change then we will return error code (-EAGAIN) from + * here. Really, it means that first try to set of xattr + * fails with error but second attempt will have success. + */ + return -EAGAIN; + case HFSPLUS_VALID_ATTR_TREE: + return 0; + case HFSPLUS_FAILED_ATTR_TREE: + return -EOPNOTSUPP; + default: + BUG(); + } + + attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID); + if (IS_ERR(attr_file)) { + pr_err("failed to load attributes file\n"); + return PTR_ERR(attr_file); + } + + BUG_ON(i_size_read(attr_file) != 0); + + hip = HFSPLUS_I(attr_file); + + clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize, + node_size, + sbi->sect_count, + HFSPLUS_ATTR_CNID); + + mutex_lock(&hip->extents_lock); + hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift; + mutex_unlock(&hip->extents_lock); + + if (sbi->free_blocks <= (hip->clump_blocks << 1)) { + err = -ENOSPC; + goto end_attr_file_creation; + } + + while (hip->alloc_blocks < hip->clump_blocks) { + err = hfsplus_file_extend(attr_file); + if (unlikely(err)) { + pr_err("failed to extend attributes file\n"); + goto end_attr_file_creation; + } + hip->phys_size = attr_file->i_size = + (loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift; + hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift; + inode_set_bytes(attr_file, attr_file->i_size); + } + + buf = kzalloc(node_size, GFP_NOFS); + if (!buf) { + pr_err("failed to allocate memory for header node\n"); + err = -ENOMEM; + goto end_attr_file_creation; + } + + hfsplus_init_header_node(attr_file, clump_size, buf, node_size); + + mapping = attr_file->i_mapping; + + index = 0; + written = 0; + for (; written < node_size; index++, written += PAGE_CACHE_SIZE) { + void *kaddr; + + page = read_mapping_page(mapping, index, NULL); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto failed_header_node_init; + } + + kaddr = kmap_atomic(page); + memcpy(kaddr, buf + written, + min_t(size_t, PAGE_CACHE_SIZE, node_size - written)); + kunmap_atomic(kaddr); + + set_page_dirty(page); + page_cache_release(page); + } + + hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY); + + sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); + if (!sbi->attr_tree) + pr_err("failed to load attributes file\n"); + +failed_header_node_init: + kfree(buf); + +end_attr_file_creation: + iput(attr_file); + + if (!err) + atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE); + else if (err == -ENOSPC) + atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE); + else + atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE); + + return err; +} + int __hfsplus_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags) { @@ -276,8 +413,9 @@ int __hfsplus_setxattr(struct inode *inode, const char *name, } if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { - err = -EOPNOTSUPP; - goto end_setxattr; + err = hfsplus_create_attributes_file(inode->i_sb); + if (unlikely(err)) + goto end_setxattr; } if (hfsplus_attr_exists(inode, name)) { -- cgit v0.10.2 From 965fd2968a5daf66c21a21a539528f6d3ec7c53b Mon Sep 17 00:00:00 2001 From: Luis Ortega Perez de Villar Date: Tue, 12 Nov 2013 15:11:10 -0800 Subject: Documentation/filesystems/vfat.txt: fix directory entry example Slots can store up to 13 characters for the file name but one of the examples has one character too many. Signed-off-by: Luis Ortega Perez de Villar Acked-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt index aa1f459..4a93e98 100644 --- a/Documentation/filesystems/vfat.txt +++ b/Documentation/filesystems/vfat.txt @@ -307,7 +307,7 @@ the following: - + -- cgit v0.10.2 From c7708649ccbdc21e85c95ca1a01b28342d939d39 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Tue, 12 Nov 2013 15:11:11 -0800 Subject: Documentation/trace/tracepoints.txt: add links to TRACE_EVENT documentation Existing tracepoint documentation doesn't mention the popular TRACE_EVENT macro. Since an excellent series of articles on proper usage already exists, respective links are added to the existing documentation. Signed-off-by: Stefan Raspl Cc: Rob Landley Cc: Jiri Kosina Acked-by: Mathieu Desnoyers Cc: Zoltan Kiss Cc: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/trace/tracepoints.txt b/Documentation/trace/tracepoints.txt index ac4170d..6b018b5 100644 --- a/Documentation/trace/tracepoints.txt +++ b/Documentation/trace/tracepoints.txt @@ -114,3 +114,8 @@ core kernel image or in modules. If the tracepoint has to be used in kernel modules, an EXPORT_TRACEPOINT_SYMBOL_GPL() or EXPORT_TRACEPOINT_SYMBOL() can be used to export the defined tracepoints. + +Note: The convenience macro TRACE_EVENT provides an alternative way to + define tracepoints. Check http://lwn.net/Articles/379903, + http://lwn.net/Articles/381064 and http://lwn.net/Articles/383362 + for a series of articles with more details. -- cgit v0.10.2 From e946c43a116526e3d947dc03aeb165c1effd9f8f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 12 Nov 2013 15:11:12 -0800 Subject: kernel-doc: improve "no structured comments found" error When using '!Ffile function' in a docbook template, and the function no longer exists, you get a "no structured comments found" error from the kernel-doc processing script. It's useful to know which functions it was looking for, so print them out in this case. Also do the same for '!Pfile doc-section' The same error also happens when using '!Efile' when some exported functions aren't documented (in the same file.) There's a very large number of such functions though, so don't print the message in this case -- right now it would give ~850 messages. Signed-off-by: Johannes Berg Cc: Rob Landley Cc: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/docproc.c b/scripts/docproc.c index 4cfdc17..2b69eaf 100644 --- a/scripts/docproc.c +++ b/scripts/docproc.c @@ -72,6 +72,7 @@ FILELINE * docsection; #define FUNCTION "-function" #define NOFUNCTION "-nofunction" #define NODOCSECTIONS "-no-doc-sections" +#define SHOWNOTFOUND "-show-not-found" static char *srctree, *kernsrctree; @@ -294,6 +295,7 @@ static void singfunc(char * filename, char * line) int startofsym = 1; vec[idx++] = KERNELDOC; vec[idx++] = DOCBOOK; + vec[idx++] = SHOWNOTFOUND; /* Split line up in individual parameters preceded by FUNCTION */ for (i=0; line[i]; i++) { @@ -325,7 +327,8 @@ static void singfunc(char * filename, char * line) */ static void docsect(char *filename, char *line) { - char *vec[6]; /* kerneldoc -docbook -function "section" file NULL */ + /* kerneldoc -docbook -show-not-found -function "section" file NULL */ + char *vec[7]; char *s; for (s = line; *s; s++) @@ -341,10 +344,11 @@ static void docsect(char *filename, char *line) vec[0] = KERNELDOC; vec[1] = DOCBOOK; - vec[2] = FUNCTION; - vec[3] = line; - vec[4] = filename; - vec[5] = NULL; + vec[2] = SHOWNOTFOUND; + vec[3] = FUNCTION; + vec[4] = line; + vec[5] = filename; + vec[6] = NULL; exec_kernel_doc(vec); } diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 4305b2f..dbd3e1e 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -257,6 +257,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')[(localtime)[4]] . " " . ((localtime)[5]+1900); +my $show_not_found = 0; # Essentially these are globals. # They probably want to be tidied up, made more localised or something. @@ -369,6 +370,8 @@ while ($ARGV[0] =~ m/^-(.*)/) { usage(); } elsif ($cmd eq '-no-doc-sections') { $no_doc_sections = 1; + } elsif ($cmd eq '-show-not-found') { + $show_not_found = 1; } } @@ -2536,6 +2539,9 @@ sub process_file($) { } if ($initial_section_counter == $section_counter) { print STDERR "Warning(${file}): no structured comments found\n"; + if (($function_only == 1) && ($show_not_found == 1)) { + print STDERR " Was looking for '$_'.\n" for keys %function_table; + } if ($output_mode eq "xml") { # The template wants at least one RefEntry here; make one. print "\n"; -- cgit v0.10.2 From ee2f51dc018e4dee06c6a6d52e821e27d701d650 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 12 Nov 2013 15:11:14 -0800 Subject: Documentation/ABI: document the non-ABI status of Kconfig and symbols Discussion at Kernel Summit made it clear that the presence or absence of specific Kconfig symbols are not considered ABI, and that no userspace (or bootloader, etc) should rely on them. In addition, kernel-internal symbols are well established as non-ABI, per Documentation/stable_api_nonsense.txt. Document both of these in Documentation/ABI/README, in a new section for notable bits of non-ABI. Signed-off-by: Josh Triplett Cc: Rob Landley Cc: Tao Ma Cc: Greg Kroah-Hartman Acked-by: H. Peter Anvin Cc: Richard Weinberger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/ABI/README b/Documentation/ABI/README index 1006982..1fafc4b 100644 --- a/Documentation/ABI/README +++ b/Documentation/ABI/README @@ -72,3 +72,16 @@ kernel tree without going through the obsolete state first. It's up to the developer to place their interfaces in the category they wish for it to start out in. + + +Notable bits of non-ABI, which should not under any circumstances be considered +stable: + +- Kconfig. Userspace should not rely on the presence or absence of any + particular Kconfig symbol, in /proc/config.gz, in the copy of .config + commonly installed to /boot, or in any invocation of the kernel build + process. + +- Kernel-internal symbols. Do not rely on the presence, absence, location, or + type of any kernel symbol, either in System.map files or the kernel binary + itself. See Documentation/stable_api_nonsense.txt. -- cgit v0.10.2 From 5721cf84d9d8d41915f77dd639969b7fa91b6a79 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke Date: Tue, 12 Nov 2013 15:11:15 -0800 Subject: procfs: clean up proc_reg_get_unmapped_area for 80-column limit Clean up proc_reg_get_unmapped_area due to its 80-column limit violation. Signed-off-by: HATAYAMA Daisuke Tested-by: Michael Holzheu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 8eaa1ba..28955d4 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -285,19 +285,23 @@ static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) return rv; } -static unsigned long proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) +static unsigned long +proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) { struct proc_dir_entry *pde = PDE(file_inode(file)); unsigned long rv = -EIO; - unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long) = NULL; + unsigned long (*get_area)(struct file *, unsigned long, unsigned long, + unsigned long, unsigned long) = NULL; if (use_pde(pde)) { #ifdef CONFIG_MMU - get_unmapped_area = current->mm->get_unmapped_area; + get_area = current->mm->get_unmapped_area; #endif if (pde->proc_fops->get_unmapped_area) - get_unmapped_area = pde->proc_fops->get_unmapped_area; - if (get_unmapped_area) - rv = get_unmapped_area(file, orig_addr, len, pgoff, flags); + get_area = pde->proc_fops->get_unmapped_area; + if (get_area) + rv = get_area(file, orig_addr, len, pgoff, flags); unuse_pde(pde); } return rv; -- cgit v0.10.2 From 1c3fc3e5cc8a81d21b199cb739d5d9c51f3688f4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 12 Nov 2013 15:11:16 -0800 Subject: kcore: add Kconfig help text Under Pseudo filesystems, /proc/kcore support has no help. Fixes a portion of kernel bugzilla #52671: https://bugzilla.kernel.org/show_bug.cgi?id=52671 Thanks for David Howells for the help text. Signed-off-by: Randy Dunlap Reported-by: Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index 15af622..2183fcf 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -31,6 +31,10 @@ config PROC_FS config PROC_KCORE bool "/proc/kcore support" if !ARM depends on PROC_FS && MMU + help + Provides a virtual ELF core file of the live kernel. This can + be read with gdb and other ELF tools. No modifications can be + made using this mechanism. config PROC_VMCORE bool "/proc/vmcore support" -- cgit v0.10.2 From d049f74f2dbe71354d43d393ac3a188947811348 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 12 Nov 2013 15:11:17 -0800 Subject: exec/ptrace: fix get_dumpable() incorrect tests The get_dumpable() return value is not boolean. Most users of the function actually want to be testing for non-SUID_DUMP_USER(1) rather than SUID_DUMP_DISABLE(0). The SUID_DUMP_ROOT(2) is also considered a protected state. Almost all places did this correctly, excepting the two places fixed in this patch. Wrong logic: if (dumpable == SUID_DUMP_DISABLE) { /* be protective */ } or if (dumpable == 0) { /* be protective */ } or if (!dumpable) { /* be protective */ } Correct logic: if (dumpable != SUID_DUMP_USER) { /* be protective */ } or if (dumpable != 1) { /* be protective */ } Without this patch, if the system had set the sysctl fs/suid_dumpable=2, a user was able to ptrace attach to processes that had dropped privileges to that user. (This may have been partially mitigated if Yama was enabled.) The macros have been moved into the file that declares get/set_dumpable(), which means things like the ia64 code can see them too. CVE-2013-2929 Reported-by: Vasily Kulikov Signed-off-by: Kees Cook Cc: "Luck, Tony" Cc: Oleg Nesterov Cc: "Eric W. Biederman" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h index e0a899a..5a84b3a 100644 --- a/arch/ia64/include/asm/processor.h +++ b/arch/ia64/include/asm/processor.h @@ -319,7 +319,7 @@ struct thread_struct { regs->loadrs = 0; \ regs->r8 = get_dumpable(current->mm); /* set "don't zap registers" flag */ \ regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ - if (unlikely(!get_dumpable(current->mm))) { \ + if (unlikely(get_dumpable(current->mm) != SUID_DUMP_USER)) { \ /* \ * Zap scratch regs to avoid leaking bits between processes with different \ * uid/privileges. \ diff --git a/fs/exec.c b/fs/exec.c index 2ea437e..1212062 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1669,6 +1669,12 @@ int __get_dumpable(unsigned long mm_flags) return (ret > SUID_DUMP_USER) ? SUID_DUMP_ROOT : ret; } +/* + * This returns the actual value of the suid_dumpable flag. For things + * that are using this for checking for privilege transitions, it must + * test against SUID_DUMP_USER rather than treating it as a boolean + * value. + */ int get_dumpable(struct mm_struct *mm) { return __get_dumpable(mm->flags); diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index e8112ae..7554fd4 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -99,9 +99,6 @@ extern void setup_new_exec(struct linux_binprm * bprm); extern void would_dump(struct linux_binprm *, struct file *); extern int suid_dumpable; -#define SUID_DUMP_DISABLE 0 /* No setuid dumping */ -#define SUID_DUMP_USER 1 /* Dump as user of process */ -#define SUID_DUMP_ROOT 2 /* Dump as root */ /* Stack area protections */ #define EXSTACK_DEFAULT 0 /* Whatever the arch defaults to */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 5e226fe..f7efc86 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -323,6 +323,10 @@ static inline void arch_pick_mmap_layout(struct mm_struct *mm) {} extern void set_dumpable(struct mm_struct *mm, int value); extern int get_dumpable(struct mm_struct *mm); +#define SUID_DUMP_DISABLE 0 /* No setuid dumping */ +#define SUID_DUMP_USER 1 /* Dump as user of process */ +#define SUID_DUMP_ROOT 2 /* Dump as root */ + /* mm flags */ /* dumpable bits */ #define MMF_DUMPABLE 0 /* core dump is permitted */ diff --git a/kernel/ptrace.c b/kernel/ptrace.c index dd562e9..1f4bcb3 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -257,7 +257,8 @@ ok: if (task->mm) dumpable = get_dumpable(task->mm); rcu_read_lock(); - if (!dumpable && !ptrace_has_cap(__task_cred(task)->user_ns, mode)) { + if (dumpable != SUID_DUMP_USER && + !ptrace_has_cap(__task_cred(task)->user_ns, mode)) { rcu_read_unlock(); return -EPERM; } -- cgit v0.10.2 From 1310a5a99d900ee30b9f171146406bde0c6c2bd4 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 12 Nov 2013 15:11:19 -0800 Subject: rbtree: fix rbtree_postorder_for_each_entry_safe() iterator The iterator rbtree_postorder_for_each_entry_safe() relies on pointer underflow behavior when testing for loop termination. In particular it expects that &rb_entry(NULL, type, field)->field is NULL. But the result of this expression is not defined by a C standard and some gcc versions (e.g. 4.3.4) assume the above expression can never be equal to NULL. The net result is an oops because the iteration is not properly terminated. Fix the problem by modifying the iterator to avoid pointer underflows. Signed-off-by: Jan Kara Signed-off-by: Cody P Schafer Cc: Michel Lespinasse Cc: "David S. Miller" Cc: Adrian Hunter Cc: Artem Bityutskiy Cc: David Woodhouse Cc: Jozsef Kadlecsik Cc: Pablo Neira Ayuso Cc: Patrick McHardy Cc: Paul Mundt Cc: Theodore Ts'o Cc: [3.12.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index aa870a4..57e75ae 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h @@ -85,6 +85,11 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, *rb_link = node; } +#define rb_entry_safe(ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? rb_entry(____ptr, type, member) : NULL; \ + }) + /** * rbtree_postorder_for_each_entry_safe - iterate over rb_root in post order of * given type safe against removal of rb_node entry @@ -95,12 +100,9 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, * @field: the name of the rb_node field within 'type'. */ #define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \ - for (pos = rb_entry(rb_first_postorder(root), typeof(*pos), field),\ - n = rb_entry(rb_next_postorder(&pos->field), \ - typeof(*pos), field); \ - &pos->field; \ - pos = n, \ - n = rb_entry(rb_next_postorder(&pos->field), \ - typeof(*pos), field)) + for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \ + pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \ + typeof(*pos), field); 1; }); \ + pos = n) #endif /* _LINUX_RBTREE_H */ -- cgit v0.10.2 From 7833819d2e5b2a0189f6e9d445ba03f4d7ba2656 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 12 Nov 2013 15:11:21 -0800 Subject: kernel/sysctl.c: check return value after call proc_put_char() in __do_proc_doulongvec_minmax() Need to check the return value of proc_put_char(), as was done in __do_proc_doulongvec_minmax(). Signed-off-by: Chen Gang Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 36547dd..d37d9dd 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2222,8 +2222,11 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int *i = val; } else { val = convdiv * (*i) / convmul; - if (!first) + if (!first) { err = proc_put_char(&buffer, &left, '\t'); + if (err) + break; + } err = proc_put_long(&buffer, &left, val, false); if (err) break; -- cgit v0.10.2 From f02147ef190b3963bb61ec0e140ec47f22889f38 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 12 Nov 2013 15:11:22 -0800 Subject: kernel/sysctl_binary.c: use scnprintf() instead of snprintf() snprintf() will return the 'ideal' length which may be larger than real buffer length, if we only want to use real length, need use scnprintf() instead of. Signed-off-by: Chen Gang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c index b609213..653cbbd 100644 --- a/kernel/sysctl_binary.c +++ b/kernel/sysctl_binary.c @@ -1024,7 +1024,7 @@ static ssize_t bin_intvec(struct file *file, if (get_user(value, vec + i)) goto out_kfree; - str += snprintf(str, end - str, "%lu\t", value); + str += scnprintf(str, end - str, "%lu\t", value); } result = kernel_write(file, buffer, str - buffer, 0); @@ -1095,7 +1095,7 @@ static ssize_t bin_ulongvec(struct file *file, if (get_user(value, vec + i)) goto out_kfree; - str += snprintf(str, end - str, "%lu\t", value); + str += scnprintf(str, end - str, "%lu\t", value); } result = kernel_write(file, buffer, str - buffer, 0); @@ -1205,7 +1205,7 @@ static ssize_t bin_dn_node_address(struct file *file, if (get_user(dnaddr, (__le16 __user *)newval)) goto out; - len = snprintf(buf, sizeof(buf), "%hu.%hu", + len = scnprintf(buf, sizeof(buf), "%hu.%hu", le16_to_cpu(dnaddr) >> 10, le16_to_cpu(dnaddr) & 0x3ff); -- cgit v0.10.2 From 3fa582663129330d57d15b97ae534dc1203fc3aa Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 12 Nov 2013 15:11:22 -0800 Subject: kernel/taskstats.c: add nla_nest_cancel() for failure processing between nla_nest_start() and nla_nest_end() When failure occurs between nla_nest_start() and nla_nest_end(), we should call nla_nest_cancel() to clean up related things. Signed-off-by: Chen Gang Cc: Balbir Singh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 145bb4d..1db6808 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -404,11 +404,15 @@ static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid) if (!na) goto err; - if (nla_put(skb, type, sizeof(pid), &pid) < 0) + if (nla_put(skb, type, sizeof(pid), &pid) < 0) { + nla_nest_cancel(skb, na); goto err; + } ret = nla_reserve(skb, TASKSTATS_TYPE_STATS, sizeof(struct taskstats)); - if (!ret) + if (!ret) { + nla_nest_cancel(skb, na); goto err; + } nla_nest_end(skb, na); return nla_data(ret); -- cgit v0.10.2 From 0d20633b041041ecda39ae562e62087acf0092f1 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 12 Nov 2013 15:11:23 -0800 Subject: kernel/taskstats.c: return -ENOMEM when alloc memory fails in add_del_listener() For registering in add_del_listener(), when kmalloc_node() fails, need return -ENOMEM instead of success code, and cmd_attr_register_cpumask() wants to know about it. After modification, give a simple common test "build -> boot up -> kernel/controllers/cgroup/getdelays by LTP tools". Signed-off-by: Chen Gang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 1db6808..9f4618e 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -290,6 +290,7 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd) struct listener_list *listeners; struct listener *s, *tmp, *s2; unsigned int cpu; + int ret = 0; if (!cpumask_subset(mask, cpu_possible_mask)) return -EINVAL; @@ -304,9 +305,10 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd) for_each_cpu(cpu, mask) { s = kmalloc_node(sizeof(struct listener), GFP_KERNEL, cpu_to_node(cpu)); - if (!s) + if (!s) { + ret = -ENOMEM; goto cleanup; - + } s->pid = pid; s->valid = 1; @@ -339,7 +341,7 @@ cleanup: } up_write(&listeners->sem); } - return 0; + return ret; } static int parse(struct nlattr *na, struct cpumask *mask) -- cgit v0.10.2 From 8cbce376e3fdf4a21f59365aefbb52eac3c2e312 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Tue, 12 Nov 2013 15:11:24 -0800 Subject: gcov: move gcov structs definitions to a gcc version specific file Since also the gcov structures(gcov_info, gcov_fn_info, gcov_ctr_info) can change between gcc releases, as shown in gcc 4.7, they cannot be defined in a common header and need to be moved to a specific gcc implemention file. This also requires to make the gcov_info structure opaque for the common code and to introduce simple helpers for accessing data inside gcov_info. Signed-off-by: Frantisek Hrbata Cc: Jan Stancek Cc: Kees Cook Acked-by: Peter Oberparleiter Cc: Rusty Russell Cc: Arnd Bergmann Cc: Andy Gospodarek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/gcov/base.c b/kernel/gcov/base.c index 9b22d03..912576a 100644 --- a/kernel/gcov/base.c +++ b/kernel/gcov/base.c @@ -20,7 +20,6 @@ #include #include "gcov.h" -static struct gcov_info *gcov_info_head; static int gcov_events_enabled; static DEFINE_MUTEX(gcov_lock); @@ -34,7 +33,7 @@ void __gcov_init(struct gcov_info *info) mutex_lock(&gcov_lock); if (gcov_version == 0) { - gcov_version = info->version; + gcov_version = gcov_info_version(info); /* * Printing gcc's version magic may prove useful for debugging * incompatibility reports. @@ -45,8 +44,7 @@ void __gcov_init(struct gcov_info *info) * Add new profiling data structure to list and inform event * listener. */ - info->next = gcov_info_head; - gcov_info_head = info; + gcov_info_link(info); if (gcov_events_enabled) gcov_event(GCOV_ADD, info); mutex_unlock(&gcov_lock); @@ -91,13 +89,15 @@ EXPORT_SYMBOL(__gcov_merge_delta); */ void gcov_enable_events(void) { - struct gcov_info *info; + struct gcov_info *info = NULL; mutex_lock(&gcov_lock); gcov_events_enabled = 1; + /* Perform event callback for previously registered entries. */ - for (info = gcov_info_head; info; info = info->next) + while ((info = gcov_info_next(info))) gcov_event(GCOV_ADD, info); + mutex_unlock(&gcov_lock); } @@ -112,25 +112,23 @@ static int gcov_module_notifier(struct notifier_block *nb, unsigned long event, void *data) { struct module *mod = data; - struct gcov_info *info; - struct gcov_info *prev; + struct gcov_info *info = NULL; + struct gcov_info *prev = NULL; if (event != MODULE_STATE_GOING) return NOTIFY_OK; mutex_lock(&gcov_lock); - prev = NULL; + /* Remove entries located in module from linked list. */ - for (info = gcov_info_head; info; info = info->next) { + while ((info = gcov_info_next(info))) { if (within(info, mod->module_core, mod->core_size)) { - if (prev) - prev->next = info->next; - else - gcov_info_head = info->next; + gcov_info_unlink(prev, info); if (gcov_events_enabled) gcov_event(GCOV_REMOVE, info); } else prev = info; } + mutex_unlock(&gcov_lock); return NOTIFY_OK; diff --git a/kernel/gcov/fs.c b/kernel/gcov/fs.c index 7a7d2ee..b49dfce 100644 --- a/kernel/gcov/fs.c +++ b/kernel/gcov/fs.c @@ -242,7 +242,7 @@ static struct gcov_node *get_node_by_name(const char *name) list_for_each_entry(node, &all_head, all) { info = get_node_info(node); - if (info && (strcmp(info->filename, name) == 0)) + if (info && (strcmp(gcov_info_filename(info), name) == 0)) return node; } @@ -279,7 +279,7 @@ static ssize_t gcov_seq_write(struct file *file, const char __user *addr, seq = file->private_data; info = gcov_iter_get_info(seq->private); mutex_lock(&node_lock); - node = get_node_by_name(info->filename); + node = get_node_by_name(gcov_info_filename(info)); if (node) { /* Reset counts or remove node for unloaded modules. */ if (node->num_loaded == 0) @@ -376,8 +376,9 @@ static void add_links(struct gcov_node *node, struct dentry *parent) if (!node->links) return; for (i = 0; i < num; i++) { - target = get_link_target(get_node_info(node)->filename, - &gcov_link[i]); + target = get_link_target( + gcov_info_filename(get_node_info(node)), + &gcov_link[i]); if (!target) goto out_err; basename = strrchr(target, '/'); @@ -576,7 +577,7 @@ static void add_node(struct gcov_info *info) struct gcov_node *parent; struct gcov_node *node; - filename = kstrdup(info->filename, GFP_KERNEL); + filename = kstrdup(gcov_info_filename(info), GFP_KERNEL); if (!filename) return; parent = &root_node; @@ -631,7 +632,7 @@ static void add_info(struct gcov_node *node, struct gcov_info *info) loaded_info = kcalloc(num + 1, sizeof(struct gcov_info *), GFP_KERNEL); if (!loaded_info) { pr_warning("could not add '%s' (out of memory)\n", - info->filename); + gcov_info_filename(info)); return; } memcpy(loaded_info, node->loaded_info, @@ -645,7 +646,8 @@ static void add_info(struct gcov_node *node, struct gcov_info *info) */ if (!gcov_info_is_compatible(node->unloaded_info, info)) { pr_warning("discarding saved data for %s " - "(incompatible version)\n", info->filename); + "(incompatible version)\n", + gcov_info_filename(info)); gcov_info_free(node->unloaded_info); node->unloaded_info = NULL; } @@ -656,7 +658,7 @@ static void add_info(struct gcov_node *node, struct gcov_info *info) */ if (!gcov_info_is_compatible(node->loaded_info[0], info)) { pr_warning("could not add '%s' (incompatible " - "version)\n", info->filename); + "version)\n", gcov_info_filename(info)); kfree(loaded_info); return; } @@ -692,7 +694,8 @@ static void save_info(struct gcov_node *node, struct gcov_info *info) node->unloaded_info = gcov_info_dup(info); if (!node->unloaded_info) { pr_warning("could not save data for '%s' " - "(out of memory)\n", info->filename); + "(out of memory)\n", + gcov_info_filename(info)); } } } @@ -708,7 +711,7 @@ static void remove_info(struct gcov_node *node, struct gcov_info *info) i = get_info_index(node, info); if (i < 0) { pr_warning("could not remove '%s' (not found)\n", - info->filename); + gcov_info_filename(info)); return; } if (gcov_persist) @@ -735,7 +738,7 @@ void gcov_event(enum gcov_action action, struct gcov_info *info) struct gcov_node *node; mutex_lock(&node_lock); - node = get_node_by_name(info->filename); + node = get_node_by_name(gcov_info_filename(info)); switch (action) { case GCOV_ADD: if (node) @@ -748,7 +751,7 @@ void gcov_event(enum gcov_action action, struct gcov_info *info) remove_info(node, info); else { pr_warning("could not remove '%s' (not found)\n", - info->filename); + gcov_info_filename(info)); } break; } diff --git a/kernel/gcov/gcc_3_4.c b/kernel/gcov/gcc_3_4.c index ae5bb42..27bc88a 100644 --- a/kernel/gcov/gcc_3_4.c +++ b/kernel/gcov/gcc_3_4.c @@ -21,6 +21,121 @@ #include #include "gcov.h" +#define GCOV_COUNTERS 5 + +static struct gcov_info *gcov_info_head; + +/** + * struct gcov_fn_info - profiling meta data per function + * @ident: object file-unique function identifier + * @checksum: function checksum + * @n_ctrs: number of values per counter type belonging to this function + * + * This data is generated by gcc during compilation and doesn't change + * at run-time. + */ +struct gcov_fn_info { + unsigned int ident; + unsigned int checksum; + unsigned int n_ctrs[0]; +}; + +/** + * struct gcov_ctr_info - profiling data per counter type + * @num: number of counter values for this type + * @values: array of counter values for this type + * @merge: merge function for counter values of this type (unused) + * + * This data is generated by gcc during compilation and doesn't change + * at run-time with the exception of the values array. + */ +struct gcov_ctr_info { + unsigned int num; + gcov_type *values; + void (*merge)(gcov_type *, unsigned int); +}; + +/** + * struct gcov_info - profiling data per object file + * @version: gcov version magic indicating the gcc version used for compilation + * @next: list head for a singly-linked list + * @stamp: time stamp + * @filename: name of the associated gcov data file + * @n_functions: number of instrumented functions + * @functions: function data + * @ctr_mask: mask specifying which counter types are active + * @counts: counter data per counter type + * + * This data is generated by gcc during compilation and doesn't change + * at run-time with the exception of the next pointer. + */ +struct gcov_info { + unsigned int version; + struct gcov_info *next; + unsigned int stamp; + const char *filename; + unsigned int n_functions; + const struct gcov_fn_info *functions; + unsigned int ctr_mask; + struct gcov_ctr_info counts[0]; +}; + +/** + * gcov_info_filename - return info filename + * @info: profiling data set + */ +const char *gcov_info_filename(struct gcov_info *info) +{ + return info->filename; +} + +/** + * gcov_info_version - return info version + * @info: profiling data set + */ +unsigned int gcov_info_version(struct gcov_info *info) +{ + return info->version; +} + +/** + * gcov_info_next - return next profiling data set + * @info: profiling data set + * + * Returns next gcov_info following @info or first gcov_info in the chain if + * @info is %NULL. + */ +struct gcov_info *gcov_info_next(struct gcov_info *info) +{ + if (!info) + return gcov_info_head; + + return info->next; +} + +/** + * gcov_info_link - link/add profiling data set to the list + * @info: profiling data set + */ +void gcov_info_link(struct gcov_info *info) +{ + info->next = gcov_info_head; + gcov_info_head = info; +} + +/** + * gcov_info_unlink - unlink/remove profiling data set from the list + * @prev: previous profiling data set + * @info: profiling data set + */ +void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info) +{ + if (prev) + prev->next = info->next; + else + gcov_info_head = info->next; +} + /* Symbolic links to be created for each profiling data file. */ const struct gcov_link gcov_link[] = { { OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */ diff --git a/kernel/gcov/gcov.h b/kernel/gcov/gcov.h index 060073e..92c8e22 100644 --- a/kernel/gcov/gcov.h +++ b/kernel/gcov/gcov.h @@ -21,7 +21,6 @@ * gcc and need to be kept as close to the original definition as possible to * remain compatible. */ -#define GCOV_COUNTERS 5 #define GCOV_DATA_MAGIC ((unsigned int) 0x67636461) #define GCOV_TAG_FUNCTION ((unsigned int) 0x01000000) #define GCOV_TAG_COUNTER_BASE ((unsigned int) 0x01a10000) @@ -34,60 +33,18 @@ typedef long gcov_type; typedef long long gcov_type; #endif -/** - * struct gcov_fn_info - profiling meta data per function - * @ident: object file-unique function identifier - * @checksum: function checksum - * @n_ctrs: number of values per counter type belonging to this function - * - * This data is generated by gcc during compilation and doesn't change - * at run-time. - */ -struct gcov_fn_info { - unsigned int ident; - unsigned int checksum; - unsigned int n_ctrs[0]; -}; - -/** - * struct gcov_ctr_info - profiling data per counter type - * @num: number of counter values for this type - * @values: array of counter values for this type - * @merge: merge function for counter values of this type (unused) - * - * This data is generated by gcc during compilation and doesn't change - * at run-time with the exception of the values array. - */ -struct gcov_ctr_info { - unsigned int num; - gcov_type *values; - void (*merge)(gcov_type *, unsigned int); -}; +/* Opaque gcov_info. The gcov structures can change as for example in gcc 4.7 so + * we cannot use full definition here and they need to be placed in gcc specific + * implementation of gcov. This also means no direct access to the members in + * generic code and usage of the interface below.*/ +struct gcov_info; -/** - * struct gcov_info - profiling data per object file - * @version: gcov version magic indicating the gcc version used for compilation - * @next: list head for a singly-linked list - * @stamp: time stamp - * @filename: name of the associated gcov data file - * @n_functions: number of instrumented functions - * @functions: function data - * @ctr_mask: mask specifying which counter types are active - * @counts: counter data per counter type - * - * This data is generated by gcc during compilation and doesn't change - * at run-time with the exception of the next pointer. - */ -struct gcov_info { - unsigned int version; - struct gcov_info *next; - unsigned int stamp; - const char *filename; - unsigned int n_functions; - const struct gcov_fn_info *functions; - unsigned int ctr_mask; - struct gcov_ctr_info counts[0]; -}; +/* Interface to access gcov_info data */ +const char *gcov_info_filename(struct gcov_info *info); +unsigned int gcov_info_version(struct gcov_info *info); +struct gcov_info *gcov_info_next(struct gcov_info *info); +void gcov_info_link(struct gcov_info *info); +void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info); /* Base interface. */ enum gcov_action { -- cgit v0.10.2 From 5f41ea0386a53414d688cfcaa321a78310e5f7c1 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Tue, 12 Nov 2013 15:11:26 -0800 Subject: gcov: add support for gcc 4.7 gcov format The gcov in-memory format changed in gcc 4.7. The biggest change, which requires this special implementation, is that gcov_info no longer contains array of counters for each counter type for all functions and gcov_fn_info is not used for mapping of function's counters to these arrays(offset). Now each gcov_fn_info contans it's counters, which makes things a little bit easier. This is heavily based on the previous gcc_3_4.c implementation and patches provided by Peter Oberparleiter. Specially the buffer gcda implementation for iterator. [akpm@linux-foundation.org: use kmemdup() and kcalloc()] [oberpar@linux.vnet.ibm.com: gcc_4_7.c needs vmalloc.h] Signed-off-by: Frantisek Hrbata Cc: Jan Stancek Cc: Kees Cook Reviewed-by: Peter Oberparleiter Cc: Rusty Russell Cc: Arnd Bergmann Cc: Andy Gospodarek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/gcov/base.c b/kernel/gcov/base.c index 912576a..f45b75b 100644 --- a/kernel/gcov/base.c +++ b/kernel/gcov/base.c @@ -79,6 +79,12 @@ void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters) } EXPORT_SYMBOL(__gcov_merge_delta); +void __gcov_merge_ior(gcov_type *counters, unsigned int n_counters) +{ + /* Unused. */ +} +EXPORT_SYMBOL(__gcov_merge_ior); + /** * gcov_enable_events - enable event reporting through gcov_event() * diff --git a/kernel/gcov/gcc_4_7.c b/kernel/gcov/gcc_4_7.c new file mode 100644 index 0000000..2c6e463 --- /dev/null +++ b/kernel/gcov/gcc_4_7.c @@ -0,0 +1,560 @@ +/* + * This code provides functions to handle gcc's profiling data format + * introduced with gcc 4.7. + * + * This file is based heavily on gcc_3_4.c file. + * + * For a better understanding, refer to gcc source: + * gcc/gcov-io.h + * libgcc/libgcov.c + * + * Uses gcc-internal data definitions. + */ + +#include +#include +#include +#include +#include +#include "gcov.h" + +#define GCOV_COUNTERS 8 +#define GCOV_TAG_FUNCTION_LENGTH 3 + +static struct gcov_info *gcov_info_head; + +/** + * struct gcov_ctr_info - information about counters for a single function + * @num: number of counter values for this type + * @values: array of counter values for this type + * + * This data is generated by gcc during compilation and doesn't change + * at run-time with the exception of the values array. + */ +struct gcov_ctr_info { + unsigned int num; + gcov_type *values; +}; + +/** + * struct gcov_fn_info - profiling meta data per function + * @key: comdat key + * @ident: unique ident of function + * @lineno_checksum: function lineo_checksum + * @cfg_checksum: function cfg checksum + * @ctrs: instrumented counters + * + * This data is generated by gcc during compilation and doesn't change + * at run-time. + * + * Information about a single function. This uses the trailing array + * idiom. The number of counters is determined from the merge pointer + * array in gcov_info. The key is used to detect which of a set of + * comdat functions was selected -- it points to the gcov_info object + * of the object file containing the selected comdat function. + */ +struct gcov_fn_info { + const struct gcov_info *key; + unsigned int ident; + unsigned int lineno_checksum; + unsigned int cfg_checksum; + struct gcov_ctr_info ctrs[0]; +}; + +/** + * struct gcov_info - profiling data per object file + * @version: gcov version magic indicating the gcc version used for compilation + * @next: list head for a singly-linked list + * @stamp: uniquifying time stamp + * @filename: name of the associated gcov data file + * @merge: merge functions (null for unused counter type) + * @n_functions: number of instrumented functions + * @functions: pointer to pointers to function information + * + * This data is generated by gcc during compilation and doesn't change + * at run-time with the exception of the next pointer. + */ +struct gcov_info { + unsigned int version; + struct gcov_info *next; + unsigned int stamp; + const char *filename; + void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int); + unsigned int n_functions; + struct gcov_fn_info **functions; +}; + +/** + * gcov_info_filename - return info filename + * @info: profiling data set + */ +const char *gcov_info_filename(struct gcov_info *info) +{ + return info->filename; +} + +/** + * gcov_info_version - return info version + * @info: profiling data set + */ +unsigned int gcov_info_version(struct gcov_info *info) +{ + return info->version; +} + +/** + * gcov_info_next - return next profiling data set + * @info: profiling data set + * + * Returns next gcov_info following @info or first gcov_info in the chain if + * @info is %NULL. + */ +struct gcov_info *gcov_info_next(struct gcov_info *info) +{ + if (!info) + return gcov_info_head; + + return info->next; +} + +/** + * gcov_info_link - link/add profiling data set to the list + * @info: profiling data set + */ +void gcov_info_link(struct gcov_info *info) +{ + info->next = gcov_info_head; + gcov_info_head = info; +} + +/** + * gcov_info_unlink - unlink/remove profiling data set from the list + * @prev: previous profiling data set + * @info: profiling data set + */ +void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info) +{ + if (prev) + prev->next = info->next; + else + gcov_info_head = info->next; +} + +/* Symbolic links to be created for each profiling data file. */ +const struct gcov_link gcov_link[] = { + { OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */ + { 0, NULL}, +}; + +/* + * Determine whether a counter is active. Doesn't change at run-time. + */ +static int counter_active(struct gcov_info *info, unsigned int type) +{ + return info->merge[type] ? 1 : 0; +} + +/* Determine number of active counters. Based on gcc magic. */ +static unsigned int num_counter_active(struct gcov_info *info) +{ + unsigned int i; + unsigned int result = 0; + + for (i = 0; i < GCOV_COUNTERS; i++) { + if (counter_active(info, i)) + result++; + } + return result; +} + +/** + * gcov_info_reset - reset profiling data to zero + * @info: profiling data set + */ +void gcov_info_reset(struct gcov_info *info) +{ + struct gcov_ctr_info *ci_ptr; + unsigned int fi_idx; + unsigned int ct_idx; + + for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) { + ci_ptr = info->functions[fi_idx]->ctrs; + + for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) { + if (!counter_active(info, ct_idx)) + continue; + + memset(ci_ptr->values, 0, + sizeof(gcov_type) * ci_ptr->num); + ci_ptr++; + } + } +} + +/** + * gcov_info_is_compatible - check if profiling data can be added + * @info1: first profiling data set + * @info2: second profiling data set + * + * Returns non-zero if profiling data can be added, zero otherwise. + */ +int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2) +{ + return (info1->stamp == info2->stamp); +} + +/** + * gcov_info_add - add up profiling data + * @dest: profiling data set to which data is added + * @source: profiling data set which is added + * + * Adds profiling counts of @source to @dest. + */ +void gcov_info_add(struct gcov_info *dst, struct gcov_info *src) +{ + struct gcov_ctr_info *dci_ptr; + struct gcov_ctr_info *sci_ptr; + unsigned int fi_idx; + unsigned int ct_idx; + unsigned int val_idx; + + for (fi_idx = 0; fi_idx < src->n_functions; fi_idx++) { + dci_ptr = dst->functions[fi_idx]->ctrs; + sci_ptr = src->functions[fi_idx]->ctrs; + + for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) { + if (!counter_active(src, ct_idx)) + continue; + + for (val_idx = 0; val_idx < sci_ptr->num; val_idx++) + dci_ptr->values[val_idx] += + sci_ptr->values[val_idx]; + + dci_ptr++; + sci_ptr++; + } + } +} + +/** + * gcov_info_dup - duplicate profiling data set + * @info: profiling data set to duplicate + * + * Return newly allocated duplicate on success, %NULL on error. + */ +struct gcov_info *gcov_info_dup(struct gcov_info *info) +{ + struct gcov_info *dup; + struct gcov_ctr_info *dci_ptr; /* dst counter info */ + struct gcov_ctr_info *sci_ptr; /* src counter info */ + unsigned int active; + unsigned int fi_idx; /* function info idx */ + unsigned int ct_idx; /* counter type idx */ + size_t fi_size; /* function info size */ + size_t cv_size; /* counter values size */ + + dup = kmemdup(info, sizeof(*dup), GFP_KERNEL); + if (!dup) + return NULL; + + dup->next = NULL; + dup->filename = NULL; + dup->functions = NULL; + + dup->filename = kstrdup(info->filename, GFP_KERNEL); + if (!dup->filename) + goto err_free; + + dup->functions = kcalloc(info->n_functions, + sizeof(struct gcov_fn_info *), GFP_KERNEL); + if (!dup->functions) + goto err_free; + + active = num_counter_active(info); + fi_size = sizeof(struct gcov_fn_info); + fi_size += sizeof(struct gcov_ctr_info) * active; + + for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) { + dup->functions[fi_idx] = kzalloc(fi_size, GFP_KERNEL); + if (!dup->functions[fi_idx]) + goto err_free; + + *(dup->functions[fi_idx]) = *(info->functions[fi_idx]); + + sci_ptr = info->functions[fi_idx]->ctrs; + dci_ptr = dup->functions[fi_idx]->ctrs; + + for (ct_idx = 0; ct_idx < active; ct_idx++) { + + cv_size = sizeof(gcov_type) * sci_ptr->num; + + dci_ptr->values = vmalloc(cv_size); + + if (!dci_ptr->values) + goto err_free; + + dci_ptr->num = sci_ptr->num; + memcpy(dci_ptr->values, sci_ptr->values, cv_size); + + sci_ptr++; + dci_ptr++; + } + } + + return dup; +err_free: + gcov_info_free(dup); + return NULL; +} + +/** + * gcov_info_free - release memory for profiling data set duplicate + * @info: profiling data set duplicate to free + */ +void gcov_info_free(struct gcov_info *info) +{ + unsigned int active; + unsigned int fi_idx; + unsigned int ct_idx; + struct gcov_ctr_info *ci_ptr; + + if (!info->functions) + goto free_info; + + active = num_counter_active(info); + + for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) { + if (!info->functions[fi_idx]) + continue; + + ci_ptr = info->functions[fi_idx]->ctrs; + + for (ct_idx = 0; ct_idx < active; ct_idx++, ci_ptr++) + vfree(ci_ptr->values); + + kfree(info->functions[fi_idx]); + } + +free_info: + kfree(info->functions); + kfree(info->filename); + kfree(info); +} + +#define ITER_STRIDE PAGE_SIZE + +/** + * struct gcov_iterator - specifies current file position in logical records + * @info: associated profiling data + * @buffer: buffer containing file data + * @size: size of buffer + * @pos: current position in file + */ +struct gcov_iterator { + struct gcov_info *info; + void *buffer; + size_t size; + loff_t pos; +}; + +/** + * store_gcov_u32 - store 32 bit number in gcov format to buffer + * @buffer: target buffer or NULL + * @off: offset into the buffer + * @v: value to be stored + * + * Number format defined by gcc: numbers are recorded in the 32 bit + * unsigned binary form of the endianness of the machine generating the + * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't + * store anything. + */ +static size_t store_gcov_u32(void *buffer, size_t off, u32 v) +{ + u32 *data; + + if (buffer) { + data = buffer + off; + *data = v; + } + + return sizeof(*data); +} + +/** + * store_gcov_u64 - store 64 bit number in gcov format to buffer + * @buffer: target buffer or NULL + * @off: offset into the buffer + * @v: value to be stored + * + * Number format defined by gcc: numbers are recorded in the 32 bit + * unsigned binary form of the endianness of the machine generating the + * file. 64 bit numbers are stored as two 32 bit numbers, the low part + * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store + * anything. + */ +static size_t store_gcov_u64(void *buffer, size_t off, u64 v) +{ + u32 *data; + + if (buffer) { + data = buffer + off; + + data[0] = (v & 0xffffffffUL); + data[1] = (v >> 32); + } + + return sizeof(*data) * 2; +} + +/** + * convert_to_gcda - convert profiling data set to gcda file format + * @buffer: the buffer to store file data or %NULL if no data should be stored + * @info: profiling data set to be converted + * + * Returns the number of bytes that were/would have been stored into the buffer. + */ +static size_t convert_to_gcda(char *buffer, struct gcov_info *info) +{ + struct gcov_fn_info *fi_ptr; + struct gcov_ctr_info *ci_ptr; + unsigned int fi_idx; + unsigned int ct_idx; + unsigned int cv_idx; + size_t pos = 0; + + /* File header. */ + pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC); + pos += store_gcov_u32(buffer, pos, info->version); + pos += store_gcov_u32(buffer, pos, info->stamp); + + for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) { + fi_ptr = info->functions[fi_idx]; + + /* Function record. */ + pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION); + pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH); + pos += store_gcov_u32(buffer, pos, fi_ptr->ident); + pos += store_gcov_u32(buffer, pos, fi_ptr->lineno_checksum); + pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum); + + ci_ptr = fi_ptr->ctrs; + + for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) { + if (!counter_active(info, ct_idx)) + continue; + + /* Counter record. */ + pos += store_gcov_u32(buffer, pos, + GCOV_TAG_FOR_COUNTER(ct_idx)); + pos += store_gcov_u32(buffer, pos, ci_ptr->num * 2); + + for (cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++) { + pos += store_gcov_u64(buffer, pos, + ci_ptr->values[cv_idx]); + } + + ci_ptr++; + } + } + + return pos; +} + +/** + * gcov_iter_new - allocate and initialize profiling data iterator + * @info: profiling data set to be iterated + * + * Return file iterator on success, %NULL otherwise. + */ +struct gcov_iterator *gcov_iter_new(struct gcov_info *info) +{ + struct gcov_iterator *iter; + + iter = kzalloc(sizeof(struct gcov_iterator), GFP_KERNEL); + if (!iter) + goto err_free; + + iter->info = info; + /* Dry-run to get the actual buffer size. */ + iter->size = convert_to_gcda(NULL, info); + iter->buffer = vmalloc(iter->size); + if (!iter->buffer) + goto err_free; + + convert_to_gcda(iter->buffer, info); + + return iter; + +err_free: + kfree(iter); + return NULL; +} + + +/** + * gcov_iter_get_info - return profiling data set for given file iterator + * @iter: file iterator + */ +void gcov_iter_free(struct gcov_iterator *iter) +{ + vfree(iter->buffer); + kfree(iter); +} + +/** + * gcov_iter_get_info - return profiling data set for given file iterator + * @iter: file iterator + */ +struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter) +{ + return iter->info; +} + +/** + * gcov_iter_start - reset file iterator to starting position + * @iter: file iterator + */ +void gcov_iter_start(struct gcov_iterator *iter) +{ + iter->pos = 0; +} + +/** + * gcov_iter_next - advance file iterator to next logical record + * @iter: file iterator + * + * Return zero if new position is valid, non-zero if iterator has reached end. + */ +int gcov_iter_next(struct gcov_iterator *iter) +{ + if (iter->pos < iter->size) + iter->pos += ITER_STRIDE; + + if (iter->pos >= iter->size) + return -EINVAL; + + return 0; +} + +/** + * gcov_iter_write - write data for current pos to seq_file + * @iter: file iterator + * @seq: seq_file handle + * + * Return zero on success, non-zero otherwise. + */ +int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq) +{ + size_t len; + + if (iter->pos >= iter->size) + return -EINVAL; + + len = ITER_STRIDE; + if (iter->pos + len > iter->size) + len = iter->size - iter->pos; + + seq_write(seq, iter->buffer + iter->pos, len); + + return 0; +} -- cgit v0.10.2 From 17c568d60af5a810208baf116dc174a2005c6c3e Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Tue, 12 Nov 2013 15:11:27 -0800 Subject: gcov: compile specific gcov implementation based on gcc version Compile the correct gcov implementation file for the specific gcc version. Signed-off-by: Frantisek Hrbata Cc: Jan Stancek Cc: Kees Cook Acked-by: Peter Oberparleiter Cc: Rusty Russell Cc: Arnd Bergmann Cc: Andy Gospodarek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/gcov.txt b/Documentation/gcov.txt index e7ca647..7b72778 100644 --- a/Documentation/gcov.txt +++ b/Documentation/gcov.txt @@ -50,6 +50,10 @@ Configure the kernel with: CONFIG_DEBUG_FS=y CONFIG_GCOV_KERNEL=y +select the gcc's gcov format, default is autodetect based on gcc version: + + CONFIG_GCOV_FORMAT_AUTODETECT=y + and to get coverage data for the entire kernel: CONFIG_GCOV_PROFILE_ALL=y diff --git a/kernel/gcov/Kconfig b/kernel/gcov/Kconfig index d4da55d..d04ce8a 100644 --- a/kernel/gcov/Kconfig +++ b/kernel/gcov/Kconfig @@ -46,4 +46,34 @@ config GCOV_PROFILE_ALL larger and run slower. Also be sure to exclude files from profiling which are not linked to the kernel image to prevent linker errors. +choice + prompt "Specify GCOV format" + depends on GCOV_KERNEL + default GCOV_FORMAT_AUTODETECT + ---help--- + The gcov format is usually determined by the GCC version, but there are + exceptions where format changes are integrated in lower-version GCCs. + In such a case use this option to adjust the format used in the kernel + accordingly. + + If unsure, choose "Autodetect". + +config GCOV_FORMAT_AUTODETECT + bool "Autodetect" + ---help--- + Select this option to use the format that corresponds to your GCC + version. + +config GCOV_FORMAT_3_4 + bool "GCC 3.4 format" + ---help--- + Select this option to use the format defined by GCC 3.4. + +config GCOV_FORMAT_4_7 + bool "GCC 4.7 format" + ---help--- + Select this option to use the format defined by GCC 4.7. + +endchoice + endmenu diff --git a/kernel/gcov/Makefile b/kernel/gcov/Makefile index e97ca59..52aa7e8 100644 --- a/kernel/gcov/Makefile +++ b/kernel/gcov/Makefile @@ -1,3 +1,33 @@ ccflags-y := -DSRCTREE='"$(srctree)"' -DOBJTREE='"$(objtree)"' -obj-$(CONFIG_GCOV_KERNEL) := base.o fs.o gcc_3_4.o +# if-lt +# Usage VAR := $(call if-lt, $(a), $(b)) +# Returns 1 if (a < b) +if-lt = $(shell [ $(1) -lt $(2) ] && echo 1) + +ifeq ($(CONFIG_GCOV_FORMAT_3_4),y) + cc-ver := 0304 +else ifeq ($(CONFIG_GCOV_FORMAT_4_7),y) + cc-ver := 0407 +else +# Use cc-version if available, otherwise set 0 +# +# scripts/Kbuild.include, which contains cc-version function, is not included +# during make clean "make -f scripts/Makefile.clean obj=kernel/gcov" +# Meaning cc-ver is empty causing if-lt test to fail with +# "/bin/sh: line 0: [: -lt: unary operator expected" error mesage. +# This has no affect on the clean phase, but the error message could be +# confusing/annoying. So this dummy workaround sets cc-ver to zero if cc-version +# is not available. We can probably move if-lt to Kbuild.include, so it's also +# not defined during clean or to include Kbuild.include in +# scripts/Makefile.clean. But the following workaround seems least invasive. + cc-ver := $(if $(call cc-version),$(call cc-version),0) +endif + +obj-$(CONFIG_GCOV_KERNEL) := base.o fs.o + +ifeq ($(call if-lt, $(cc-ver), 0407),1) + obj-$(CONFIG_GCOV_KERNEL) += gcc_3_4.o +else + obj-$(CONFIG_GCOV_KERNEL) += gcc_4_7.o +endif -- cgit v0.10.2 From bddb12b32f90c571b177439a650f1046c3185c2e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 12 Nov 2013 15:11:28 -0800 Subject: kernel/module.c: use pr_foo() kernel/module.c uses a mix of printk(KERN_foo and pr_foo(). Convert it all to pr_foo and make the offered cleanups. Not sure what to do about the printk(KERN_DEFAULT). We don't have a pr_default(). Cc: Rusty Russell Cc: Joe Perches Cc: Frantisek Hrbata Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/module.c b/kernel/module.c index dc58274..af5ebd2 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -378,23 +378,21 @@ static bool check_symbol(const struct symsearch *syms, if (syms->licence == GPL_ONLY) return false; if (syms->licence == WILL_BE_GPL_ONLY && fsa->warn) { - printk(KERN_WARNING "Symbol %s is being used " - "by a non-GPL module, which will not " - "be allowed in the future\n", fsa->name); + pr_warn("Symbol %s is being used by a non-GPL module, " + "which will not be allowed in the future\n", + fsa->name); } } #ifdef CONFIG_UNUSED_SYMBOLS if (syms->unused && fsa->warn) { - printk(KERN_WARNING "Symbol %s is marked as UNUSED, " - "however this module is using it.\n", fsa->name); - printk(KERN_WARNING - "This symbol will go away in the future.\n"); - printk(KERN_WARNING - "Please evalute if this is the right api to use and if " - "it really is, submit a report the linux kernel " - "mailinglist together with submitting your code for " - "inclusion.\n"); + pr_warn("Symbol %s is marked as UNUSED, however this module is " + "using it.\n", fsa->name); + pr_warn("This symbol will go away in the future.\n"); + pr_warn("Please evalute if this is the right api to use and if " + "it really is, submit a report the linux kernel " + "mailinglist together with submitting your code for " + "inclusion.\n"); } #endif @@ -492,16 +490,15 @@ static int percpu_modalloc(struct module *mod, struct load_info *info) return 0; if (align > PAGE_SIZE) { - printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n", - mod->name, align, PAGE_SIZE); + pr_warn("%s: per-cpu alignment %li > %li\n", + mod->name, align, PAGE_SIZE); align = PAGE_SIZE; } mod->percpu = __alloc_reserved_percpu(pcpusec->sh_size, align); if (!mod->percpu) { - printk(KERN_WARNING - "%s: Could not allocate %lu bytes percpu data\n", - mod->name, (unsigned long)pcpusec->sh_size); + pr_warn("%s: Could not allocate %lu bytes percpu data\n", + mod->name, (unsigned long)pcpusec->sh_size); return -ENOMEM; } mod->percpu_size = pcpusec->sh_size; @@ -679,7 +676,7 @@ static int add_module_usage(struct module *a, struct module *b) pr_debug("Allocating new usage for %s.\n", a->name); use = kmalloc(sizeof(*use), GFP_ATOMIC); if (!use) { - printk(KERN_WARNING "%s: out of memory loading\n", a->name); + pr_warn("%s: out of memory loading\n", a->name); return -ENOMEM; } @@ -1145,8 +1142,7 @@ static int try_to_force_load(struct module *mod, const char *reason) { #ifdef CONFIG_MODULE_FORCE_LOAD if (!test_taint(TAINT_FORCED_MODULE)) - printk(KERN_WARNING "%s: %s: kernel tainted.\n", - mod->name, reason); + pr_warn("%s: %s: kernel tainted.\n", mod->name, reason); add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_NOW_UNRELIABLE); return 0; #else @@ -1199,8 +1195,7 @@ static int check_version(Elf_Shdr *sechdrs, goto bad_version; } - printk(KERN_WARNING "%s: no symbol version for %s\n", - mod->name, symname); + pr_warn("%s: no symbol version for %s\n", mod->name, symname); return 0; bad_version: @@ -1309,8 +1304,8 @@ resolve_symbol_wait(struct module *mod, !IS_ERR(ksym = resolve_symbol(mod, info, name, owner)) || PTR_ERR(ksym) != -EBUSY, 30 * HZ) <= 0) { - printk(KERN_WARNING "%s: gave up waiting for init of module %s.\n", - mod->name, owner); + pr_warn("%s: gave up waiting for init of module %s.\n", + mod->name, owner); } return ksym; } @@ -1626,15 +1621,14 @@ static int mod_sysfs_init(struct module *mod) struct kobject *kobj; if (!module_sysfs_initialized) { - printk(KERN_ERR "%s: module sysfs not initialized\n", - mod->name); + pr_err("%s: module sysfs not initialized\n", mod->name); err = -EINVAL; goto out; } kobj = kset_find_obj(module_kset, mod->name); if (kobj) { - printk(KERN_ERR "%s: module is already loaded\n", mod->name); + pr_err("%s: module is already loaded\n", mod->name); kobject_put(kobj); err = -EINVAL; goto out; @@ -1961,8 +1955,7 @@ static int verify_export_symbols(struct module *mod) for (i = 0; i < ARRAY_SIZE(arr); i++) { for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { if (find_symbol(s->name, &owner, NULL, true, false)) { - printk(KERN_ERR - "%s: exports duplicate symbol %s" + pr_err("%s: exports duplicate symbol %s" " (owned by %s)\n", mod->name, s->name, module_name(owner)); return -ENOEXEC; @@ -2013,8 +2006,8 @@ static int simplify_symbols(struct module *mod, const struct load_info *info) if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK) break; - printk(KERN_WARNING "%s: Unknown symbol %s (err %li)\n", - mod->name, name, PTR_ERR(ksym)); + pr_warn("%s: Unknown symbol %s (err %li)\n", + mod->name, name, PTR_ERR(ksym)); ret = PTR_ERR(ksym) ?: -ENOENT; break; @@ -2168,8 +2161,8 @@ static void set_license(struct module *mod, const char *license) if (!license_is_gpl_compatible(license)) { if (!test_taint(TAINT_PROPRIETARY_MODULE)) - printk(KERN_WARNING "%s: module license '%s' taints " - "kernel.\n", mod->name, license); + pr_warn("%s: module license '%s' taints kernel.\n", + mod->name, license); add_taint_module(mod, TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE); } @@ -2405,8 +2398,8 @@ static void dynamic_debug_setup(struct _ddebug *debug, unsigned int num) return; #ifdef CONFIG_DYNAMIC_DEBUG if (ddebug_add_module(debug, num, debug->modname)) - printk(KERN_ERR "dynamic debug error adding module: %s\n", - debug->modname); + pr_err("dynamic debug error adding module: %s\n", + debug->modname); #endif } @@ -2619,8 +2612,7 @@ static int rewrite_section_headers(struct load_info *info, int flags) Elf_Shdr *shdr = &info->sechdrs[i]; if (shdr->sh_type != SHT_NOBITS && info->len < shdr->sh_offset + shdr->sh_size) { - printk(KERN_ERR "Module len %lu truncated\n", - info->len); + pr_err("Module len %lu truncated\n", info->len); return -ENOEXEC; } @@ -2682,15 +2674,14 @@ static struct module *setup_load_info(struct load_info *info, int flags) info->index.mod = find_sec(info, ".gnu.linkonce.this_module"); if (!info->index.mod) { - printk(KERN_WARNING "No module found in object\n"); + pr_warn("No module found in object\n"); return ERR_PTR(-ENOEXEC); } /* This is temporary: point mod into copy of data. */ mod = (void *)info->sechdrs[info->index.mod].sh_addr; if (info->index.sym == 0) { - printk(KERN_WARNING "%s: module has no symbols (stripped?)\n", - mod->name); + pr_warn("%s: module has no symbols (stripped?)\n", mod->name); return ERR_PTR(-ENOEXEC); } @@ -2717,7 +2708,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags) if (err) return err; } else if (!same_magic(modmagic, vermagic, info->index.vers)) { - printk(KERN_ERR "%s: version magic '%s' should be '%s'\n", + pr_err("%s: version magic '%s' should be '%s'\n", mod->name, modmagic, vermagic); return -ENOEXEC; } @@ -2727,9 +2718,8 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags) if (get_modinfo(info, "staging")) { add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK); - printk(KERN_WARNING "%s: module is from the staging directory," - " the quality is unknown, you have been warned.\n", - mod->name); + pr_warn("%s: module is from the staging directory, the quality " + "is unknown, you have been warned.\n", mod->name); } /* Set up license info based on the info section */ @@ -2801,8 +2791,7 @@ static void find_module_sections(struct module *mod, struct load_info *info) sizeof(*mod->extable), &mod->num_exentries); if (section_addr(info, "__obsparm")) - printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", - mod->name); + pr_warn("%s: Ignoring obsolete parameters\n", mod->name); info->debug = section_objs(info, "__verbose", sizeof(*info->debug), &info->num_debug); @@ -3078,11 +3067,10 @@ static int do_init_module(struct module *mod) return ret; } if (ret > 0) { - printk(KERN_WARNING -"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n" -"%s: loading module anyway...\n", - __func__, mod->name, ret, - __func__); + pr_warn("%s: '%s'->init suspiciously returned %d, it should " + "follow 0/-E convention\n" + "%s: loading module anyway...\n", + __func__, mod->name, ret, __func__); dump_stack(); } @@ -3205,10 +3193,8 @@ static int unknown_module_param_cb(char *param, char *val, const char *modname) { /* Check for magic 'dyndbg' arg */ int ret = ddebug_dyndbg_module_param_cb(param, val, modname); - if (ret != 0) { - printk(KERN_WARNING "%s: unknown parameter '%s' ignored\n", - modname, param); - } + if (ret != 0) + pr_warn("%s: unknown parameter '%s' ignored\n", modname, param); return 0; } @@ -3243,10 +3229,9 @@ static int load_module(struct load_info *info, const char __user *uargs, #ifdef CONFIG_MODULE_SIG mod->sig_ok = info->sig_ok; if (!mod->sig_ok) { - printk_once(KERN_NOTICE - "%s: module verification failed: signature and/or" - " required key missing - tainting kernel\n", - mod->name); + pr_notice_once("%s: module verification failed: signature " + "and/or required key missing - tainting " + "kernel\n", mod->name); add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_STILL_OK); } #endif -- cgit v0.10.2 From a5ebb87508a48d7816a6897ed53419e46a507eb5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 12 Nov 2013 15:11:29 -0800 Subject: kernel/gcov/fs.c: use pr_warn() pr_warning() is deprecated in favor of pr_warn() Cc: Andy Gospodarek Cc: Arnd Bergmann Cc: Frantisek Hrbata Cc: Jan Stancek Cc: Kees Cook Cc: Peter Oberparleiter Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/gcov/fs.c b/kernel/gcov/fs.c index b49dfce..e892ad9 100644 --- a/kernel/gcov/fs.c +++ b/kernel/gcov/fs.c @@ -75,7 +75,7 @@ static int __init gcov_persist_setup(char *str) unsigned long val; if (kstrtoul(str, 0, &val)) { - pr_warning("invalid gcov_persist parameter '%s'\n", str); + pr_warn("invalid gcov_persist parameter '%s'\n", str); return 0; } gcov_persist = val; @@ -451,7 +451,7 @@ static struct gcov_node *new_node(struct gcov_node *parent, } else node->dentry = debugfs_create_dir(node->name, parent->dentry); if (!node->dentry) { - pr_warning("could not create file\n"); + pr_warn("could not create file\n"); kfree(node); return NULL; } @@ -464,7 +464,7 @@ static struct gcov_node *new_node(struct gcov_node *parent, err_nomem: kfree(node); - pr_warning("out of memory\n"); + pr_warn("out of memory\n"); return NULL; } @@ -631,8 +631,8 @@ static void add_info(struct gcov_node *node, struct gcov_info *info) */ loaded_info = kcalloc(num + 1, sizeof(struct gcov_info *), GFP_KERNEL); if (!loaded_info) { - pr_warning("could not add '%s' (out of memory)\n", - gcov_info_filename(info)); + pr_warn("could not add '%s' (out of memory)\n", + gcov_info_filename(info)); return; } memcpy(loaded_info, node->loaded_info, @@ -645,9 +645,9 @@ static void add_info(struct gcov_node *node, struct gcov_info *info) * data set replaces the copy of the last one. */ if (!gcov_info_is_compatible(node->unloaded_info, info)) { - pr_warning("discarding saved data for %s " - "(incompatible version)\n", - gcov_info_filename(info)); + pr_warn("discarding saved data for %s " + "(incompatible version)\n", + gcov_info_filename(info)); gcov_info_free(node->unloaded_info); node->unloaded_info = NULL; } @@ -657,8 +657,8 @@ static void add_info(struct gcov_node *node, struct gcov_info *info) * The initial one takes precedence. */ if (!gcov_info_is_compatible(node->loaded_info[0], info)) { - pr_warning("could not add '%s' (incompatible " - "version)\n", gcov_info_filename(info)); + pr_warn("could not add '%s' (incompatible " + "version)\n", gcov_info_filename(info)); kfree(loaded_info); return; } @@ -693,9 +693,9 @@ static void save_info(struct gcov_node *node, struct gcov_info *info) else { node->unloaded_info = gcov_info_dup(info); if (!node->unloaded_info) { - pr_warning("could not save data for '%s' " - "(out of memory)\n", - gcov_info_filename(info)); + pr_warn("could not save data for '%s' " + "(out of memory)\n", + gcov_info_filename(info)); } } } @@ -710,8 +710,8 @@ static void remove_info(struct gcov_node *node, struct gcov_info *info) i = get_info_index(node, info); if (i < 0) { - pr_warning("could not remove '%s' (not found)\n", - gcov_info_filename(info)); + pr_warn("could not remove '%s' (not found)\n", + gcov_info_filename(info)); return; } if (gcov_persist) @@ -750,8 +750,8 @@ void gcov_event(enum gcov_action action, struct gcov_info *info) if (node) remove_info(node, info); else { - pr_warning("could not remove '%s' (not found)\n", - gcov_info_filename(info)); + pr_warn("could not remove '%s' (not found)\n", + gcov_info_filename(info)); } break; } -- cgit v0.10.2 From 1931d433d7a641e6a366854566ab1207a32972a6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 Nov 2013 15:11:31 -0800 Subject: gcov: reuse kbasename helper To get name of the file from a pathname let's use kbasename() helper. Signed-off-by: Andy Shevchenko Cc: Jingoo Han Cc: Peter Oberparleiter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/gcov/fs.c b/kernel/gcov/fs.c index e892ad9..15ff01a 100644 --- a/kernel/gcov/fs.c +++ b/kernel/gcov/fs.c @@ -365,7 +365,7 @@ static const char *deskew(const char *basename) */ static void add_links(struct gcov_node *node, struct dentry *parent) { - char *basename; + const char *basename; char *target; int num; int i; @@ -381,10 +381,9 @@ static void add_links(struct gcov_node *node, struct dentry *parent) &gcov_link[i]); if (!target) goto out_err; - basename = strrchr(target, '/'); - if (!basename) + basename = kbasename(target); + if (basename == target) goto out_err; - basename++; node->links[i] = debugfs_create_symlink(deskew(basename), parent, target); if (!node->links[i]) -- cgit v0.10.2 From 01284764713b02be23e72338227ce536c740399a Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 12 Nov 2013 15:11:32 -0800 Subject: kernel/panic.c: reduce 1 byte usage for print tainted buffer sizeof("Tainted: ") already counts '\0', and after first sprintf(), 's' will start from the current string end (its' value is '\0'). So need not add additional 1 byte for maximized usage of 'buf' in print_tainted(). Signed-off-by: Chen Gang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/panic.c b/kernel/panic.c index b6c482c..c00b4ce 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -233,7 +233,7 @@ static const struct tnt tnts[] = { */ const char *print_tainted(void) { - static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ") + 1]; + static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ")]; if (tainted_mask) { char *s; -- cgit v0.10.2 From 1a10bd9424d463e550676e74f4875863d1bae3f5 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 12 Nov 2013 15:11:33 -0800 Subject: drivers/pps/clients/pps-gpio.c: remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Cc: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 9966124..f41bacf 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -201,7 +201,7 @@ static struct platform_driver pps_gpio_driver = { .driver = { .name = PPS_GPIO_NAME, .owner = THIS_MODULE, - .of_match_table = of_match_ptr(pps_gpio_dt_ids), + .of_match_table = pps_gpio_dt_ids, }, }; -- cgit v0.10.2 From be2d3f97e90cdf9f1523daaba705f320c3efaf00 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 12 Nov 2013 15:11:39 -0800 Subject: drivers/memstick/core/mspro_block.c: fix attributes array allocation attrs field of attribute_group structure is a pointer to a pointer (as in an array of pointers) rather than pointer to attribute struct (as in an array of structures), so when allocating size of the pointer sholud be used instead of the structure it is pointing to. While at it, also change the call to use kcalloc rather than kzalloc. Signed-off-by: Michal Nazarewicz Cc: Tejun Heo Cc: Al Viro Cc: Alex Dubov Cc: Maxim Levitsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index f4176ca..fc145d2 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -1023,8 +1023,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) } else attr_count = attr->count; - msb->attr_group.attrs = kzalloc((attr_count + 1) - * sizeof(struct attribute), + msb->attr_group.attrs = kcalloc(attr_count + 1, + sizeof(*msb->attr_group.attrs), GFP_KERNEL); if (!msb->attr_group.attrs) { rc = -ENOMEM; -- cgit v0.10.2 From a0e5a12fd18d47aa87a7a8c60ca5bc422b136564 Mon Sep 17 00:00:00 2001 From: Roger Tseng Date: Tue, 12 Nov 2013 15:11:40 -0800 Subject: drivers/memstick/core/ms_block.c: fix unreachable state in h_msb_read_page() In h_msb_read_page() in ms_block.c, flow never reaches case MSB_RP_RECIVE_STATUS_REG. This causes error when MEMSTICK_INT_ERR is encountered and status error bits are going to be examined, but the status will never be copied back. Fix it by transitioning to MSB_RP_RECIVE_STATUS_REG right after MSB_RP_SEND_READ_STATUS_REG. Signed-off-by: Roger Tseng Acked-by: Maxim Levitsky Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index 08e7023..9188ef5 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -401,7 +401,7 @@ again: sizeof(struct ms_status_register))) return 0; - msb->state = MSB_RP_RECEIVE_OOB_READ; + msb->state = MSB_RP_RECIVE_STATUS_REG; return 0; case MSB_RP_RECIVE_STATUS_REG: -- cgit v0.10.2 From 75f9e937d24fdf661ebd5c9bed05caa4aad90539 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Nov 2013 15:11:41 -0800 Subject: drivers/w1/masters/ds1wm.cuse dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. This is a cosmetic change to make the code simpler and enhance the readability. Signed-off-by: Jingoo Han Acked-by: Evgeniy Polyakov Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 41613f9..02df3b1 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -255,17 +255,17 @@ static int ds1wm_find_divisor(int gclk) static void ds1wm_up(struct ds1wm_data *ds1wm_data) { int divisor; - struct ds1wm_driver_data *plat = ds1wm_data->pdev->dev.platform_data; + struct device *dev = &ds1wm_data->pdev->dev; + struct ds1wm_driver_data *plat = dev_get_platdata(dev); if (ds1wm_data->cell->enable) ds1wm_data->cell->enable(ds1wm_data->pdev); divisor = ds1wm_find_divisor(plat->clock_rate); - dev_dbg(&ds1wm_data->pdev->dev, - "found divisor 0x%x for clock %d\n", divisor, plat->clock_rate); + dev_dbg(dev, "found divisor 0x%x for clock %d\n", + divisor, plat->clock_rate); if (divisor == 0) { - dev_err(&ds1wm_data->pdev->dev, - "no suitable divisor for %dHz clock\n", + dev_err(dev, "no suitable divisor for %dHz clock\n", plat->clock_rate); return; } @@ -481,7 +481,7 @@ static int ds1wm_probe(struct platform_device *pdev) ds1wm_data->cell = mfd_get_cell(pdev); if (!ds1wm_data->cell) return -ENODEV; - plat = pdev->dev.platform_data; + plat = dev_get_platdata(&pdev->dev); if (!plat) return -ENODEV; -- cgit v0.10.2 From bb67093796a41e0f2601f5c0022fd8873ed59fee Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 12 Nov 2013 15:11:42 -0800 Subject: drivers: w1: make w1_slave::flags long to avoid memory corruption On architectures where long is more then 32 bits, modifying a 32-bit field with set_bit (and other atomic bit operations) may cause bytes following the field to by modified. Because the endianness of the bits within a field is the native endianness of the CPU[1], on big-endian machines, bit number zero is in the last byte of the field. Therefore, `set_bit(0, ptr)' on a 64-bit big-endian machine is roughly equivalent to `((char *)ptr)[7] |= 1', and since w1 driver uses a 32-bit field for holding the flags, this causes bytes beyond the field to be modified. [1] From Documentation/atomic_ops.txt: Native atomic bit operations are defined to operate on objects aligned to the size of an "unsigned long" C data type, and are least of that size. The endianness of the bits within each "unsigned long" are the native endianness of the cpu. Signed-off-by: Michal Nazarewicz Cc: Evgeniy Polyakov Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index fa932c2..66efa96 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -709,7 +709,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) sl->owner = THIS_MODULE; sl->master = dev; - set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); + set_bit(W1_SLAVE_ACTIVE, &sl->flags); memset(&msg, 0, sizeof(msg)); memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); @@ -866,7 +866,7 @@ void w1_slave_found(struct w1_master *dev, u64 rn) sl = w1_slave_search_device(dev, tmp); if (sl) { - set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); + set_bit(W1_SLAVE_ACTIVE, &sl->flags); } else { if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7)) w1_attach_slave_device(dev, tmp); @@ -984,14 +984,14 @@ void w1_search_process_cb(struct w1_master *dev, u8 search_type, struct w1_slave *sl, *sln; list_for_each_entry(sl, &dev->slist, w1_slave_entry) - clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); + clear_bit(W1_SLAVE_ACTIVE, &sl->flags); w1_search_devices(dev, search_type, cb); list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { - if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) + if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) w1_slave_detach(sl); - else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) + else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags)) sl->ttl = dev->slave_ttl; } diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 45908e5..ca8081a 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -67,8 +67,8 @@ struct w1_slave struct w1_reg_num reg_num; atomic_t refcnt; u8 rom[9]; - u32 flags; int ttl; + unsigned long flags; struct w1_master *master; struct w1_family *family; -- cgit v0.10.2 From 69f0554ec261fd686ac7fa1c598cc9eb27b83a80 Mon Sep 17 00:00:00 2001 From: Christian Ruppert Date: Tue, 12 Nov 2013 15:11:43 -0800 Subject: init/Kconfig: add option to disable kernel compression Some ARC users say they can boot faster with without kernel compression. This probably depends on things like the FLASH chip they use etc. Until now, kernel compression can only be disabled by removing "select HAVE_" lines from the architecture Kconfig. So add the Kconfig logic to permit disabling of kernel compression. Signed-off-by: Christian Ruppert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/init/Kconfig b/init/Kconfig index bc8911f..5496f30 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -118,7 +118,6 @@ config HAVE_KERNEL_LZ4 choice prompt "Kernel compression mode" default KERNEL_GZIP - depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 help The linux kernel is a kind of self-extracting executable. Several compression algorithms are available, which differ @@ -137,6 +136,13 @@ choice If in doubt, select 'gzip' +config KERNEL_UNCOMPRESSED + bool "No compression" + help + No compression at all. The kernel is huge but the compression and + decompression times are zero. + This is usually not what you want. + config KERNEL_GZIP bool "Gzip" depends on HAVE_KERNEL_GZIP -- cgit v0.10.2 From 1bf49dd4be0b000030c6f04c4a16a17d9affdbd3 Mon Sep 17 00:00:00 2001 From: P J P Date: Tue, 12 Nov 2013 15:11:44 -0800 Subject: ./Makefile: export initial ramdisk compression config option Make menuconfig allows one to choose compression format of an initial ramdisk image. But this choice does not result in duly compressed ramdisk image. Because - $ make install - does not pass on the selected compression choice to the dracut(8) tool, which creates the initramfs file. dracut(8) generates the image with the default compression, ie. gzip(1). This patch exports the selected compression option to a sub-shell environment, so that it could be used by dracut(8) tool to generate appropriately compressed initramfs images. There isn't a straightforward way to pass on options to dracut(8) via positional parameters. Because it is indirectly invoked at the end of a $ make install sequence. # make install -> arch/$arch/boot/Makefile -> arch/$arch/boot/install.sh -> /sbing/installkernel ... -> /sbin/new-kernel-pkg ... -> /sbin/dracut ... Signed-off-by: P J P Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Makefile b/Makefile index 67077ad..606a66c 100644 --- a/Makefile +++ b/Makefile @@ -720,6 +720,22 @@ mod_strip_cmd = true endif # INSTALL_MOD_STRIP export mod_strip_cmd +# Select initial ramdisk compression format, default is gzip(1). +# This shall be used by the dracut(8) tool while creating an initramfs image. +# +INITRD_COMPRESS=gzip +ifeq ($(CONFIG_RD_BZIP2), y) + INITRD_COMPRESS=bzip2 +else ifeq ($(CONFIG_RD_LZMA), y) + INITRD_COMPRESS=lzma +else ifeq ($(CONFIG_RD_XZ), y) + INITRD_COMPRESS=xz +else ifeq ($(CONFIG_RD_LZO), y) + INITRD_COMPRESS=lzo +else ifeq ($(CONFIG_RD_LZ4), y) + INITRD_COMPRESS=lz4 +endif +export INITRD_COMPRESS ifdef CONFIG_MODULE_SIG_ALL MODSECKEY = ./signing_key.priv diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c index 143e98d..7c098ac 100644 --- a/init/do_mounts_rd.c +++ b/init/do_mounts_rd.c @@ -57,6 +57,11 @@ static int __init crd_load(int in_fd, int out_fd, decompress_fn deco); * cramfs * squashfs * gzip + * bzip2 + * lzma + * xz + * lzo + * lz4 */ static int __init identify_ramdisk_image(int fd, int start_block, decompress_fn *decompressor) -- cgit v0.10.2 From 66da0e1f9034140ae2f571ef96e254a25083906c Mon Sep 17 00:00:00 2001 From: Ilija Hadzic Date: Tue, 12 Nov 2013 15:11:45 -0800 Subject: devpts: plug the memory leak in kill_sb When devpts is unmounted, there may be a no-longer-used IDR tree hanging off the superblock we are about to kill. This needs to be cleaned up before destroying the SB. The leak is usually not a big deal because unmounting devpts is typically done when shutting down the whole machine. However, shutting down an LXC container instead of a physical machine exposes the problem (the garbage is detectable with kmemleak). Signed-off-by: Ilija Hadzic Cc: Sukadev Bhattiprolu Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 073d30b..a726b9f 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -498,6 +498,7 @@ static void devpts_kill_sb(struct super_block *sb) { struct pts_fs_info *fsi = DEVPTS_SB(sb); + ida_destroy(&fsi->allocated_ptys); kfree(fsi); kill_litter_super(sb); } -- cgit v0.10.2 From 206fa940977260ede421151aae067e2509356116 Mon Sep 17 00:00:00 2001 From: Xie XiuQi Date: Tue, 12 Nov 2013 15:11:46 -0800 Subject: ipc/util.c: remove unnecessary work pending test Remove unnecessary work pending test before calling schedule_work(). It has been tested in queue_work_on() already. No functional changed. Signed-off-by: Xie XiuQi Cc: Tejun Heo Reviewed-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/ipc/util.c b/ipc/util.c index 7684f41..3ae17a4 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -90,10 +90,8 @@ static int ipc_memory_callback(struct notifier_block *self, * In order not to keep the lock on the hotplug memory chain * for too long, queue a work item that will, when waken up, * activate the ipcns notification chain. - * No need to keep several ipc work items on the queue. */ - if (!work_pending(&ipc_memory_wq)) - schedule_work(&ipc_memory_wq); + schedule_work(&ipc_memory_wq); break; case MEM_GOING_ONLINE: case MEM_GOING_OFFLINE: -- cgit v0.10.2 From 4e9b45a19241354daec281d7a785739829b52359 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Tue, 12 Nov 2013 15:11:47 -0800 Subject: ipc, msg: fix message length check for negative values On 64 bit systems the test for negative message sizes is bogus as the size, which may be positive when evaluated as a long, will get truncated to an int when passed to load_msg(). So a long might very well contain a positive value but when truncated to an int it would become negative. That in combination with a small negative value of msg_ctlmax (which will be promoted to an unsigned type for the comparison against msgsz, making it a big positive value and therefore make it pass the check) will lead to two problems: 1/ The kmalloc() call in alloc_msg() will allocate a too small buffer as the addition of alen is effectively a subtraction. 2/ The copy_from_user() call in load_msg() will first overflow the buffer with userland data and then, when the userland access generates an access violation, the fixup handler copy_user_handle_tail() will try to fill the remainder with zeros -- roughly 4GB. That almost instantly results in a system crash or reset. ,-[ Reproducer (needs to be run as root) ]-- | #include | #include | #include | #include | | int main(void) { | long msg = 1; | int fd; | | fd = open("/proc/sys/kernel/msgmax", O_WRONLY); | write(fd, "-1", 2); | close(fd); | | msgsnd(0, &msg, 0xfffffff0, IPC_NOWAIT); | | return 0; | } '--- Fix the issue by preventing msgsz from getting truncated by consistently using size_t for the message length. This way the size checks in do_msgsnd() could still be passed with a negative value for msg_ctlmax but we would fail on the buffer allocation in that case and error out. Also change the type of m_ts from int to size_t to avoid similar nastiness in other code paths -- it is used in similar constructs, i.e. signed vs. unsigned checks. It should never become negative under normal circumstances, though. Setting msg_ctlmax to a negative value is an odd configuration and should be prevented. As that might break existing userland, it will be handled in a separate commit so it could easily be reverted and reworked without reintroducing the above described bug. Hardening mechanisms for user copy operations would have catched that bug early -- e.g. checking slab object sizes on user copy operations as the usercopy feature of the PaX patch does. Or, for that matter, detect the long vs. int sign change due to truncation, as the size overflow plugin of the very same patch does. [akpm@linux-foundation.org: fix i386 min() warnings] Signed-off-by: Mathias Krause Cc: Pax Team Cc: Davidlohr Bueso Cc: Brad Spengler Cc: Manfred Spraul Cc: [ v2.3.27+ -- yes, that old ;) ] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/msg.h b/include/linux/msg.h index 391af8d..e21f9d4 100644 --- a/include/linux/msg.h +++ b/include/linux/msg.h @@ -6,9 +6,9 @@ /* one msg_msg structure for each message */ struct msg_msg { - struct list_head m_list; - long m_type; - int m_ts; /* message text size */ + struct list_head m_list; + long m_type; + size_t m_ts; /* message text size */ struct msg_msgseg* next; void *security; /* the actual message follows immediately */ diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 491e71f..7e70959 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -41,15 +41,15 @@ struct msg_msgseg { /* the next part of the message follows immediately */ }; -#define DATALEN_MSG (int)(PAGE_SIZE-sizeof(struct msg_msg)) -#define DATALEN_SEG (int)(PAGE_SIZE-sizeof(struct msg_msgseg)) +#define DATALEN_MSG ((size_t)PAGE_SIZE-sizeof(struct msg_msg)) +#define DATALEN_SEG ((size_t)PAGE_SIZE-sizeof(struct msg_msgseg)) -static struct msg_msg *alloc_msg(int len) +static struct msg_msg *alloc_msg(size_t len) { struct msg_msg *msg; struct msg_msgseg **pseg; - int alen; + size_t alen; alen = min(len, DATALEN_MSG); msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL); @@ -80,12 +80,12 @@ out_err: return NULL; } -struct msg_msg *load_msg(const void __user *src, int len) +struct msg_msg *load_msg(const void __user *src, size_t len) { struct msg_msg *msg; struct msg_msgseg *seg; int err = -EFAULT; - int alen; + size_t alen; msg = alloc_msg(len); if (msg == NULL) @@ -117,8 +117,8 @@ out_err: struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst) { struct msg_msgseg *dst_pseg, *src_pseg; - int len = src->m_ts; - int alen; + size_t len = src->m_ts; + size_t alen; BUG_ON(dst == NULL); if (src->m_ts > dst->m_ts) @@ -147,9 +147,9 @@ struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst) return ERR_PTR(-ENOSYS); } #endif -int store_msg(void __user *dest, struct msg_msg *msg, int len) +int store_msg(void __user *dest, struct msg_msg *msg, size_t len) { - int alen; + size_t alen; struct msg_msgseg *seg; alen = min(len, DATALEN_MSG); diff --git a/ipc/util.h b/ipc/util.h index f2f5036..59d78aa 100644 --- a/ipc/util.h +++ b/ipc/util.h @@ -148,9 +148,9 @@ int ipc_parse_version (int *cmd); #endif extern void free_msg(struct msg_msg *msg); -extern struct msg_msg *load_msg(const void __user *src, int len); +extern struct msg_msg *load_msg(const void __user *src, size_t len); extern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst); -extern int store_msg(void __user *dest, struct msg_msg *msg, int len); +extern int store_msg(void __user *dest, struct msg_msg *msg, size_t len); extern void recompute_msgmni(struct ipc_namespace *); -- cgit v0.10.2