From patchwork Fri Sep 28 01:04:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 10618825 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 362FB112B for ; Fri, 28 Sep 2018 01:04:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 25CF22ACE7 for ; Fri, 28 Sep 2018 01:04:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 194D12AE4C; Fri, 28 Sep 2018 01:04:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4F9EF2ACE7 for ; Fri, 28 Sep 2018 01:04:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726083AbeI1HZm (ORCPT ); Fri, 28 Sep 2018 03:25:42 -0400 Received: from userp2130.oracle.com ([156.151.31.86]:49396 "EHLO userp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726060AbeI1HZm (ORCPT ); Fri, 28 Sep 2018 03:25:42 -0400 Received: from pps.filterd (userp2130.oracle.com [127.0.0.1]) by userp2130.oracle.com (8.16.0.22/8.16.0.22) with SMTP id w8S14Xgh104428; Fri, 28 Sep 2018 01:04:35 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=subject : from : to : cc : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=corp-2018-07-02; bh=Mm7+JapBDHScltvVTGNNQfgax5/SrB9f6GX+PHrUEWs=; b=yh2g0M7W8/uQ+bSRd8MNze/dgjRvsWA8xA2sEj4L8jgnu08ohV+k9D+aR8KSvGh21Mib 8dxzs990oxoeptJMvICuwSoRd8Ufi3QJ/WZ4vHbPje8oZdhMuRSgc/git+UcMZfYukgo URECyrx1+dZQE4SSIzZqJwu9pwEbRxqVccPX29qLM38sxJ3DUpY14mdSagSgC3ajrby/ e8pRKBfsVwueJL5r5CZSscPCutYy8xD4nXaUbtr88Abbr9uG1GZGP3COWVUgIGH7eY9Q J3I8/sS5npQPaORX1I/QIPpCoeImyRi5bTT6RVlxeux5lAe3iswatjNuljczyi0+H9Te ww== Received: from aserv0022.oracle.com (aserv0022.oracle.com [141.146.126.234]) by userp2130.oracle.com with ESMTP id 2mnd5tw7jw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 28 Sep 2018 01:04:35 +0000 Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by aserv0022.oracle.com (8.14.4/8.14.4) with ESMTP id w8S14YKY013381 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 28 Sep 2018 01:04:34 GMT Received: from abhmp0009.oracle.com (abhmp0009.oracle.com [141.146.116.15]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id w8S14Ygk021494; Fri, 28 Sep 2018 01:04:34 GMT Received: from localhost (/10.159.248.246) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 27 Sep 2018 18:04:32 -0700 Subject: [PATCH 1/6] libxfs: port kernel transaction code From: "Darrick J. Wong" To: sandeen@redhat.com, darrick.wong@oracle.com Cc: linux-xfs@vger.kernel.org Date: Thu, 27 Sep 2018 18:04:27 -0700 Message-ID: <153809666737.32548.9381431859319686309.stgit@magnolia> In-Reply-To: <153809666117.32548.6836488790026631787.stgit@magnolia> References: <153809666117.32548.6836488790026631787.stgit@magnolia> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=nai engine=5900 definitions=9029 signatures=668707 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=2 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1807170000 definitions=main-1809280010 Sender: linux-xfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Darrick J. Wong Restructure the userspace transaction code to resemble the kernel code more closely. This will make deferred operations behave the same (with respect to transaction lifetimes) as the kernel. Signed-off-by: Darrick J. Wong --- libxfs/trans.c | 238 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 187 insertions(+), 51 deletions(-) diff --git a/libxfs/trans.c b/libxfs/trans.c index b1543b0c..11a2098d 100644 --- a/libxfs/trans.c +++ b/libxfs/trans.c @@ -20,6 +20,10 @@ #include "xfs_defer.h" static void xfs_trans_free_items(struct xfs_trans *tp); +STATIC struct xfs_trans *xfs_trans_dup(struct xfs_trans *tp); +static int xfs_trans_reserve(struct xfs_trans *tp, struct xfs_trans_res *resp, + uint blocks, uint rtextents); +static int __xfs_trans_commit(struct xfs_trans *tp, bool regrant); /* * Simple transaction interface @@ -76,24 +80,17 @@ int libxfs_trans_roll( struct xfs_trans **tpp) { - struct xfs_mount *mp; struct xfs_trans *trans = *tpp; struct xfs_trans_res tres; - unsigned int old_blk_res; - xfs_fsblock_t old_firstblock; - struct list_head old_dfops; int error; /* * Copy the critical parameters from one trans to the next. */ - mp = trans->t_mountp; tres.tr_logres = trans->t_log_res; tres.tr_logcount = trans->t_log_count; - old_blk_res = trans->t_blk_res; - old_firstblock = trans->t_firstblock; - /* structure copy */ - old_dfops = trans->t_dfops; + + *tpp = xfs_trans_dup(trans); /* * Commit the current transaction. @@ -102,7 +99,7 @@ libxfs_trans_roll( * is in progress. The caller takes the responsibility to cancel * the duplicate transaction that gets returned. */ - error = xfs_trans_commit(trans); + error = __xfs_trans_commit(trans, true); if (error) return error; @@ -115,14 +112,7 @@ libxfs_trans_roll( * the prior and the next transactions. */ tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; - error = libxfs_trans_alloc(mp, &tres, 0, 0, 0, tpp); - trans = *tpp; - trans->t_blk_res = old_blk_res; - trans->t_firstblock = old_firstblock; - /* structure copy */ - trans->t_dfops = old_dfops; - - return 0; + return xfs_trans_reserve(*tpp, &tres, 0, 0); } /* @@ -136,40 +126,150 @@ xfs_trans_free( kmem_zone_free(xfs_trans_zone, tp); } -int -libxfs_trans_alloc( - struct xfs_mount *mp, - struct xfs_trans_res *resp, - unsigned int blocks, - unsigned int rtextents, - unsigned int flags, - struct xfs_trans **tpp) +/* + * This is called to create a new transaction which will share the + * permanent log reservation of the given transaction. The remaining + * unused block and rt extent reservations are also inherited. This + * implies that the original transaction is no longer allowed to allocate + * blocks. Locks and log items, however, are no inherited. They must + * be added to the new transaction explicitly. + */ +STATIC struct xfs_trans * +xfs_trans_dup( + struct xfs_trans *tp) +{ + struct xfs_trans *ntp; + ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); + + /* + * Initialize the new transaction structure. + */ + ntp->t_mountp = tp->t_mountp; + INIT_LIST_HEAD(&ntp->t_items); + INIT_LIST_HEAD(&ntp->t_dfops); + ntp->t_firstblock = NULLFSBLOCK; + + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + + ntp->t_flags = XFS_TRANS_PERM_LOG_RES | + (tp->t_flags & XFS_TRANS_RESERVE) | + (tp->t_flags & XFS_TRANS_NO_WRITECOUNT); + /* We gave our writer reference to the new transaction */ + tp->t_flags |= XFS_TRANS_NO_WRITECOUNT; + + /* move deferred ops over to the new tp */ + xfs_defer_move(ntp, tp); + + return ntp; +} + +/* + * This is called to reserve free disk blocks and log space for the + * given transaction. This must be done before allocating any resources + * within the transaction. + * + * This will return ENOSPC if there are not enough blocks available. + * It will sleep waiting for available log space. + * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which + * is used by long running transactions. If any one of the reservations + * fails then they will all be backed out. + * + * This does not do quota reservations. That typically is done by the + * caller afterwards. + */ +static int +xfs_trans_reserve( + struct xfs_trans *tp, + struct xfs_trans_res *resp, + uint blocks, + uint rtextents) { - struct xfs_sb *sb = &mp->m_sb; - struct xfs_trans *ptr; + int error = 0; /* * Attempt to reserve the needed disk blocks by decrementing - * the number needed from the number available. This will + * the number needed from the number available. This will * fail if the count would go below zero. */ if (blocks > 0) { - if (sb->sb_fdblocks < blocks) + if (tp->t_mountp->m_sb.sb_fdblocks < blocks) return -ENOSPC; + tp->t_blk_res += blocks; + } + + /* + * Reserve the log space needed for this transaction. + */ + if (resp->tr_logres > 0) { + ASSERT(tp->t_log_res == 0 || + tp->t_log_res == resp->tr_logres); + ASSERT(tp->t_log_count == 0 || + tp->t_log_count == resp->tr_logcount); + + if (resp->tr_logflags & XFS_TRANS_PERM_LOG_RES) + tp->t_flags |= XFS_TRANS_PERM_LOG_RES; + else + ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); + + tp->t_log_res = resp->tr_logres; + tp->t_log_count = resp->tr_logcount; } - ptr = kmem_zone_zalloc(xfs_trans_zone, + /* + * Attempt to reserve the needed realtime extents by decrementing + * the number needed from the number available. This will + * fail if the count would go below zero. + */ + if (rtextents > 0) { + if (tp->t_mountp->m_sb.sb_rextents < rtextents) { + error = -ENOSPC; + goto undo_blocks; + } + } + + return 0; + + /* + * Error cases jump to one of these labels to undo any + * reservations which have already been performed. + */ +undo_blocks: + if (blocks > 0) + tp->t_blk_res = 0; + + return error; +} + +int +libxfs_trans_alloc( + struct xfs_mount *mp, + struct xfs_trans_res *resp, + unsigned int blocks, + unsigned int rtextents, + unsigned int flags, + struct xfs_trans **tpp) + +{ + struct xfs_trans *tp; + int error; + + tp = kmem_zone_zalloc(xfs_trans_zone, (flags & XFS_TRANS_NOFS) ? KM_NOFS : KM_SLEEP); - ptr->t_mountp = mp; - ptr->t_blk_res = blocks; - INIT_LIST_HEAD(&ptr->t_items); - INIT_LIST_HEAD(&ptr->t_dfops); - ptr->t_firstblock = NULLFSBLOCK; + tp->t_mountp = mp; + INIT_LIST_HEAD(&tp->t_items); + INIT_LIST_HEAD(&tp->t_dfops); + tp->t_firstblock = NULLFSBLOCK; + + error = xfs_trans_reserve(tp, resp, blocks, rtextents); + if (error) { + xfs_trans_cancel(tp); + return error; + } #ifdef XACT_DEBUG - fprintf(stderr, "allocated new transaction %p\n", ptr); + fprintf(stderr, "allocated new transaction %p\n", tp); #endif - *tpp = ptr; + *tpp = tp; return 0; } @@ -197,18 +297,25 @@ libxfs_trans_alloc_empty( void libxfs_trans_cancel( - xfs_trans_t *tp) + struct xfs_trans *tp) { #ifdef XACT_DEBUG - xfs_trans_t *otp = tp; + struct xfs_trans *otp = tp; #endif - if (tp != NULL) { - xfs_trans_free_items(tp); - xfs_trans_free(tp); - } + if (tp == NULL) + goto out; + + if (tp->t_flags & XFS_TRANS_PERM_LOG_RES) + xfs_defer_cancel(tp); + + xfs_trans_free_items(tp); + xfs_trans_free(tp); + +out: #ifdef XACT_DEBUG fprintf(stderr, "## cancelled transaction %p\n", otp); #endif + return; } int @@ -261,6 +368,9 @@ libxfs_trans_ijoin( ASSERT(iip->ili_flags == 0); ASSERT(iip->ili_inode != NULL); + ASSERT(iip->ili_lock_flags == 0); + iip->ili_lock_flags = lock_flags; + xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); ip->i_transp = tp; @@ -839,22 +949,36 @@ xfs_trans_free_items( /* * Commit the changes represented by this transaction */ -int -libxfs_trans_commit( - xfs_trans_t *tp) +static int +__xfs_trans_commit( + struct xfs_trans *tp, + bool regrant) { - xfs_sb_t *sbp; + struct xfs_sb *sbp; + int error = 0; if (tp == NULL) return 0; + /* + * Finish deferred items on final commit. Only permanent transactions + * should ever have deferred ops. + */ + WARN_ON_ONCE(!list_empty(&tp->t_dfops) && + !(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); + if (!regrant && (tp->t_flags & XFS_TRANS_PERM_LOG_RES)) { + error = xfs_defer_finish_noroll(&tp); + if (error) { + xfs_defer_cancel(tp); + goto out_unreserve; + } + } + if (!(tp->t_flags & XFS_TRANS_DIRTY)) { #ifdef XACT_DEBUG fprintf(stderr, "committed clean transaction %p\n", tp); #endif - xfs_trans_free_items(tp); - xfs_trans_free(tp); - return 0; + goto out_unreserve; } if (tp->t_flags & XFS_TRANS_SB_DIRTY) { @@ -878,4 +1002,16 @@ libxfs_trans_commit( /* That's it for the transaction structure. Free it. */ xfs_trans_free(tp); return 0; + +out_unreserve: + xfs_trans_free_items(tp); + xfs_trans_free(tp); + return error; +} + +int +libxfs_trans_commit( + struct xfs_trans *tp) +{ + return __xfs_trans_commit(tp, false); }