ANDROID: sdcardfs: Check for NULL in revalidate
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / fs / sdcardfs / dentry.c
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 */
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
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
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 */
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
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