blob: cb573f1efbfc41e28c73d272fd32b277de2ce882 [file] [log] [blame]
Daniel Campello874b3442015-07-20 16:23:50 -07001/*
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 */
29static 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 return 0;
55 }
56
57 parent_dentry = dget_parent(dentry);
58 sdcardfs_get_lower_path(parent_dentry, &parent_lower_path);
59 sdcardfs_get_real_lower(dentry, &lower_path);
60 parent_lower_dentry = parent_lower_path.dentry;
61 lower_dentry = lower_path.dentry;
62 lower_cur_parent_dentry = dget_parent(lower_dentry);
63
64 if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) {
65 err = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
66 if (err == 0) {
67 goto out;
68 }
69 }
70
71 spin_lock(&lower_dentry->d_lock);
72 if (d_unhashed(lower_dentry)) {
73 spin_unlock(&lower_dentry->d_lock);
74 err = 0;
75 goto out;
76 }
77 spin_unlock(&lower_dentry->d_lock);
78
79 if (parent_lower_dentry != lower_cur_parent_dentry) {
80 err = 0;
81 goto out;
82 }
83
84 if (dentry < lower_dentry) {
85 spin_lock(&dentry->d_lock);
86 spin_lock_nested(&lower_dentry->d_lock, DENTRY_D_LOCK_NESTED);
87 } else {
88 spin_lock(&lower_dentry->d_lock);
89 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
90 }
91
92 if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) {
93 err = 0;
94 }
95
96 if (dentry < lower_dentry) {
97 spin_unlock(&lower_dentry->d_lock);
98 spin_unlock(&dentry->d_lock);
99 } else {
100 spin_unlock(&dentry->d_lock);
101 spin_unlock(&lower_dentry->d_lock);
102 }
103 if (!err)
104 goto out;
105
106 /* If our top's inode is gone, we may be out of date */
107 inode = igrab(d_inode(dentry));
108 if (inode) {
109 data = top_data_get(SDCARDFS_I(inode));
110 if (!data || data->abandoned) {
111 err = 0;
112 }
113 if (data)
114 data_put(data);
115 iput(inode);
116 }
117
118out:
119 dput(parent_dentry);
120 dput(lower_cur_parent_dentry);
121 sdcardfs_put_lower_path(parent_dentry, &parent_lower_path);
122 sdcardfs_put_real_lower(dentry, &lower_path);
123 return err;
124}
125
126/* 1 = delete, 0 = cache */
127static int sdcardfs_d_delete(const struct dentry *d)
128{
129 return SDCARDFS_SB(d->d_sb)->options.nocache ? 1 : 0;
130}
131
132static void sdcardfs_d_release(struct dentry *dentry)
133{
134 if (!dentry || !dentry->d_fsdata)
135 return;
136 /* release and reset the lower paths */
137 if (has_graft_path(dentry))
138 sdcardfs_put_reset_orig_path(dentry);
139 sdcardfs_put_reset_lower_path(dentry);
140 free_dentry_private_data(dentry);
141}
142
143static int sdcardfs_hash_ci(const struct dentry *dentry,
144 struct qstr *qstr)
145{
146 /*
147 * This function is copy of vfat_hashi.
148 * FIXME Should we support national language?
149 * Refer to vfat_hashi()
150 * struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
151 */
152 const unsigned char *name;
153 unsigned int len;
154 unsigned long hash;
155
156 name = qstr->name;
157 len = qstr->len;
158
159 hash = init_name_hash(dentry);
160 while (len--)
161 hash = partial_name_hash(tolower(*name++), hash);
162 qstr->hash = end_name_hash(hash);
163
164 return 0;
165}
166
167/*
168 * Case insensitive compare of two vfat names.
169 */
170static int sdcardfs_cmp_ci(const struct dentry *dentry,
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
182static 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
188const struct dentry_operations sdcardfs_ci_dops = {
189 .d_revalidate = sdcardfs_d_revalidate,
190 .d_delete = sdcardfs_d_delete,
191 .d_release = sdcardfs_d_release,
192 .d_hash = sdcardfs_hash_ci,
193 .d_compare = sdcardfs_cmp_ci,
194 .d_canonical_path = sdcardfs_canonical_path,
195};
196