/* * 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, see . */ /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ /* FILE : sdfat_api.c */ /* PURPOSE : sdFAT volume lock layer */ /* */ /************************************************************************/ #include #include #include #include #include "version.h" #include "config.h" #include "sdfat.h" #include "core.h" /*----------------------------------------------------------------------*/ /* Internal structures */ /*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /* Constant & Macro Definitions */ /*----------------------------------------------------------------------*/ static DEFINE_MUTEX(_lock_core); /*----------------------------------------------------------------------*/ /* Global Variable Definitions */ /*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /* Local Variable Definitions */ /*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /* Local Function Declarations */ /*----------------------------------------------------------------------*/ /*======================================================================*/ /* Global Function Definitions */ /* - All functions for global use have same return value format, */ /* that is, 0 on success and minus error number on */ /* various error condition. */ /*======================================================================*/ /*----------------------------------------------------------------------*/ /* sdFAT Filesystem Init & Exit Functions */ /*----------------------------------------------------------------------*/ s32 fsapi_init(void) { return fscore_init(); } s32 fsapi_shutdown(void) { return fscore_shutdown(); } /*----------------------------------------------------------------------*/ /* Volume Management Functions */ /*----------------------------------------------------------------------*/ /* mount the file system volume */ s32 fsapi_mount(struct super_block *sb) { s32 err; /* acquire the core lock for file system ccritical section */ mutex_lock(&_lock_core); err = meta_cache_init(sb); if (err) goto out; err = fscore_mount(sb); out: if (err) meta_cache_shutdown(sb); /* release the core lock for file system critical section */ mutex_unlock(&_lock_core); return err; } EXPORT_SYMBOL(fsapi_mount); /* unmount the file system volume */ s32 fsapi_umount(struct super_block *sb) { s32 err; /* acquire the core lock for file system ccritical section */ mutex_lock(&_lock_core); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_umount(sb); meta_cache_shutdown(sb); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); /* release the core lock for file system critical section */ mutex_unlock(&_lock_core); return err; } EXPORT_SYMBOL(fsapi_umount); /* get the information of a file system volume */ s32 fsapi_statfs(struct super_block *sb, VOL_INFO_T *info) { FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); /* check the validity of pointer parameters */ ASSERT(info); if (fsi->used_clusters == (u32) ~0) { s32 err; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_statfs(sb, info); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } info->FatType = fsi->vol_type; info->ClusterSize = fsi->cluster_size; info->NumClusters = fsi->num_clusters - 2; /* clu 0 & 1 */ info->UsedClusters = fsi->used_clusters + fsi->reserved_clusters; info->FreeClusters = info->NumClusters - info->UsedClusters; return 0; } EXPORT_SYMBOL(fsapi_statfs); /* synchronize a file system volume */ s32 fsapi_sync_fs(struct super_block *sb, s32 do_sync) { s32 err; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_sync_fs(sb, do_sync); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_sync_fs); s32 fsapi_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_sync) { s32 err; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_set_vol_flags(sb, new_flag, always_sync); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_set_vol_flags); /*----------------------------------------------------------------------*/ /* File Operation Functions */ /*----------------------------------------------------------------------*/ /* lookup */ s32 fsapi_lookup(struct inode *inode, u8 *path, FILE_ID_T *fid) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid && path); if (unlikely(!strlen(path))) return -EINVAL; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_lookup(inode, path, fid); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_lookup); /* create a file */ s32 fsapi_create(struct inode *inode, u8 *path, u8 mode, FILE_ID_T *fid) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid && path); if (unlikely(!strlen(path))) return -EINVAL; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_create(inode, path, mode, fid); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_create); /* read the target string of symlink */ s32 fsapi_read_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid && buffer); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_read_link(inode, fid, buffer, count, rcount); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_read_link); /* write the target string of symlink */ s32 fsapi_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid && buffer); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_write_link(inode, fid, buffer, count, wcount); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_write_link); /* resize the file length */ s32 fsapi_truncate(struct inode *inode, u64 old_size, u64 new_size) { s32 err; struct super_block *sb = inode->i_sb; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); TMSG("%s entered (inode %p size %llu)\n", __func__, inode, new_size); err = fscore_truncate(inode, old_size, new_size); TMSG("%s exitted (%d)\n", __func__, err); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_truncate); /* rename or move a old file into a new file */ s32 fsapi_rename(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) { s32 err; struct super_block *sb = old_parent_inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_rename(old_parent_inode, fid, new_parent_inode, new_dentry); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_rename); /* remove a file */ s32 fsapi_remove(struct inode *inode, FILE_ID_T *fid) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_remove(inode, fid); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_remove); /* get the information of a given file */ s32 fsapi_read_inode(struct inode *inode, DIR_ENTRY_T *info) { s32 err; struct super_block *sb = inode->i_sb; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); TMSG("%s entered (inode %p info %p\n", __func__, inode, info); err = fscore_read_inode(inode, info); TMSG("%s exited (err:%d)\n", __func__, err); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_read_inode); /* set the information of a given file */ s32 fsapi_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync) { s32 err; struct super_block *sb = inode->i_sb; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); TMSG("%s entered (inode %p info %p sync:%d\n", __func__, inode, info, sync); err = fscore_write_inode(inode, info, sync); TMSG("%s exited (err:%d)\n", __func__, err); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_write_inode); /* return the cluster number in the given cluster offset */ s32 fsapi_map_clus(struct inode *inode, u32 clu_offset, u32 *clu, int dest) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(clu); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); TMSG("%s entered (inode:%p clus:%08x dest:%d\n", __func__, inode, *clu, dest); err = fscore_map_clus(inode, clu_offset, clu, dest); TMSG("%s exited (clu:%08x err:%d)\n", __func__, *clu, err); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_map_clus); /* reserve a cluster */ s32 fsapi_reserve_clus(struct inode *inode) { s32 err; struct super_block *sb = inode->i_sb; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); TMSG("%s entered (inode:%p)\n", __func__, inode); err = fscore_reserve_clus(inode); TMSG("%s exited (err:%d)\n", __func__, err); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_reserve_clus); /*----------------------------------------------------------------------*/ /* Directory Operation Functions */ /*----------------------------------------------------------------------*/ /* create(make) a directory */ s32 fsapi_mkdir(struct inode *inode, u8 *path, FILE_ID_T *fid) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid && path); if (unlikely(!strlen(path))) return -EINVAL; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_mkdir(inode, path, fid); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_mkdir); /* read a directory entry from the opened directory */ s32 fsapi_readdir(struct inode *inode, DIR_ENTRY_T *dir_entry) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(dir_entry); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_readdir(inode, dir_entry); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_readdir); /* remove a directory */ s32 fsapi_rmdir(struct inode *inode, FILE_ID_T *fid) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_rmdir(inode, fid); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_rmdir); /* unlink a file. * that is, remove an entry from a directory. BUT don't truncate */ s32 fsapi_unlink(struct inode *inode, FILE_ID_T *fid) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(fid); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = fscore_unlink(inode, fid); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_unlink); /* reflect the internal dirty flags to VFS bh dirty flags */ s32 fsapi_cache_flush(struct super_block *sb, int do_sync) { mutex_lock(&(SDFAT_SB(sb)->s_vlock)); fcache_flush(sb, do_sync); dcache_flush(sb, do_sync); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return 0; } EXPORT_SYMBOL(fsapi_cache_flush); /* release FAT & buf cache */ s32 fsapi_cache_release(struct super_block *sb) { #ifdef CONFIG_SDFAT_DEBUG mutex_lock(&(SDFAT_SB(sb)->s_vlock)); fcache_release_all(sb); dcache_release_all(sb); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); #endif /* CONFIG_SDFAT_DEBUG */ return 0; } EXPORT_SYMBOL(fsapi_cache_release); u32 fsapi_get_au_stat(struct super_block *sb, s32 mode) { /* volume lock is not required */ return fscore_get_au_stat(sb, mode); } EXPORT_SYMBOL(fsapi_get_au_stat); /* clear extent cache */ void fsapi_invalidate_extent(struct inode *inode) { /* Volume lock is not required, * because it is only called by evict_inode. * If any other function can call it, * you should check whether volume lock is needed or not. */ extent_cache_inval_inode(inode); } EXPORT_SYMBOL(fsapi_invalidate_extent); /* check device is ejected */ s32 fsapi_check_bdi_valid(struct super_block *sb) { return fscore_check_bdi_valid(sb); } EXPORT_SYMBOL(fsapi_check_bdi_valid); #ifdef CONFIG_SDFAT_DFR /*----------------------------------------------------------------------*/ /* Defragmentation related */ /*----------------------------------------------------------------------*/ s32 fsapi_dfr_get_info(struct super_block *sb, void *arg) { /* volume lock is not required */ return defrag_get_info(sb, (struct defrag_info_arg *)arg); } EXPORT_SYMBOL(fsapi_dfr_get_info); s32 fsapi_dfr_scan_dir(struct super_block *sb, void *args) { s32 err; /* check the validity of pointer parameters */ ASSERT(args); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = defrag_scan_dir(sb, (struct defrag_trav_arg *)args); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_dfr_scan_dir); s32 fsapi_dfr_validate_clus(struct inode *inode, void *chunk, int skip_prev) { s32 err; struct super_block *sb = inode->i_sb; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = defrag_validate_cluster(inode, (struct defrag_chunk_info *)chunk, skip_prev); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_dfr_validate_clus); s32 fsapi_dfr_reserve_clus(struct super_block *sb, s32 nr_clus) { s32 err; mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = defrag_reserve_clusters(sb, nr_clus); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_dfr_reserve_clus); s32 fsapi_dfr_mark_ignore(struct super_block *sb, unsigned int clus) { /* volume lock is not required */ return defrag_mark_ignore(sb, clus); } EXPORT_SYMBOL(fsapi_dfr_mark_ignore); void fsapi_dfr_unmark_ignore_all(struct super_block *sb) { /* volume lock is not required */ defrag_unmark_ignore_all(sb); } EXPORT_SYMBOL(fsapi_dfr_unmark_ignore_all); s32 fsapi_dfr_map_clus(struct inode *inode, u32 clu_offset, u32 *clu) { s32 err; struct super_block *sb = inode->i_sb; /* check the validity of pointer parameters */ ASSERT(clu); mutex_lock(&(SDFAT_SB(sb)->s_vlock)); err = defrag_map_cluster(inode, clu_offset, clu); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); return err; } EXPORT_SYMBOL(fsapi_dfr_map_clus); void fsapi_dfr_writepage_endio(struct page *page) { /* volume lock is not required */ defrag_writepage_end_io(page); } EXPORT_SYMBOL(fsapi_dfr_writepage_endio); void fsapi_dfr_update_fat_prev(struct super_block *sb, int force) { mutex_lock(&(SDFAT_SB(sb)->s_vlock)); defrag_update_fat_prev(sb, force); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); } EXPORT_SYMBOL(fsapi_dfr_update_fat_prev); void fsapi_dfr_update_fat_next(struct super_block *sb) { mutex_lock(&(SDFAT_SB(sb)->s_vlock)); defrag_update_fat_next(sb); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); } EXPORT_SYMBOL(fsapi_dfr_update_fat_next); void fsapi_dfr_check_discard(struct super_block *sb) { mutex_lock(&(SDFAT_SB(sb)->s_vlock)); defrag_check_discard(sb); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); } EXPORT_SYMBOL(fsapi_dfr_check_discard); void fsapi_dfr_free_clus(struct super_block *sb, u32 clus) { mutex_lock(&(SDFAT_SB(sb)->s_vlock)); defrag_free_cluster(sb, clus); mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); } EXPORT_SYMBOL(fsapi_dfr_free_clus); s32 fsapi_dfr_check_dfr_required(struct super_block *sb, int *totalau, int *cleanau, int *fullau) { /* volume lock is not required */ return defrag_check_defrag_required(sb, totalau, cleanau, fullau); } EXPORT_SYMBOL(fsapi_dfr_check_dfr_required); s32 fsapi_dfr_check_dfr_on(struct inode *inode, loff_t start, loff_t end, s32 cancel, const char *caller) { /* volume lock is not required */ return defrag_check_defrag_on(inode, start, end, cancel, caller); } EXPORT_SYMBOL(fsapi_dfr_check_dfr_on); #ifdef CONFIG_SDFAT_DFR_DEBUG void fsapi_dfr_spo_test(struct super_block *sb, int flag, const char *caller) { /* volume lock is not required */ defrag_spo_test(sb, flag, caller); } EXPORT_SYMBOL(fsapi_dfr_spo_test); #endif #endif /* CONFIG_SDFAT_DFR */ /* end of sdfat_api.c */