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

Configure Feed

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

fbcon: Maintain a private array of fb_info

Accessing the one in fbmem.c without taking the right locks is a bad
idea. Instead maintain our own private copy, which is fully protected
by console_lock() (like everything else in fbcon.c). That copy is
serialized through fbcon_fb_registered/unregistered() calls.

Also this means we do not need to hold a full fb_info reference, which
is nice because doing so would mean a refcount loop between the
console and the fb_info. But it's also not nice since it means
console_lock() must be held absolutely everywhere. Well strictly
speaking we could still try to do some refcounting games again by
calling get_fb_info before we drop the console_lock. But things will
get tricky.

Acked-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: Claudio Suarez <cssk@net-c.es>
Cc: Du Cheng <ducheng2@gmail.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20220405210335.3434130-18-daniel.vetter@ffwll.ch

+43 -39
+43 -39
drivers/video/fbdev/core/fbcon.c
··· 86 86 * - fbcon state itself is protected by the console_lock, and the code does a 87 87 * pretty good job at making sure that lock is held everywhere it's needed. 88 88 * 89 - * - access to the registered_fb array is entirely unprotected. This should use 90 - * proper object lifetime handling, i.e. get/put_fb_info. This also means 91 - * switching from indices to proper pointers for fb_info everywhere. 92 - * 93 89 * - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it 94 90 * means concurrent access to the same fbdev from both fbcon and userspace 95 91 * will blow up. To fix this all fbcon calls from fbmem.c need to be moved out ··· 103 107 104 108 static struct fbcon_display fb_display[MAX_NR_CONSOLES]; 105 109 110 + struct fb_info *fbcon_registered_fb[FB_MAX]; 111 + int fbcon_num_registered_fb; 112 + 113 + #define fbcon_for_each_registered_fb(i) \ 114 + for (i = 0; WARN_CONSOLE_UNLOCKED(), i < FB_MAX; i++) \ 115 + if (!fbcon_registered_fb[i]) {} else 116 + 106 117 static signed char con2fb_map[MAX_NR_CONSOLES]; 107 118 static signed char con2fb_map_boot[MAX_NR_CONSOLES]; 108 119 ··· 117 114 { 118 115 WARN_CONSOLE_UNLOCKED(); 119 116 120 - /* 121 - * Note that only con2fb_map is protected by the console lock, 122 - * registered_fb is protected by a separate mutex. This lookup can 123 - * therefore race. 124 - */ 125 - return registered_fb[con2fb_map[console]]; 117 + return fbcon_registered_fb[con2fb_map[console]]; 126 118 } 127 119 128 120 static int logo_lines; ··· 516 518 { 517 519 int err, i; 518 520 519 - if (!num_registered_fb) 521 + if (!fbcon_num_registered_fb) 520 522 return -ENODEV; 521 523 522 524 if (!show_logo) ··· 819 821 { 820 822 struct vc_data *vc = vc_cons[unit].d; 821 823 int oldidx = con2fb_map[unit]; 822 - struct fb_info *info = registered_fb[newidx]; 824 + struct fb_info *info = fbcon_registered_fb[newidx]; 823 825 struct fb_info *oldinfo = NULL; 824 826 int found, err = 0, show_logo; 825 827 ··· 837 839 } 838 840 839 841 if (oldidx != -1) 840 - oldinfo = registered_fb[oldidx]; 842 + oldinfo = fbcon_registered_fb[oldidx]; 841 843 842 844 found = search_fb_in_map(newidx); 843 845 ··· 929 931 * If num_registered_fb is zero, this is a call for the dummy part. 930 932 * The frame buffer devices weren't initialized yet. 931 933 */ 932 - if (!num_registered_fb || info_idx == -1) 934 + if (!fbcon_num_registered_fb || info_idx == -1) 933 935 return display_desc; 934 936 /* 935 937 * Instead of blindly using registered_fb[0], we use info_idx, set by 936 938 * fbcon_fb_registered(); 937 939 */ 938 - info = registered_fb[info_idx]; 940 + info = fbcon_registered_fb[info_idx]; 939 941 if (!info) 940 942 return NULL; 941 943 ··· 1148 1150 struct fb_info *info; 1149 1151 int i, j, mapped; 1150 1152 1151 - for_each_registered_fb(i) { 1153 + fbcon_for_each_registered_fb(i) { 1152 1154 mapped = 0; 1153 - info = registered_fb[i]; 1155 + info = fbcon_registered_fb[i]; 1154 1156 1155 1157 for (j = first_fb_vc; j <= last_fb_vc; j++) { 1156 1158 if (con2fb_map[j] == i) { ··· 1177 1179 if (idx == -1) 1178 1180 goto finished; 1179 1181 1180 - info = registered_fb[idx]; 1182 + info = fbcon_registered_fb[idx]; 1181 1183 1182 1184 if (!info) 1183 1185 goto finished; ··· 2096 2098 * 2097 2099 * info->currcon = vc->vc_num; 2098 2100 */ 2099 - for_each_registered_fb(i) { 2100 - if (registered_fb[i]->fbcon_par) { 2101 - struct fbcon_ops *o = registered_fb[i]->fbcon_par; 2101 + fbcon_for_each_registered_fb(i) { 2102 + if (fbcon_registered_fb[i]->fbcon_par) { 2103 + struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par; 2102 2104 2103 2105 o->currcon = vc->vc_num; 2104 2106 } ··· 2743 2745 j = con2fb_map[i]; 2744 2746 if (j == -1) 2745 2747 continue; 2746 - fb_info = registered_fb[j]; 2748 + fb_info = fbcon_registered_fb[j]; 2747 2749 if (fb_info != info) 2748 2750 continue; 2749 2751 p = &fb_display[i]; ··· 2799 2801 set_con2fb_map(i, new_idx, 0); 2800 2802 } 2801 2803 } else { 2802 - struct fb_info *info = registered_fb[idx]; 2804 + struct fb_info *info = fbcon_registered_fb[idx]; 2803 2805 2804 2806 /* This is sort of like set_con2fb_map, except it maps 2805 2807 * the consoles to no device and then releases the ··· 2829 2831 2830 2832 console_lock(); 2831 2833 2834 + fbcon_registered_fb[info->node] = NULL; 2835 + fbcon_num_registered_fb--; 2836 + 2832 2837 if (deferred_takeover) { 2833 2838 console_unlock(); 2834 2839 return; ··· 2846 2845 if (idx == info_idx) { 2847 2846 info_idx = -1; 2848 2847 2849 - for_each_registered_fb(i) { 2848 + fbcon_for_each_registered_fb(i) { 2850 2849 info_idx = i; 2851 2850 break; 2852 2851 } ··· 2862 2861 if (primary_device == idx) 2863 2862 primary_device = -1; 2864 2863 2865 - if (!num_registered_fb) 2864 + if (!fbcon_num_registered_fb) 2866 2865 do_unregister_con_driver(&fb_con); 2867 2866 console_unlock(); 2868 2867 } ··· 2936 2935 console_lock(); 2937 2936 else 2938 2937 atomic_inc(&ignore_console_lock_warning); 2938 + 2939 + fbcon_registered_fb[info->node] = info; 2940 + fbcon_num_registered_fb++; 2939 2941 2940 2942 idx = info->node; 2941 2943 fbcon_select_primary(info); ··· 3059 3055 return -EINVAL; 3060 3056 if (con2fb.framebuffer >= FB_MAX) 3061 3057 return -EINVAL; 3062 - if (!registered_fb[con2fb.framebuffer]) 3058 + if (!fbcon_registered_fb[con2fb.framebuffer]) 3063 3059 request_module("fb%d", con2fb.framebuffer); 3064 - if (!registered_fb[con2fb.framebuffer]) { 3060 + if (!fbcon_registered_fb[con2fb.framebuffer]) { 3065 3061 return -EINVAL; 3066 3062 } 3067 3063 ··· 3128 3124 console_lock(); 3129 3125 idx = con2fb_map[fg_console]; 3130 3126 3131 - if (idx == -1 || registered_fb[idx] == NULL) 3127 + if (idx == -1 || fbcon_registered_fb[idx] == NULL) 3132 3128 goto err; 3133 3129 3134 - info = registered_fb[idx]; 3130 + info = fbcon_registered_fb[idx]; 3135 3131 rotate = simple_strtoul(buf, last, 0); 3136 3132 fbcon_rotate(info, rotate); 3137 3133 err: ··· 3150 3146 console_lock(); 3151 3147 idx = con2fb_map[fg_console]; 3152 3148 3153 - if (idx == -1 || registered_fb[idx] == NULL) 3149 + if (idx == -1 || fbcon_registered_fb[idx] == NULL) 3154 3150 goto err; 3155 3151 3156 - info = registered_fb[idx]; 3152 + info = fbcon_registered_fb[idx]; 3157 3153 rotate = simple_strtoul(buf, last, 0); 3158 3154 fbcon_rotate_all(info, rotate); 3159 3155 err: ··· 3170 3166 console_lock(); 3171 3167 idx = con2fb_map[fg_console]; 3172 3168 3173 - if (idx == -1 || registered_fb[idx] == NULL) 3169 + if (idx == -1 || fbcon_registered_fb[idx] == NULL) 3174 3170 goto err; 3175 3171 3176 - info = registered_fb[idx]; 3172 + info = fbcon_registered_fb[idx]; 3177 3173 rotate = fbcon_get_rotate(info); 3178 3174 err: 3179 3175 console_unlock(); ··· 3190 3186 console_lock(); 3191 3187 idx = con2fb_map[fg_console]; 3192 3188 3193 - if (idx == -1 || registered_fb[idx] == NULL) 3189 + if (idx == -1 || fbcon_registered_fb[idx] == NULL) 3194 3190 goto err; 3195 3191 3196 - info = registered_fb[idx]; 3192 + info = fbcon_registered_fb[idx]; 3197 3193 ops = info->fbcon_par; 3198 3194 3199 3195 if (!ops) ··· 3216 3212 console_lock(); 3217 3213 idx = con2fb_map[fg_console]; 3218 3214 3219 - if (idx == -1 || registered_fb[idx] == NULL) 3215 + if (idx == -1 || fbcon_registered_fb[idx] == NULL) 3220 3216 goto err; 3221 3217 3222 - info = registered_fb[idx]; 3218 + info = fbcon_registered_fb[idx]; 3223 3219 3224 3220 if (!info->fbcon_par) 3225 3221 goto err; ··· 3279 3275 deferred_takeover = false; 3280 3276 logo_shown = FBCON_LOGO_DONTSHOW; 3281 3277 3282 - for_each_registered_fb(i) 3283 - fbcon_fb_registered(registered_fb[i]); 3278 + fbcon_for_each_registered_fb(i) 3279 + fbcon_fb_registered(fbcon_registered_fb[i]); 3284 3280 3285 3281 console_unlock(); 3286 3282 }