/* * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "exfat_config.h" #include "exfat_global.h" #include "exfat_blkdev.h" #include "exfat_data.h" #include "exfat_api.h" #include "exfat_super.h" INT32 bdev_init(void) { return(FFS_SUCCESS); } INT32 bdev_shutdown(void) { return(FFS_SUCCESS); } INT32 bdev_open(struct super_block *sb) { BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); if (p_bd->opened) return(FFS_SUCCESS); p_bd->sector_size = bdev_logical_block_size(sb->s_bdev); p_bd->sector_size_bits = my_log2(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; return(FFS_SUCCESS); } INT32 bdev_close(struct super_block *sb) { BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); if (!p_bd->opened) return(FFS_SUCCESS); p_bd->opened = FALSE; return(FFS_SUCCESS); } INT32 bdev_read(struct super_block *sb, UINT32 secno, struct buffer_head **bh, UINT32 num_secs, INT32 read) { BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); #if EXFAT_CONFIG_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 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(FFS_SUCCESS); WARN(!p_fs->dev_ejected, "[EXFAT] No bh, device seems wrong or to be ejected.\n"); return(FFS_MEDIAERR); } INT32 bdev_write(struct super_block *sb, UINT32 secno, struct buffer_head *bh, UINT32 num_secs, INT32 sync) { INT32 count; struct buffer_head *bh2; BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); #if EXFAT_CONFIG_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 if (!p_bd->opened) return(FFS_MEDIAERR); if (secno == bh->b_blocknr) { set_buffer_uptodate(bh); mark_buffer_dirty(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 == NULL) 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(FFS_SUCCESS); no_bh: WARN(!p_fs->dev_ejected, "[EXFAT] No bh, device seems wrong or to be ejected.\n"); return (FFS_MEDIAERR); } INT32 bdev_sync(struct super_block *sb) { BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); #if EXFAT_CONFIG_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 if (!p_bd->opened) return(FFS_MEDIAERR); return sync_blockdev(sb->s_bdev); } INT32 bdev_reada(struct super_block *sb, UINT32 secno, UINT32 num_secs) { BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); UINT32 sects_per_page = (PAGE_SIZE >> sb->s_blocksize_bits); struct blk_plug plug; UINT32 i; if (!p_bd->opened) return (FFS_MEDIAERR); blk_start_plug(&plug); for (i = 0; i < num_secs; i++) { if (i && !(i & (sects_per_page - 1))) blk_flush_plug_list(&plug, false); sb_breadahead(sb, secno + i); } blk_finish_plug(&plug); return 0; }