From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 59D51C432C0 for ; Tue, 19 Nov 2019 09:40:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 13B6522304 for ; Tue, 19 Nov 2019 09:40:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="rhuyykRF" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727653AbfKSJkc (ORCPT ); Tue, 19 Nov 2019 04:40:32 -0500 Received: from mailout2.samsung.com ([203.254.224.25]:40683 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727504AbfKSJk2 (ORCPT ); Tue, 19 Nov 2019 04:40:28 -0500 Received: from epcas1p2.samsung.com (unknown [182.195.41.46]) by mailout2.samsung.com (KnoxPortal) with ESMTP id 20191119094025epoutp02bd3615ea34c68cd72bf428ab93d10e72~Yhu3FsxRP0391103911epoutp02H for ; Tue, 19 Nov 2019 09:40:25 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.samsung.com 20191119094025epoutp02bd3615ea34c68cd72bf428ab93d10e72~Yhu3FsxRP0391103911epoutp02H DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1574156425; bh=moFSjqom8tMKVgnAIE+bliJo2nyGZ77U3BbjnQGWtEE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rhuyykRFmUWYHocNOox+UxweK3oHvQDGxU/fKILTIyYqissFklwU5Pcpy5tZ7jwMH GUuxp2mT+BAZkQbbP5dZBUtoh4/8YMz74OoAz47PuBADofeWrsS5yCOS01iZ+UrXh0 s2YEMGkd2i8fhu8tB1nO8j3OboTzIVJLZiBLaIKs= Received: from epsnrtp1.localdomain (unknown [182.195.42.162]) by epcas1p3.samsung.com (KnoxPortal) with ESMTP id 20191119094025epcas1p38d0c76c7ff87ad5c9e428e5d67ebe645~Yhu2sv9a60934409344epcas1p3a; Tue, 19 Nov 2019 09:40:25 +0000 (GMT) Received: from epsmges1p1.samsung.com (unknown [182.195.40.159]) by epsnrtp1.localdomain (Postfix) with ESMTP id 47HLQw0TwkzMqYlh; Tue, 19 Nov 2019 09:40:24 +0000 (GMT) Received: from epcas1p1.samsung.com ( [182.195.41.45]) by epsmges1p1.samsung.com (Symantec Messaging Gateway) with SMTP id 12.33.04072.788B3DD5; Tue, 19 Nov 2019 18:40:24 +0900 (KST) Received: from epsmtrp1.samsung.com (unknown [182.195.40.13]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPA id 20191119094023epcas1p4976d19f4b9a859ba4bd5b3068cafa88a~Yhu1eBIR20057100571epcas1p4I; Tue, 19 Nov 2019 09:40:23 +0000 (GMT) Received: from epsmgms1p1new.samsung.com (unknown [182.195.42.41]) by epsmtrp1.samsung.com (KnoxPortal) with ESMTP id 20191119094023epsmtrp1bfd0ccd2012991400c9d6abc4034ef8d~Yhu1c4V-T0080100801epsmtrp1n; Tue, 19 Nov 2019 09:40:23 +0000 (GMT) X-AuditID: b6c32a35-9bdff70000000fe8-50-5dd3b88706b6 Received: from epsmtip2.samsung.com ( [182.195.34.31]) by epsmgms1p1new.samsung.com (Symantec Messaging Gateway) with SMTP id 73.12.03654.788B3DD5; Tue, 19 Nov 2019 18:40:23 +0900 (KST) Received: from localhost.localdomain (unknown [10.88.103.87]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20191119094023epsmtip25085d770e64fac0b2aa43d5460b0566e~Yhu1LhEgn0820508205epsmtip2C; Tue, 19 Nov 2019 09:40:23 +0000 (GMT) From: Namjae Jeon To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org Cc: gregkh@linuxfoundation.org, valdis.kletnieks@vt.edu, hch@lst.de, linkinjeon@gmail.com, Markus.Elfring@web.de, sj1557.seo@samsung.com, dwagner@suse.de, Namjae Jeon Subject: [PATCH v3 06/13] exfat: add exfat entry operations Date: Tue, 19 Nov 2019 04:37:11 -0500 Message-Id: <20191119093718.3501-7-namjae.jeon@samsung.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191119093718.3501-1-namjae.jeon@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpmk+LIzCtJLcpLzFFi42LZdlhTV7djx+VYg1+vGC0OP57EbtG8eD2b xcrVR5ksrt+9xWyxZ+9JFovLu+awWfyf9ZzV4sf0eost/46wWlx6/4HFgctj56y77B77565h 99h9s4HNo2/LKkaPzaerPT5vkvM4tP0Nm8ftZ9tYAjiicmwyUhNTUosUUvOS81My89JtlbyD 453jTc0MDHUNLS3MlRTyEnNTbZVcfAJ03TJzgE5UUihLzCkFCgUkFhcr6dvZFOWXlqQqZOQX l9gqpRak5BQYGhToFSfmFpfmpesl5+daGRoYGJkCVSbkZNxaYlrQFFVx/O8ZpgbGDrcuRk4O CQETiQ+3pjCB2EICOxglVt/m6mLkArI/MUp0vZvKDuF8Y5S4s+s0E0zHoZ9fmCESexkllv5p Z4Vr+bqvGSjDwcEmoC3xZ4soSIOIgL3E5tkHWEBqmAWOMEq8+DKBHSQhLGAtMfHXLzCbRUBV onHmXDYQmxcoPmfhORaIbfISqzccYAaxOQVsJB7OXsYIMkhC4AibxLae28wQRS4SB7f0sUPY whKvjm+BsqUkXva3sYMcJCFQLfFxP1R5B9AR320hbGOJm+s3sIKUMAtoSqzfpQ8RVpTY+Xsu I4jNLMAn8e5rDyvEFF6JjjYhiBJVib5Lh6FhIi3R1f4BaqmHxNS791khIdrPKHH0ltUERrlZ CAsWMDKuYhRLLSjOTU8tNiwwRI6uTYzgBKhluoNxyjmfQ4wCHIxKPLwK6pdjhVgTy4orcw8x SnAwK4nw+j26ECvEm5JYWZValB9fVJqTWnyI0RQYjhOZpUST84HJOa8k3tDUyNjY2MLEzNzM 1FhJnJfjx8VYIYH0xJLU7NTUgtQimD4mDk6pBsYFJRXxQlaXAnyt/BdlZuuI3l1fPe3cyveW wkX9HW5CzT06DPYCm/M4v9h9u8UYwfGlaebOz20CoqVrHikHb2LqSmlaZLh6duRFm/6Dy9Jk GOX0Vtt9/7ssYcL/q7/ijs25JVcdrWuts0dGWDx46+clBxe9VX3DzucR3Vx1VpDdOetmT5PE LyWW4oxEQy3mouJEAEtKLQ6WAwAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrHLMWRmVeSWpSXmKPExsWy7bCSvG77jsuxBtcna1kcfjyJ3aJ58Xo2 i5WrjzJZXL97i9liz96TLBaXd81hs/g/6zmrxY/p9RZb/h1htbj0/gOLA5fHzll32T32z13D 7rH7ZgObR9+WVYwem09Xe3zeJOdxaPsbNo/bz7axBHBEcdmkpOZklqUW6dslcGXcWmJa0BRV cfzvGaYGxg63LkZODgkBE4lDP78wdzFycQgJ7GaUeDS9iQUiIS1x7MQZoAQHkC0scfhwMUTN B0aJDedXM4HE2QS0Jf5sEQUpFxFwlOjddZgFpIZZ4ByjxM5nyxhBEsIC1hITf/1iB7FZBFQl GmfOZQOxeYHicxaeg9olL7F6wwFmEJtTwEbi4WyIXiGgmsZHzewTGPkWMDKsYpRMLSjOTc8t NiwwzEst1ytOzC0uzUvXS87P3cQIDlUtzR2Ml5fEH2IU4GBU4uE9oXI5Vog1say4MvcQowQH s5IIr9+jC7FCvCmJlVWpRfnxRaU5qcWHGKU5WJTEeZ/mHYsUEkhPLEnNTk0tSC2CyTJxcEo1 MDZuOG+ofnZ2J0ex/m3tKKtLgl++u4i3uD7KZKh3vJK/ujDgzY+KMBfb/k2ReZX2C46tZefo nPC1k8V57YFraQrfvQz6Xh1Ic1DiNbbQ33r+993nB3dsSv+QJ+DgwHNh7woORdbjHqs6/qxY 5TrzaHIkc+yCCW7By/KqHpVcF5u3UjSqd8e2aiWW4oxEQy3mouJEAEg7okpRAgAA X-CMS-MailID: 20191119094023epcas1p4976d19f4b9a859ba4bd5b3068cafa88a X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" X-Sendblock-Type: SVC_REQ_APPROVE CMS-TYPE: 101P DLP-Filter: Pass X-CFilter-Loop: Reflected X-CMS-RootMailID: 20191119094023epcas1p4976d19f4b9a859ba4bd5b3068cafa88a References: <20191119093718.3501-1-namjae.jeon@samsung.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This adds the implementation of exfat entry operations for exfat. Signed-off-by: Namjae Jeon Signed-off-by: Sungjong Seo --- fs/exfat/fatent.c | 475 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 fs/exfat/fatent.c diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c new file mode 100644 index 000000000000..006c513ae5c0 --- /dev/null +++ b/fs/exfat/fatent.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include + +#include "exfat_raw.h" +#include "exfat_fs.h" + +static int __exfat_ent_get(struct super_block *sb, unsigned int loc, + unsigned int *content) +{ + unsigned int off, _content; + sector_t sec; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + + sec = sbi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2)); + off = (loc << 2) & (sb->s_blocksize - 1); + + bh = sb_bread(sb, sec); + if (!bh) + return -EIO; + + _content = le32_to_cpu(*(__le32 *)(&bh->b_data[off])); + + /* remap reserved clusters to simplify code */ + if (_content >= CLUSTER_32(0xFFFFFFF8)) + _content = EOF_CLUSTER; + + *content = CLUSTER_32(_content); + brelse(bh); + return 0; +} + +int exfat_ent_set(struct super_block *sb, unsigned int loc, + unsigned int content) +{ + unsigned int off; + sector_t sec; + __le32 *fat_entry; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + + sec = sbi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2)); + off = (loc << 2) & (sb->s_blocksize - 1); + + bh = sb_bread(sb, sec); + if (!bh) + return -EIO; + + fat_entry = (__le32 *)&(bh->b_data[off]); + *fat_entry = cpu_to_le32(content); + exfat_update_bh(sb, bh, sb->s_flags & SB_SYNCHRONOUS); + exfat_mirror_bh(sb, sec, bh); + brelse(bh); + return 0; +} + +static inline bool is_reserved_cluster(unsigned int clus) +{ + if (clus == FREE_CLUSTER || clus == EOF_CLUSTER || clus == BAD_CLUSTER) + return true; + return false; +} + +static inline bool is_valid_cluster(struct exfat_sb_info *sbi, + unsigned int clus) +{ + if (clus < BASE_CLUSTER || sbi->num_clusters <= clus) + return false; + return true; +} + +int exfat_ent_get(struct super_block *sb, unsigned int loc, + unsigned int *content) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + int err; + + if (!is_valid_cluster(sbi, loc)) { + exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", + loc); + return -EIO; + } + + err = __exfat_ent_get(sb, loc, content); + if (err) { + exfat_fs_error(sb, + "failed to access to FAT (entry 0x%08x, err:%d)", + loc, err); + return err; + } + + if (!is_reserved_cluster(*content) && + !is_valid_cluster(sbi, *content)) { + exfat_fs_error(sb, + "invalid access to FAT (entry 0x%08x) bogus content (0x%08x)", + loc, *content); + return -EIO; + } + + if (*content == FREE_CLUSTER) { + exfat_fs_error(sb, + "invalid access to FAT free cluster (entry 0x%08x)", + loc); + return -EIO; + } + + if (*content == BAD_CLUSTER) { + exfat_fs_error(sb, + "invalid access to FAT bad cluster (entry 0x%08x)", + loc); + return -EIO; + } + + return 0; +} + +int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, + unsigned int len) +{ + if (!len) + return 0; + + while (len > 1) { + if (exfat_ent_set(sb, chain, chain + 1)) + return -EIO; + chain++; + len--; + } + + if (exfat_ent_set(sb, chain, EOF_CLUSTER)) + return -EIO; + return 0; +} + +int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) +{ + unsigned int num_clusters = 0; + unsigned int clu; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + /* invalid cluster number */ + if (p_chain->dir == FREE_CLUSTER || p_chain->dir == EOF_CLUSTER) + return 0; + + /* no cluster to truncate */ + if (p_chain->size == 0) + return 0; + + /* check cluster validation */ + if (p_chain->dir < 2 && p_chain->dir >= sbi->num_clusters) { + exfat_msg(sb, KERN_ERR, "invalid start cluster (%u)", + p_chain->dir); + return -EIO; + } + + WRITE_ONCE(sbi->s_dirt, true); + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + do { + exfat_clear_bitmap(inode, clu-2); + clu++; + + num_clusters++; + } while (num_clusters < p_chain->size); + } else { + do { + exfat_clear_bitmap(inode, (clu - BASE_CLUSTER)); + + if (exfat_get_next_cluster(sb, &clu)) + goto out; + + num_clusters++; + } while (clu != EOF_CLUSTER); + } + +out: + sbi->used_clusters -= num_clusters; + return 0; +} + +int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, + unsigned int *ret_clu) +{ + unsigned int clu, next; + unsigned int count = 0; + + next = p_chain->dir; + if (p_chain->flags == 0x03) { + *ret_clu = next + p_chain->size - 1; + return 0; + } + + do { + count++; + clu = next; + if (exfat_ent_get(sb, clu, &next)) + return -EIO; + } while (next != EOF_CLUSTER); + + if (p_chain->size != count) { + exfat_fs_error(sb, + "bogus directory size (clus : ondisk(%d) != counted(%d))", + p_chain->size, count); + return -EIO; + } + + *ret_clu = clu; + return 0; +} + +static inline int exfat_sync_bhs(struct buffer_head **bhs, int nr_bhs) +{ + int i, err = 0; + + for (i = 0; i < nr_bhs; i++) + write_dirty_buffer(bhs[i], 0); + + for (i = 0; i < nr_bhs; i++) { + wait_on_buffer(bhs[i]); + if (!err && !buffer_uptodate(bhs[i])) + err = -EIO; + } + return err; +} + +int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) +{ + struct super_block *sb = dir->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bhs[MAX_BUF_PER_PAGE]; + int nr_bhs = MAX_BUF_PER_PAGE; + sector_t blknr, last_blknr; + int err, i, n; + + blknr = exfat_cluster_to_sector(sbi, clu); + last_blknr = blknr + sbi->sect_per_clus; + + if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) { + exfat_fs_error_ratelimit(sb, + "%s: out of range(sect:%llu len:%u)", + __func__, (unsigned long long)blknr, + sbi->sect_per_clus); + return -EIO; + } + + /* Zeroing the unused blocks on this cluster */ + n = 0; + while (blknr < last_blknr) { + bhs[n] = sb_getblk(sb, blknr); + if (!bhs[n]) { + err = -ENOMEM; + goto error; + } + memset(bhs[n]->b_data, 0, sb->s_blocksize); + exfat_update_bh(sb, bhs[n], 0); + + n++; + blknr++; + + if (n == nr_bhs) { + if (IS_DIRSYNC(dir)) { + err = exfat_sync_bhs(bhs, n); + if (err) + goto error; + } + + for (i = 0; i < n; i++) + brelse(bhs[i]); + n = 0; + } + } + + if (IS_DIRSYNC(dir)) { + err = exfat_sync_bhs(bhs, n); + if (err) + goto error; + } + + for (i = 0; i < n; i++) + brelse(bhs[i]); + + return 0; + +error: + exfat_msg(sb, KERN_ERR, "failed zeroed sect %llu\n", + (unsigned long long)blknr); + for (i = 0; i < n; i++) + bforget(bhs[i]); + + return err; +} + +int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, + struct exfat_chain *p_chain) +{ + int ret = -ENOSPC; + unsigned int num_clusters = 0, total_cnt; + unsigned int hint_clu, new_clu, last_clu = EOF_CLUSTER; + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + total_cnt = sbi->num_clusters - BASE_CLUSTER; + + if (unlikely(total_cnt < sbi->used_clusters)) { + exfat_fs_error_ratelimit(sb, + "%s: invalid used clusters(t:%u,u:%u)\n", + __func__, total_cnt, sbi->used_clusters); + return -EIO; + } + + if (num_alloc > total_cnt - sbi->used_clusters) + return -ENOSPC; + + hint_clu = p_chain->dir; + /* find new cluster */ + if (hint_clu == EOF_CLUSTER) { + if (sbi->clu_srch_ptr < BASE_CLUSTER) { + exfat_msg(sb, KERN_ERR, + "sbi->clu_srch_ptr is invalid (%u)\n", + sbi->clu_srch_ptr); + sbi->clu_srch_ptr = BASE_CLUSTER; + } + + hint_clu = exfat_test_bitmap(sb, + sbi->clu_srch_ptr - BASE_CLUSTER); + if (hint_clu == EOF_CLUSTER) + return -ENOSPC; + } + + /* check cluster validation */ + if (hint_clu < BASE_CLUSTER && hint_clu >= sbi->num_clusters) { + exfat_msg(sb, KERN_ERR, "hint_cluster is invalid (%u)\n", + hint_clu); + hint_clu = BASE_CLUSTER; + if (p_chain->flags == 0x03) { + if (exfat_chain_cont_cluster(sb, p_chain->dir, + num_clusters)) + return -EIO; + p_chain->flags = 0x01; + } + } + + WRITE_ONCE(sbi->s_dirt, true); + + p_chain->dir = EOF_CLUSTER; + + while ((new_clu = exfat_test_bitmap(sb, + hint_clu - BASE_CLUSTER)) != EOF_CLUSTER) { + if (new_clu != hint_clu && p_chain->flags == 0x03) { + if (exfat_chain_cont_cluster(sb, p_chain->dir, + num_clusters)) { + ret = -EIO; + goto error; + } + p_chain->flags = 0x01; + } + + /* update allocation bitmap */ + if (exfat_set_bitmap(inode, new_clu - BASE_CLUSTER)) { + ret = -EIO; + goto error; + } + + num_clusters++; + + /* update FAT table */ + if (p_chain->flags == 0x01) { + if (exfat_ent_set(sb, new_clu, EOF_CLUSTER)) { + ret = -EIO; + goto error; + } + } + + if (p_chain->dir == EOF_CLUSTER) { + p_chain->dir = new_clu; + } else if (p_chain->flags == 0x01) { + if (exfat_ent_set(sb, last_clu, new_clu)) { + ret = -EIO; + goto error; + } + } + last_clu = new_clu; + + if (--num_alloc == 0) { + sbi->clu_srch_ptr = hint_clu; + sbi->used_clusters += num_clusters; + + p_chain->size += num_clusters; + return 0; + } + + hint_clu = new_clu + 1; + if (hint_clu >= sbi->num_clusters) { + hint_clu = BASE_CLUSTER; + + if (p_chain->flags == 0x03) { + if (exfat_chain_cont_cluster(sb, p_chain->dir, + num_clusters)) { + ret = -EIO; + goto error; + } + p_chain->flags = 0x01; + } + } + } +error: + if (num_clusters) + exfat_free_cluster(inode, p_chain); + return ret; +} + +int exfat_count_num_clusters(struct super_block *sb, + struct exfat_chain *p_chain, unsigned int *ret_count) +{ + unsigned int i, count; + unsigned int clu; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + if (!p_chain->dir || p_chain->dir == EOF_CLUSTER) { + *ret_count = 0; + return 0; + } + + if (p_chain->flags == 0x03) { + *ret_count = p_chain->size; + return 0; + } + + clu = p_chain->dir; + count = 0; + for (i = BASE_CLUSTER; i < sbi->num_clusters; i++) { + count++; + if (exfat_ent_get(sb, clu, &clu)) + return -EIO; + if (clu == EOF_CLUSTER) + break; + } + + *ret_count = count; + return 0; +} + +int exfat_mirror_bh(struct super_block *sb, sector_t sec, + struct buffer_head *bh) +{ + struct buffer_head *c_bh; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sector_t sec2; + int err = 0; + + if (sbi->FAT2_start_sector != sbi->FAT1_start_sector) { + sec2 = sec - sbi->FAT1_start_sector + sbi->FAT2_start_sector; + c_bh = sb_getblk(sb, sec2); + if (!c_bh) { + err = -ENOMEM; + goto out; + } + memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize); + set_buffer_uptodate(c_bh); + mark_buffer_dirty(c_bh); + if (sb->s_flags & SB_SYNCHRONOUS) + err = sync_dirty_buffer(c_bh); + brelse(c_bh); + } +out: + return err; +} -- 2.17.1