From patchwork Sun Jul 8 21:56:49 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Herrmann X-Patchwork-Id: 1170291 Return-Path: X-Original-To: patchwork-linux-fbdev@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 8161240134 for ; Sun, 8 Jul 2012 22:06:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752616Ab2GHV5z (ORCPT ); Sun, 8 Jul 2012 17:57:55 -0400 Received: from mail-wi0-f178.google.com ([209.85.212.178]:37264 "EHLO mail-wi0-f178.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752483Ab2GHV5E (ORCPT ); Sun, 8 Jul 2012 17:57:04 -0400 Received: by wibhr14 with SMTP id hr14so2728419wib.1 for ; Sun, 08 Jul 2012 14:57:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=nFbRtAOsx9z6sp7PEVEhVxJlktcv6R42XwgcoVncVDg=; b=qi6R1P/bWQwKu2sbZl/0Ym+gQiTzn5WzN0CL0FFIjVUwEra8sV38zO0a1t95sMn6zK b18kMUlu8cpmb966VJgW7/SKTVacZk+ydmVnsUoCO/OV8KJLBmuKMBCv1jQrQ2TkltAT /1ew7RirD9m6DHqlxbpanvmb4tKJGADpH2D95C1E35j4JA4yuxJpsJcDc939Qp/jPola Fk5ufNBTx4dHHSaSDN8OtW0lBDYid0dlRyusKwwbt8TR9NNYOoBa/Q6RO8ZxI5myVnO1 qglvzhezqnKhCLg0586jBeMir9XT/Ud7ggF9H0af7HjmVQdMGxWq5bnVUjfXWqvUsQFP bDug== Received: by 10.180.82.39 with SMTP id f7mr24414302wiy.2.1341784622722; Sun, 08 Jul 2012 14:57:02 -0700 (PDT) Received: from localhost.localdomain (stgt-5f719b43.pool.mediaWays.net. [95.113.155.67]) by mx.google.com with ESMTPS id j6sm29743837wiy.4.2012.07.08.14.57.01 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 08 Jul 2012 14:57:02 -0700 (PDT) From: David Herrmann To: linux-serial@vger.kernel.org Cc: linux-kernel@vger.kernel.org, florianschandinat@gmx.de, linux-fbdev@vger.kernel.org, gregkh@linuxfoundation.org, alan@lxorguk.ukuu.org.uk, bonbons@linux-vserver.org, David Herrmann Subject: [PATCH v2 06/11] fblog: open fb on registration Date: Sun, 8 Jul 2012 23:56:49 +0200 Message-Id: <1341784614-2797-7-git-send-email-dh.herrmann@googlemail.com> X-Mailer: git-send-email 1.7.11.1 In-Reply-To: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com> References: <1341784614-2797-1-git-send-email-dh.herrmann@googlemail.com> Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org This opens the framebuffer upon registration so we can use it for drawing-operations. On unregistration we close it again. To avoid deadlocks, we need to tell fblog_open/close() whether the framebuffer is currently locked. This is because some fb-notifiers are called with the lock held and others without it. We cannot release it in the notifier as this might confuse other registered callbacks if they actually depend on the lock to be continously held (such a callback is currently no available in the kernel, but may be added some time later). Signed-off-by: David Herrmann --- drivers/video/console/fblog.c | 91 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/drivers/video/console/fblog.c b/drivers/video/console/fblog.c index 3e0b471..113be36 100644 --- a/drivers/video/console/fblog.c +++ b/drivers/video/console/fblog.c @@ -30,12 +30,14 @@ enum fblog_flags { FBLOG_KILLED, + FBLOG_OPEN, }; struct fblog_fb { unsigned long flags; struct fb_info *info; struct device dev; + struct mutex lock; }; static DEFINE_MUTEX(fblog_registration_lock); @@ -43,6 +45,77 @@ static struct fblog_fb *fblog_fbs[FB_MAX]; #define to_fblog_dev(_d) container_of(_d, struct fblog_fb, dev) +static int fblog_open(struct fblog_fb *fb, bool locked) +{ + int ret; + + mutex_lock(&fb->lock); + + if (test_bit(FBLOG_KILLED, &fb->flags)) { + ret = -ENODEV; + goto unlock; + } + + if (test_bit(FBLOG_OPEN, &fb->flags)) { + ret = 0; + goto unlock; + } + + if (!locked) + mutex_lock(&fb->info->lock); + + if (!try_module_get(fb->info->fbops->owner)) { + ret = -ENODEV; + goto out_killed; + } + + if (fb->info->fbops->fb_open && fb->info->fbops->fb_open(fb->info, 0)) { + ret = -EIO; + goto out_unref; + } + + if (!locked) + mutex_unlock(&fb->info->lock); + + set_bit(FBLOG_OPEN, &fb->flags); + mutex_unlock(&fb->lock); + return 0; + +out_unref: + module_put(fb->info->fbops->owner); +out_killed: + if (!locked) + mutex_unlock(&fb->info->lock); + set_bit(FBLOG_KILLED, &fb->flags); +unlock: + mutex_unlock(&fb->lock); + return ret; +} + +static void fblog_close(struct fblog_fb *fb, bool kill_dev, bool locked) +{ + mutex_lock(&fb->lock); + + if (test_bit(FBLOG_OPEN, &fb->flags)) { + if (!locked) + mutex_lock(&fb->info->lock); + + if (fb->info->fbops->fb_release) + fb->info->fbops->fb_release(fb->info, 0); + module_put(fb->info->fbops->owner); + + if (!locked) + mutex_unlock(&fb->info->lock); + + clear_bit(FBLOG_OPEN, &fb->flags); + } + + if (kill_dev) + set_bit(FBLOG_KILLED, &fb->flags); + + mutex_unlock(&fb->lock); +} + /* * fblog framebuffer list * The fblog_fbs[] array contains all currently registered framebuffers. If a @@ -75,6 +148,7 @@ static void fblog_do_unregister(struct fb_info *info) fblog_fbs[info->node] = NULL; + fblog_close(fb, true, false); device_del(&fb->dev); put_device(&fb->dev); } @@ -97,6 +171,7 @@ static void fblog_do_register(struct fb_info *info, bool force) return; fb->info = info; + mutex_init(&fb->lock); __module_get(THIS_MODULE); device_initialize(&fb->dev); fb->dev.class = fb_class; @@ -111,6 +186,8 @@ static void fblog_do_register(struct fb_info *info, bool force) put_device(&fb->dev); return; } + + fblog_open(fb, true); } static void fblog_register(struct fb_info *info, bool force) @@ -132,6 +209,7 @@ static int fblog_event(struct notifier_block *self, unsigned long action, { struct fb_event *event = data; struct fb_info *info = event->info; + struct fblog_fb *fb; switch(action) { case FB_EVENT_FB_REGISTERED: @@ -146,6 +224,17 @@ static int fblog_event(struct notifier_block *self, unsigned long action, * lock might not be held. */ fblog_unregister(info); break; + case FB_EVENT_FB_UNBIND: + /* Called directly before unregistering an FB. The FB is still + * valid here and the registration lock is held but the console + * lock might not be held (really?). */ + mutex_lock(&fblog_registration_lock); + fb = fblog_fbs[info->node]; + mutex_unlock(&fblog_registration_lock); + + if (fb) + fblog_close(fb, true, true); + break; } return 0; @@ -161,7 +250,9 @@ static void fblog_scan(void) if (!info || IS_ERR(info)) continue; + mutex_lock(&info->lock); fblog_register(info, false); + mutex_unlock(&info->lock); /* There is a very subtle race-condition. Even though we might * own a reference to the fb, it may still get unregistered