• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * fs/sdcardfs/lookup.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/delay.h"
23 
24 /* The dentry cache is just so we have properly sized dentries */
25 static struct kmem_cache *sdcardfs_dentry_cachep;
26 
sdcardfs_init_dentry_cache(void)27 int sdcardfs_init_dentry_cache(void)
28 {
29 	sdcardfs_dentry_cachep =
30 		kmem_cache_create("sdcardfs_dentry",
31 				  sizeof(struct sdcardfs_dentry_info),
32 				  0, SLAB_RECLAIM_ACCOUNT, NULL);
33 
34 	return sdcardfs_dentry_cachep ? 0 : -ENOMEM;
35 }
36 
sdcardfs_destroy_dentry_cache(void)37 void sdcardfs_destroy_dentry_cache(void)
38 {
39 	kmem_cache_destroy(sdcardfs_dentry_cachep);
40 }
41 
free_dentry_private_data(struct dentry * dentry)42 void free_dentry_private_data(struct dentry *dentry)
43 {
44 	if (!dentry || !dentry->d_fsdata)
45 		return;
46 	kmem_cache_free(sdcardfs_dentry_cachep, dentry->d_fsdata);
47 	dentry->d_fsdata = NULL;
48 }
49 
50 /* allocate new dentry private data */
new_dentry_private_data(struct dentry * dentry)51 int new_dentry_private_data(struct dentry *dentry)
52 {
53 	struct sdcardfs_dentry_info *info = SDCARDFS_D(dentry);
54 
55 	/* use zalloc to init dentry_info.lower_path */
56 	info = kmem_cache_zalloc(sdcardfs_dentry_cachep, GFP_ATOMIC);
57 	if (!info)
58 		return -ENOMEM;
59 
60 	spin_lock_init(&info->lock);
61 	dentry->d_fsdata = info;
62 
63 	return 0;
64 }
65 
66 struct inode_data {
67 	struct inode *lower_inode;
68 	userid_t id;
69 };
70 
sdcardfs_inode_test(struct inode * inode,void * candidate_data)71 static int sdcardfs_inode_test(struct inode *inode, void *candidate_data/*void *candidate_lower_inode*/)
72 {
73 	struct inode *current_lower_inode = sdcardfs_lower_inode(inode);
74 	userid_t current_userid = SDCARDFS_I(inode)->data->userid;
75 
76 	if (current_lower_inode == ((struct inode_data *)candidate_data)->lower_inode &&
77 			current_userid == ((struct inode_data *)candidate_data)->id)
78 		return 1; /* found a match */
79 	else
80 		return 0; /* no match */
81 }
82 
sdcardfs_inode_set(struct inode * inode,void * lower_inode)83 static int sdcardfs_inode_set(struct inode *inode, void *lower_inode)
84 {
85 	/* we do actual inode initialization in sdcardfs_iget */
86 	return 0;
87 }
88 
sdcardfs_iget(struct super_block * sb,struct inode * lower_inode,userid_t id)89 struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, userid_t id)
90 {
91 	struct sdcardfs_inode_info *info;
92 	struct inode_data data;
93 	struct inode *inode; /* the new inode to return */
94 
95 	if (!igrab(lower_inode))
96 		return ERR_PTR(-ESTALE);
97 
98 	data.id = id;
99 	data.lower_inode = lower_inode;
100 	inode = iget5_locked(sb, /* our superblock */
101 			     /*
102 			      * hashval: we use inode number, but we can
103 			      * also use "(unsigned long)lower_inode"
104 			      * instead.
105 			      */
106 			     lower_inode->i_ino, /* hashval */
107 			     sdcardfs_inode_test, /* inode comparison function */
108 			     sdcardfs_inode_set, /* inode init function */
109 			     &data); /* data passed to test+set fxns */
110 	if (!inode) {
111 		iput(lower_inode);
112 		return ERR_PTR(-ENOMEM);
113 	}
114 	/* if found a cached inode, then just return it (after iput) */
115 	if (!(inode->i_state & I_NEW)) {
116 		iput(lower_inode);
117 		return inode;
118 	}
119 
120 	/* initialize new inode */
121 	info = SDCARDFS_I(inode);
122 
123 	inode->i_ino = lower_inode->i_ino;
124 	sdcardfs_set_lower_inode(inode, lower_inode);
125 
126 	inode->i_version++;
127 
128 	/* use different set of inode ops for symlinks & directories */
129 	if (S_ISDIR(lower_inode->i_mode))
130 		inode->i_op = &sdcardfs_dir_iops;
131 	else if (S_ISLNK(lower_inode->i_mode))
132 		inode->i_op = &sdcardfs_symlink_iops;
133 	else
134 		inode->i_op = &sdcardfs_main_iops;
135 
136 	/* use different set of file ops for directories */
137 	if (S_ISDIR(lower_inode->i_mode))
138 		inode->i_fop = &sdcardfs_dir_fops;
139 	else
140 		inode->i_fop = &sdcardfs_main_fops;
141 
142 	inode->i_mapping->a_ops = &sdcardfs_aops;
143 
144 	inode->i_atime.tv_sec = 0;
145 	inode->i_atime.tv_nsec = 0;
146 	inode->i_mtime.tv_sec = 0;
147 	inode->i_mtime.tv_nsec = 0;
148 	inode->i_ctime.tv_sec = 0;
149 	inode->i_ctime.tv_nsec = 0;
150 
151 	/* properly initialize special inodes */
152 	if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) ||
153 	    S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode))
154 		init_special_inode(inode, lower_inode->i_mode,
155 				   lower_inode->i_rdev);
156 
157 	/* all well, copy inode attributes */
158 	sdcardfs_copy_and_fix_attrs(inode, lower_inode);
159 	fsstack_copy_inode_size(inode, lower_inode);
160 
161 	unlock_new_inode(inode);
162 	return inode;
163 }
164 
165 /*
166  * Helper interpose routine, called directly by ->lookup to handle
167  * spliced dentries.
168  */
__sdcardfs_interpose(struct dentry * dentry,struct super_block * sb,struct path * lower_path,userid_t id)169 static struct dentry *__sdcardfs_interpose(struct dentry *dentry,
170 					 struct super_block *sb,
171 					 struct path *lower_path,
172 					 userid_t id)
173 {
174 	struct inode *inode;
175 	struct inode *lower_inode;
176 	struct super_block *lower_sb;
177 	struct dentry *ret_dentry;
178 
179 	lower_inode = lower_path->dentry->d_inode;
180 	lower_sb = sdcardfs_lower_super(sb);
181 
182 	/* check that the lower file system didn't cross a mount point */
183 	if (lower_inode->i_sb != lower_sb) {
184 		ret_dentry = ERR_PTR(-EXDEV);
185 		goto out;
186 	}
187 
188 	/*
189 	 * We allocate our new inode below by calling sdcardfs_iget,
190 	 * which will initialize some of the new inode's fields
191 	 */
192 
193 	/* inherit lower inode number for sdcardfs's inode */
194 	inode = sdcardfs_iget(sb, lower_inode, id);
195 	if (IS_ERR(inode)) {
196 		ret_dentry = ERR_CAST(inode);
197 		goto out;
198 	}
199 
200 	ret_dentry = d_splice_alias(inode, dentry);
201 	dentry = ret_dentry ?: dentry;
202 	if (!IS_ERR(dentry))
203 		update_derived_permission_lock(dentry);
204 out:
205 	return ret_dentry;
206 }
207 
208 /*
209  * Connect an sdcardfs inode dentry/inode with several lower ones.  This is
210  * the classic stackable file system "vnode interposition" action.
211  *
212  * @dentry: sdcardfs's dentry which interposes on lower one
213  * @sb: sdcardfs's super_block
214  * @lower_path: the lower path (caller does path_get/put)
215  */
sdcardfs_interpose(struct dentry * dentry,struct super_block * sb,struct path * lower_path,userid_t id)216 int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb,
217 		     struct path *lower_path, userid_t id)
218 {
219 	struct dentry *ret_dentry;
220 
221 	ret_dentry = __sdcardfs_interpose(dentry, sb, lower_path, id);
222 	return PTR_ERR(ret_dentry);
223 }
224 
225 struct sdcardfs_name_data {
226 	struct dir_context ctx;
227 	const struct qstr *to_find;
228 	char *name;
229 	bool found;
230 };
231 
sdcardfs_name_match(void * __buf,const char * name,int namelen,loff_t offset,u64 ino,unsigned int d_type)232 static int sdcardfs_name_match(void *__buf, const char *name, int namelen,
233 		loff_t offset, u64 ino, unsigned int d_type)
234 {
235 	struct sdcardfs_name_data *buf = (struct sdcardfs_name_data *) __buf;
236 	struct qstr candidate = QSTR_INIT(name, namelen);
237 
238 	if (qstr_case_eq(buf->to_find, &candidate)) {
239 		memcpy(buf->name, name, namelen);
240 		buf->name[namelen] = 0;
241 		buf->found = true;
242 		return 1;
243 	}
244 	return 0;
245 }
246 
247 /*
248  * Main driver function for sdcardfs's lookup.
249  *
250  * Returns: NULL (ok), ERR_PTR if an error occurred.
251  * Fills in lower_parent_path with <dentry,mnt> on success.
252  */
__sdcardfs_lookup(struct dentry * dentry,unsigned int flags,struct path * lower_parent_path,userid_t id)253 static struct dentry *__sdcardfs_lookup(struct dentry *dentry,
254 		unsigned int flags, struct path *lower_parent_path, userid_t id)
255 {
256 	int err = 0;
257 	struct vfsmount *lower_dir_mnt;
258 	struct dentry *lower_dir_dentry = NULL;
259 	struct dentry *lower_dentry;
260 	const struct qstr *name;
261 	struct path lower_path;
262 	struct qstr dname;
263 	struct dentry *ret_dentry = NULL;
264 	struct sdcardfs_sb_info *sbi;
265 
266 	sbi = SDCARDFS_SB(dentry->d_sb);
267 	/* must initialize dentry operations */
268 	d_set_d_op(dentry, &sdcardfs_ci_dops);
269 
270 	if (IS_ROOT(dentry))
271 		goto out;
272 
273 	name = &dentry->d_name;
274 
275 	/* now start the actual lookup procedure */
276 	lower_dir_dentry = lower_parent_path->dentry;
277 	lower_dir_mnt = lower_parent_path->mnt;
278 
279 	/* Use vfs_path_lookup to check if the dentry exists or not */
280 	err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name->name, 0,
281 				&lower_path);
282 	/* check for other cases */
283 	if (err == -ENOENT) {
284 		struct file *file;
285 		const struct cred *cred = current_cred();
286 
287 		struct sdcardfs_name_data buffer = {
288 			.ctx.actor = sdcardfs_name_match,
289 			.to_find = name,
290 			.name = __getname(),
291 			.found = false,
292 		};
293 
294 		if (!buffer.name) {
295 			err = -ENOMEM;
296 			goto out;
297 		}
298 		file = dentry_open(lower_parent_path, O_RDONLY, cred);
299 		if (IS_ERR(file)) {
300 			err = PTR_ERR(file);
301 			goto put_name;
302 		}
303 		err = iterate_dir(file, &buffer.ctx);
304 		fput(file);
305 		if (err)
306 			goto put_name;
307 
308 		if (buffer.found)
309 			err = vfs_path_lookup(lower_dir_dentry,
310 						lower_dir_mnt,
311 						buffer.name, 0,
312 						&lower_path);
313 		else
314 			err = -ENOENT;
315 put_name:
316 		__putname(buffer.name);
317 	}
318 
319 	/* no error: handle positive dentries */
320 	if (!err) {
321 		/* check if the dentry is an obb dentry
322 		 * if true, the lower_inode must be replaced with
323 		 * the inode of the graft path
324 		 */
325 
326 		if (need_graft_path(dentry)) {
327 
328 			/* setup_obb_dentry()
329 			 * The lower_path will be stored to the dentry's orig_path
330 			 * and the base obbpath will be copyed to the lower_path variable.
331 			 * if an error returned, there's no change in the lower_path
332 			 * returns: -ERRNO if error (0: no error)
333 			 */
334 			err = setup_obb_dentry(dentry, &lower_path);
335 
336 			if (err) {
337 				/* if the sbi->obbpath is not available, we can optionally
338 				 * setup the lower_path with its orig_path.
339 				 * but, the current implementation just returns an error
340 				 * because the sdcard daemon also regards this case as
341 				 * a lookup fail.
342 				 */
343 				pr_info("sdcardfs: base obbpath is not available\n");
344 				sdcardfs_put_reset_orig_path(dentry);
345 				goto out;
346 			}
347 		}
348 
349 		sdcardfs_set_lower_path(dentry, &lower_path);
350 		ret_dentry =
351 			__sdcardfs_interpose(dentry, dentry->d_sb, &lower_path, id);
352 		if (IS_ERR(ret_dentry)) {
353 			err = PTR_ERR(ret_dentry);
354 			 /* path_put underlying path on error */
355 			sdcardfs_put_reset_lower_path(dentry);
356 		}
357 		goto out;
358 	}
359 
360 	/*
361 	 * We don't consider ENOENT an error, and we want to return a
362 	 * negative dentry.
363 	 */
364 	if (err && err != -ENOENT)
365 		goto out;
366 
367 	/* instatiate a new negative dentry */
368 	dname.name = name->name;
369 	dname.len = name->len;
370 
371 	/* See if the low-level filesystem might want
372 	 * to use its own hash
373 	 */
374 	lower_dentry = d_hash_and_lookup(lower_dir_dentry, &dname);
375 	if (IS_ERR(lower_dentry))
376 		return lower_dentry;
377 	if (!lower_dentry) {
378 		/* We called vfs_path_lookup earlier, and did not get a negative
379 		 * dentry then. Don't confuse the lower filesystem by forcing
380 		 * one on it now...
381 		 */
382 		err = -ENOENT;
383 		goto out;
384 	}
385 
386 	lower_path.dentry = lower_dentry;
387 	lower_path.mnt = mntget(lower_dir_mnt);
388 	sdcardfs_set_lower_path(dentry, &lower_path);
389 
390 	/*
391 	 * If the intent is to create a file, then don't return an error, so
392 	 * the VFS will continue the process of making this negative dentry
393 	 * into a positive one.
394 	 */
395 	if (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET))
396 		err = 0;
397 
398 out:
399 	if (err)
400 		return ERR_PTR(err);
401 	return ret_dentry;
402 }
403 
404 /*
405  * On success:
406  * fills dentry object appropriate values and returns NULL.
407  * On fail (== error)
408  * returns error ptr
409  *
410  * @dir : Parent inode. It is locked (dir->i_mutex)
411  * @dentry : Target dentry to lookup. we should set each of fields.
412  *	     (dentry->d_name is initialized already)
413  * @nd : nameidata of parent inode
414  */
sdcardfs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)415 struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry,
416 			     unsigned int flags)
417 {
418 	struct dentry *ret = NULL, *parent;
419 	struct path lower_parent_path;
420 	int err = 0;
421 	const struct cred *saved_cred = NULL;
422 
423 	parent = dget_parent(dentry);
424 
425 	if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) {
426 		ret = ERR_PTR(-EACCES);
427 		goto out_err;
428 	}
429 
430 	/* save current_cred and override it */
431 	OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
432 
433 	sdcardfs_get_lower_path(parent, &lower_parent_path);
434 
435 	/* allocate dentry private data.  We free it in ->d_release */
436 	err = new_dentry_private_data(dentry);
437 	if (err) {
438 		ret = ERR_PTR(err);
439 		goto out;
440 	}
441 
442 	ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path,
443 				SDCARDFS_I(dir)->data->userid);
444 	if (IS_ERR(ret))
445 		goto out;
446 	if (ret)
447 		dentry = ret;
448 	if (dentry->d_inode) {
449 		fsstack_copy_attr_times(dentry->d_inode,
450 					sdcardfs_lower_inode(dentry->d_inode));
451 		/* get derived permission */
452 		get_derived_permission(parent, dentry);
453 		fixup_tmp_permissions(dentry->d_inode);
454 		fixup_lower_ownership(dentry, dentry->d_name.name);
455 	}
456 	/* update parent directory's atime */
457 	fsstack_copy_attr_atime(parent->d_inode,
458 				sdcardfs_lower_inode(parent->d_inode));
459 
460 out:
461 	sdcardfs_put_lower_path(parent, &lower_parent_path);
462 	REVERT_CRED(saved_cred);
463 out_err:
464 	dput(parent);
465 	return ret;
466 }
467