• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * fs/sdcardfs/dentry.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 "linux/ctype.h"
23 
24 /*
25  * returns: -ERRNO if error (returned to user)
26  *          0: tell VFS to invalidate dentry
27  *          1: dentry is valid
28  */
sdcardfs_d_revalidate(struct dentry * dentry,unsigned int flags)29 static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags)
30 {
31 	int err = 1;
32 	struct path parent_lower_path, lower_path;
33 	struct dentry *parent_dentry = NULL;
34 	struct dentry *parent_lower_dentry = NULL;
35 	struct dentry *lower_cur_parent_dentry = NULL;
36 	struct dentry *lower_dentry = NULL;
37 	struct inode *inode;
38 	struct sdcardfs_inode_data *data;
39 
40 	if (flags & LOOKUP_RCU)
41 		return -ECHILD;
42 
43 	spin_lock(&dentry->d_lock);
44 	if (IS_ROOT(dentry)) {
45 		spin_unlock(&dentry->d_lock);
46 		return 1;
47 	}
48 	spin_unlock(&dentry->d_lock);
49 
50 	/* check uninitialized obb_dentry and
51 	 * whether the base obbpath has been changed or not
52 	 */
53 	if (is_obbpath_invalid(dentry)) {
54 		d_drop(dentry);
55 		return 0;
56 	}
57 
58 	parent_dentry = dget_parent(dentry);
59 	sdcardfs_get_lower_path(parent_dentry, &parent_lower_path);
60 	sdcardfs_get_real_lower(dentry, &lower_path);
61 	parent_lower_dentry = parent_lower_path.dentry;
62 	lower_dentry = lower_path.dentry;
63 	lower_cur_parent_dentry = dget_parent(lower_dentry);
64 
65 	if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) {
66 		err = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
67 		if (err == 0) {
68 			d_drop(dentry);
69 			goto out;
70 		}
71 	}
72 
73 	spin_lock(&lower_dentry->d_lock);
74 	if (d_unhashed(lower_dentry)) {
75 		spin_unlock(&lower_dentry->d_lock);
76 		d_drop(dentry);
77 		err = 0;
78 		goto out;
79 	}
80 	spin_unlock(&lower_dentry->d_lock);
81 
82 	if (parent_lower_dentry != lower_cur_parent_dentry) {
83 		d_drop(dentry);
84 		err = 0;
85 		goto out;
86 	}
87 
88 	if (dentry < lower_dentry) {
89 		spin_lock(&dentry->d_lock);
90 		spin_lock_nested(&lower_dentry->d_lock, DENTRY_D_LOCK_NESTED);
91 	} else {
92 		spin_lock(&lower_dentry->d_lock);
93 		spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
94 	}
95 
96 	if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) {
97 		__d_drop(dentry);
98 		err = 0;
99 	}
100 
101 	if (dentry < lower_dentry) {
102 		spin_unlock(&lower_dentry->d_lock);
103 		spin_unlock(&dentry->d_lock);
104 	} else {
105 		spin_unlock(&dentry->d_lock);
106 		spin_unlock(&lower_dentry->d_lock);
107 	}
108 	if (!err)
109 		goto out;
110 
111 	/* If our top's inode is gone, we may be out of date */
112 	inode = igrab(dentry->d_inode);
113 	if (inode) {
114 		data = top_data_get(SDCARDFS_I(inode));
115 		if (!data || data->abandoned) {
116 			d_drop(dentry);
117 			err = 0;
118 		}
119 		if (data)
120 			data_put(data);
121 		iput(inode);
122 	}
123 
124 out:
125 	dput(parent_dentry);
126 	dput(lower_cur_parent_dentry);
127 	sdcardfs_put_lower_path(parent_dentry, &parent_lower_path);
128 	sdcardfs_put_real_lower(dentry, &lower_path);
129 	return err;
130 }
131 
sdcardfs_d_release(struct dentry * dentry)132 static void sdcardfs_d_release(struct dentry *dentry)
133 {
134 	/* release and reset the lower paths */
135 	if (has_graft_path(dentry))
136 		sdcardfs_put_reset_orig_path(dentry);
137 	sdcardfs_put_reset_lower_path(dentry);
138 	free_dentry_private_data(dentry);
139 }
140 
sdcardfs_hash_ci(const struct dentry * dentry,const struct inode * inode,struct qstr * qstr)141 static int sdcardfs_hash_ci(const struct dentry *dentry,
142 				const struct inode *inode, struct qstr *qstr)
143 {
144 	/*
145 	 * This function is copy of vfat_hashi.
146 	 * FIXME Should we support national language?
147 	 *       Refer to vfat_hashi()
148 	 * struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
149 	 */
150 	const unsigned char *name;
151 	unsigned int len;
152 	unsigned long hash;
153 
154 	name = qstr->name;
155 	len = qstr->len;
156 
157 	hash = init_name_hash();
158 	while (len--)
159 		hash = partial_name_hash(tolower(*name++), hash);
160 	qstr->hash = end_name_hash(hash);
161 
162 	return 0;
163 }
164 
165 /*
166  * Case insensitive compare of two vfat names.
167  */
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)168 static int sdcardfs_cmp_ci(const struct dentry *parent,
169 		const struct inode *pinode,
170 		const struct dentry *dentry, const struct inode *inode,
171 		unsigned int len, const char *str, const struct qstr *name)
172 {
173 	/* FIXME Should we support national language? */
174 
175 	if (name->len == len) {
176 		if (str_n_case_eq(name->name, str, len))
177 			return 0;
178 	}
179 	return 1;
180 }
181 
sdcardfs_canonical_path(const struct path * path,struct path * actual_path)182 static void sdcardfs_canonical_path(const struct path *path,
183 				struct path *actual_path)
184 {
185 	sdcardfs_get_real_lower(path->dentry, actual_path);
186 }
187 
188 const struct dentry_operations sdcardfs_ci_dops = {
189 	.d_revalidate	= sdcardfs_d_revalidate,
190 	.d_release	= sdcardfs_d_release,
191 	.d_hash	= sdcardfs_hash_ci,
192 	.d_compare	= sdcardfs_cmp_ci,
193 	.d_canonical_path = sdcardfs_canonical_path,
194 };
195 
196