123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- /*
- * fs/sdcardfs/dentry.c
- *
- * Copyright (c) 2013 Samsung Electronics Co. Ltd
- * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
- * Sunghwan Yun, Sungjong Seo
- *
- * This program has been developed as a stackable file system based on
- * the WrapFS which written by
- *
- * Copyright (c) 1998-2011 Erez Zadok
- * Copyright (c) 2009 Shrikar Archak
- * Copyright (c) 2003-2011 Stony Brook University
- * Copyright (c) 2003-2011 The Research Foundation of SUNY
- *
- * This file is dual licensed. It may be redistributed and/or modified
- * under the terms of the Apache 2.0 License OR version 2 of the GNU
- * General Public License.
- */
- #include "sdcardfs.h"
- #include "linux/ctype.h"
- /*
- * returns: -ERRNO if error (returned to user)
- * 0: tell VFS to invalidate dentry
- * 1: dentry is valid
- */
- static int sdcardfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
- {
- int err = 1;
- struct path parent_lower_path, lower_path;
- struct dentry *parent_dentry = NULL;
- struct dentry *parent_lower_dentry = NULL;
- struct dentry *lower_cur_parent_dentry = NULL;
- struct dentry *lower_dentry = NULL;
- struct inode *inode;
- struct sdcardfs_inode_data *data;
- if (nd && nd->flags & LOOKUP_RCU)
- return -ECHILD;
- spin_lock(&dentry->d_lock);
- if (IS_ROOT(dentry)) {
- spin_unlock(&dentry->d_lock);
- return 1;
- }
- spin_unlock(&dentry->d_lock);
- /* check uninitialized obb_dentry and
- * whether the base obbpath has been changed or not
- */
- if (is_obbpath_invalid(dentry)) {
- return 0;
- }
- parent_dentry = dget_parent(dentry);
- sdcardfs_get_lower_path(parent_dentry, &parent_lower_path);
- sdcardfs_get_real_lower(dentry, &lower_path);
- parent_lower_dentry = parent_lower_path.dentry;
- lower_dentry = lower_path.dentry;
- lower_cur_parent_dentry = dget_parent(lower_dentry);
- if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) {
- struct path ptmp;
- if (nd) {
- pathcpy(&ptmp, &nd->path);
- pathcpy(&nd->path, &lower_path);
- }
- err = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
- if (nd)
- pathcpy(&nd->path, &ptmp);
- if (err == 0) {
- goto out;
- }
- }
- spin_lock(&lower_dentry->d_lock);
- if (d_unhashed(lower_dentry)) {
- spin_unlock(&lower_dentry->d_lock);
- err = 0;
- goto out;
- }
- spin_unlock(&lower_dentry->d_lock);
- if (parent_lower_dentry != lower_cur_parent_dentry) {
- err = 0;
- goto out;
- }
- if (dentry < lower_dentry) {
- spin_lock(&dentry->d_lock);
- spin_lock_nested(&lower_dentry->d_lock, DENTRY_D_LOCK_NESTED);
- } else {
- spin_lock(&lower_dentry->d_lock);
- spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
- }
- if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) {
- err = 0;
- }
- if (dentry < lower_dentry) {
- spin_unlock(&lower_dentry->d_lock);
- spin_unlock(&dentry->d_lock);
- } else {
- spin_unlock(&dentry->d_lock);
- spin_unlock(&lower_dentry->d_lock);
- }
- if (!err)
- goto out;
- /* If our top's inode is gone, we may be out of date */
- inode = igrab(dentry->d_inode);
- if (inode) {
- data = top_data_get(SDCARDFS_I(inode));
- if (!data || data->abandoned) {
- err = 0;
- }
- if (data)
- data_put(data);
- iput(inode);
- }
- out:
- dput(parent_dentry);
- dput(lower_cur_parent_dentry);
- sdcardfs_put_lower_path(parent_dentry, &parent_lower_path);
- sdcardfs_put_real_lower(dentry, &lower_path);
- return err;
- }
- /* 1 = delete, 0 = cache */
- static int sdcardfs_d_delete(const struct dentry *d)
- {
- return SDCARDFS_SB(d->d_sb)->options.nocache ? 1 : 0;
- }
- static void sdcardfs_d_release(struct dentry *dentry)
- {
- if (!dentry || !dentry->d_fsdata)
- return;
- /* release and reset the lower paths */
- if (has_graft_path(dentry))
- sdcardfs_put_reset_orig_path(dentry);
- sdcardfs_put_reset_lower_path(dentry);
- free_dentry_private_data(dentry);
- }
- static int sdcardfs_hash_ci(const struct dentry *dentry,
- const struct inode *inode, struct qstr *qstr)
- {
- /*
- * This function is copy of vfat_hashi.
- * FIXME Should we support national language?
- * Refer to vfat_hashi()
- * struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
- */
- const unsigned char *name;
- unsigned int len;
- unsigned long hash;
- name = qstr->name;
- len = qstr->len;
- hash = init_name_hash();
- while (len--)
- hash = partial_name_hash(tolower(*name++), hash);
- qstr->hash = end_name_hash(hash);
- return 0;
- }
- /*
- * Case insensitive compare of two vfat names.
- */
- static int sdcardfs_cmp_ci(const struct dentry *parent,
- const struct inode *pinode,
- const struct dentry *dentry, const struct inode *inode,
- unsigned int len, const char *str, const struct qstr *name)
- {
- /* FIXME Should we support national language? */
- if (name->len == len) {
- if (str_n_case_eq(name->name, str, len))
- return 0;
- }
- return 1;
- }
- static void sdcardfs_canonical_path(const struct path *path,
- struct path *actual_path)
- {
- sdcardfs_get_real_lower(path->dentry, actual_path);
- }
- const struct dentry_operations sdcardfs_ci_dops = {
- .d_revalidate = sdcardfs_d_revalidate,
- .d_delete = sdcardfs_d_delete,
- .d_release = sdcardfs_d_release,
- .d_hash = sdcardfs_hash_ci,
- .d_compare = sdcardfs_cmp_ci,
- .d_canonical_path = sdcardfs_canonical_path,
- };
|