└── fs └── sdcardfs ├── Kconfig ├── packagelist.h ├── Makefile ├── android_filesystem_config.h ├── misc.h ├── multiuser.h ├── macros.h ├── packagelist.c ├── xattr.c ├── trace-events.h ├── mmap.c ├── remove.c ├── create.c ├── sysfs.c ├── super.c ├── dir_ci.c ├── configfs.c ├── derived_perm.c ├── tree.c ├── namei.c ├── dentry.c ├── file.c ├── main.c ├── inode.c └── sdcardfs.h /fs/sdcardfs/Kconfig: -------------------------------------------------------------------------------- 1 | config SDCARD_FS 2 | tristate "sdcard file system" 3 | depends on CONFIGFS_FS 4 | default n 5 | help 6 | Sdcardfs is based on Wrapfs file system. 7 | 8 | config SDCARD_FS_FADV_NOACTIVE 9 | bool "sdcardfs fadvise noactive support" 10 | depends on FADV_NOACTIVE 11 | default y 12 | help 13 | Sdcardfs supports fadvise noactive mode. 14 | -------------------------------------------------------------------------------- /fs/sdcardfs/packagelist.h: -------------------------------------------------------------------------------- 1 | #ifndef __SDCARDFS_PACKAGELIST_H 2 | #define __SDCARDFS_PACKAGELIST_H 3 | 4 | #include 5 | #include 6 | #include "multiuser.h" 7 | 8 | struct sdcardfs_packagelist_entry { 9 | union { 10 | struct config_item item; 11 | struct rcu_head rcu; 12 | }; 13 | struct hlist_node hlist; 14 | char *app_name; 15 | appid_t appid; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /fs/sdcardfs/Makefile: -------------------------------------------------------------------------------- 1 | SDCARDFS_VERSION="1.0" 2 | 3 | ccflags-y += -DSDCARDFS_VERSION=\"$(SDCARDFS_VERSION)\" -DSDCARDFS_CASE_INSENSITIVE -DSDCARDFS_SUPPORT_RESERVED_SPACE \ 4 | -DSDCARDFS_UNDERLAY_MULTI_ALIASES -DSDCARDFS_SYSFS_FEATURE -DSDCARDFS_PLUGIN_PRIVACY_SPACE -g -Wall 5 | 6 | obj-$(CONFIG_SDCARD_FS) += sdcardfs.o 7 | sdcardfs-objs := dentry.o file.o inode.o configfs.o dir_ci.o main.o super.o namei.o \ 8 | mmap.o packagelist.o derived_perm.o tree.o xattr.o sysfs.o 9 | 10 | -------------------------------------------------------------------------------- /fs/sdcardfs/android_filesystem_config.h: -------------------------------------------------------------------------------- 1 | #ifndef _ANDROID_FILESYSTEM_CONFIG_H_ 2 | #define _ANDROID_FILESYSTEM_CONFIG_H_ 3 | 4 | /* This is the master Users and Groups config for the platform. 5 | * DO NOT EVER RENUMBER 6 | */ 7 | 8 | #define AID_ROOT 0 /* traditional unix root user */ 9 | 10 | #define AID_SYSTEM 1000 /* system server */ 11 | 12 | #define AID_SDCARD_RW 1015 /* external storage write access */ 13 | 14 | #define AID_MEDIA_RW 1023 /* internal media storage write access */ 15 | 16 | #define AID_SDCARD_R 1028 /* external storage read access */ 17 | #define AID_SDCARD_PICS 1033 /* external storage photos access */ 18 | #define AID_SDCARD_AV 1034 /* external storage audio/video access */ 19 | #define AID_SDCARD_ALL 1035 /* access all users external storage */ 20 | 21 | #define AID_PACKAGE_INFO 1032 /* access to installed package details */ 22 | 23 | #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */ 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /fs/sdcardfs/misc.h: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/misc.h 4 | * Reusable code-snippets / Utilities for the sdcardfs implementation 5 | * 6 | * Copyright (C) 2017 HUAWEI, Inc. 7 | * Author: gaoxiang 8 | * 9 | * This file is subject to the terms and conditions of the GNU General Public 10 | * License. See the file COPYING in the main directory of the Linux 11 | * distribution for more details. 12 | */ 13 | #if defined(__SDCARDFS_MISC__SHOW_OPTIONS) 14 | #undef __SDCARDFS_MISC__SHOW_OPTIONS 15 | if (opts->fs_low_uid) 16 | xx(",fsuid=%u", opts->fs_low_uid); 17 | if (opts->fs_low_gid) 18 | xx(",fsgid=%u", opts->fs_low_gid); 19 | if (opts->gid) 20 | xx(",gid=%u", opts->gid); 21 | if (opts->multiuser) 22 | xx(",multiuser"); 23 | if (opts->mask) 24 | xx(",mask=%u", opts->mask); 25 | if (opts->fs_user_id) 26 | xx(",userid=%u", opts->fs_user_id); 27 | if (opts->reserved_mb) 28 | xx(",reserved_mb=%u", opts->reserved_mb); 29 | if (opts->quiet) 30 | xx(",quiet"); 31 | #else 32 | #error precompiled macro is not defined 33 | #endif 34 | 35 | -------------------------------------------------------------------------------- /fs/sdcardfs/multiuser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * fs/sdcardfs/multiuser.h 3 | * 4 | * Copyright (c) 2013 Samsung Electronics Co. Ltd 5 | * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, 6 | * Sunghwan Yun, Sungjong Seo 7 | * 8 | * This program has been developed as a stackable file system based on 9 | * the WrapFS which written by 10 | * 11 | * Copyright (c) 1998-2011 Erez Zadok 12 | * Copyright (c) 2009 Shrikar Archak 13 | * Copyright (c) 2003-2011 Stony Brook University 14 | * Copyright (c) 2003-2011 The Research Foundation of SUNY 15 | * 16 | * This file is dual licensed. It may be redistributed and/or modified 17 | * under the terms of the Apache 2.0 License OR version 2 of the GNU 18 | * General Public License. 19 | */ 20 | #ifndef __SDCARDFS_MULTIUSER_H 21 | #define __SDCARDFS_MULTIUSER_H 22 | 23 | #define MULTIUSER_APP_PER_USER_RANGE 100000 24 | 25 | typedef uid_t userid_t; 26 | typedef uid_t appid_t; 27 | 28 | static inline userid_t multiuser_get_user_id(uid_t uid) { 29 | return uid / MULTIUSER_APP_PER_USER_RANGE; 30 | } 31 | 32 | static inline appid_t multiuser_get_app_id(uid_t uid) { 33 | return uid % MULTIUSER_APP_PER_USER_RANGE; 34 | } 35 | 36 | static inline uid_t multiuser_get_uid(userid_t userId, appid_t appId) { 37 | return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE); 38 | } 39 | 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /fs/sdcardfs/macros.h: -------------------------------------------------------------------------------- 1 | #ifndef __LINUX_MACROS_H 2 | #define __LINUX_MACROS_H 3 | 4 | #ifndef d_inode 5 | #define d_inode(x) ((x)->d_inode) 6 | #endif 7 | 8 | #ifndef inode_lock_nested 9 | #define inode_lock_nested(x, y) mutex_lock_nested(&(x)->i_mutex, (y)) 10 | #endif 11 | 12 | #ifndef inode_lock 13 | #define inode_lock(x) mutex_lock(&(x)->i_mutex) 14 | #endif 15 | 16 | #ifndef inode_unlock 17 | #define inode_unlock(x) mutex_unlock(&(x)->i_mutex) 18 | #endif 19 | 20 | #ifndef lockless_dereference 21 | /** 22 | * lockless_dereference() - safely load a pointer for later dereference 23 | * @p: The pointer to load 24 | * 25 | * Similar to rcu_dereference(), but for situations where the pointed-to 26 | * object's lifetime is managed by something other than RCU. That 27 | * "something other" might be reference counting or simple immortality. 28 | * 29 | * The seemingly unused variable ___typecheck_p validates that @p is 30 | * indeed a pointer type by using a pointer to typeof(*p) as the type. 31 | * Taking a pointer to typeof(*p) again is needed in case p is void *. 32 | */ 33 | #define lockless_dereference(p) \ 34 | ({ \ 35 | typeof(p) _________p1 = ACCESS_ONCE(p); \ 36 | typeof(*(p)) *___typecheck_p __maybe_unused; \ 37 | smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ 38 | (_________p1); \ 39 | }) 40 | #endif 41 | 42 | #ifndef d_really_is_negative 43 | #define d_really_is_negative(dentry) ((dentry)->d_inode == NULL) 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /fs/sdcardfs/packagelist.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/packagelist.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | #include "packagelist.h" 14 | #include 15 | 16 | DEFINE_HASHTABLE(pkgl_hashtable, 8); 17 | 18 | /* BKDR Hash Function */ 19 | static u32 str_hash(const char *str) 20 | { 21 | const u32 seed = 131; /* 31 131 1313 13131 131313 etc.. */ 22 | u32 hash = 0; 23 | 24 | while (*str != '\0') 25 | hash = hash * seed + tolower(*str++); 26 | return hash; 27 | } 28 | 29 | appid_t get_appid(const char *app_name) 30 | { 31 | appid_t retid = 0; 32 | struct sdcardfs_packagelist_entry *iter; 33 | u32 hashval = str_hash(app_name); 34 | 35 | rcu_read_lock(); 36 | hash_for_each_possible_rcu(pkgl_hashtable, iter, hlist, hashval) { 37 | if (!strcasecmp(iter->app_name, app_name)) { 38 | retid = iter->appid; 39 | break; 40 | } 41 | } 42 | rcu_read_unlock(); 43 | return retid; 44 | } 45 | 46 | struct sdcardfs_packagelist_entry * 47 | sdcardfs_packagelist_entry_alloc(void) 48 | { 49 | return kzalloc( 50 | sizeof(struct sdcardfs_packagelist_entry), 51 | GFP_KERNEL); 52 | } 53 | 54 | void sdcardfs_packagelist_entry_register( 55 | struct sdcardfs_packagelist_entry *pkg, 56 | const char *app_name, appid_t appid 57 | ) { 58 | pkg->app_name = kstrdup(app_name, GFP_KERNEL); 59 | pkg->appid = appid; 60 | hash_add_rcu(pkgl_hashtable, &pkg->hlist, 61 | str_hash(app_name)); 62 | } 63 | 64 | static void __rcu_free(struct rcu_head *rcu) 65 | { 66 | struct sdcardfs_packagelist_entry *pkg = 67 | container_of(rcu, struct sdcardfs_packagelist_entry, rcu); 68 | 69 | BUG_ON(pkg->app_name == NULL); 70 | kfree(pkg->app_name); 71 | kfree(pkg); 72 | } 73 | 74 | void sdcardfs_packagelist_entry_release( 75 | struct sdcardfs_packagelist_entry *pkg 76 | ) { 77 | hash_del_rcu(&pkg->hlist); 78 | call_rcu(&pkg->rcu, __rcu_free); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /fs/sdcardfs/xattr.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/xattr.c 4 | * 5 | * Copyright (c) 2013 Samsung Electronics Co. Ltd 6 | * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, 7 | * Sunghwan Yun, Sungjong Seo 8 | * 9 | * This file is subject to the terms and conditions of the GNU General Public 10 | * License. See the file COPYING in the main directory of the Linux 11 | * distribution for more details. 12 | */ 13 | #include 14 | #include "sdcardfs.h" 15 | 16 | int sdcardfs_setxattr(struct dentry *dentry, const char *name, 17 | const void *value, size_t size, int flags) 18 | { 19 | int rc; 20 | struct dentry *lower_dentry = sdcardfs_get_lower_dentry(dentry); 21 | struct inode *lower_inode = d_inode(lower_dentry); 22 | 23 | if (unlikely(lower_inode->i_op->setxattr == NULL)) { 24 | rc = -EOPNOTSUPP; 25 | goto out; 26 | } 27 | 28 | rc = vfs_setxattr(lower_dentry, name, value, size, flags); 29 | out: 30 | dput(lower_dentry); 31 | return rc; 32 | } 33 | 34 | ssize_t sdcardfs_getxattr(struct dentry *dentry, 35 | const char *name, void *value, size_t size) 36 | { 37 | ssize_t rc; 38 | struct dentry *lower_dentry = sdcardfs_get_lower_dentry(dentry); 39 | struct inode *lower_inode = d_inode(lower_dentry); 40 | 41 | if (unlikely(lower_inode->i_op->getxattr == NULL)) { 42 | rc = -EOPNOTSUPP; 43 | goto out; 44 | } 45 | 46 | rc = lower_inode->i_op->getxattr(lower_dentry, name, value, size); 47 | out: 48 | dput(lower_dentry); 49 | return rc; 50 | } 51 | 52 | ssize_t sdcardfs_listxattr(struct dentry *dentry, char *list, size_t size) 53 | { 54 | ssize_t rc; 55 | struct dentry *lower_dentry = sdcardfs_get_lower_dentry(dentry); 56 | struct inode *lower_inode = d_inode(lower_dentry); 57 | 58 | if (unlikely(lower_inode->i_op->listxattr == NULL)) { 59 | rc = -EOPNOTSUPP; 60 | goto out; 61 | } 62 | 63 | rc = lower_inode->i_op->listxattr(lower_dentry, list, size); 64 | out: 65 | dput(lower_dentry); 66 | return rc; 67 | } 68 | 69 | int sdcardfs_removexattr(struct dentry *dentry, const char *name) 70 | { 71 | ssize_t rc; 72 | struct dentry *lower_dentry = sdcardfs_get_lower_dentry(dentry); 73 | struct inode *lower_inode = d_inode(lower_dentry); 74 | 75 | if (unlikely(lower_inode->i_op->removexattr == NULL)) { 76 | rc = -EOPNOTSUPP; 77 | goto out; 78 | } 79 | 80 | inode_lock(lower_inode); 81 | rc = lower_inode->i_op->removexattr(lower_dentry, name); 82 | inode_unlock(lower_inode); 83 | out: 84 | dput(lower_dentry); 85 | return rc; 86 | } 87 | -------------------------------------------------------------------------------- /fs/sdcardfs/trace-events.h: -------------------------------------------------------------------------------- 1 | #undef TRACE_SYSTEM 2 | #define TRACE_SYSTEM sdcardfs 3 | 4 | #if !defined(__SDCARDFS_TRACE_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ) 5 | #define __SDCARDFS_TRACE_EVENTS_H 6 | 7 | #include 8 | 9 | TRACE_EVENT(sdcardfs_ialloc, 10 | TP_PROTO(struct inode *inode), 11 | 12 | TP_ARGS(inode), 13 | 14 | TP_STRUCT__entry( 15 | __field(struct inode *, inode) 16 | __field(ino_t, ino) 17 | __field(mode_t, mode) 18 | ), 19 | 20 | TP_fast_assign( 21 | __entry->inode = inode; 22 | __entry->ino = inode->i_ino; 23 | __entry->mode = inode->i_mode; 24 | ), 25 | 26 | TP_printk("(inode 0x%p) ino %lu mode 0%o", 27 | __entry->inode, (unsigned long) __entry->ino, __entry->mode) 28 | ); 29 | 30 | TRACE_EVENT(sdcardfs_lookup, 31 | TP_PROTO(struct inode *dir, 32 | struct dentry *dentry, 33 | unsigned int flags), 34 | TP_ARGS(dir, dentry, flags), 35 | 36 | TP_STRUCT__entry( 37 | __field(struct inode *, dir) 38 | __field(struct dentry *, dentry) 39 | __field(unsigned int, flags) 40 | __string(name, dentry->d_name.name) 41 | ), 42 | 43 | TP_fast_assign( 44 | __entry->dir = dir; 45 | __entry->dentry = dentry; 46 | __entry->flags = flags; 47 | __assign_str(name, dentry->d_name.name); 48 | ), 49 | 50 | TP_printk("(dentry 0x%p) name %s dir 0x%p flags %x", 51 | __entry->dentry, __get_str(name), 52 | __entry->dir, __entry->flags) 53 | ); 54 | 55 | #define trace_sdcardfs_d_delete_enter(a) 56 | #define trace_sdcardfs_d_delete_exit(a, b) 57 | 58 | #define trace_sdcardfs_d_revalidate_fast_enter(a, b) 59 | #define trace_sdcardfs_d_revalidate_fast_refwalk(a, b) 60 | #define trace_sdcardfs_d_revalidate_fast_exit(a, b, c) 61 | 62 | #define trace_sdcardfs_d_revalidate_slow_enter(a, b) 63 | #define trace_sdcardfs_d_revalidate_slow_miss(a, b) 64 | #define trace_sdcardfs_d_revalidate_slow_exit(a, b, c) 65 | 66 | #define trace_sdcardfs_create_enter(a, b, c, d) 67 | #define trace_sdcardfs_create_exit(a, b, c, d, e) 68 | 69 | #define trace_sdcardfs_mkdir_enter(a, b, c) 70 | #define trace_sdcardfs_mkdir_exit(a, b, c, d) 71 | 72 | #define trace_sdcardfs_unlink_enter(a, b) 73 | #define trace_sdcardfs_unlink_exit(a, b, c) 74 | 75 | #define trace_sdcardfs_rmdir_enter(a, b) 76 | #define trace_sdcardfs_rmdir_exit(a, b, c) 77 | 78 | #define trace_sdcardfs_rename_enter(a, b, c, d) 79 | #define trace_sdcardfs_rename_exit(a, b, c, d, e) 80 | 81 | #endif 82 | /***** NOTICE! The #if protection ends here. *****/ 83 | 84 | #undef TRACE_INCLUDE_PATH 85 | #undef TRACE_INCLUDE_FILE 86 | #define TRACE_INCLUDE_PATH . 87 | 88 | #define TRACE_INCLUDE_FILE trace-events 89 | 90 | /* This part must be outside protection */ 91 | #include 92 | -------------------------------------------------------------------------------- /fs/sdcardfs/mmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fs/sdcardfs/mmap.c 3 | * 4 | * Copyright (c) 2013 Samsung Electronics Co. Ltd 5 | * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, 6 | * Sunghwan Yun, Sungjong Seo 7 | * 8 | * This program has been developed as a stackable file system based on 9 | * the WrapFS which written by 10 | * 11 | * Copyright (c) 1998-2011 Erez Zadok 12 | * Copyright (c) 2009 Shrikar Archak 13 | * Copyright (c) 2003-2011 Stony Brook University 14 | * Copyright (c) 2003-2011 The Research Foundation of SUNY 15 | * 16 | * This file is dual licensed. It may be redistributed and/or modified 17 | * under the terms of the Apache 2.0 License OR version 2 of the GNU 18 | * General Public License. 19 | */ 20 | 21 | #include "sdcardfs.h" 22 | #include 23 | 24 | static int sdcardfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 25 | { 26 | int err; 27 | struct file *file; 28 | const struct vm_operations_struct *lower_vm_ops; 29 | 30 | file = (struct file *)vma->vm_private_data; 31 | lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; 32 | BUG_ON(!lower_vm_ops); 33 | 34 | err = lower_vm_ops->fault(vma, vmf); 35 | return err; 36 | } 37 | 38 | static void sdcardfs_vm_open(struct vm_area_struct *vma) 39 | { 40 | struct file *file = (struct file *)vma->vm_private_data; 41 | 42 | get_file(file); 43 | } 44 | 45 | static void sdcardfs_vm_close(struct vm_area_struct *vma) 46 | { 47 | struct file *file = (struct file *)vma->vm_private_data; 48 | 49 | fput(file); 50 | } 51 | 52 | static int sdcardfs_page_mkwrite(struct vm_area_struct *vma, 53 | struct vm_fault *vmf) 54 | { 55 | int err = 0; 56 | struct file *file; 57 | const struct vm_operations_struct *lower_vm_ops; 58 | 59 | file = (struct file *)vma->vm_private_data; 60 | lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; 61 | BUG_ON(!lower_vm_ops); 62 | if (!lower_vm_ops->page_mkwrite) 63 | goto out; 64 | 65 | err = lower_vm_ops->page_mkwrite(vma, vmf); 66 | out: 67 | return err; 68 | } 69 | 70 | static ssize_t sdcardfs_direct_IO( 71 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) 72 | int rw, 73 | #endif 74 | struct kiocb *iocb 75 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) 76 | , struct iov_iter *iter 77 | #else 78 | , const struct iovec *iov 79 | #endif 80 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)) 81 | , loff_t offset 82 | #endif 83 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) 84 | , unsigned long nr_segs 85 | #endif 86 | ) { 87 | /* 88 | * This function should never be called directly. We need it 89 | * to exist, to get past a check in open_check_o_direct(), 90 | * which is called from do_last(). 91 | */ 92 | return -EINVAL; 93 | } 94 | 95 | const struct address_space_operations sdcardfs_aops = { 96 | .direct_IO = sdcardfs_direct_IO, 97 | }; 98 | 99 | const struct vm_operations_struct sdcardfs_vm_ops = { 100 | .fault = sdcardfs_fault, 101 | .page_mkwrite = sdcardfs_page_mkwrite, 102 | .open = sdcardfs_vm_open, 103 | .close = sdcardfs_vm_close, 104 | }; 105 | -------------------------------------------------------------------------------- /fs/sdcardfs/remove.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/remove.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | 13 | /* this file is as part of other files used for including source (eg. inode.c) */ 14 | 15 | /* context for sdcardfs_do_remove_xxxx */ 16 | typedef struct sdcardfs_do_remove_struct { 17 | struct dentry *real_dentry; 18 | struct dentry *real_dir_dentry; 19 | const struct cred *saved_cred; 20 | } _sdcardfs_do_remove_struct; 21 | 22 | 23 | #define this(x) __->x 24 | 25 | static int __sdcardfs_do_remove_begin( 26 | _sdcardfs_do_remove_struct *__, 27 | struct inode *dir, 28 | struct dentry *dentry 29 | ) { 30 | int err; 31 | struct dentry *real; 32 | 33 | /* some forbidden filenames should be checked before removing */ 34 | if (permission_denied_to_remove(dir, dentry->d_name.name)) { 35 | errln("permission denied to remove %s", dentry->d_name.name); 36 | return -EACCES; 37 | } 38 | 39 | this(real_dentry) = sdcardfs_get_real_dentry(dentry); 40 | BUG_ON(this(real_dentry) == NULL); 41 | 42 | retry: 43 | this(real_dir_dentry) = dget_parent(this(real_dentry)); 44 | 45 | /* TODO: disconnected dentry is not supported yet.*/ 46 | BUG_ON(this(real_dir_dentry) == NULL); 47 | 48 | /* note that real_dir_dentry ?(!=) lower_dentry(dget_parent(dentry)). 49 | * and it's unsafe to check by use IS_ROOT since inode_lock isnt taken */ 50 | if (unlikely(this(real_dentry) == 51 | this(real_dir_dentry))) { 52 | err = -EBUSY; 53 | goto dput_err; 54 | } 55 | inode_lock_nested(d_inode(this(real_dir_dentry)), I_MUTEX_PARENT); 56 | 57 | if (unlikely(this(real_dir_dentry) != 58 | this(real_dentry)->d_parent)) { 59 | inode_unlock(d_inode(this(real_dir_dentry))); 60 | dput(this(real_dir_dentry)); 61 | goto retry; 62 | } 63 | 64 | /* save current_cred and override it */ 65 | OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), this(saved_cred)); 66 | if (IS_ERR(this(saved_cred))) { 67 | err = PTR_ERR(this(saved_cred)); 68 | goto unlock_err; 69 | } 70 | 71 | /* real_dentry must be hashed and in the real_dir */ 72 | real = lookup_one_len(this(real_dentry)->d_name.name, 73 | this(real_dir_dentry), this(real_dentry)->d_name.len); 74 | if (IS_ERR(real)) { 75 | /* maybe some err or real_dir_dentry DEADDIR */ 76 | err = PTR_ERR(real); 77 | goto revert_cred_err; 78 | } 79 | 80 | dput(real); 81 | 82 | /* 1) although we find a dentry with the same name in lower fs, 83 | it's not the old real dentry stored in tree_entry 84 | 2) if real isn't found(negative dentry) */ 85 | if (this(real_dentry) != real/* && 86 | d_is_negative(real)*/) { 87 | err = -ESTALE; 88 | 89 | /* since we dont support hashed but negative dentry */ 90 | d_invalidate(dentry); 91 | goto revert_cred_err; 92 | } 93 | return 0; 94 | 95 | revert_cred_err: 96 | REVERT_CRED(this(saved_cred)); 97 | unlock_err: 98 | inode_unlock(d_inode(this(real_dir_dentry))); 99 | dput_err: 100 | dput(this(real_dir_dentry)); 101 | dput(this(real_dentry)); 102 | return err; 103 | } 104 | 105 | static void __sdcardfs_do_remove_end( 106 | _sdcardfs_do_remove_struct *__, 107 | struct inode *dir 108 | ) { 109 | REVERT_CRED(this(saved_cred)); 110 | fsstack_copy_inode_size(dir, d_inode(this(real_dir_dentry))); 111 | 112 | inode_unlock(d_inode(this(real_dir_dentry))); 113 | dput(this(real_dir_dentry)); 114 | dput(this(real_dentry)); 115 | } 116 | 117 | -------------------------------------------------------------------------------- /fs/sdcardfs/create.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/create.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | 13 | /* this file is as part of other files used for including source (eg. inode.c) */ 14 | 15 | /* context for sdcardfs_do_create_xxxx */ 16 | typedef struct sdcardfs_do_create_struct { 17 | struct dentry *parent, *real_dentry; 18 | struct dentry *real_dir_dentry; 19 | const struct cred *saved_cred; 20 | struct fs_struct *saved_fs; 21 | } _sdcardfs_do_create_struct; 22 | 23 | #define this(x) __->x 24 | 25 | static int __sdcardfs_do_create_begin( 26 | _sdcardfs_do_create_struct *__, 27 | struct inode *dir, 28 | struct dentry *dentry 29 | ) { 30 | int err; 31 | struct sdcardfs_sb_info *sbi; 32 | 33 | if (SDCARDFS_D(dentry) != NULL) { 34 | warnln("%s, negative dentry(%s) should not have tree entry", 35 | __FUNCTION__, dentry->d_name.name); 36 | return -ESTALE; 37 | } 38 | 39 | /* some forbidden filenames should be checked before creating */ 40 | if (permission_denied_to_create(dir, dentry->d_name.name)) { 41 | errln("permission denied to create %s", dentry->d_name.name); 42 | return -EACCES; 43 | } 44 | 45 | this(parent) = dget_parent(dentry); 46 | BUG_ON(d_inode(this(parent)) != dir); 47 | 48 | this(real_dir_dentry) = sdcardfs_get_lower_dentry(this(parent)); 49 | BUG_ON(this(real_dir_dentry) == NULL); 50 | 51 | inode_lock_nested(d_inode(this(real_dir_dentry)), I_MUTEX_PARENT); 52 | 53 | /* save current_cred and override it */ 54 | sbi = SDCARDFS_SB(dir->i_sb); 55 | OVERRIDE_CRED(sbi, this(saved_cred)); 56 | if (IS_ERR(this(saved_cred))) { 57 | err = PTR_ERR(this(saved_cred)); 58 | goto unlock_err; 59 | } 60 | 61 | #ifdef SDCARDFS_CASE_INSENSITIVE 62 | if (sbi->ci->may_create != NULL) { 63 | struct path path = {.dentry = this(real_dir_dentry), 64 | .mnt = sbi->lower_mnt}; 65 | 66 | err = sbi->ci->may_create(&path, &dentry->d_name); 67 | if (err) { 68 | goto revert_cred_err; 69 | } 70 | } 71 | #endif 72 | 73 | this(real_dentry) = lookup_one_len(dentry->d_name.name, 74 | this(real_dir_dentry), dentry->d_name.len); 75 | 76 | if (IS_ERR(this(real_dentry))) { 77 | err = PTR_ERR(this(real_dentry)); 78 | goto revert_cred_err; 79 | } 80 | 81 | if (d_is_positive(this(real_dentry))) { 82 | err = -ESTALE; 83 | goto dput_err; 84 | } 85 | 86 | BUG_ON(sbi->override_fs == NULL); 87 | this(saved_fs) = override_current_fs(sbi->override_fs); 88 | return 0; 89 | 90 | dput_err: 91 | dput(this(real_dentry)); 92 | revert_cred_err: 93 | REVERT_CRED(this(saved_cred)); 94 | unlock_err: 95 | inode_unlock(d_inode(this(real_dir_dentry))); 96 | dput(this(real_dir_dentry)); 97 | dput(this(parent)); 98 | return err; 99 | } 100 | 101 | static int __sdcardfs_do_create_end( 102 | _sdcardfs_do_create_struct *__, 103 | const char *__caller_FUNCTION__, 104 | struct inode *dir, 105 | struct dentry *dentry, 106 | int err 107 | ) { 108 | revert_current_fs(this(saved_fs)); 109 | REVERT_CRED(this(saved_cred)); 110 | 111 | if (err) { 112 | dput(this(real_dentry)); 113 | goto out; 114 | } 115 | 116 | err = PTR_ERR(sdcardfs_interpose(this(parent), 117 | dentry, this(real_dentry))); 118 | if (err) 119 | errln("%s, unexpected error when interposing: %d", 120 | __caller_FUNCTION__, err); 121 | 122 | out: 123 | fsstack_copy_inode_size(dir, d_inode(this(real_dir_dentry))); 124 | 125 | inode_unlock(d_inode(this(real_dir_dentry))); 126 | dput(this(real_dir_dentry)); 127 | dput(this(parent)); 128 | return err; 129 | } 130 | -------------------------------------------------------------------------------- /fs/sdcardfs/sysfs.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/sysfs.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | 14 | #ifdef SDCARDFS_PLUGIN_PRIVACY_SPACE 15 | static ssize_t 16 | sdcardfs_sysfs_sb_blocked_users_show(struct kobject *kobj, 17 | struct kobj_attribute *attr, char *buf) { 18 | 19 | struct sdcardfs_sb_info *sbi = container_of(kobj, 20 | struct sdcardfs_sb_info, kobj); 21 | ssize_t len = 0; 22 | 23 | if (sbi->blocked_userid >= 0) 24 | len = snprintf(buf, PAGE_SIZE, "%d %d", 25 | sbi->blocked_userid, sbi->appid_excluded); 26 | buf[len++] = '\n'; 27 | buf[len++] = '\0'; 28 | return len; 29 | } 30 | 31 | static ssize_t 32 | sdcardfs_sysfs_sb_blocked_users_store(struct kobject *kobj, 33 | struct kobj_attribute *attr, 34 | const char *buf, size_t len) { 35 | 36 | struct sdcardfs_sb_info *sbi = container_of(kobj, 37 | struct sdcardfs_sb_info, kobj); 38 | 39 | int args = sscanf(buf, "%d%d", &sbi->blocked_userid, 40 | &sbi->appid_excluded); 41 | 42 | if (args <= 0) 43 | sbi->blocked_userid = -1; 44 | else if (args <= 1) 45 | sbi->appid_excluded = -1; 46 | 47 | /* print some debug messages for the privacyspace feature */ 48 | if (sbi->blocked_userid < 0) 49 | warnln("all users have access to %s now", kobj->name); 50 | else { 51 | warnln("user/%d has been blocked from accessing %s", 52 | sbi->blocked_userid, kobj->name); 53 | 54 | if (sbi->appid_excluded >= 0) 55 | warnln("but appid/%d will be excluded", 56 | sbi->appid_excluded); 57 | } 58 | return len; 59 | } 60 | #endif 61 | 62 | static ssize_t 63 | sdcardfs_sysfs_sb_device_show(struct kobject *kobj, 64 | struct kobj_attribute *attr, char *buf) { 65 | 66 | struct sdcardfs_sb_info *sbi = container_of(kobj, 67 | struct sdcardfs_sb_info, kobj); 68 | 69 | return snprintf(buf, PAGE_SIZE, "%s\n", sbi->devpath_s); 70 | } 71 | 72 | static void __sdcardfs_sysfs_sb_release(struct kobject *kobj) 73 | { 74 | struct sdcardfs_sb_info *sbi = container_of(kobj, 75 | struct sdcardfs_sb_info, kobj); 76 | 77 | kfree(sbi); 78 | } 79 | 80 | static ssize_t 81 | sdcardfs_sysfs_attr_show(struct kobject *kobj, 82 | struct attribute *attr, char *buf) 83 | { 84 | struct kobj_attribute *ka = 85 | container_of(attr, struct kobj_attribute, attr); 86 | 87 | return ka->show(kobj, ka, buf); 88 | } 89 | 90 | static ssize_t 91 | sdcardfs_sysfs_attr_store(struct kobject *kobj, 92 | struct attribute *attr, const char *buf, 93 | size_t len) 94 | { 95 | struct kobj_attribute *ka; 96 | 97 | char *s = skip_spaces(buf); 98 | len -= s - buf; 99 | buf = s; 100 | 101 | if (len == 0 || *buf == '\0') 102 | return -EINVAL; 103 | 104 | ka = container_of(attr, struct kobj_attribute, attr); 105 | return ka->store(kobj, ka, buf, len); 106 | } 107 | 108 | #define __SYSFS_ATTR_RW(name) \ 109 | (struct kobj_attribute)__ATTR(name, S_IWUSR | S_IRUGO, \ 110 | sdcardfs_sysfs_sb_##name##_show, sdcardfs_sysfs_sb_##name##_store) 111 | 112 | #define __SYSFS_ATTR_RO(name) \ 113 | (struct kobj_attribute)__ATTR(name, S_IRUGO, \ 114 | sdcardfs_sysfs_sb_##name##_show, NULL) 115 | 116 | static struct sysfs_ops sysfs_op = { 117 | .show = sdcardfs_sysfs_attr_show, 118 | .store = sdcardfs_sysfs_attr_store 119 | }; 120 | 121 | static struct attribute *sb_attrs[] = { 122 | &__SYSFS_ATTR_RO(device).attr, 123 | #ifdef SDCARDFS_PLUGIN_PRIVACY_SPACE 124 | &__SYSFS_ATTR_RW(blocked_users).attr, 125 | #endif 126 | NULL, /* need to NULL terminate the list of attributes */ 127 | }; 128 | 129 | static struct kobj_type sb_ktype = { 130 | .release = __sdcardfs_sysfs_sb_release, 131 | .sysfs_ops = &sysfs_op, 132 | .default_attrs = sb_attrs, 133 | }; 134 | 135 | static struct kset *sdcardfs_kset; 136 | 137 | int sdcardfs_sysfs_init(void) 138 | { 139 | /* located under /sys/fs/ */ 140 | sdcardfs_kset = kset_create_and_add(SDCARDFS_NAME, NULL, fs_kobj); 141 | return sdcardfs_kset == NULL ? -ENOMEM : 0; 142 | } 143 | 144 | void sdcardfs_sysfs_exit(void) 145 | { 146 | BUG_ON(sdcardfs_kset == NULL); 147 | 148 | kset_unregister(sdcardfs_kset); 149 | } 150 | 151 | int sdcardfs_sysfs_register_sb(struct super_block *sb) 152 | { 153 | int err; 154 | struct sdcardfs_sb_info *sbi = SDCARDFS_SB(sb); 155 | 156 | BUG_ON(sdcardfs_kset == NULL); 157 | 158 | sbi->kobj.kset = sdcardfs_kset; 159 | err = kobject_init_and_add(&sbi->kobj, &sb_ktype, NULL, 160 | "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev)); 161 | if (err) { 162 | errln("failed to kobject_init_and_add, err=%d", err); 163 | return err; 164 | } 165 | 166 | /* send the uevent that the kobject is added to the sysfs */ 167 | kobject_uevent(&sbi->kobj, KOBJ_ADD); 168 | return 0; 169 | } 170 | 171 | -------------------------------------------------------------------------------- /fs/sdcardfs/super.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/super.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | 14 | /* could be triggered after deactivate_locked_super() 15 | is called, thus including umount and failed to initialize. */ 16 | static void sdcardfs_put_super(struct super_block *sb) 17 | { 18 | struct vfsmount *lower_mnt; 19 | struct sdcardfs_sb_info *sbi = SDCARDFS_SB(sb); 20 | 21 | /* failed to read_super */ 22 | if (sbi == NULL) 23 | return; 24 | 25 | /* if exists, dput(shared_obb) */ 26 | dput(sbi->shared_obb); 27 | 28 | if (sbi->sdcardd_cred != NULL) 29 | put_cred(sbi->sdcardd_cred); 30 | 31 | free_fs_struct(sbi->override_fs); 32 | 33 | if (sbi->devpath_s == NULL) 34 | errln("%s, unexpected sbi->devpath_s == NULL", 35 | __FUNCTION__); 36 | else { 37 | infoln("unmounting on top of %s", sbi->devpath_s); 38 | __putname(sbi->devpath_s); 39 | } 40 | 41 | /* deal with lower_sb & lower_mnt */ 42 | lower_mnt = sbi->lower_mnt; 43 | BUG_ON(lower_mnt == NULL); 44 | atomic_dec(&lower_mnt->mnt_sb->s_active); 45 | mntput(lower_mnt); 46 | 47 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 48 | _path_put(&sbi->basepath); 49 | #endif 50 | 51 | #ifdef SDCARDFS_SYSFS_FEATURE 52 | kobject_put(&sbi->kobj); 53 | #else 54 | kfree(sbi); 55 | #endif 56 | sb->s_fs_info = NULL; 57 | } 58 | 59 | static int sdcardfs_statfs(struct dentry *dentry, struct kstatfs *buf) 60 | { 61 | int err; 62 | 63 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 64 | struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); 65 | err = vfs_statfs(&sbi->basepath, buf); 66 | 67 | if (sbi->options.reserved_mb) { 68 | u64 min_blocks; 69 | 70 | /* Invalid statfs informations. */ 71 | if (!buf->f_bsize) { 72 | errln("f_bsize == 0 returned by underlay_statfs."); 73 | return -EINVAL; 74 | } 75 | 76 | min_blocks = ((u64)sbi->options.reserved_mb << 20) / (u64)buf->f_bsize; 77 | buf->f_blocks -= min_blocks; 78 | 79 | if (buf->f_bavail > min_blocks) 80 | buf->f_bavail -= min_blocks; 81 | else 82 | buf->f_bavail = 0; 83 | 84 | /* Make reserved blocks invisiable to media storage */ 85 | buf->f_bfree = buf->f_bavail; 86 | } 87 | #else 88 | struct path lower_path; 89 | 90 | sdcardfs_get_lower_path(dentry, &lower_path); 91 | err = vfs_statfs(&lower_path, buf); 92 | _path_put(&lower_path); 93 | #endif 94 | 95 | /* set return buf to our f/s to avoid confusing user-level utils */ 96 | buf->f_type = SDCARDFS_SUPER_MAGIC; 97 | 98 | return err; 99 | } 100 | 101 | /* @flags: numeric mount options 102 | @options: mount options string */ 103 | static int sdcardfs_remount_fs(struct super_block *sb, int *flags, char *options) 104 | { 105 | int err = 0; 106 | 107 | /* The VFS will take care of "ro" and "rw" flags among others. We 108 | can safely accept a few flags (RDONLY, MANDLOCK), and honor 109 | SILENT, but anything else left over is an error. */ 110 | if ((*flags & ~(MS_RDONLY | MS_MANDLOCK | MS_SILENT)) != 0) { 111 | errln("remount flags 0x%x unsupported", *flags); 112 | err = -EINVAL; 113 | } 114 | 115 | return err; 116 | } 117 | 118 | /* 119 | * Called by iput() when the inode reference count reached zero 120 | * and the inode is not hashed anywhere. Used to clear anything 121 | * that needs to be, before the inode is completely destroyed and put 122 | * on the inode free list. 123 | */ 124 | static void sdcardfs_evict_inode(struct inode *inode) 125 | { 126 | truncate_inode_pages(&inode->i_data, 0); 127 | clear_inode(inode); 128 | } 129 | 130 | /* 131 | * Used only in nfs, to kill any pending RPC tasks, so that subsequent 132 | * code can actually succeed and won't leave tasks that need handling. 133 | */ 134 | static void sdcardfs_umount_begin(struct super_block *sb) 135 | { 136 | struct super_block *lower_sb; 137 | 138 | lower_sb = sdcardfs_lower_super(sb); 139 | if (lower_sb && lower_sb->s_op && lower_sb->s_op->umount_begin) 140 | lower_sb->s_op->umount_begin(lower_sb); 141 | } 142 | 143 | static int sdcardfs_show_options(struct seq_file *m, 144 | struct dentry *root) 145 | { 146 | struct sdcardfs_mount_options *opts 147 | = &SDCARDFS_SB(root->d_sb)->options; 148 | 149 | #define xx(...) seq_printf(m, __VA_ARGS__) 150 | #define __SDCARDFS_MISC__SHOW_OPTIONS 151 | #include "misc.h" 152 | return 0; 153 | }; 154 | 155 | const struct super_operations sdcardfs_sops = { 156 | .put_super = sdcardfs_put_super, 157 | .statfs = sdcardfs_statfs, 158 | .remount_fs = sdcardfs_remount_fs, 159 | .evict_inode = sdcardfs_evict_inode, 160 | .umount_begin = sdcardfs_umount_begin, 161 | .show_options = sdcardfs_show_options, 162 | .drop_inode = generic_delete_inode, 163 | }; 164 | -------------------------------------------------------------------------------- /fs/sdcardfs/dir_ci.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/dir_ci.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | #include 14 | 15 | struct __generic_ci_readdir_private { 16 | struct dir_context ctx; 17 | const struct qstr *to_find; 18 | union { 19 | char *name; 20 | bool found; 21 | } u; 22 | }; 23 | 24 | static int __generic_lookup_ci_match( 25 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) 26 | void *_ctx, const char *name, int namelen, 27 | #else 28 | struct dir_context *_ctx, const char *name, int namelen, 29 | #endif 30 | loff_t offset, u64 ino, unsigned int d_type 31 | ) { 32 | struct __generic_ci_readdir_private *buf = container_of(_ctx, 33 | struct __generic_ci_readdir_private, ctx); 34 | 35 | if (unlikely(namelen == buf->to_find->len && 36 | !strncasecmp(name, buf->to_find->name, namelen))) { 37 | buf->u.name = __getname(); 38 | if (buf->u.name == NULL) 39 | buf->u.name = ERR_PTR(-ENOMEM); 40 | else { 41 | memcpy(buf->u.name, name, namelen); 42 | buf->u.name[namelen] = '\0'; 43 | } 44 | return -1; 45 | } 46 | return 0; 47 | } 48 | 49 | static int __generic_may_create_ci_match( 50 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) 51 | void *_ctx, const char *name, int namelen, 52 | #else 53 | struct dir_context *_ctx, const char *name, int namelen, 54 | #endif 55 | loff_t offset, u64 ino, unsigned int d_type) 56 | { 57 | struct __generic_ci_readdir_private *buf = container_of(_ctx, 58 | struct __generic_ci_readdir_private, ctx); 59 | 60 | if (unlikely(namelen == buf->to_find->len && 61 | !strncasecmp(name, buf->to_find->name, namelen))) { 62 | buf->u.found = true; 63 | return -1; /* found */ 64 | } 65 | return 0; 66 | } 67 | 68 | static inline int __iterate_dir_locked(struct file *file, 69 | struct dir_context *ctx) 70 | { 71 | struct inode *inode; 72 | int res; 73 | if (file->f_op->iterate == NULL) 74 | return -ENOTDIR; 75 | 76 | inode = file_inode(file); 77 | if (IS_DEADDIR(inode)) 78 | return -ENOENT; 79 | 80 | ctx->pos = file->f_pos; 81 | res = file->f_op->iterate(file, ctx); 82 | file->f_pos = ctx->pos; 83 | return res; 84 | } 85 | 86 | /* remember that the currect cred has been overrided */ 87 | static char * 88 | __generic_lookup_ci_begin(struct path *dir, 89 | struct qstr *name, bool locked) 90 | { 91 | int err; 92 | struct file *file; 93 | struct __generic_ci_readdir_private buffer = { 94 | .ctx.actor = __generic_lookup_ci_match, 95 | .to_find = name, 96 | .u.name = NULL, 97 | }; 98 | 99 | /* any risk dentry_open within inode_lock(dir)? */ 100 | file = dentry_open(dir, O_RDONLY | O_DIRECTORY 101 | | O_NOATIME, current_cred()); 102 | 103 | if (IS_ERR(file)) { 104 | errln("%s: unexpected error when dentry_open, err=%ld", 105 | __FUNCTION__, PTR_ERR(file)); 106 | return ERR_CAST(file); 107 | } 108 | 109 | err = locked ? __iterate_dir_locked(file, &buffer.ctx) : 110 | iterate_dir(file, &buffer.ctx); 111 | fput(file); 112 | if (err) 113 | return ERR_PTR(err); 114 | return buffer.u.name; 115 | } 116 | 117 | static struct dentry *sdcardfs_generic_lookup_ci( 118 | struct path *dir, 119 | struct qstr *orig, bool locked) 120 | { 121 | struct dentry *dentry; 122 | char *name; 123 | 124 | name = __generic_lookup_ci_begin(dir, orig, locked); 125 | if (IS_ERR(name)) 126 | return (struct dentry *)name; 127 | else if (name == NULL) 128 | return ERR_PTR(-ENOENT); 129 | 130 | if (!locked) 131 | inode_lock_nested(d_inode(dir->dentry), I_MUTEX_PARENT); 132 | dentry = lookup_one_len(name, dir->dentry, orig->len); 133 | if (!locked) 134 | inode_unlock(d_inode(dir->dentry)); 135 | __putname(name); 136 | /* remember that lookup_one_len never returns NULL */ 137 | return dentry; 138 | } 139 | 140 | static int 141 | sdcardfs_generic_may_create_ci(struct path *dir, struct qstr *name) 142 | { 143 | int err; 144 | struct file *file; 145 | struct __generic_ci_readdir_private buffer = { 146 | .ctx.actor = __generic_may_create_ci_match, 147 | .to_find = name, 148 | .u.found = false 149 | }; 150 | 151 | /* any risk dentry_open within inode_lock(dir)? */ 152 | file = dentry_open(dir, O_RDONLY | O_DIRECTORY 153 | | O_NOATIME, current_cred()); 154 | if (IS_ERR(file)) { 155 | err = PTR_ERR(file); 156 | errln("%s: unexpected error when dentry_open, err=%d", 157 | __FUNCTION__, err); 158 | return err; 159 | } 160 | err = __iterate_dir_locked(file, &buffer.ctx); 161 | fput(file); 162 | if (err) 163 | return err; 164 | return buffer.u.found ? -EEXIST : 0; 165 | } 166 | 167 | struct sdcardfs_dir_ci_ops sdcardfs_generic_dir_ci_op = { 168 | .lookup = sdcardfs_generic_lookup_ci, 169 | .may_create = sdcardfs_generic_may_create_ci 170 | }, sdcardfs_stub_dir_ci_op = { 171 | .lookup = NULL, 172 | .may_create = NULL 173 | }; 174 | 175 | #define EXFAT_SUPER_MAGIC (0x2011BAB0L) 176 | #define NTFS_SUPER_MAGIC (0x5346544EL) 177 | 178 | struct sdcardfs_dir_ci_ops *sdcardfs_lowerfs_ci_ops(struct super_block *sb) 179 | { 180 | if (sb->s_magic == MSDOS_SUPER_MAGIC 181 | || sb->s_magic == EXFAT_SUPER_MAGIC 182 | || sb->s_magic == NTFS_SUPER_MAGIC) 183 | return &sdcardfs_stub_dir_ci_op; 184 | return &sdcardfs_generic_dir_ci_op; 185 | } 186 | 187 | -------------------------------------------------------------------------------- /fs/sdcardfs/configfs.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/configfs.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | #include "packagelist.h" 14 | #include 15 | 16 | static ssize_t 17 | sdcardfs_configfs_pkgdir_appid_show( 18 | struct config_item *item, char *page 19 | ) { 20 | struct sdcardfs_packagelist_entry *pkg = container_of( 21 | item, struct sdcardfs_packagelist_entry, item); 22 | 23 | return scnprintf(page, PAGE_SIZE, "%d\n", (int)pkg->appid); 24 | } 25 | 26 | static ssize_t sdcardfs_configfs_pkgdir_appid_store( 27 | struct config_item *item, 28 | const char *page, size_t count 29 | ) { 30 | unsigned int tmp; 31 | int ret; 32 | 33 | struct sdcardfs_packagelist_entry *pkg = container_of( 34 | item, struct sdcardfs_packagelist_entry, item); 35 | 36 | ret = kstrtouint(page, 10, &tmp); 37 | if (ret) 38 | return ret; 39 | 40 | pkg->appid = tmp; 41 | return count; 42 | } 43 | 44 | /* all users should have R & W permission */ 45 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) 46 | 47 | #define SDCARDFS_CONFIGFS_ATTR(_pfx, _name) \ 48 | static struct configfs_attribute _pfx##_attr_##_name = { \ 49 | .ca_name = __stringify(_name), \ 50 | .ca_mode = S_IRUGO | S_IWUGO, \ 51 | .ca_owner = THIS_MODULE, \ 52 | .show = _pfx##_##_name##_show, \ 53 | .store = _pfx##_##_name##_store, \ 54 | } 55 | 56 | #else 57 | 58 | struct sdcardfs_configfs_attribute { 59 | struct configfs_attribute attr; 60 | ssize_t (*show)(struct configfs_item *, char *); 61 | ssize_t (*store)(struct configfs_item *, const char *, size_t); 62 | }; 63 | 64 | #define SDCARDFS_CONFIGFS_ATTR(_pfx, _name) \ 65 | static struct sdcardfs_configfs_attribute _pfx##_attr_##_name = \ 66 | __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUGO, \ 67 | _pfx##_##_name##_show, _pfx##_##_name##_store) 68 | 69 | static ssize_t sdcardfs_configfs_attr_show(struct config_item *item, 70 | struct configfs_attribute *attr, char *page) 71 | { 72 | struct sdcardfs_configfs_attribute *_attr = 73 | container_of(attr, struct sdcardfs_configfs_attribute, attr); 74 | 75 | return _attr->show != NULL ? _attr->show(item, page) : 0; 76 | } 77 | 78 | static ssize_t sdcardfs_configfs_attr_store(struct config_item *item, 79 | struct configfs_attribute *attr, 80 | const char *page, size_t count) 81 | { 82 | struct sdcardfs_configfs_attribute *_attr = 83 | container_of(attr, struct sdcardfs_configfs_attribute, attr); 84 | 85 | return _attr->store != NULL ? 86 | _attr->store(item, page, count) : -EINVAL; 87 | } 88 | 89 | #endif 90 | 91 | SDCARDFS_CONFIGFS_ATTR(sdcardfs_configfs_pkgdir, appid); 92 | 93 | /* there exists a pkgdir and some attributes for 94 | * each Android package dir under rootdir */ 95 | static struct configfs_attribute *sdcardfs_configfs_pkgdir_attrs[] = { 96 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) 97 | &sdcardfs_configfs_pkgdir_attr_appid, 98 | #else 99 | &sdcardfs_configfs_pkgdir_attr_appid.attr, 100 | #endif 101 | NULL, 102 | }; 103 | 104 | /* remove a pkgdir */ 105 | static 106 | void sdcardfs_configfs_pkgdir_item_release( 107 | struct config_item *item 108 | ) { 109 | struct sdcardfs_packagelist_entry *pkg = container_of( 110 | item, struct sdcardfs_packagelist_entry, item); 111 | 112 | sdcardfs_packagelist_entry_release(pkg); 113 | } 114 | 115 | static struct configfs_item_operations sdcardfs_configfs_pkgdir_item_ops = { 116 | .release = sdcardfs_configfs_pkgdir_item_release, 117 | 118 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) 119 | .show_attribute = sdcardfs_configfs_attr_show, 120 | .store_attribute = sdcardfs_configfs_attr_store, 121 | #endif 122 | }; 123 | 124 | static struct config_item_type sdcardfs_configfs_pkgdir_type = { 125 | .ct_attrs = sdcardfs_configfs_pkgdir_attrs, 126 | .ct_item_ops = &sdcardfs_configfs_pkgdir_item_ops, 127 | .ct_owner = THIS_MODULE, 128 | }; 129 | 130 | /* rootdir consists of all pkgdirs + an extersion dir */ 131 | static 132 | struct config_item * 133 | sdcardfs_configfs_rootdir_group_make_item( 134 | struct config_group *group, 135 | const char *name 136 | ) { 137 | struct sdcardfs_packagelist_entry *pkg; 138 | 139 | pkg = sdcardfs_packagelist_entry_alloc(); 140 | if (pkg == NULL) 141 | return NULL; 142 | config_item_init_type_name(&pkg->item, 143 | name, &sdcardfs_configfs_pkgdir_type); 144 | sdcardfs_packagelist_entry_register(pkg, name, 0); 145 | return &pkg->item; 146 | } 147 | 148 | static struct configfs_group_operations sdcardfs_configfs_rootdir_group_ops = { 149 | .make_item = sdcardfs_configfs_rootdir_group_make_item, 150 | }; 151 | 152 | static struct config_item_type sdcardfs_configfs_rootdir_type = { 153 | .ct_owner = THIS_MODULE, 154 | .ct_group_ops = &sdcardfs_configfs_rootdir_group_ops, 155 | }; 156 | 157 | static struct configfs_subsystem sdcardfs_configfs_subsys = { 158 | .su_group = { 159 | .cg_item = { 160 | .ci_namebuf = "sdcardfs", 161 | .ci_type = &sdcardfs_configfs_rootdir_type, 162 | }, 163 | }, 164 | }; 165 | 166 | int sdcardfs_configfs_init(void) 167 | { 168 | int ret; 169 | struct configfs_subsystem *subsys = &sdcardfs_configfs_subsys; 170 | 171 | config_group_init(&subsys->su_group); 172 | mutex_init(&subsys->su_mutex); 173 | ret = configfs_register_subsystem(subsys); 174 | if (ret) { 175 | errln("failed to register configfs subsystem(%s): %d", 176 | subsys->su_group.cg_item.ci_namebuf, ret); 177 | } 178 | return ret; 179 | } 180 | 181 | void sdcardfs_configfs_exit(void) { 182 | configfs_unregister_subsystem(&sdcardfs_configfs_subsys); 183 | } 184 | 185 | -------------------------------------------------------------------------------- /fs/sdcardfs/derived_perm.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/derived_perm.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | 14 | const struct cred *prepare_fsids(struct sdcardfs_sb_info *sbi) 15 | { 16 | struct cred *cred = prepare_creds(); 17 | 18 | if (cred == NULL) 19 | return NULL; 20 | cred->fsuid = make_kuid(&init_user_ns, sbi->options.fs_low_uid); 21 | cred->fsgid = make_kgid(&init_user_ns, sbi->options.fs_low_gid); 22 | #ifdef CONFIG_SECURITY 23 | /* if necessary, override security field */ 24 | if (unlikely(sbi->options.has_fssecid)) { 25 | const struct cred *saved_cred = override_creds(sbi->sdcardd_cred); 26 | if (likely(saved_cred != NULL)) { 27 | int ret = set_security_override(cred, sbi->options.fs_low_secid); 28 | if (unlikely(ret < 0)) { 29 | critln("Security denies permission to nominate" 30 | " security context: %d", ret); 31 | sbi->options.has_fssecid = false; 32 | } 33 | revert_creds(saved_cred); 34 | } 35 | } 36 | #endif 37 | return cred; 38 | } 39 | 40 | /* Do not directly use this function. Use OVERRIDE_CRED() instead. */ 41 | const struct cred *override_fsids(struct sdcardfs_sb_info *sbi) { 42 | const struct cred *cred = prepare_fsids(sbi); 43 | 44 | if (cred == NULL) 45 | return ERR_PTR(-ENOMEM); 46 | return override_creds(cred); 47 | } 48 | 49 | /* Do not directly use this function, use REVERT_CRED() instead. */ 50 | void revert_fsids(const struct cred *old_cred) 51 | { 52 | const struct cred *cur_cred = current->cred; 53 | 54 | revert_creds(old_cred); 55 | put_cred(cur_cred); 56 | } 57 | 58 | struct fs_struct *prepare_fs_struct( 59 | struct path *root, 60 | int umask 61 | ) { 62 | struct fs_struct *fs; 63 | 64 | fs = kzalloc(sizeof(struct fs_struct), GFP_KERNEL); 65 | if (fs == NULL) 66 | return NULL; 67 | 68 | /* no need to lock fs before committing to task_struct */ 69 | fs->users = 1; 70 | fs->in_exec = 0; 71 | spin_lock_init(&fs->lock); 72 | seqcount_init(&fs->seq); 73 | fs->umask = umask; 74 | fs->root = *root; 75 | path_get(&fs->root); 76 | fs->pwd = *root; 77 | path_get(&fs->pwd); 78 | return fs; 79 | } 80 | 81 | /* copy derived state from parent inode */ 82 | static inline void 83 | __inherit_derived_state( 84 | struct sdcardfs_tree_entry *pi, /* parent tree entry */ 85 | struct sdcardfs_tree_entry *ci /* tree entry that we want to inherit */ 86 | ) { 87 | ci->revision = pi->revision; 88 | 89 | ci->perm = PERM_INHERIT; 90 | ci->userid = pi->userid; 91 | ci->d_uid = pi->d_uid; 92 | ci->under_android = pi->under_android; 93 | } 94 | 95 | void __get_derived_permission(struct super_block *sb, const char *name, 96 | struct sdcardfs_tree_entry *pi, struct sdcardfs_tree_entry *ci) 97 | { 98 | unsigned userid; 99 | appid_t appid; 100 | 101 | /* By default, each node inherits from its parent */ 102 | __inherit_derived_state(pi, ci); 103 | 104 | /* Derive custom permissions based on parent and current node */ 105 | switch (pi->perm) { 106 | case PERM_INHERIT: 107 | /* Already inherited above */ 108 | break; 109 | 110 | case PERM_PRE_ROOT: 111 | /* Legacy internal layout places users at top level */ 112 | ci->perm = PERM_ROOT; 113 | if (!kstrtouint(name, 10, &userid)) 114 | ci->userid = userid; 115 | break; 116 | 117 | case PERM_ROOT: 118 | /* Assume masked off by default. */ 119 | if (!strcasecmp(name, "Android")) { 120 | /* App-specific directories inside; let anyone traverse */ 121 | ci->perm = PERM_ANDROID; 122 | ci->under_android = true; 123 | /* Moved from check_caller_access_to_name() */ 124 | /* Always block security-sensitive files at root */ 125 | } else if (!strcasecmp(name, "autorun.inf") 126 | || !strcasecmp(name, ".android_secure") 127 | || !strcasecmp(name, "android_secure")) 128 | ci->perm = PERM_JAILHOUSE; 129 | break; 130 | 131 | case PERM_ANDROID: 132 | if (!strcasecmp(name, "data")) { 133 | /* App-specific directories inside; let anyone traverse */ 134 | ci->perm = PERM_ANDROID_DATA; 135 | } else if (!strcasecmp(name, "obb")) { 136 | /* App-specific directories inside; let anyone traverse */ 137 | ci->perm = PERM_ANDROID_OBB; 138 | 139 | /* Single OBB directory is always shared */ 140 | /* if shared_obb != NULL, Single OBB directory is available */ 141 | ci->ovl = SDCARDFS_SB(sb)->shared_obb; 142 | } else if (!strcasecmp(name, "media")) { 143 | /* App-specific directories inside; let anyone traverse */ 144 | ci->perm = PERM_ANDROID_MEDIA; 145 | } 146 | break; 147 | 148 | case PERM_ANDROID_DATA: 149 | case PERM_ANDROID_OBB: 150 | case PERM_ANDROID_MEDIA: 151 | appid = get_appid(name); 152 | if (appid < AID_SYSTEM) 153 | ci->revision = 0; 154 | else 155 | ci->d_uid = multiuser_get_uid(pi->userid, appid); 156 | break; 157 | 158 | case PERM_JAILHOUSE: 159 | /* always denied due to security issues */ 160 | ci->perm = PERM_JAILHOUSE; 161 | break; 162 | } 163 | } 164 | 165 | void get_derived_permission4(struct dentry *parent, 166 | struct dentry *dentry, 167 | const char *rename, bool lazy_recursive) 168 | { 169 | struct sdcardfs_tree_entry *pi = SDCARDFS_DI_R(parent); 170 | struct sdcardfs_tree_entry *ci = SDCARDFS_DI_W(dentry); 171 | 172 | __get_derived_permission(dentry->d_sb, rename, pi, ci); 173 | if (lazy_recursive) 174 | ci->revision = get_next_revision(dentry); 175 | write_unlock(&ci->lock); 176 | read_unlock(&pi->lock); 177 | } 178 | 179 | void get_derived_permission(struct dentry *parent, struct dentry *dentry) 180 | { 181 | get_derived_permission4(parent, dentry, 182 | dentry->d_name.name, false); 183 | } 184 | -------------------------------------------------------------------------------- /fs/sdcardfs/tree.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/tree.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | 14 | /* The tree cache is just so we have properly sized dentries */ 15 | static struct kmem_cache *sdcardfs_tree_entry_cachep; 16 | 17 | int sdcardfs_init_tree_cache(void) 18 | { 19 | sdcardfs_tree_entry_cachep = kmem_cache_create("sdcardfs_tree_entry", 20 | sizeof(struct sdcardfs_tree_entry), 21 | 0, SLAB_RECLAIM_ACCOUNT, NULL); 22 | return sdcardfs_tree_entry_cachep != NULL ? 0 : -ENOMEM; 23 | } 24 | 25 | void sdcardfs_destroy_tree_cache(void) 26 | { 27 | BUG_ON(sdcardfs_tree_entry_cachep == NULL); 28 | kmem_cache_destroy(sdcardfs_tree_entry_cachep); 29 | } 30 | 31 | struct sdcardfs_tree_entry * 32 | sdcardfs_init_tree_entry(struct dentry *dentry, 33 | struct dentry *real) 34 | { 35 | struct sdcardfs_tree_entry *te = 36 | kmem_cache_zalloc(sdcardfs_tree_entry_cachep, GFP_KERNEL); 37 | 38 | if (te == NULL) 39 | return NULL; 40 | te->real.d_seq = __read_seqcount_begin(&real->d_seq); 41 | te->real.dentry = real; 42 | rwlock_init(&te->lock); 43 | 44 | smp_wmb(); 45 | ACCESS_ONCE(dentry->d_fsdata) = te; 46 | return te; 47 | } 48 | 49 | /* no lock for callers plz */ 50 | void sdcardfs_free_tree_entry(struct dentry *dentry) 51 | { 52 | struct sdcardfs_tree_entry *te = SDCARDFS_DI_X(dentry); 53 | 54 | if (te != NULL) { 55 | struct dentry *real = te->real.dentry_invalid ? 56 | NULL : te->real.dentry; 57 | 58 | debugln("%s, dentry(%p, %s) free %p", 59 | __FUNCTION__, dentry, dentry->d_name.name, te); 60 | write_unlock(&te->lock); 61 | 62 | /* dput could lead to reclaim lower_dentry/inode. 63 | so, it is not suitable to put dput in a rwlock */ 64 | dput(real); 65 | kmem_cache_free(sdcardfs_tree_entry_cachep, te); 66 | } 67 | } 68 | 69 | struct __sdcardfs_ilookup5_priv_data { 70 | unsigned long ino; 71 | __u32 generation; 72 | }; 73 | 74 | static int 75 | __sdcardfs_ilookup5_test(struct inode *inode, void *_priv) 76 | { 77 | struct __sdcardfs_ilookup5_priv_data *p = _priv; 78 | 79 | return p->generation == inode->i_generation && 80 | p->ino == inode->i_ino; 81 | } 82 | 83 | /* find the exact alias */ 84 | static struct dentry *__sdcardfs_d_reclaim_alias( 85 | struct inode *inode, 86 | struct dentry *reclaim_dentry, 87 | unsigned d_seq 88 | ) { 89 | struct dentry *found = NULL; 90 | if (likely(!hlist_empty(&inode->i_dentry))) { 91 | spin_lock(&inode->i_lock); 92 | hlist_for_each_entry(found, &inode->i_dentry, d_u.d_alias) { 93 | spin_lock(&found->d_lock); 94 | if (found == reclaim_dentry && 95 | !__read_seqcount_retry(&found->d_seq, d_seq)) { 96 | dget_dlock(found); 97 | spin_unlock(&found->d_lock); 98 | break; 99 | } 100 | spin_unlock(&found->d_lock); 101 | } 102 | spin_unlock(&inode->i_lock); 103 | } 104 | return found; 105 | } 106 | 107 | #ifdef SDCARDFS_UNDERLAY_MULTI_ALIASES 108 | static int __sdcardfs_evaluate_real_locked( 109 | const struct dentry *dentry, 110 | struct sdcardfs_tree_entry *te, 111 | struct dentry *candidate 112 | ) { 113 | struct sdcardfs_tree_entry *pte; 114 | struct dentry *parent; 115 | int valid = 1; 116 | 117 | /* avoid deadlock -- will check again*/ 118 | write_unlock(&te->lock); 119 | 120 | /* make sure that the parent cannot be released */ 121 | rcu_read_lock(); 122 | parent = ACCESS_ONCE(dentry->d_parent); 123 | BUG_ON(parent == dentry); 124 | pte = SDCARDFS_DI_R(parent); 125 | rcu_read_unlock(); 126 | /* parent dentry shouldn't invalid since referenced */ 127 | BUG_ON(pte->real.dentry_invalid); 128 | 129 | if (candidate->d_parent != pte->real.dentry) 130 | valid = 0; 131 | 132 | read_unlock(&pte->lock); 133 | 134 | if (valid) { 135 | if (dentry->d_name.len != 136 | candidate->d_name.len) 137 | valid = 0; 138 | else { 139 | spin_lock(&candidate->d_lock); 140 | valid = !strcasecmp( 141 | dentry->d_name.name, 142 | candidate->d_name.name 143 | ); 144 | spin_unlock(&candidate->d_lock); 145 | } 146 | } 147 | write_lock(&te->lock); 148 | /* check d_seq again at last :) */ 149 | if (valid) 150 | valid = !__read_seqcount_retry(&candidate->d_seq, 151 | te->real.d_seq); 152 | return valid; 153 | } 154 | #endif 155 | 156 | struct dentry * 157 | _sdcardfs_reactivate_real_locked( 158 | const struct dentry *dentry, 159 | struct sdcardfs_tree_entry *te 160 | ) { 161 | struct dentry *pivot, *victim = NULL; 162 | struct inode *real_inode; 163 | struct __sdcardfs_ilookup5_priv_data priv; 164 | 165 | BUG_ON(!te->real.dentry_invalid); 166 | 167 | priv.ino = te->real.ino; 168 | priv.generation = te->real.generation; 169 | read_unlock(&te->lock); 170 | 171 | real_inode = ilookup5_nowait( 172 | sdcardfs_lower_super(dentry->d_sb), 173 | priv.ino, __sdcardfs_ilookup5_test, 174 | &priv); 175 | 176 | write_lock(&te->lock); 177 | 178 | /* safe accessed without te lock */ 179 | if (!te->real.dentry_invalid) { 180 | goto out_unlock; 181 | } 182 | 183 | if (real_inode == NULL || 184 | /* if the real_inode is in I_NEW state, 185 | it shouldn't be the original real one */ 186 | test_bit(__I_NEW, &real_inode->i_state)) { 187 | pivot = NULL; 188 | goto out_pivot; 189 | } 190 | 191 | /* if the real is still not updated */ 192 | pivot = __sdcardfs_d_reclaim_alias(real_inode, 193 | te->real.dentry, te->real.d_seq); 194 | 195 | #ifdef SDCARDFS_UNDERLAY_MULTI_ALIASES 196 | if (pivot != NULL) { 197 | int valid; 198 | 199 | valid = __sdcardfs_evaluate_real_locked(dentry, te, pivot); 200 | /* someone updates it in _sdcardfs_evaluate_real_locked */ 201 | if (!te->real.dentry_invalid) { 202 | victim = pivot; 203 | goto out_unlock; 204 | } 205 | if (!valid) { 206 | victim = pivot; 207 | pivot = NULL; 208 | } 209 | } 210 | #endif 211 | 212 | out_pivot: 213 | te->real.dentry = pivot; 214 | te->real.dentry_invalid = false; 215 | out_unlock: 216 | write_unlock(&te->lock); 217 | iput(real_inode); 218 | dput(victim); 219 | read_lock(&te->lock); 220 | return te->real.dentry; 221 | } 222 | 223 | -------------------------------------------------------------------------------- /fs/sdcardfs/namei.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/namei.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | #include "linux/delay.h" 14 | #include 15 | 16 | #include "trace-events.h" 17 | 18 | static int __is_weird_inode(mode_t mode) { 19 | return S_ISBLK(mode) || S_ISCHR(mode) || 20 | S_ISFIFO(mode) || S_ISSOCK(mode) || S_ISLNK(mode); 21 | } 22 | 23 | struct inode *sdcardfs_ialloc( 24 | struct super_block *sb, 25 | mode_t mode 26 | ){ 27 | struct inode *inode = new_inode(sb); 28 | 29 | if (unlikely(inode == NULL)) 30 | return ERR_PTR(-ENOMEM); 31 | 32 | inode->i_ino = get_next_ino(); 33 | inode->i_version = 1; 34 | inode->i_generation = get_seconds(); 35 | 36 | BUG_ON(__is_weird_inode(mode)); 37 | 38 | /* use different set of inode ops for symlinks & directories */ 39 | if (S_ISDIR(mode)) { 40 | inode->i_op = &sdcardfs_dir_iops; 41 | inode->i_fop = &sdcardfs_dir_fops; 42 | } else { 43 | inode->i_op = &sdcardfs_main_iops; 44 | inode->i_fop = &sdcardfs_main_fops; 45 | } 46 | 47 | inode->i_flags |= S_NOATIME | S_NOCMTIME; 48 | inode->i_mode = mode; 49 | inode->i_mapping->a_ops = &sdcardfs_aops; 50 | 51 | trace_sdcardfs_ialloc(inode); 52 | return inode; 53 | } 54 | 55 | /* 1) it's optional to lock the parent by the caller. 56 | so we cannot assume real_dentry is still hashed now 57 | 2) sdcardfs_interpose use a real_dentry refcount 58 | increased by the caller */ 59 | struct dentry *sdcardfs_interpose( 60 | struct dentry *parent, 61 | struct dentry *dentry, 62 | struct dentry *real_dentry 63 | ) { 64 | /* d_sb has been assigned by d_alloc */ 65 | struct sdcardfs_tree_entry *te; 66 | struct dentry *lower_dentry; 67 | struct inode *inode, *lower_inode; 68 | struct super_block *sb = dentry->d_sb; 69 | 70 | /* dentry cannot be seen by others, so it's no need 71 | taking dentry d_lock */ 72 | BUG_ON(!d_unhashed(dentry)); 73 | BUG_ON(d_really_is_positive(dentry)); 74 | 75 | /* since the real_dentry is referenced, it cannot turn 76 | into negative state. therefore it is no need taking d_lock. 77 | there are some races with parent, d_name? */ 78 | BUG_ON(d_is_negative(real_dentry)); 79 | 80 | te = sdcardfs_init_tree_entry(dentry, real_dentry); 81 | if (unlikely(te == NULL)) { 82 | dput(real_dentry); 83 | return ERR_PTR(-ENOMEM); 84 | } 85 | get_derived_permission(parent, dentry); 86 | 87 | /* before d_add, we can access lower_dentry without locking */ 88 | lower_dentry = (te->ovl != NULL ? te->ovl : te->real.dentry); 89 | 90 | lower_inode = d_inode(lower_dentry); 91 | inode = sdcardfs_ialloc(sb, lower_inode->i_mode); 92 | if (IS_ERR(inode)) { 93 | errln("%s, failed to alloc inode, err=%ld", 94 | __FUNCTION__, PTR_ERR(inode)); 95 | 96 | sdcardfs_free_tree_entry(dentry); 97 | return (struct dentry *)inode; 98 | } 99 | 100 | /* used for revalidate in inode_permission */ 101 | inode->i_private = te; 102 | fsstack_copy_inode_size(inode, lower_inode); 103 | 104 | __fix_derived_permission(te, inode); 105 | d_add(dentry, inode); 106 | return NULL; 107 | } 108 | 109 | static int __is_weird_dentry(struct dentry *dentry) 110 | { 111 | int weird = dentry->d_flags & (DCACHE_NEED_AUTOMOUNT | 112 | DCACHE_MANAGE_TRANSIT); 113 | if (likely(!weird)) { 114 | /* since whether d_inode == NULL has 115 | been checked by the caller */ 116 | weird = __is_weird_inode(d_inode(dentry)->i_mode); 117 | } 118 | return weird; 119 | } 120 | 121 | static inline 122 | struct dentry *__after_lookup_real(struct dentry *real) 123 | { 124 | if (IS_ERR(real)) { 125 | if (real == ERR_PTR(-ENOENT)) 126 | real = NULL; 127 | } else if (d_really_is_negative(real)) { 128 | dput(real); 129 | real = NULL; 130 | } else if (__is_weird_dentry(real)) { 131 | dput(real); 132 | /* Don't support traversing automounts 133 | and other weirdness */ 134 | real = ERR_PTR(-EREMOTE); 135 | } 136 | return real; 137 | } 138 | 139 | static inline 140 | struct dentry *__lookup_real_ci( 141 | struct sdcardfs_sb_info *sbi, 142 | struct dentry *dir, 143 | struct qstr *orig) 144 | { 145 | struct dentry *dentry; 146 | 147 | inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); 148 | dentry = __after_lookup_real(lookup_one_len(orig->name, 149 | dir, orig->len)); 150 | #ifdef SDCARDFS_CASE_INSENSITIVE 151 | /* if case-exact lookup don't find a inode and 152 | the case-insensitive lookup is available on 153 | the underlayfs, try to lookup_ci again. */ 154 | if (dentry == NULL && sbi->ci->lookup != NULL) { 155 | struct dentry *found; 156 | struct path path = {.dentry = dir, 157 | .mnt = sbi->lower_mnt}; 158 | 159 | /* remember that lookup(_ci) wont return NULL */ 160 | found = sbi->ci->lookup(&path, orig, true); 161 | dentry = __after_lookup_real(found); 162 | 163 | if (unlikely(dentry == NULL && !IS_ERR(found))) 164 | dentry = ERR_PTR(-ESTALE); 165 | } 166 | #endif 167 | inode_unlock(d_inode(dir)); 168 | return dentry; 169 | } 170 | 171 | /* parent dir lock should be locked */ 172 | struct dentry * 173 | sdcardfs_lookup(struct inode *dir, 174 | struct dentry *dentry, unsigned int flags) 175 | { 176 | struct dentry *parent; 177 | struct dentry *lower_dir_dentry, *ret; 178 | struct inode *lower_dir_inode; 179 | struct sdcardfs_sb_info *sbi; 180 | const struct cred *saved_cred; 181 | 182 | BUG_ON(IS_ROOT(dentry)); 183 | 184 | parent = dget_parent(dentry); 185 | BUG_ON(d_inode(parent) != dir); 186 | 187 | /* d_revalidate should have been triggered. so 188 | the lower_dir_entry must be hashed */ 189 | lower_dir_dentry = sdcardfs_get_lower_dentry(parent); 190 | BUG_ON(lower_dir_dentry == NULL); 191 | 192 | lower_dir_inode = d_inode(lower_dir_dentry); 193 | BUG_ON(lower_dir_inode == NULL); 194 | 195 | sbi = SDCARDFS_SB(dentry->d_sb); 196 | OVERRIDE_CRED(sbi, saved_cred); 197 | if (IS_ERR(saved_cred)) { 198 | ret = (struct dentry *)saved_cred; 199 | goto out; 200 | } 201 | 202 | ret = __lookup_real_ci(sbi, lower_dir_dentry, &dentry->d_name); 203 | REVERT_CRED(saved_cred); 204 | if (ret == NULL) { 205 | if (!(flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))) 206 | ret = ERR_PTR(-ENOENT); 207 | else { 208 | /* in this case, the dentry is still negative. 209 | fsdata will be initialized in create/rename */ 210 | 211 | /* and, we dont need to d_instantiate the dentry */ 212 | /* since DCACHE_MISS_TYPE == 0x00000000 */ 213 | /* d_instantiate(dentry, NULL); */ 214 | } 215 | goto out; 216 | } 217 | 218 | if (!IS_ERR(ret)) 219 | ret = sdcardfs_interpose(parent, dentry, ret); 220 | out: 221 | /* Only in __sdcardfs_interpose, sdcardfs_init_tree_entry would 222 | be called. So we can d_release a dentry without tree_entry */ 223 | dput(lower_dir_dentry); 224 | dput(parent); 225 | 226 | trace_sdcardfs_lookup(dir, dentry, flags); 227 | return ret; 228 | } 229 | -------------------------------------------------------------------------------- /fs/sdcardfs/dentry.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/dentry.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | #include "linux/ctype.h" 14 | #include 15 | 16 | #include "trace-events.h" 17 | 18 | static inline void dentry_rcuwalk_barrier(struct dentry *dentry) 19 | { 20 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) 21 | assert_spin_locked(&dentry->d_lock); 22 | /* Go through a barrier */ 23 | write_seqcount_barrier(&dentry->d_seq); 24 | #else 25 | lockdep_assert_held(&dentry->d_lock); 26 | /* Go through am invalidation barrier */ 27 | write_seqcount_invalidate(&dentry->d_seq); 28 | #endif 29 | } 30 | 31 | /* locking order: 32 | * dentry->d_lock 33 | * SDCARDFS_DI_LOCK 34 | * te->lock */ 35 | 36 | static int sdcardfs_d_delete(const struct dentry *dentry) 37 | { 38 | struct sdcardfs_tree_entry *te; 39 | struct dentry *real_dentry; 40 | struct inode *real_inode; 41 | int ret = 1; /* kill it by default */ 42 | 43 | trace_sdcardfs_d_delete_enter(dentry); 44 | 45 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)) 46 | /* only for Linux versions which "vfs: reorganize dput() 47 | memory accesses" from Linus is not applied */ 48 | if (unlikely(d_unhashed(dentry))) 49 | goto out; 50 | #endif 51 | 52 | te = SDCARDFS_DI_W(dentry); 53 | /* since dentry is hashed, there is no way that te == NULL */ 54 | BUG_ON(te == NULL); 55 | 56 | /* Since d_delete can be "deleted" for many times, 57 | * it may break in just after d_revalidate 58 | * 59 | * lookup_fast 60 | * dput 61 | * d_delete <--- invalid 62 | * d_revalidate_fast <--- -ECHILD 63 | * unlazy_walk 64 | * dget 65 | * dput 66 | * d_delete <---- already invalid */ 67 | if (te->real.dentry_invalid == true) { 68 | ret = 0; /* maybe better than kill it */ 69 | goto out_unlock; 70 | } 71 | 72 | real_dentry = te->real.dentry; 73 | BUG_ON(real_dentry == NULL); 74 | 75 | /* some dentry interposed with unhashed dentry, we should kill it */ 76 | spin_lock(&real_dentry->d_lock); 77 | if (d_unhashed(real_dentry)) { 78 | spin_unlock(&real_dentry->d_lock); 79 | goto out_unlock; 80 | } 81 | real_inode = d_inode(real_dentry); 82 | spin_unlock(&real_dentry->d_lock); 83 | 84 | /* including unlink/rmdir(d_delete), rename(d_move) ... */ 85 | if (!__read_seqcount_retry(&real_dentry->d_seq, 86 | te->real.d_seq)) { 87 | struct dentry *cast = (struct dentry *)dentry; 88 | /* hashed and positive, deactivate the dentry! */ 89 | te->real.ino = real_inode->i_ino; 90 | te->real.generation = real_inode->i_generation; 91 | 92 | debugln("%s, dentry=%p (ino=%lu, gen=%u)", __FUNCTION__, dentry, 93 | te->real.ino, te->real.generation); 94 | 95 | te->real.dentry_invalid = true; 96 | 97 | /* since real_dentry is invalid, we should prevent 98 | the dentry revalidated in the lookup_fast path */ 99 | dentry_rcuwalk_barrier(cast); 100 | write_unlock(&te->lock); 101 | 102 | /* it's ok...safe to unlock & lock d_lock again */ 103 | spin_unlock(&cast->d_lock); 104 | 105 | /* dput may be blocked, so take it out of the locks */ 106 | dput(real_dentry); 107 | 108 | spin_lock(&cast->d_lock); 109 | 110 | ret = likely(d_count(dentry) == 1) ? 111 | /* we need to check again whether it is unreachable now. */ 112 | d_unhashed(dentry) : 0; 113 | goto out; 114 | } 115 | 116 | out_unlock: 117 | write_unlock(&te->lock); 118 | out: 119 | trace_sdcardfs_d_delete_exit(dentry, ret); 120 | return ret; 121 | } 122 | 123 | /* d_revalidate only focus on revalidating the real dentry. 124 | because we assume that the ovldentry cannot be d_drop. */ 125 | static int __sdcardfs_d_revalidate_fast( 126 | struct dentry *dentry, 127 | unsigned int flags 128 | ) { 129 | struct sdcardfs_tree_entry *te; 130 | struct dentry *real_dentry; 131 | int err = 1; 132 | 133 | trace_sdcardfs_d_revalidate_fast_enter(dentry, flags); 134 | 135 | /* if dentry_unlink_inode() before, should invalidate it (differ 136 | from VFS). think why we needn't considering after :) */ 137 | if (unlikely(!d_inode_rcu(dentry))) { 138 | err = 0; 139 | goto out; 140 | } 141 | 142 | te = sdcardfs_real_dentry_rcu_locked(dentry, &real_dentry); 143 | 144 | /* hashed but without te...hmm, reclaiming */ 145 | if (te == NULL) { 146 | err = 0; 147 | goto out; 148 | } 149 | 150 | if (real_dentry == NULL) { 151 | /* fall back to ref-walk mode, then reactivate it */ 152 | out_refwalk: 153 | trace_sdcardfs_d_revalidate_fast_refwalk(dentry, flags); 154 | err = -ECHILD; 155 | goto out_unlock; 156 | } 157 | 158 | /* if real_dentry was hashed, 159 | it will remain hashed iff d_seq isnt changed. */ 160 | if (__read_seqcount_retry(&real_dentry->d_seq, 161 | te->real.d_seq)) { 162 | /* we cannot confirm the following case, 163 | add a WARN_ON to notice that (outdated) */ 164 | WARN_ON(IS_ROOT(dentry)); 165 | 166 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) 167 | err = 0; /* dentry invalid */ 168 | goto out_unlock; 169 | #else 170 | err = -ENOENT; 171 | read_unlock(&te->lock); 172 | d_invalidate(dentry); 173 | goto out; 174 | #endif 175 | } 176 | 177 | if (need_fixup_permission( 178 | d_inode_rcu(ACCESS_ONCE(dentry->d_parent)), te)) { 179 | /* XXX: it's not suitble for us 180 | to get_derived_permission in RCU lookup now :-( */ 181 | goto out_refwalk; 182 | } 183 | 184 | if ((real_dentry->d_flags & DCACHE_OP_REVALIDATE)) { 185 | err = real_dentry->d_op->d_revalidate(real_dentry, flags); 186 | if (err < 0) 187 | goto out_unlock; 188 | 189 | /* follow overlayfs? 190 | give a chance and fall back to ref-walk */ 191 | else if (err == 0) 192 | goto out_refwalk; 193 | } 194 | 195 | out_unlock: 196 | read_unlock(&te->lock); 197 | out: 198 | trace_sdcardfs_d_revalidate_fast_exit(dentry, flags, err); 199 | return err; 200 | } 201 | 202 | static int __sdcardfs_d_revalidate_slow( 203 | struct dentry *dentry, 204 | unsigned int flags 205 | ) { 206 | struct dentry *parent, *real_dentry; 207 | unsigned seq; 208 | int ret = 0; 209 | 210 | trace_sdcardfs_d_revalidate_slow_enter(dentry, flags); 211 | 212 | /* ref-walk takes a refcount so nothing to worry about */ 213 | if (unlikely(d_really_is_negative(dentry))) 214 | goto out; 215 | 216 | real_dentry = sdcardfs_get_real_dentry_with_seq(dentry, &seq); 217 | if (real_dentry == NULL) { 218 | trace_sdcardfs_d_revalidate_slow_miss(dentry, flags); 219 | goto out; 220 | } 221 | 222 | ret = 1; 223 | if (real_dentry->d_flags & DCACHE_OP_REVALIDATE) { 224 | ret = real_dentry->d_op->d_revalidate(real_dentry, flags); 225 | if (ret <= 0) 226 | goto out_dput; 227 | } 228 | 229 | retry: 230 | parent = dget_parent(dentry); 231 | if (need_fixup_permission(d_inode(parent), SDCARDFS_D(dentry))) 232 | get_derived_permission(parent, dentry); 233 | dput(parent); 234 | 235 | if (parent != ACCESS_ONCE(dentry->d_parent)) 236 | goto retry; 237 | 238 | /* check if the hierarchy of this dentry was changed */ 239 | if (unlikely(__read_seqcount_retry(&real_dentry->d_seq, seq))) { 240 | /* we cannot confirm the following case, 241 | add a WARN_ON to notice that (outdated) */ 242 | WARN_ON(IS_ROOT(dentry)); 243 | ret = 0; 244 | } 245 | 246 | out_dput: 247 | dput(real_dentry); 248 | out: 249 | trace_sdcardfs_d_revalidate_slow_exit(dentry, flags, ret); 250 | return ret; 251 | } 252 | 253 | /* return value: -ERRNO if error (returned to user) 254 | * 0: tell VFS to invalidate dentry 255 | * 1: dentry is valid */ 256 | static int sdcardfs_d_revalidate( 257 | struct dentry *dentry, 258 | unsigned int flags 259 | ) { 260 | /* d_revalidate should not be called on root dentry. 261 | and we dont have disconnected dentry now */ 262 | BUG_ON(READ_ONCE(dentry->d_parent) == dentry)); 263 | if (flags & LOOKUP_RCU) 264 | return __sdcardfs_d_revalidate_fast(dentry, flags); 265 | return __sdcardfs_d_revalidate_slow(dentry, flags); 266 | } 267 | 268 | static void sdcardfs_canonical_path(const struct path *path, 269 | struct path *actual_path) { 270 | sdcardfs_get_lower_path(path->dentry, actual_path); 271 | } 272 | 273 | /* __sdcardfs_d_release is an alias of sdcardfs_free_tree_entry */ 274 | #define sdcardfs_d_release sdcardfs_free_tree_entry 275 | 276 | const struct dentry_operations sdcardfs_ci_dops = { 277 | .d_delete = sdcardfs_d_delete, 278 | .d_revalidate = sdcardfs_d_revalidate, 279 | .d_release = sdcardfs_d_release, 280 | 281 | .d_canonical_path = sdcardfs_canonical_path, 282 | }; 283 | -------------------------------------------------------------------------------- /fs/sdcardfs/file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fs/sdcardfs/file.c 3 | * 4 | * Copyright (c) 2013 Samsung Electronics Co. Ltd 5 | * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, 6 | * Sunghwan Yun, Sungjong Seo 7 | * 8 | * This program has been developed as a stackable file system based on 9 | * the WrapFS which written by 10 | * 11 | * Copyright (c) 1998-2011 Erez Zadok 12 | * Copyright (c) 2009 Shrikar Archak 13 | * Copyright (c) 2003-2011 Stony Brook University 14 | * Copyright (c) 2003-2011 The Research Foundation of SUNY 15 | * 16 | * This file is dual licensed. It may be redistributed and/or modified 17 | * under the terms of the Apache 2.0 License OR version 2 of the GNU 18 | * General Public License. 19 | */ 20 | 21 | #include "sdcardfs.h" 22 | #ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE 23 | #include 24 | #endif 25 | #include 26 | #include 27 | 28 | static ssize_t sdcardfs_read(struct file *file, char __user *buf, 29 | size_t count, loff_t *ppos) 30 | { 31 | int err; 32 | struct file *lower_file; 33 | struct dentry *dentry = file->f_path.dentry; 34 | #ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE 35 | struct backing_dev_info *bdi; 36 | #endif 37 | 38 | lower_file = sdcardfs_lower_file(file); 39 | 40 | #ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE 41 | if (file->f_mode & FMODE_NOACTIVE) { 42 | if (!(lower_file->f_mode & FMODE_NOACTIVE)) { 43 | bdi = lower_file->f_mapping->backing_dev_info; 44 | lower_file->f_ra.ra_pages = bdi->ra_pages * 2; 45 | spin_lock(&lower_file->f_lock); 46 | lower_file->f_mode |= FMODE_NOACTIVE; 47 | spin_unlock(&lower_file->f_lock); 48 | } 49 | } 50 | #endif 51 | 52 | err = vfs_read(lower_file, buf, count, ppos); 53 | /* update our inode atime upon a successful lower read */ 54 | if (err >= 0) { 55 | fsstack_copy_attr_atime(d_inode(dentry), 56 | file_inode(lower_file)); 57 | } 58 | 59 | return err; 60 | } 61 | 62 | static ssize_t sdcardfs_write(struct file *file, const char __user *buf, 63 | size_t count, loff_t *ppos) 64 | { 65 | int err; 66 | struct file *lower_file; 67 | struct dentry *dentry = file->f_path.dentry; 68 | 69 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 70 | /* check disk space */ 71 | if (!check_min_free_space(dentry->d_sb, count, 0)) { 72 | infoln("%s, No minimum free space.", __FUNCTION__); 73 | return -ENOSPC; 74 | } 75 | #endif 76 | 77 | lower_file = sdcardfs_lower_file(file); 78 | err = vfs_write(lower_file, buf, count, ppos); 79 | /* update our inode times+sizes upon a successful lower write */ 80 | if (err >= 0) { 81 | fsstack_copy_inode_size(d_inode(dentry), 82 | file_inode(lower_file)); 83 | fsstack_copy_attr_times(d_inode(dentry), 84 | file_inode(lower_file)); 85 | } 86 | 87 | return err; 88 | } 89 | 90 | static int sdcardfs_readdir(struct file *file, struct dir_context *ctx) 91 | { 92 | int err; 93 | struct file *lower_file = NULL; 94 | struct dentry *dentry = file->f_path.dentry; 95 | 96 | lower_file = sdcardfs_lower_file(file); 97 | 98 | lower_file->f_pos = file->f_pos; 99 | err = iterate_dir(lower_file, ctx); 100 | file->f_pos = lower_file->f_pos; 101 | if (err >= 0) /* copy the atime */ 102 | fsstack_copy_attr_atime(d_inode(dentry), 103 | file_inode(lower_file)); 104 | return err; 105 | } 106 | 107 | static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd, 108 | unsigned long arg) 109 | { 110 | long err = -ENOTTY; 111 | struct file *lower_file = sdcardfs_lower_file(file); 112 | 113 | /* XXX: use vfs_ioctl if/when VFS exports it */ 114 | if (lower_file != NULL && lower_file->f_op != NULL 115 | && lower_file->f_op->unlocked_ioctl != NULL) { 116 | const struct cred *saved_cred = 117 | override_creds(lower_file->f_cred); 118 | 119 | err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); 120 | revert_creds(saved_cred); 121 | } 122 | 123 | return err; 124 | } 125 | 126 | #ifdef CONFIG_COMPAT 127 | static long sdcardfs_compat_ioctl(struct file *file, unsigned int cmd, 128 | unsigned long arg) 129 | { 130 | long err = -ENOTTY; 131 | struct file *lower_file = sdcardfs_lower_file(file); 132 | 133 | /* XXX: use vfs_ioctl if/when VFS exports it */ 134 | if (lower_file != NULL && lower_file->f_op != NULL 135 | && lower_file->f_op->compat_ioctl != NULL) { 136 | const struct cred *saved_cred = 137 | override_creds(lower_file->f_cred); 138 | 139 | err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg); 140 | revert_creds(saved_cred); 141 | } 142 | 143 | return err; 144 | } 145 | #endif 146 | 147 | static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) 148 | { 149 | int err = 0; 150 | bool willwrite; 151 | struct file *lower_file; 152 | const struct vm_operations_struct *saved_vm_ops = NULL; 153 | 154 | /* this might be deferred to mmap's writepage */ 155 | willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); 156 | 157 | /* 158 | * File systems which do not implement ->writepage may use 159 | * generic_file_readonly_mmap as their ->mmap op. If you call 160 | * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL. 161 | * But we cannot call the lower ->mmap op, so we can't tell that 162 | * writeable mappings won't work. Therefore, our only choice is to 163 | * check if the lower file system supports the ->writepage, and if 164 | * not, return EINVAL (the same error that 165 | * generic_file_readonly_mmap returns in that case). 166 | */ 167 | lower_file = sdcardfs_lower_file(file); 168 | if (willwrite && !lower_file->f_mapping->a_ops->writepage) { 169 | err = -EINVAL; 170 | errln("lower file system does not support writeable mmap"); 171 | goto out; 172 | } 173 | 174 | /* 175 | * find and save lower vm_ops. 176 | * 177 | * XXX: the VFS should have a cleaner way of finding the lower vm_ops 178 | */ 179 | if (!SDCARDFS_F(file)->lower_vm_ops) { 180 | err = lower_file->f_op->mmap(lower_file, vma); 181 | if (err) { 182 | errln("lower mmap failed %d", err); 183 | goto out; 184 | } 185 | saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */ 186 | } 187 | 188 | /* 189 | * Next 3 lines are all I need from generic_file_mmap. I definitely 190 | * don't want its test for ->readpage which returns -ENOEXEC. 191 | */ 192 | file_accessed(file); 193 | vma->vm_ops = &sdcardfs_vm_ops; 194 | 195 | file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */ 196 | if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */ 197 | SDCARDFS_F(file)->lower_vm_ops = saved_vm_ops; 198 | vma->vm_private_data = file; 199 | get_file(lower_file); 200 | vma->vm_file = lower_file; 201 | 202 | out: 203 | return err; 204 | } 205 | 206 | static int sdcardfs_open(struct inode *inode, struct file *file) 207 | { 208 | int err; 209 | struct file *lower_file; 210 | struct path lower_path; 211 | 212 | struct dentry *dentry = file->f_path.dentry; 213 | struct dentry *parent = dget_parent(dentry); 214 | struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); 215 | const struct cred *saved_cred = NULL; 216 | 217 | /* don't open unhashed/deleted files */ 218 | if (d_unhashed(dentry)) { 219 | err = -ENOENT; 220 | goto out_err; 221 | } 222 | 223 | /* save current_cred and override it */ 224 | OVERRIDE_CRED(sbi, saved_cred); 225 | if (IS_ERR(saved_cred)) { 226 | err = PTR_ERR(saved_cred); 227 | goto out_err; 228 | } 229 | 230 | file->private_data = 231 | kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); 232 | if (!SDCARDFS_F(file)) { 233 | err = -ENOMEM; 234 | goto out_revert_cred; 235 | } 236 | 237 | /* open lower object and link sdcardfs's file struct to lower's */ 238 | sdcardfs_get_lower_path(dentry, &lower_path); 239 | lower_file = dentry_open(&lower_path, file->f_flags, current_cred()); 240 | /* TODO: add file opened statistics */ 241 | if (IS_ERR(lower_file)) { 242 | err = PTR_ERR(lower_file); 243 | kfree(SDCARDFS_F(file)); 244 | } else { 245 | SDCARDFS_F(file)->lower_file = lower_file; 246 | sdcardfs_copy_and_fix_attrs(inode, d_inode(lower_path.dentry)); 247 | err = 0; /* open success */ 248 | } 249 | _path_put(&lower_path); 250 | 251 | out_revert_cred: 252 | REVERT_CRED(saved_cred); 253 | out_err: 254 | dput(parent); 255 | return err; 256 | } 257 | 258 | static int sdcardfs_flush(struct file *file, fl_owner_t id) 259 | { 260 | int err = 0; 261 | struct file *lower_file = NULL; 262 | 263 | lower_file = sdcardfs_lower_file(file); 264 | if (lower_file && lower_file->f_op && lower_file->f_op->flush) { 265 | filemap_write_and_wait(file->f_mapping); 266 | err = lower_file->f_op->flush(lower_file, id); 267 | } 268 | 269 | return err; 270 | } 271 | 272 | /* release all lower object references & free the file info structure */ 273 | static int sdcardfs_file_release(struct inode *inode, struct file *file) 274 | { 275 | struct file *lower_file; 276 | 277 | lower_file = sdcardfs_lower_file(file); 278 | if (lower_file) { 279 | SDCARDFS_F(file)->lower_file = NULL; 280 | fput(lower_file); 281 | } 282 | 283 | kfree(SDCARDFS_F(file)); 284 | return 0; 285 | } 286 | 287 | static int sdcardfs_fsync(struct file *file, loff_t start, loff_t end, 288 | int datasync) 289 | { 290 | int err; 291 | 292 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) 293 | err = __generic_file_fsync(file, start, end, datasync); 294 | #else 295 | err = generic_file_fsync(file, start, end, datasync); 296 | #endif 297 | if (!err) { 298 | struct file *lower_file = sdcardfs_lower_file(file); 299 | 300 | /* call data & metadata sync of underlayfs */ 301 | err = vfs_fsync_range(lower_file, start, end, datasync); 302 | } 303 | 304 | return err; 305 | } 306 | 307 | static int sdcardfs_fasync(int fd, struct file *file, int flag) 308 | { 309 | int err = 0; 310 | struct file *lower_file = NULL; 311 | 312 | lower_file = sdcardfs_lower_file(file); 313 | if (lower_file != NULL && lower_file->f_op != NULL 314 | && lower_file->f_op->fasync != NULL) 315 | err = lower_file->f_op->fasync(fd, lower_file, flag); 316 | 317 | return err; 318 | } 319 | 320 | static ssize_t sdcardfs_read_iter(struct kiocb *iocb, struct iov_iter *iter) 321 | { 322 | int err; 323 | struct file *file = iocb->ki_filp, *lower_file; 324 | 325 | lower_file = sdcardfs_lower_file(file); 326 | if (!lower_file->f_op->read_iter) { 327 | err = -EINVAL; 328 | goto out; 329 | } 330 | 331 | get_file(lower_file); /* prevent lower_file from being released */ 332 | iocb->ki_filp = lower_file; 333 | err = lower_file->f_op->read_iter(iocb, iter); 334 | iocb->ki_filp = file; 335 | fput(lower_file); 336 | out: 337 | return err; 338 | } 339 | 340 | ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter) 341 | { 342 | int err; 343 | struct file *file = iocb->ki_filp, 344 | *lower_file = sdcardfs_lower_file(file); 345 | 346 | if (lower_file->f_op->write_iter == NULL) { 347 | err = -EINVAL; 348 | goto out; 349 | } 350 | 351 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 352 | /* check disk space */ 353 | if (!check_min_free_space(file->f_path.dentry->d_sb, 354 | iov_iter_count(iter), 0)) { 355 | infoln("%s, No minimum free space.", __FUNCTION__); 356 | err = -ENOSPC; 357 | goto out; 358 | } 359 | #endif 360 | get_file(lower_file); /* prevent lower_file from being released */ 361 | iocb->ki_filp = lower_file; 362 | err = lower_file->f_op->write_iter(iocb, iter); 363 | iocb->ki_filp = file; 364 | fput(lower_file); 365 | 366 | /* update overlay inode sizes upon a successful lower write */ 367 | if (err >= 0 || err == -EIOCBQUEUED) 368 | fsstack_copy_inode_size(d_inode(file->f_path.dentry), 369 | file_inode(lower_file)); 370 | out: 371 | return err; 372 | } 373 | 374 | /* 375 | * Sdcardfs cannot use generic_file_llseek as ->llseek, because it would 376 | * only set the offset of the upper file. So we have to implement our 377 | * own method to set both the upper and lower file offsets 378 | * consistently. 379 | */ 380 | static loff_t sdcardfs_file_llseek(struct file *file, loff_t offset, int whence) 381 | { 382 | int err; 383 | struct file *lower_file; 384 | 385 | err = generic_file_llseek(file, offset, whence); 386 | if (err < 0) 387 | goto out; 388 | 389 | lower_file = sdcardfs_lower_file(file); 390 | err = generic_file_llseek(lower_file, offset, whence); 391 | 392 | out: 393 | return err; 394 | } 395 | 396 | 397 | const struct file_operations sdcardfs_main_fops = { 398 | .llseek = generic_file_llseek, 399 | .read = sdcardfs_read, 400 | .write = sdcardfs_write, 401 | .unlocked_ioctl = sdcardfs_unlocked_ioctl, 402 | #ifdef CONFIG_COMPAT 403 | .compat_ioctl = sdcardfs_compat_ioctl, 404 | #endif 405 | .mmap = sdcardfs_mmap, 406 | .open = sdcardfs_open, 407 | .flush = sdcardfs_flush, 408 | .release = sdcardfs_file_release, 409 | .fsync = sdcardfs_fsync, 410 | .fasync = sdcardfs_fasync, 411 | .read_iter = sdcardfs_read_iter, 412 | .write_iter = sdcardfs_write_iter, 413 | }; 414 | 415 | /* trimmed directory options */ 416 | const struct file_operations sdcardfs_dir_fops = { 417 | .llseek = sdcardfs_file_llseek, 418 | .read = generic_read_dir, 419 | .iterate = sdcardfs_readdir, 420 | .unlocked_ioctl = sdcardfs_unlocked_ioctl, 421 | #ifdef CONFIG_COMPAT 422 | .compat_ioctl = sdcardfs_compat_ioctl, 423 | #endif 424 | .open = sdcardfs_open, 425 | .release = sdcardfs_file_release, 426 | .flush = sdcardfs_flush, 427 | .fsync = sdcardfs_fsync, 428 | .fasync = sdcardfs_fasync, 429 | }; 430 | -------------------------------------------------------------------------------- /fs/sdcardfs/main.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/main.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | #include 14 | #include 15 | #include 16 | 17 | #define CREATE_TRACE_POINTS 18 | #include "trace-events.h" 19 | 20 | enum { 21 | Opt_fsuid, 22 | Opt_fsgid, 23 | Opt_gid, 24 | Opt_debug, 25 | Opt_mask, 26 | Opt_multiuser, 27 | Opt_userid, 28 | Opt_fs_scontext, 29 | Opt_reserved_mb, 30 | Opt_quiet, 31 | Opt_gid_derivation, 32 | Opt_err, 33 | }; 34 | 35 | static const match_table_t sdcardfs_tokens = { 36 | {Opt_fsuid, "fsuid=%u"}, 37 | {Opt_fsgid, "fsgid=%u"}, 38 | {Opt_gid, "gid=%u"}, 39 | {Opt_debug, "debug"}, 40 | {Opt_mask, "mask=%u"}, 41 | {Opt_userid, "userid=%d"}, 42 | {Opt_multiuser, "multiuser"}, 43 | {Opt_fs_scontext, "fs_scontext=%s"}, 44 | {Opt_reserved_mb, "reserved_mb=%u"}, 45 | {Opt_quiet, "quiet"}, 46 | {Opt_gid_derivation, "derive_gid"}, /* for OC-MR1 compatibility only */ 47 | {Opt_err, NULL} 48 | }; 49 | 50 | static void default_options(struct sdcardfs_mount_options *opts) 51 | { 52 | /* by default, we use AID_MEDIA_RW as uid, gid */ 53 | opts->fs_low_uid = AID_MEDIA_RW; 54 | opts->fs_low_gid = AID_MEDIA_RW; 55 | opts->mask = 0; 56 | opts->multiuser = false; 57 | opts->fs_user_id = 0; 58 | opts->gid = AID_SDCARD_RW; 59 | opts->has_fssecid = false; 60 | /* by default, 0MB is reserved */ 61 | opts->reserved_mb = 0; 62 | opts->quiet = false; 63 | 64 | /* too buggy, therefore we never use gid derivation */ 65 | /* opts->gid_derivation = false; */ 66 | } 67 | 68 | int sdcardfs_parse_options(struct sdcardfs_mount_options *opts, 69 | char *options, int silent, int *debug) 70 | { 71 | char *p, *string_option; 72 | substring_t args[MAX_OPT_ARGS]; 73 | int option; 74 | 75 | if (options == NULL) 76 | return 0; 77 | 78 | while ((p = strsep(&options, ",")) != NULL) { 79 | int token; 80 | if (*p == '\0') 81 | continue; 82 | 83 | token = match_token(p, sdcardfs_tokens, args); 84 | 85 | switch (token) { 86 | case Opt_debug: 87 | break; 88 | case Opt_fsuid: 89 | if (match_int(&args[0], &option)) 90 | return 0; 91 | opts->fs_low_uid = option; 92 | break; 93 | case Opt_fsgid: 94 | if (match_int(&args[0], &option)) 95 | return 0; 96 | opts->fs_low_gid = option; 97 | break; 98 | case Opt_gid: 99 | if (match_int(&args[0], &option)) 100 | return 0; 101 | opts->gid = option; 102 | break; 103 | case Opt_userid: 104 | if (match_int(&args[0], &option)) 105 | return 0; 106 | opts->fs_user_id = option; 107 | break; 108 | case Opt_mask: 109 | if (match_int(&args[0], &option)) 110 | return 0; 111 | opts->mask = option; 112 | break; 113 | case Opt_multiuser: 114 | opts->multiuser = true; 115 | break; 116 | case Opt_fs_scontext: 117 | string_option = match_strdup(&args[0]); 118 | if (string_option == NULL) 119 | return -ENOMEM; 120 | 121 | if (!strcmp(string_option, "current")) { 122 | security_task_getsecid(current, 123 | &opts->fs_low_secid); 124 | option = 0; 125 | } else 126 | option = security_secctx_to_secid(string_option, 127 | strlen(string_option), &opts->fs_low_secid); 128 | kfree(string_option); 129 | 130 | if (unlikely(option < 0)) { 131 | if (!silent) 132 | errln("Invalid fs_scontext: %d", 133 | opts->fs_low_secid); 134 | return -EINVAL; 135 | } 136 | opts->has_fssecid = true; 137 | break; 138 | case Opt_reserved_mb: 139 | if (match_int(&args[0], &option)) 140 | return 0; 141 | opts->reserved_mb = option; 142 | break; 143 | case Opt_quiet: 144 | opts->quiet = true; 145 | break; 146 | case Opt_gid_derivation: 147 | /* dummy */ 148 | break; 149 | default: /* unknown option */ 150 | if (!silent) 151 | errln("Unrecognized mount option \"%s\" " 152 | "or missing value", p); 153 | return -EINVAL; 154 | } 155 | } 156 | return 0; 157 | } 158 | 159 | static int __sdcardfs_setup_root( 160 | struct dentry *root, 161 | struct dentry *realdir, 162 | userid_t userid, 163 | int multiuser 164 | ) { 165 | struct sdcardfs_tree_entry *te; 166 | struct inode *inode; 167 | 168 | /* link the upper and lower dentries */ 169 | te = sdcardfs_init_tree_entry(root, realdir); 170 | if (te == NULL) 171 | return -ENOMEM; 172 | 173 | te->revision = get_next_revision(root); 174 | 175 | /* setup permission policy */ 176 | te->userid = userid; 177 | te->d_uid = AID_ROOT; 178 | te->under_android = false; 179 | te->perm = multiuser ? PERM_PRE_ROOT : PERM_ROOT; 180 | 181 | inode = d_inode(root); 182 | 183 | /* if inode->i_version < te->revision, 184 | uid/gid/mode will be updated at the right time */ 185 | inode->i_version = te->revision; 186 | 187 | /* used for revalidate in inode_permission */ 188 | inode->i_private = te; 189 | 190 | __fix_derived_permission(te, inode); 191 | return 0; 192 | } 193 | 194 | static inline 195 | struct dentry *__prepare_dir( 196 | const char *path_s, 197 | mode_t mode, uid_t uid, gid_t gid) 198 | { 199 | struct path parent; 200 | struct dentry *dent = kern_path_create(AT_FDCWD, 201 | path_s, &parent, LOOKUP_DIRECTORY); 202 | if (IS_ERR(dent)) { 203 | if (dent == ERR_PTR(-EEXIST)) 204 | dent = NULL; 205 | } else { 206 | int err = vfs_mkdir(d_inode(parent.dentry), dent, mode); 207 | if (err) { 208 | done_path_create(&parent, dent); 209 | dent = ERR_PTR(err); 210 | } else { 211 | struct iattr attrs = {.ia_valid = ATTR_UID | ATTR_GID}; 212 | attrs.ia_uid = make_kuid(&init_user_ns, uid); 213 | attrs.ia_gid = make_kgid(&init_user_ns, gid); 214 | 215 | inode_lock(d_inode(dent)); 216 | notify_change(dent, &attrs, NULL); 217 | inode_unlock(d_inode(dent)); 218 | 219 | BUG_ON(dent != dget(dent)); 220 | done_path_create(&parent, dent); 221 | } 222 | } 223 | return dent; 224 | } 225 | 226 | static 227 | struct dentry *prepare_dir( 228 | const char *path_s, 229 | mode_t mode, uid_t uid, gid_t gid) 230 | { 231 | struct dentry *dir = 232 | __prepare_dir(path_s, mode, uid, gid); 233 | if (dir == NULL) { 234 | struct path path; 235 | int err = kern_path(path_s, LOOKUP_DIRECTORY, &path); 236 | 237 | if (err) 238 | dir = ERR_PTR(-ESTALE); 239 | else if (d_is_negative(path.dentry) || 240 | !S_ISDIR(d_inode(path.dentry)->i_mode)) { 241 | path_put(&path); 242 | dir = ERR_PTR(-ENOTDIR); 243 | } else { 244 | dir = dget(path.dentry); 245 | path_put(&path); 246 | } 247 | } 248 | return dir; 249 | } 250 | 251 | /* There is no need to lock the sdcardfs_super_info's rwsem as there is no 252 | way anyone can have a reference to the superblock at this point in time. */ 253 | static int sdcardfs_read_super(struct super_block *sb, 254 | const char *dev_name, void *raw_data, int silent) 255 | { 256 | int err = 0; 257 | int debug; 258 | struct super_block *lower_sb; 259 | struct path lower_path; 260 | struct sdcardfs_sb_info *sbi; 261 | struct inode *inode, *lower_inode; 262 | 263 | /* avoid WARN_ON in sdcardfs_kill_sb */ 264 | sb->s_magic = SDCARDFS_SUPER_MAGIC; 265 | 266 | if (dev_name == NULL) { 267 | errln("%s, missing dev_name argument", __FUNCTION__); 268 | err = -EINVAL; 269 | goto out; 270 | } 271 | 272 | infoln("read_super, device -> %s", dev_name); 273 | infoln("options -> %s", (char *)raw_data); 274 | 275 | /* parse lower path */ 276 | err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, 277 | &lower_path); 278 | if (err) { 279 | errln("%s, error accessing device '%s'", __FUNCTION__, dev_name); 280 | goto out; 281 | } 282 | 283 | lower_inode = d_inode(lower_path.dentry); 284 | if (!S_ISDIR(lower_inode->i_mode)) { 285 | errln("%s, device '%s' should be a directory", 286 | __FUNCTION__, dev_name); 287 | err = -EINVAL; 288 | goto out_free; 289 | } 290 | 291 | /* allocate superblock private data */ 292 | sbi = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); 293 | if (sbi == NULL) { 294 | critln("%s, out of memory", __FUNCTION__); 295 | err = -ENOMEM; 296 | goto out_free; 297 | } 298 | 299 | sb->s_fs_info = sbi; 300 | default_options(&sbi->options); 301 | 302 | /* parse options */ 303 | err = sdcardfs_parse_options(&sbi->options, raw_data, silent, &debug); 304 | if (err) { 305 | errln("%s, invalid options", __FUNCTION__); 306 | goto out_freesbi; 307 | } 308 | 309 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 310 | sbi->basepath = lower_path; 311 | path_get(&sbi->basepath); 312 | #endif 313 | 314 | /* set the lower superblock field of upper superblock */ 315 | sbi->lower_mnt = lower_path.mnt; 316 | lower_sb = lower_path.dentry->d_sb; 317 | BUG_ON(lower_path.mnt->mnt_sb != lower_sb); 318 | 319 | sbi->next_revision = 1; 320 | 321 | /* increment lower_sb active references */ 322 | atomic_inc(&lower_sb->s_active); 323 | 324 | /* inherit maxbytes from lower file system */ 325 | sb->s_maxbytes = lower_sb->s_maxbytes; 326 | 327 | /* Our c/m/atime granularity is 1 ns because we may stack on file 328 | systems whose granularity is as good. */ 329 | sb->s_time_gran = 1; 330 | sb->s_op = &sdcardfs_sops; 331 | sb->s_d_op = &sdcardfs_ci_dops; 332 | 333 | /* get a inode and allocate our root dentry */ 334 | inode = sdcardfs_ialloc(sb, lower_inode->i_mode); 335 | if (IS_ERR(inode)) { 336 | err = PTR_ERR(inode); 337 | goto out_sput; 338 | } 339 | 340 | /* make the sdcardfs root dentry */ 341 | sb->s_root = d_make_root(inode); 342 | if (sb->s_root == NULL) { 343 | err = -ENOMEM; 344 | goto out_iput; 345 | } 346 | 347 | /* setup tree entry for root dentry */ 348 | err = __sdcardfs_setup_root(sb->s_root, lower_path.dentry, 349 | sbi->options.fs_user_id, sbi->options.multiuser); 350 | if (err) 351 | goto out_freeroot; 352 | 353 | /* save obbpath(devpath) to sbi */ 354 | sbi->devpath_s = __getname(); 355 | if (sbi->devpath_s == NULL) { 356 | err = -ENOMEM; 357 | goto out_freetreeentry; 358 | } 359 | 360 | snprintf(sbi->devpath_s, PATH_MAX, "%s", dev_name); 361 | sbi->devpath_s[PATH_MAX - 1] = '\0'; 362 | 363 | #ifdef SDCARDFS_PLUGIN_PRIVACY_SPACE 364 | sbi->blocked_userid = sbi->appid_excluded = -1; 365 | #endif 366 | 367 | #ifdef SDCARDFS_SYSFS_FEATURE 368 | /* use kobject_unregister instread of kfree to free sbi after succeed */ 369 | err = sdcardfs_sysfs_register_sb(sb); 370 | if (err) 371 | goto out_putname; 372 | #endif 373 | 374 | #ifdef SDCARDFS_CASE_INSENSITIVE 375 | /* prepare ci ops for lowerfs */ 376 | sbi->ci = sdcardfs_lowerfs_ci_ops(lower_sb); 377 | #endif 378 | 379 | /* prepare fs_struct */ 380 | sbi->override_fs = prepare_fs_struct(&lower_path, 0); 381 | if (sbi->override_fs == NULL) { 382 | err = -ENOMEM; 383 | goto out_putname; 384 | } 385 | 386 | if (sbi->options.has_fssecid) { 387 | sbi->sdcardd_cred = prepare_creds(); 388 | if (sbi->sdcardd_cred == NULL) { 389 | errln("%s, failed to prepare creds " 390 | "in order to override secid", __FUNCTION__); 391 | sbi->options.has_fssecid = false; 392 | } 393 | } 394 | 395 | if (!sbi->options.multiuser) { 396 | sbi->shared_obb = NULL; 397 | } else { 398 | struct dentry *dir; 399 | struct fs_struct *saved_fs = override_current_fs(sbi->override_fs); 400 | dir = prepare_dir("obb", 0775, sbi->options.fs_low_uid, 401 | sbi->options.fs_low_gid); 402 | revert_current_fs(saved_fs); 403 | 404 | if (IS_ERR(dir)) { 405 | err = PTR_ERR(dir); 406 | goto out_freefsstruct; 407 | } 408 | 409 | sbi->shared_obb = dir; 410 | } 411 | 412 | /* No need to call interpose because we already have 413 | a positive dentry, which was instantiated by 414 | d_make_root. Just need to d_rehash it. */ 415 | d_rehash(sb->s_root); 416 | 417 | if (!silent) 418 | infoln("mounted on top of %s type %s", dev_name, 419 | lower_sb->s_type->name); 420 | goto out; 421 | 422 | out_freefsstruct: 423 | free_fs_struct(sbi->override_fs); 424 | out_putname: 425 | __putname(sbi->devpath_s); 426 | out_freetreeentry: 427 | /* because dput_final will go into d_release, so it is no need 428 | to call sdcardfs_free_tree_entry(sb->s_root) explicitly; */ 429 | dget(lower_path.dentry); 430 | out_freeroot: 431 | dput(sb->s_root); 432 | out_iput: 433 | if (sb->s_root == NULL) 434 | iput(inode); 435 | out_sput: 436 | /* drop refs we took earlier */ 437 | atomic_dec(&lower_sb->s_active); 438 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 439 | _path_put(&sbi->basepath); 440 | #endif 441 | out_freesbi: 442 | /* it ensures the right behavior in sdcardfs_put_super */ 443 | sb->s_fs_info = NULL; 444 | #ifdef SDCARDFS_SYSFS_FEATURE 445 | if (sbi->kobj.state_initialized) 446 | kobject_put(&sbi->kobj); 447 | else 448 | #endif 449 | kfree(sbi); 450 | out_free: 451 | _path_put(&lower_path); 452 | out: 453 | return err; 454 | } 455 | 456 | struct _sdcardfs_mount_private { 457 | const char *dev_name; 458 | char *options; 459 | }; 460 | 461 | /* A feature which supports mount_nodev() with options */ 462 | static int __sdcardfs_fill_super(struct super_block *sb, 463 | void *_priv, int silent) 464 | { 465 | struct _sdcardfs_mount_private *priv = _priv; 466 | 467 | return sdcardfs_read_super(sb, priv->dev_name, 468 | priv->options, silent); 469 | } 470 | 471 | static struct dentry * 472 | sdcardfs_mount(struct file_system_type *fs_type, int flags, 473 | const char *dev_name, void *raw_data) 474 | { 475 | struct _sdcardfs_mount_private priv = { 476 | .dev_name = dev_name, 477 | .options = raw_data 478 | }; 479 | 480 | return mount_nodev(fs_type, flags, 481 | (void *)&priv, __sdcardfs_fill_super); 482 | } 483 | 484 | static void sdcardfs_kill_sb(struct super_block *sb) 485 | { 486 | WARN_ON(sb->s_magic != SDCARDFS_SUPER_MAGIC); 487 | 488 | kill_anon_super(sb); 489 | } 490 | 491 | static struct file_system_type sdcardfs_fs_type = { 492 | .owner = THIS_MODULE, 493 | .name = SDCARDFS_NAME, 494 | .mount = sdcardfs_mount, 495 | .kill_sb = sdcardfs_kill_sb, 496 | .fs_flags = 0, 497 | }; 498 | 499 | static int __init init_sdcardfs_fs(void) 500 | { 501 | int err; 502 | 503 | infoln("initialize HUAWEI sdcardfs v" SDCARDFS_VERSION); 504 | 505 | err = sdcardfs_init_tree_cache(); 506 | if (err) 507 | goto err; 508 | 509 | err = sdcardfs_configfs_init(); 510 | if (err) 511 | goto err_tree; 512 | 513 | #ifdef SDCARDFS_SYSFS_FEATURE 514 | err = sdcardfs_sysfs_init(); 515 | if (err) 516 | goto err_configfs; 517 | #endif 518 | 519 | err = register_filesystem(&sdcardfs_fs_type); 520 | if (!err) 521 | return 0; 522 | 523 | #ifdef SDCARDFS_SYSFS_FEATURE 524 | sdcardfs_sysfs_exit(); 525 | err_configfs: 526 | #endif 527 | sdcardfs_configfs_exit(); 528 | err_tree: 529 | sdcardfs_destroy_tree_cache(); 530 | err: 531 | return err; 532 | } 533 | 534 | static void __exit exit_sdcardfs_fs(void) 535 | { 536 | unregister_filesystem(&sdcardfs_fs_type); 537 | #ifdef SDCARDFS_SYSFS_FEATURE 538 | sdcardfs_sysfs_exit(); 539 | #endif 540 | sdcardfs_configfs_exit(); 541 | sdcardfs_destroy_tree_cache(); 542 | infoln("finalize sdcardfs module successfully"); 543 | } 544 | 545 | MODULE_AUTHOR("Gao Xiang , CONSUMER BG, HUAWEI inc."); 546 | MODULE_DESCRIPTION("HUAWEI Sdcardfs " SDCARDFS_VERSION); 547 | MODULE_LICENSE("GPL"); 548 | 549 | module_init(init_sdcardfs_fs); 550 | module_exit(exit_sdcardfs_fs); 551 | -------------------------------------------------------------------------------- /fs/sdcardfs/inode.c: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/inode.c 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #include "sdcardfs.h" 13 | #include 14 | #include 15 | 16 | #include "trace-events.h" 17 | 18 | #include "create.c" 19 | 20 | static int sdcardfs_create(struct inode *dir, struct dentry *dentry, 21 | umode_t mode, bool want_excl) 22 | { 23 | _sdcardfs_do_create_struct this; 24 | int err; 25 | 26 | trace_sdcardfs_create_enter(dir, dentry, mode, want_excl); 27 | 28 | err = __sdcardfs_do_create_begin(&this, dir, dentry); 29 | if (err) 30 | goto out; 31 | 32 | /* for regular files, the last 16bit of mode is 0664 */ 33 | mode = (mode & S_IFMT) | 0664; 34 | 35 | err = vfs_create(d_inode(this.real_dir_dentry), 36 | this.real_dentry, mode, want_excl); 37 | 38 | err = __sdcardfs_do_create_end(&this, __FUNCTION__, dir, dentry, err); 39 | out: 40 | trace_sdcardfs_create_exit(dir, dentry, mode, want_excl, err); 41 | return err; 42 | } 43 | 44 | static struct dentry *dentry_creat( 45 | struct dentry *parent, 46 | char *name, 47 | int len 48 | ) { 49 | struct dentry *dentry; 50 | 51 | inode_lock(d_inode(parent)); 52 | dentry = lookup_one_len(name, parent, len); 53 | if (unlikely(dentry == NULL)) 54 | dentry = ERR_PTR(-ENOENT); 55 | else if (!IS_ERR(dentry)) { 56 | int err = (d_is_positive(dentry) ? 57 | -EEXIST : vfs_create(d_inode(parent), 58 | dentry, S_IFREG | 0664, 0)); 59 | if (err) { 60 | dput(dentry); 61 | dentry = ERR_PTR(err); 62 | } 63 | } 64 | inode_unlock(d_inode(parent)); 65 | return dentry; 66 | } 67 | 68 | int touch_nomedia(struct dentry *parent) 69 | { 70 | int err; 71 | struct dentry *d_nomedia; 72 | 73 | d_nomedia = dentry_creat(parent, ".nomedia", sizeof(".nomedia")-1); 74 | if (IS_ERR(d_nomedia)) 75 | err = PTR_ERR(d_nomedia); 76 | else { 77 | dput(d_nomedia); 78 | err = 0; 79 | } 80 | return err; 81 | } 82 | 83 | static int sdcardfs_mkdir(struct inode *dir, 84 | struct dentry *dentry, umode_t mode 85 | ) { 86 | _sdcardfs_do_create_struct this; 87 | int err; 88 | 89 | trace_sdcardfs_mkdir_enter(dir, dentry, mode); 90 | 91 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 92 | if (!check_min_free_space(dir->i_sb, 0, 1)) { 93 | errln("%s, No minimum free space.", __FUNCTION__); 94 | err = -ENOSPC; 95 | goto out; 96 | } 97 | #endif 98 | err = __sdcardfs_do_create_begin(&this, dir, dentry); 99 | if (err) 100 | goto out; 101 | 102 | /* for directories, the last 16bit of mode is 0775 */ 103 | mode = (mode & S_IFMT) | 0775; 104 | 105 | err = vfs_mkdir(d_inode(this.real_dir_dentry), 106 | this.real_dentry, mode); 107 | 108 | /* When creating /Android/data and /Android/obb, mark them as .nomedia */ 109 | if (!err && d_is_positive(this.real_dentry)) { 110 | struct sdcardfs_tree_entry *pte = SDCARDFS_D(this.parent); 111 | if (unlikely(pte->perm == PERM_ANDROID)) { 112 | if (unlikely(!strcasecmp(dentry->d_name.name, "data"))) { 113 | touch_real: 114 | err = touch_nomedia(this.real_dentry); 115 | WARN_ON(err == -EEXIST); 116 | } else if (unlikely(!strcasecmp(dentry->d_name.name, "obb"))) { 117 | /* not multiuser obb */ 118 | if (SDCARDFS_SB(dir->i_sb)->shared_obb == NULL) 119 | goto touch_real; 120 | err = touch_nomedia(SDCARDFS_SB(dir->i_sb)->shared_obb); 121 | if (err == -EEXIST) 122 | err = 0; 123 | } 124 | 125 | if (unlikely(err)) 126 | errln("sdcardfs: failed to create .nomedia in %s: %d", 127 | dentry->d_name.name, err); 128 | } 129 | } 130 | 131 | err = __sdcardfs_do_create_end(&this, __FUNCTION__, dir, dentry, err); 132 | out: 133 | trace_sdcardfs_mkdir_exit(dir, dentry, mode, err); 134 | return err; 135 | } 136 | 137 | #include "remove.c" 138 | 139 | static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) 140 | { 141 | _sdcardfs_do_remove_struct this; 142 | int ret; 143 | struct inode *real_inode; 144 | 145 | trace_sdcardfs_unlink_enter(dir, dentry); 146 | 147 | ret = __sdcardfs_do_remove_begin(&this, dir, dentry); 148 | if (ret) 149 | goto out; 150 | 151 | real_inode = d_inode(this.real_dentry); 152 | ihold(real_inode); 153 | 154 | ret = S_ISDIR(real_inode->i_mode) ? 155 | -EISDIR : vfs_unlink(d_inode(this.real_dir_dentry), this.real_dentry, NULL); 156 | 157 | __sdcardfs_do_remove_end(&this, dir); 158 | iput(real_inode); /* truncate real_inode here */ 159 | out: 160 | trace_sdcardfs_unlink_exit(dir, dentry, ret); 161 | return ret; 162 | } 163 | 164 | static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) 165 | { 166 | _sdcardfs_do_remove_struct this; 167 | int ret; 168 | 169 | trace_sdcardfs_rmdir_enter(dir, dentry); 170 | 171 | ret = __sdcardfs_do_remove_begin(&this, dir, dentry); 172 | if (ret) 173 | goto out; 174 | 175 | ret = vfs_rmdir(d_inode(this.real_dir_dentry), this.real_dentry); 176 | __sdcardfs_do_remove_end(&this, dir); 177 | out: 178 | trace_sdcardfs_rmdir_exit(dir, dentry, ret); 179 | return ret; 180 | } 181 | 182 | #ifdef SDCARDFS_CASE_INSENSITIVE 183 | static inline 184 | struct dentry *__lookup_rename_ci( 185 | struct sdcardfs_sb_info *sbi, 186 | struct dentry *dir, struct qstr *name) 187 | { 188 | struct dentry *ret; 189 | 190 | if (sbi->ci->lookup == NULL) 191 | return NULL; 192 | else { 193 | struct path path = {.dentry = dir, .mnt = sbi->lower_mnt}; 194 | 195 | ret = sbi->ci->lookup(&path, name, true); 196 | /* once again sbi->ci->lookup() never returns NULL */ 197 | if (IS_ERR(ret)) { 198 | if (ret == ERR_PTR(-ENOENT)) 199 | ret = NULL; 200 | /* hashed (see d_delete) and unhashed(by d_alloc) but negative */ 201 | } else if (d_is_negative(ret)) { 202 | dput(ret); 203 | ret = ERR_PTR(-ESTALE); 204 | } 205 | return ret; 206 | } 207 | } 208 | #endif 209 | 210 | static int sdcardfs_rename( 211 | struct inode *old_dir, 212 | struct dentry *old_dentry, 213 | struct inode *new_dir, struct dentry *new_dentry 214 | ) { 215 | int err; 216 | struct dentry *trap, *dentry; 217 | struct dentry *real_old_parent, *real_new_parent; 218 | struct dentry *real_old_dentry, *real_new_dentry; 219 | const struct cred *saved_cred; 220 | bool overlapped = true; 221 | 222 | trace_sdcardfs_rename_enter(old_dir, old_dentry, new_dir, new_dentry); 223 | 224 | /* some forbidden filenames should be checked before removing */ 225 | if (permission_denied_to_remove(old_dir, old_dentry->d_name.name) 226 | || permission_denied_to_create(new_dir, new_dentry->d_name.name) 227 | || permission_denied_to_remove(new_dir, new_dentry->d_name.name)) { 228 | err = -EACCES; 229 | goto out; 230 | } 231 | 232 | /* since old_dir, new_old both have inode_locked, so 233 | it is no need to use dget_parent */ 234 | real_old_dentry = sdcardfs_get_real_dentry(old_dentry); 235 | real_old_parent = dget_parent(real_old_dentry); 236 | 237 | /* note that real_dir_dentry ?(!=) lower_dentry(dget_parent(dentry)). 238 | and it's unsafe to check by use IS_ROOT since inode_lock isnt taken */ 239 | if (unlikely(real_old_parent == real_old_dentry)) { 240 | err = -EBUSY; 241 | goto dput_err; 242 | } 243 | 244 | real_new_parent = sdcardfs_get_lower_dentry(new_dentry->d_parent); 245 | 246 | trap = lock_rename(real_old_parent, real_new_parent); 247 | 248 | /* source should not be ancestor of target */ 249 | if (real_old_dentry == trap) { 250 | err = -EINVAL; 251 | goto unlock_err; 252 | } 253 | 254 | err = -ESTALE; 255 | /* avoid race between dget_parent and lock_rename */ 256 | if (unlikely(real_old_parent != real_old_dentry->d_parent)) 257 | goto unlock_err; 258 | 259 | /* save current_cred and override it */ 260 | OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred); 261 | if (IS_ERR(saved_cred)) { 262 | err = PTR_ERR(saved_cred); 263 | goto unlock_err; 264 | } 265 | 266 | /* real_old_dentry must be hashed and in the real_old_dir */ 267 | dentry = lookup_one_len(real_old_dentry->d_name.name, 268 | real_old_parent, real_old_dentry->d_name.len); 269 | if (IS_ERR(dentry)) { 270 | /* maybe some err or real_old_parent DEADDIR */ 271 | err = PTR_ERR(dentry); 272 | goto revert_cred_err; 273 | } 274 | 275 | dput(dentry); 276 | 277 | if (real_old_dentry != dentry) 278 | goto revert_cred_err; 279 | 280 | /* real_target may be a negative unhashed dentry */ 281 | #ifdef SDCARDFS_CASE_INSENSITIVE 282 | dentry = __lookup_rename_ci(SDCARDFS_SB(new_dentry->d_sb), 283 | real_new_parent, &new_dentry->d_name); 284 | if (IS_ERR(dentry)) { 285 | err = PTR_ERR(dentry); 286 | goto revert_cred_err; 287 | } else if (dentry != NULL && dentry != real_old_dentry) { 288 | real_new_dentry = dentry; 289 | /* target should not be ancestor of source */ 290 | if (dentry == trap) { 291 | err = -ENOTEMPTY; 292 | goto dput2_err; 293 | } 294 | } else { 295 | if (dentry == real_old_dentry) 296 | dput(dentry); 297 | /* and if dentry == real_old_dentry, new_dentry 298 | could be positive */ 299 | #endif 300 | real_new_dentry = lookup_one_len(new_dentry->d_name.name, 301 | real_new_parent, new_dentry->d_name.len); 302 | if (IS_ERR(real_new_dentry)) { 303 | err = PTR_ERR(real_new_dentry); 304 | goto revert_cred_err; 305 | } 306 | overlapped = d_is_positive(real_new_dentry); 307 | #ifdef SDCARDFS_CASE_INSENSITIVE 308 | } 309 | #endif 310 | 311 | err = vfs_rename(d_inode(real_old_parent), real_old_dentry, 312 | d_inode(real_new_parent), real_new_dentry, NULL, 0); 313 | 314 | dentry = new_dentry->d_parent; 315 | get_derived_permission4(dentry, 316 | old_dentry, new_dentry->d_name.name, true); 317 | 318 | fsstack_copy_inode_size(old_dir, d_inode(real_new_parent)); 319 | if (new_dir != old_dir) 320 | fsstack_copy_inode_size(new_dir, d_inode(real_new_parent)); 321 | 322 | dput2_err: 323 | dput(real_new_dentry); 324 | revert_cred_err: 325 | REVERT_CRED(saved_cred); 326 | unlock_err: 327 | unlock_rename(real_old_parent, real_new_parent); 328 | dput(real_new_parent); 329 | dput_err: 330 | dput(real_old_parent); 331 | dput(real_old_dentry); 332 | 333 | out: 334 | trace_sdcardfs_rename_exit(old_dir, old_dentry, new_dir, new_dentry, err); 335 | return err; 336 | } 337 | 338 | static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) 339 | { 340 | int err; 341 | struct iattr copied_ia; 342 | struct inode *inode = d_inode(dentry); 343 | 344 | /* since sdcardfs uses its own uid/gid derived policy, 345 | so uid/gid modification is unsupported */ 346 | if (unlikely(ia->ia_valid & ATTR_FORCE)) { 347 | copied_ia = *ia; 348 | copied_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE); 349 | ia = &copied_ia; 350 | } else 351 | /* We strictly follow the fat/exfat file system behavior */ 352 | if (((ia->ia_valid & ATTR_UID) && 353 | !uid_eq(ia->ia_uid, inode->i_uid)) || 354 | ((ia->ia_valid & ATTR_GID) && 355 | !gid_eq(ia->ia_gid, inode->i_gid)) || 356 | ((ia->ia_valid & ATTR_MODE) && 357 | (ia->ia_mode & ~SDCARDFS_VALID_MODE))) { 358 | err = SDCARDFS_SB(dentry->d_sb)->options.quiet ? 0 : -EPERM; 359 | goto out; 360 | } else 361 | /* We don't return -EPERM here. Yes, strange, but this is too 362 | * old behavior. */ 363 | if (ia->ia_valid & ATTR_MODE) 364 | ia->ia_valid &= ~ATTR_MODE; 365 | 366 | err = inode_change_ok(inode, ia); 367 | if (!err) { 368 | struct dentry *lower_dentry; 369 | 370 | if (ia->ia_valid & ATTR_SIZE) { 371 | err = inode_newsize_ok(inode, ia->ia_size); 372 | if (err) 373 | goto out; 374 | truncate_setsize(inode, ia->ia_size); 375 | } 376 | 377 | if (ia->ia_valid & ATTR_FILE) { 378 | struct file *lower_file = sdcardfs_lower_file(ia->ia_file); 379 | WARN_ON(lower_file == NULL); 380 | ia->ia_file = lower_file; 381 | } 382 | 383 | lower_dentry = sdcardfs_get_lower_dentry(dentry); 384 | 385 | if (lower_dentry != NULL) { 386 | const struct cred *saved_cred; 387 | 388 | /* Allow touch updating timestamps. */ 389 | ia->ia_valid |= ATTR_FORCE; 390 | 391 | /* save current_cred and override it */ 392 | OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred); 393 | if (unlikely(IS_ERR(saved_cred))) 394 | err = PTR_ERR(saved_cred); 395 | else { 396 | inode_lock(d_inode(lower_dentry)); 397 | err = notify_change(lower_dentry, ia, NULL); 398 | inode_unlock(d_inode(lower_dentry)); 399 | 400 | REVERT_CRED(saved_cred); 401 | } 402 | dput(lower_dentry); 403 | } 404 | } 405 | out: 406 | return err; 407 | } 408 | 409 | static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 410 | struct kstat *stat) 411 | { 412 | int err; 413 | struct path lower_path; 414 | const struct cred *saved_cred; 415 | 416 | debugln("%s, dentry=%p, name=%s", __FUNCTION__, 417 | dentry, dentry->d_name.name); 418 | 419 | if (sdcardfs_get_lower_path(dentry, &lower_path)) { 420 | WARN_ON(1); 421 | err = -ESTALE; 422 | goto out; 423 | } 424 | 425 | /* save current_cred and override it */ 426 | OVERRIDE_CRED(SDCARDFS_SB(mnt->mnt_sb), saved_cred); 427 | if (IS_ERR(saved_cred)) { 428 | err = PTR_ERR(saved_cred); 429 | goto out_pathput; 430 | } 431 | 432 | err = vfs_getattr(&lower_path, stat); 433 | REVERT_CRED(saved_cred); 434 | 435 | if (!err) { 436 | struct inode *inode = d_inode(dentry); 437 | struct sdcardfs_tree_entry *te = inode->i_private; 438 | 439 | /* note that generic_fillattr dont take any lock */ 440 | stat->nlink = S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink; 441 | 442 | if (te->revision > inode->i_version) { 443 | inode_lock(inode); 444 | __fix_derived_permission(te, inode); 445 | inode_unlock(inode); 446 | } 447 | stat->uid = inode->i_uid; 448 | stat->gid = inode->i_gid; 449 | stat->mode = inode->i_mode; 450 | stat->dev = inode->i_sb->s_dev; /* fix df */ 451 | } 452 | 453 | out_pathput: 454 | _path_put(&lower_path); 455 | out: 456 | return err; 457 | } 458 | 459 | static int sdcardfs_permission(struct inode *inode, int mask) 460 | { 461 | bool need_reval; 462 | #ifdef SDCARDFS_PLUGIN_PRIVACY_SPACE 463 | struct sdcardfs_sb_info *sbi; 464 | #endif 465 | struct sdcardfs_tree_entry *te = inode->i_private; 466 | 467 | need_reval = te->revision > inode->i_version; 468 | 469 | if (need_reval) { 470 | if (mask & MAY_NOT_BLOCK) 471 | return -ECHILD; 472 | 473 | /* it's now safe to take the inode i_mutex */ 474 | inode_lock(inode); 475 | __fix_derived_permission(te, inode); 476 | inode_unlock(inode); 477 | } 478 | 479 | /* have no access to PERM_JAILHOUSE via sdcardfs */ 480 | if (unlikely(te->perm == PERM_JAILHOUSE)) 481 | return -EACCES; 482 | 483 | #ifdef SDCARDFS_PLUGIN_PRIVACY_SPACE 484 | sbi = SDCARDFS_SB(inode->i_sb); 485 | 486 | if (unlikely(sbi->blocked_userid >= 0)) { 487 | uid_t uid = from_kuid(&init_user_ns, current_fsuid()); 488 | 489 | if (multiuser_get_user_id(uid) == sbi->blocked_userid && 490 | multiuser_get_app_id(uid) != sbi->appid_excluded) 491 | return -EACCES; 492 | } 493 | #endif 494 | 495 | return generic_permission(inode, mask); 496 | } 497 | 498 | const struct inode_operations sdcardfs_dir_iops = { 499 | .create = sdcardfs_create, 500 | .lookup = sdcardfs_lookup, 501 | .permission = sdcardfs_permission, 502 | .unlink = sdcardfs_unlink, 503 | .mkdir = sdcardfs_mkdir, 504 | .rmdir = sdcardfs_rmdir, 505 | .rename = sdcardfs_rename, 506 | .setattr = sdcardfs_setattr, 507 | .getattr = sdcardfs_getattr, 508 | 509 | .setxattr = sdcardfs_setxattr, 510 | .getxattr = sdcardfs_getxattr, 511 | .listxattr = sdcardfs_listxattr, 512 | .removexattr = sdcardfs_removexattr, 513 | }; 514 | 515 | const struct inode_operations sdcardfs_main_iops = { 516 | .permission = sdcardfs_permission, 517 | .setattr = sdcardfs_setattr, 518 | .getattr = sdcardfs_getattr, 519 | 520 | .setxattr = sdcardfs_setxattr, 521 | .getxattr = sdcardfs_getxattr, 522 | .listxattr = sdcardfs_listxattr, 523 | .removexattr = sdcardfs_removexattr, 524 | }; 525 | -------------------------------------------------------------------------------- /fs/sdcardfs/sdcardfs.h: -------------------------------------------------------------------------------- 1 | /* vim:set ts=4 sw=4 tw=0 noet ft=c: 2 | * 3 | * fs/sdcardfs/sdcardfs.h 4 | * 5 | * Copyright (C) 2017 HUAWEI, Inc. 6 | * Author: gaoxiang 7 | * 8 | * This file is subject to the terms and conditions of the GNU General Public 9 | * License. See the file COPYING in the main directory of the Linux 10 | * distribution for more details. 11 | */ 12 | #ifndef __SDCARDFS_H 13 | #define __SDCARDFS_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #ifdef SDCARDFS_SYSFS_FEATURE 36 | #include 37 | #endif 38 | 39 | #include "multiuser.h" 40 | #include "macros.h" 41 | 42 | /* the file system magic number */ 43 | #define SDCARDFS_SUPER_MAGIC 0x5dca2df5 44 | 45 | /* the file system name */ 46 | #define SDCARDFS_NAME "sdcardfs" 47 | 48 | #undef pr_fmt 49 | #define pr_fmt(fmt) SDCARDFS_NAME ": " fmt 50 | 51 | #define debugln(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__) 52 | #define infoln(fmt, ...) pr_info(fmt "\n", ##__VA_ARGS__) 53 | #define warnln(fmt, ...) pr_warn(fmt "\n", ##__VA_ARGS__) 54 | #define errln(fmt, ...) pr_err(fmt "\n", ##__VA_ARGS__) 55 | #define critln(fmt, ...) pr_crit(fmt "\n", ##__VA_ARGS__) 56 | 57 | #define infoln_ratelimited(fmt, ...) pr_info_ratelimited(fmt "\n", ##__VA_ARGS__) 58 | 59 | #include "android_filesystem_config.h" 60 | 61 | static inline 62 | struct fs_struct *override_current_fs( 63 | struct fs_struct *fs 64 | ) { 65 | struct fs_struct *saved_fs; 66 | 67 | task_lock(current); 68 | saved_fs = current->fs; 69 | current->fs = fs; 70 | task_unlock(current); 71 | return saved_fs; 72 | } 73 | 74 | static inline 75 | void __free_fs_struct(struct fs_struct *fs) 76 | { 77 | path_put(&fs->root); 78 | path_put(&fs->pwd); 79 | 80 | kfree(fs); 81 | } 82 | 83 | #define revert_current_fs override_current_fs 84 | #define free_fs_struct __free_fs_struct 85 | 86 | /* OVERRIDE_CRED() and REVERT_CRED() 87 | * - OVERRIDE_CRED() 88 | * backup original task->cred 89 | * and modifies task->cred->fsuid/fsgid to specified value. 90 | * - REVERT_CRED() 91 | * restore original task->cred->fsuid/fsgid. 92 | * Remember that these two macros should be used in pair */ 93 | 94 | #define OVERRIDE_CRED(sdcardfs_sbi, saved_cred) (saved_cred = override_fsids(sdcardfs_sbi)) 95 | #define REVERT_CRED(saved_cred) revert_fsids(saved_cred) 96 | 97 | /* Android 6.0 runtime permissions model */ 98 | 99 | /* Permission mode for a specific node. Controls how file permissions 100 | * are derived for children nodes. */ 101 | typedef enum { 102 | /* Nothing special; this node should just inherit from its parent. */ 103 | PERM_INHERIT, 104 | /* This node is one level above a normal root; used for legacy layouts 105 | * which use the first level to represent user_id. */ 106 | PERM_PRE_ROOT, 107 | /* This node is "/" */ 108 | PERM_ROOT, 109 | /* This node is "/Android" */ 110 | PERM_ANDROID, 111 | /* This node is "/Android/data" */ 112 | PERM_ANDROID_DATA, 113 | /* This node is "/Android/obb" */ 114 | PERM_ANDROID_OBB, 115 | /* This node is "/Android/media" */ 116 | PERM_ANDROID_MEDIA, 117 | /* nodes which have security issues */ 118 | PERM_JAILHOUSE, 119 | } perm_t; 120 | 121 | struct sdcardfs_sb_info; 122 | struct sdcardfs_mount_options; 123 | 124 | /* derived_perm.c */ 125 | const struct cred *override_fsids(struct sdcardfs_sb_info *sbi); 126 | void revert_fsids(const struct cred *old_cred); 127 | 128 | extern struct fs_struct *prepare_fs_struct(struct path *, int); 129 | 130 | /* operations defined in specific files */ 131 | extern const struct file_operations sdcardfs_main_fops, sdcardfs_dir_fops; 132 | extern const struct inode_operations sdcardfs_main_iops, sdcardfs_dir_iops; 133 | extern const struct super_operations sdcardfs_sops; 134 | extern const struct dentry_operations sdcardfs_ci_dops; 135 | extern const struct address_space_operations sdcardfs_aops; 136 | extern const struct vm_operations_struct sdcardfs_vm_ops; 137 | 138 | /* lookup_ci.c */ 139 | extern struct sdcardfs_dir_ci_ops * 140 | sdcardfs_lowerfs_ci_ops(struct super_block *); 141 | 142 | /* namei.c */ 143 | extern struct dentry *sdcardfs_lookup(struct inode *dir, 144 | struct dentry *dentry, unsigned int flags); 145 | 146 | /* used for lookup/create/mkdir */ 147 | extern struct dentry *sdcardfs_interpose(struct dentry *, 148 | struct dentry *, struct dentry *); 149 | 150 | /* inode.c */ 151 | extern struct inode *sdcardfs_ialloc(struct super_block *, mode_t); 152 | extern int touch_nomedia(struct dentry *parent); 153 | 154 | /* tree.c */ 155 | extern int sdcardfs_init_tree_cache(void); 156 | extern void sdcardfs_destroy_tree_cache(void); 157 | 158 | /* xattr.c */ 159 | extern int sdcardfs_setxattr(struct dentry *dentry, 160 | const char *name, const void *value, size_t size, int flags); 161 | extern ssize_t sdcardfs_getxattr(struct dentry *dentry, 162 | const char *name, void *value, size_t size); 163 | extern ssize_t sdcardfs_listxattr(struct dentry *dentry, 164 | char *list, size_t size); 165 | extern int sdcardfs_removexattr(struct dentry *dentry, const char *name); 166 | 167 | /* valid file mode bits */ 168 | #define SDCARDFS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) 169 | 170 | /* file private data */ 171 | struct sdcardfs_file_info { 172 | struct file *lower_file; 173 | const struct vm_operations_struct *lower_vm_ops; 174 | }; 175 | 176 | struct sdcardfs_mount_options { 177 | uid_t fs_low_uid; 178 | gid_t fs_low_gid; 179 | userid_t fs_user_id; 180 | gid_t gid; 181 | mode_t mask; 182 | bool multiuser; 183 | /* used for overiding secid */ 184 | bool has_fssecid; 185 | /* set = fake successful chmods and chowns */ 186 | bool quiet; 187 | u32 fs_low_secid; 188 | unsigned int reserved_mb; 189 | }; 190 | 191 | #ifdef SDCARDFS_CASE_INSENSITIVE 192 | struct sdcardfs_dir_ci_ops { 193 | struct dentry *(*lookup)(struct path *, struct qstr *, bool); 194 | int (*may_create)(struct path *, struct qstr *); 195 | }; 196 | #endif 197 | 198 | /* sdcardfs super-block data in memory */ 199 | struct sdcardfs_sb_info { 200 | struct vfsmount *lower_mnt; 201 | /* derived perm policy : some of options have been added 202 | * to sdcardfs_mount_options (Android 4.4 support) */ 203 | struct sdcardfs_mount_options options; 204 | char *devpath_s; 205 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 206 | struct path basepath; 207 | #endif 208 | struct dentry *shared_obb; 209 | 210 | struct fs_struct *override_fs; 211 | struct cred *sdcardd_cred; 212 | 213 | #ifdef SDCARDFS_SYSFS_FEATURE 214 | struct kobject kobj; 215 | #endif 216 | 217 | #ifdef SDCARDFS_PLUGIN_PRIVACY_SPACE 218 | int blocked_userid, appid_excluded; 219 | #endif 220 | 221 | unsigned next_revision; 222 | #ifdef SDCARDFS_CASE_INSENSITIVE 223 | struct sdcardfs_dir_ci_ops *ci; 224 | #endif 225 | }; 226 | 227 | /* superblock to private data */ 228 | #define SDCARDFS_SB(super) ((struct sdcardfs_sb_info *)(super)->s_fs_info) 229 | 230 | #define get_next_revision(d) (SDCARDFS_SB((d)->d_sb)->next_revision++) 231 | 232 | /* superblock to lower superblock */ 233 | static inline struct super_block *sdcardfs_lower_super( 234 | const struct super_block *sb) 235 | { 236 | struct sdcardfs_sb_info *sbi = SDCARDFS_SB(sb); 237 | 238 | BUG_ON(sbi->lower_mnt == NULL); 239 | return sbi->lower_mnt->mnt_sb; 240 | } 241 | 242 | struct sdcardfs_tree_entry { 243 | rwlock_t lock; 244 | 245 | struct dentry *ovl; 246 | struct { 247 | struct dentry *dentry; 248 | 249 | /* if sdcardfs_disconnected, use ino/genertion pair 250 | to connect real again. */ 251 | unsigned long ino; 252 | __u32 generation; 253 | 254 | bool dentry_invalid; 255 | unsigned d_seq; 256 | } real; 257 | 258 | /* a number used to decide whether permissions 259 | should be updated from the parent when revalidated */ 260 | unsigned revision; 261 | 262 | /* state derived based on current position in hierachy */ 263 | perm_t perm; 264 | userid_t userid; 265 | uid_t d_uid; 266 | bool under_android; 267 | }; 268 | 269 | #define SDCARDFS_DI_LOCKED ((void *)0x19921118) 270 | 271 | /* keep in mind SDCARDFS_D is unsafe for RCU lookup */ 272 | static inline 273 | struct sdcardfs_tree_entry *SDCARDFS_D( 274 | const struct dentry *d 275 | ) { 276 | struct sdcardfs_tree_entry *te; 277 | 278 | while ((te = (struct sdcardfs_tree_entry *) 279 | lockless_dereference(d->d_fsdata)) == SDCARDFS_DI_LOCKED) 280 | cpu_relax(); 281 | return te; 282 | } 283 | 284 | static inline 285 | struct sdcardfs_tree_entry *SDCARDFS_DI_X( 286 | const struct dentry *_d 287 | ) { 288 | struct dentry *d = (struct dentry *)_d; 289 | struct sdcardfs_tree_entry *te; 290 | 291 | while ((te = (struct sdcardfs_tree_entry *)xchg( 292 | &d->d_fsdata, SDCARDFS_DI_LOCKED)) == SDCARDFS_DI_LOCKED) 293 | cpu_relax(); 294 | 295 | smp_mb(); 296 | ACCESS_ONCE(d->d_fsdata) = NULL; 297 | if (te != NULL) 298 | write_lock(&te->lock); 299 | return te; 300 | } 301 | 302 | /* acquire tree entry with te read locked */ 303 | static inline 304 | struct sdcardfs_tree_entry *SDCARDFS_DI_R( 305 | const struct dentry *_d 306 | ) { 307 | struct dentry *d = (struct dentry *)_d; 308 | struct sdcardfs_tree_entry *te; 309 | 310 | while ((te = (struct sdcardfs_tree_entry *)xchg( 311 | &d->d_fsdata, SDCARDFS_DI_LOCKED)) == SDCARDFS_DI_LOCKED) 312 | cpu_relax(); 313 | BUG_ON(te == NULL); 314 | read_lock(&te->lock); 315 | return ACCESS_ONCE(d->d_fsdata) = te; 316 | } 317 | 318 | /* acquire tree entry with te write locked */ 319 | static inline 320 | struct sdcardfs_tree_entry *SDCARDFS_DI_W( 321 | const struct dentry *_d 322 | ) { 323 | struct dentry *d = (struct dentry *)_d; 324 | struct sdcardfs_tree_entry *te; 325 | 326 | while ((te = (struct sdcardfs_tree_entry *)xchg( 327 | &d->d_fsdata, SDCARDFS_DI_LOCKED)) == SDCARDFS_DI_LOCKED) 328 | cpu_relax(); 329 | BUG_ON(te == NULL); 330 | write_lock(&te->lock); 331 | return ACCESS_ONCE(d->d_fsdata) = te; 332 | } 333 | 334 | extern struct dentry * 335 | _sdcardfs_reactivate_real_locked(const struct dentry *dentry, 336 | struct sdcardfs_tree_entry *te); 337 | 338 | static inline 339 | struct sdcardfs_tree_entry * 340 | sdcardfs_tree_entry_real_locked( 341 | const struct dentry *dentry, 342 | struct dentry **real_dentry 343 | ) { 344 | struct sdcardfs_tree_entry *te = SDCARDFS_DI_R(dentry); 345 | *real_dentry = (!te->real.dentry_invalid ? te->real.dentry : 346 | _sdcardfs_reactivate_real_locked(dentry, te)); 347 | return te; 348 | } 349 | 350 | static inline 351 | struct sdcardfs_tree_entry * 352 | sdcardfs_tree_entry_lower_locked( 353 | const struct dentry *dentry, 354 | struct dentry **lower_dentry 355 | ) { 356 | struct sdcardfs_tree_entry *te = SDCARDFS_DI_R(dentry); 357 | *lower_dentry = (te->ovl != NULL ? te->ovl : 358 | (!te->real.dentry_invalid ? te->real.dentry : 359 | _sdcardfs_reactivate_real_locked(dentry, te))); 360 | return te; 361 | } 362 | 363 | static inline 364 | struct sdcardfs_tree_entry * 365 | sdcardfs_real_dentry_rcu_locked( 366 | struct dentry *d, 367 | struct dentry **real_dentry 368 | ) { 369 | /* it is needed to treat differently for RCU approach. 370 | * because countref isnt taken and free_tree_entry 371 | * could be triggered at the same time */ 372 | struct sdcardfs_tree_entry *te; 373 | 374 | while ((te = (struct sdcardfs_tree_entry *)xchg( 375 | &d->d_fsdata, SDCARDFS_DI_LOCKED)) == SDCARDFS_DI_LOCKED) 376 | cpu_relax(); 377 | 378 | if (te != NULL) { 379 | read_lock(&te->lock); 380 | *real_dentry = (te->real.dentry_invalid ? NULL : 381 | te->real.dentry); 382 | } 383 | ACCESS_ONCE(d->d_fsdata) = te; 384 | return te; 385 | } 386 | 387 | static inline 388 | struct dentry *sdcardfs_get_real_dentry_with_seq( 389 | const struct dentry *dentry, 390 | unsigned *d_seq 391 | ) { 392 | struct sdcardfs_tree_entry *te; 393 | struct dentry *real_dentry; 394 | 395 | te = sdcardfs_tree_entry_real_locked(dentry, &real_dentry); 396 | real_dentry = dget(real_dentry); 397 | *d_seq = te->real.d_seq; 398 | read_unlock(&te->lock); 399 | 400 | return real_dentry; 401 | } 402 | 403 | static inline 404 | struct dentry *sdcardfs_get_real_dentry( 405 | const struct dentry *dentry 406 | ) { 407 | unsigned d_seq; 408 | 409 | return sdcardfs_get_real_dentry_with_seq( 410 | dentry, &d_seq); 411 | } 412 | 413 | static inline 414 | struct dentry *sdcardfs_get_lower_dentry( 415 | const struct dentry *dentry 416 | ) { 417 | struct sdcardfs_tree_entry *te; 418 | struct dentry *lower_dentry; 419 | 420 | te = sdcardfs_tree_entry_lower_locked(dentry, &lower_dentry); 421 | lower_dentry = dget(lower_dentry); 422 | read_unlock(&te->lock); 423 | 424 | return lower_dentry; 425 | } 426 | 427 | extern struct sdcardfs_tree_entry * 428 | sdcardfs_init_tree_entry(struct dentry *, struct dentry *); 429 | extern void sdcardfs_free_tree_entry(struct dentry *); 430 | 431 | /* need fixup its permission from its parent */ 432 | static inline int need_fixup_permission( 433 | struct inode *dir, 434 | struct sdcardfs_tree_entry *te 435 | ) { 436 | return te->revision < dir->i_version; 437 | } 438 | 439 | static inline void __fix_derived_permission( 440 | struct sdcardfs_tree_entry *te, 441 | struct inode *inode 442 | ) { 443 | int visible_mode, owner_mode, filtered_mode; 444 | struct sdcardfs_mount_options *opts = 445 | &SDCARDFS_SB(inode->i_sb)->options; 446 | 447 | inode->i_uid = make_kuid(&init_user_ns, te->d_uid); 448 | 449 | if (opts->gid == AID_SDCARD_RW) { 450 | /* As an optimization, certain trusted system components only run 451 | * as owner but operate across all users. Since we're now handing 452 | * out the sdcard_rw GID only to trusted apps, we're okay relaxing 453 | * the user boundary enforcement for the default view. The UIDs 454 | * assigned to app directories are still multiuser aware. */ 455 | inode->i_gid = make_kgid(&init_user_ns, AID_SDCARD_RW); 456 | } else { 457 | inode->i_gid = make_kgid(&init_user_ns, 458 | multiuser_get_uid(te->userid, opts->gid)); 459 | } 460 | 461 | /* sdcard storage has its "i_mode" derived algorithm */ 462 | visible_mode = 0775 & ~opts->mask; 463 | 464 | if (te->perm == PERM_PRE_ROOT) { 465 | /* Top of multi-user view should always be visible to ensure 466 | * secondary users can traverse inside. */ 467 | visible_mode = 0711; 468 | } else if (te->under_android) { 469 | /* Block "other" access to Android directories, since only apps 470 | * belonging to a specific user should be in there; we still 471 | * leave +x open for the default view. */ 472 | if (opts->gid == AID_SDCARD_RW) 473 | visible_mode = visible_mode & ~0006; 474 | else 475 | visible_mode = visible_mode & ~0007; 476 | } 477 | owner_mode = inode->i_mode & 0700; 478 | filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6)); 479 | inode->i_mode = (inode->i_mode & S_IFMT) | filtered_mode; 480 | 481 | inode->i_version = te->revision; 482 | } 483 | 484 | static inline void fix_derived_permission( 485 | struct dentry *dentry 486 | ) { 487 | struct sdcardfs_tree_entry *te = SDCARDFS_DI_R(dentry); 488 | 489 | __fix_derived_permission(te, d_inode(dentry)); 490 | read_unlock(&te->lock); 491 | } 492 | 493 | /* file to private Data */ 494 | #define SDCARDFS_F(file) ((struct sdcardfs_file_info *)((file)->private_data)) 495 | 496 | /* file to lower file */ 497 | #define sdcardfs_lower_file(f) (SDCARDFS_F(f)->lower_file) 498 | 499 | static inline int sdcardfs_get_lower_path( 500 | const struct dentry *dentry, struct path *path 501 | ) { 502 | path->dentry = sdcardfs_get_lower_dentry(dentry); 503 | if (path->dentry != NULL) { 504 | path->mnt = mntget(SDCARDFS_SB(dentry->d_sb)->lower_mnt); 505 | debugln("%s, dentry=%p, lower_path(dentry=%p, mnt=%p)", 506 | __FUNCTION__, dentry, path->dentry, path->mnt); 507 | return 0; 508 | } 509 | debugln("%s, dentry=%p, lower_path(null)", __FUNCTION__, dentry); 510 | return -1; 511 | } 512 | 513 | static inline void _path_put(const struct path *path) 514 | { 515 | debugln("%s, lower_path(dentry=%p, mnt=%p)", 516 | __FUNCTION__, path->dentry, path->mnt); 517 | 518 | path_put(path); 519 | } 520 | 521 | /* main.c */ 522 | int sdcardfs_parse_options(struct sdcardfs_mount_options *, char *, int, int *); 523 | 524 | /* packagelist.c */ 525 | extern appid_t get_appid(const char *app_name); 526 | 527 | extern struct sdcardfs_packagelist_entry *sdcardfs_packagelist_entry_alloc(void); 528 | 529 | extern void sdcardfs_packagelist_entry_register(struct sdcardfs_packagelist_entry *pkg, 530 | const char *app_name, appid_t appid); 531 | extern void sdcardfs_packagelist_entry_release(struct sdcardfs_packagelist_entry *); 532 | 533 | /* configfs.c */ 534 | extern int sdcardfs_configfs_init(void); 535 | extern void sdcardfs_configfs_exit(void); 536 | 537 | /* sysfs.c */ 538 | #ifdef SDCARDFS_SYSFS_FEATURE 539 | extern int sdcardfs_sysfs_init(void); 540 | extern void sdcardfs_sysfs_exit(void); 541 | extern int sdcardfs_sysfs_register_sb(struct super_block *); 542 | #endif 543 | 544 | /* derived_perm.c */ 545 | extern void get_derived_permission4(struct dentry *, 546 | struct dentry *, const char *, bool); 547 | extern void get_derived_permission(struct dentry *, struct dentry *); 548 | 549 | static inline bool 550 | permission_denied_to_create(struct inode *dir, const char *name) 551 | { 552 | struct sdcardfs_tree_entry *te = dir->i_private; 553 | 554 | if (te != NULL && te->perm == PERM_ROOT) 555 | return !strcasecmp(name, "autorun.inf"); 556 | return false; 557 | } 558 | 559 | static inline bool 560 | permission_denied_to_remove(struct inode *dir, const char *name) 561 | { 562 | struct sdcardfs_tree_entry *te = dir->i_private; 563 | 564 | if (te != NULL && te->perm == PERM_ROOT) 565 | return !strcasecmp(name, ".android_secure") || 566 | !strcasecmp(name, "android_secure"); 567 | return false; 568 | } 569 | 570 | #ifdef SDCARDFS_SUPPORT_RESERVED_SPACE 571 | /* Return 1, if a disk has enough free space, otherwise 0. 572 | * We assume that any files can not be overwritten. */ 573 | static inline int check_min_free_space(struct super_block *sb, 574 | size_t size, int isdir) 575 | { 576 | struct sdcardfs_sb_info *sbi = SDCARDFS_SB(sb); 577 | 578 | if (sbi->options.reserved_mb) { 579 | int err; 580 | struct kstatfs statfs; 581 | u64 avail; 582 | 583 | err = vfs_statfs(&sbi->basepath, &statfs); 584 | if (unlikely(err)) { 585 | out_invalid: 586 | infoln("statfs : invalid return"); 587 | infoln("vfs_statfs error# : %d", err); 588 | infoln("statfs.f_type : 0x%X", (u32)statfs.f_type); 589 | infoln("statfs.f_blocks : %llu blocks", statfs.f_blocks); 590 | infoln("statfs.f_bfree : %llu blocks", statfs.f_bfree); 591 | infoln("statfs.f_files : %llu", statfs.f_files); 592 | infoln("statfs.f_ffree : %llu", statfs.f_ffree); 593 | infoln("statfs.f_fsid.val[1] : 0x%X", (u32)statfs.f_fsid.val[1]); 594 | infoln("statfs.f_fsid.val[0] : 0x%X", (u32)statfs.f_fsid.val[0]); 595 | infoln("statfs.f_namelen : %ld", statfs.f_namelen); 596 | infoln("statfs.f_frsize : %ld", statfs.f_frsize); 597 | infoln("statfs.f_flags : %ld", statfs.f_flags); 598 | infoln("sdcardfs reserved_mb : %u", sbi->options.reserved_mb); 599 | if (sbi->devpath_s != NULL) 600 | infoln("sdcardfs dev_name : %s", sbi->devpath_s); 601 | out_nospc: 602 | infoln_ratelimited("statfs.f_bavail : %llu blocks / " 603 | "statfs.f_bsize : %ld bytes / " 604 | "required size : %llu byte", 605 | statfs.f_bavail, statfs.f_bsize, (u64)size); 606 | return 0; 607 | } 608 | 609 | /* Invalid statfs informations. */ 610 | if (unlikely(!statfs.f_bsize)) 611 | goto out_invalid; 612 | 613 | /* if you are checking directory, set size to f_bsize. */ 614 | if (isdir) 615 | size = statfs.f_bsize; 616 | 617 | /* available size */ 618 | avail = statfs.f_bavail * statfs.f_bsize; 619 | 620 | /* not enough space */ 621 | if ((u64)size > avail || 622 | (avail - size) < (u64)sbi->options.reserved_mb << 20) 623 | goto out_nospc; 624 | } 625 | /* enough space */ 626 | return 1; 627 | } 628 | #endif 629 | 630 | /* Copies attrs and maintains sdcardfs managed attrs */ 631 | static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct inode *src) 632 | { 633 | dest->i_rdev = src->i_rdev; 634 | dest->i_atime = src->i_atime; 635 | dest->i_mtime = src->i_mtime; 636 | dest->i_ctime = src->i_ctime; 637 | dest->i_blkbits = src->i_blkbits; 638 | dest->i_flags = src->i_flags; 639 | set_nlink(dest, src->i_nlink); 640 | } 641 | #endif /* not _SDCARDFS_H_ */ 642 | --------------------------------------------------------------------------------