fs: Import sdFAT version 2.4.5
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / fs / sdfat / api.c
diff --git a/fs/sdfat/api.c b/fs/sdfat/api.c
new file mode 100644 (file)
index 0000000..45b0c41
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ *  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 <http://www.gnu.org/licenses/>.
+ */
+
+/************************************************************************/
+/*                                                                      */
+/*  PROJECT : exFAT & FAT12/16/32 File System                           */
+/*  FILE    : sdfat_api.c                                               */
+/*  PURPOSE : sdFAT volume lock layer                                   */
+/*                                                                      */
+/************************************************************************/
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+
+#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 */