summaryrefslogtreecommitdiffstats
path: root/drivers/staging/exfat/exfat_blkdev.c
diff options
context:
space:
mode:
authorValdis Klētnieks <valdis.kletnieks@vt.edu>2019-08-28 18:08:17 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-08-30 08:55:08 +0200
commitc48c9f7ff32b8b3965a08e40eb6763682d905b5d (patch)
treecdab82889ecc2783c645bb962aadf5ab75640281 /drivers/staging/exfat/exfat_blkdev.c
parent3982f1df00df57768f0782bc702fc4fbea347ca2 (diff)
downloadlinux-stable-c48c9f7ff32b8b3965a08e40eb6763682d905b5d.tar.gz
linux-stable-c48c9f7ff32b8b3965a08e40eb6763682d905b5d.tar.bz2
linux-stable-c48c9f7ff32b8b3965a08e40eb6763682d905b5d.zip
staging: exfat: add exfat filesystem code to staging
The exfat code needs a lot of work to get it into "real" shape for the fs/ part of the kernel, so put it into drivers/staging/ for now so that it can be worked on by everyone in the community. The full specification of the filesystem can be found at: https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification Signed-off-by: Valdis Kletnieks <valdis.kletnieks@vt.edu> Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Link: https://lore.kernel.org/r/20190828160817.6250-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/exfat/exfat_blkdev.c')
-rw-r--r--drivers/staging/exfat/exfat_blkdev.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/drivers/staging/exfat/exfat_blkdev.c b/drivers/staging/exfat/exfat_blkdev.c
new file mode 100644
index 000000000000..f086c75e7076
--- /dev/null
+++ b/drivers/staging/exfat/exfat_blkdev.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/fs.h>
+#include "exfat.h"
+
+void bdev_open(struct super_block *sb)
+{
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ if (p_bd->opened)
+ return;
+
+ p_bd->sector_size = bdev_logical_block_size(sb->s_bdev);
+ p_bd->sector_size_bits = ilog2(p_bd->sector_size);
+ p_bd->sector_size_mask = p_bd->sector_size - 1;
+ p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >>
+ p_bd->sector_size_bits;
+ p_bd->opened = true;
+}
+
+void bdev_close(struct super_block *sb)
+{
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+
+ p_bd->opened = false;
+}
+
+int bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh,
+ u32 num_secs, bool read)
+{
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ long flags = sbi->debug_flags;
+
+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
+ return FFS_MEDIAERR;
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+ if (!p_bd->opened)
+ return FFS_MEDIAERR;
+
+ if (*bh)
+ __brelse(*bh);
+
+ if (read)
+ *bh = __bread(sb->s_bdev, secno,
+ num_secs << p_bd->sector_size_bits);
+ else
+ *bh = __getblk(sb->s_bdev, secno,
+ num_secs << p_bd->sector_size_bits);
+
+ if (*bh)
+ return 0;
+
+ WARN(!p_fs->dev_ejected,
+ "[EXFAT] No bh, device seems wrong or to be ejected.\n");
+
+ return FFS_MEDIAERR;
+}
+
+int bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh,
+ u32 num_secs, bool sync)
+{
+ s32 count;
+ struct buffer_head *bh2;
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ long flags = sbi->debug_flags;
+
+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
+ return FFS_MEDIAERR;
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+ if (!p_bd->opened)
+ return FFS_MEDIAERR;
+
+ if (secno == bh->b_blocknr) {
+ lock_buffer(bh);
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+ unlock_buffer(bh);
+ if (sync && (sync_dirty_buffer(bh) != 0))
+ return FFS_MEDIAERR;
+ } else {
+ count = num_secs << p_bd->sector_size_bits;
+
+ bh2 = __getblk(sb->s_bdev, secno, count);
+ if (!bh2)
+ goto no_bh;
+
+ lock_buffer(bh2);
+ memcpy(bh2->b_data, bh->b_data, count);
+ set_buffer_uptodate(bh2);
+ mark_buffer_dirty(bh2);
+ unlock_buffer(bh2);
+ if (sync && (sync_dirty_buffer(bh2) != 0)) {
+ __brelse(bh2);
+ goto no_bh;
+ }
+ __brelse(bh2);
+ }
+
+ return 0;
+
+no_bh:
+ WARN(!p_fs->dev_ejected,
+ "[EXFAT] No bh, device seems wrong or to be ejected.\n");
+
+ return FFS_MEDIAERR;
+}
+
+int bdev_sync(struct super_block *sb)
+{
+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
+#ifdef CONFIG_EXFAT_KERNEL_DEBUG
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ long flags = sbi->debug_flags;
+
+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
+ return FFS_MEDIAERR;
+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */
+
+ if (!p_bd->opened)
+ return FFS_MEDIAERR;
+
+ return sync_blockdev(sb->s_bdev);
+}