mirror of https://github.com/OpenIPC/firmware.git
194 lines
5.0 KiB
Diff
194 lines
5.0 KiB
Diff
diff -drupN a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c
|
|
--- a/fs/sdcardfs/dentry.c 1970-01-01 03:00:00.000000000 +0300
|
|
+++ b/fs/sdcardfs/dentry.c 2022-06-12 05:28:14.000000000 +0300
|
|
@@ -0,0 +1,189 @@
|
|
+/*
|
|
+ * 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, unsigned int flags)
|
|
+{
|
|
+ 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 (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)) {
|
|
+ err = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
|
|
+ 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(d_inode(dentry));
|
|
+ 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;
|
|
+}
|
|
+
|
|
+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,
|
|
+ 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(dentry);
|
|
+ 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 *dentry,
|
|
+ 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_release = sdcardfs_d_release,
|
|
+ .d_hash = sdcardfs_hash_ci,
|
|
+ .d_compare = sdcardfs_cmp_ci,
|
|
+ .d_canonical_path = sdcardfs_canonical_path,
|
|
+};
|
|
+
|