1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * fs/sharefs/lookup.c 4 * 5 * Copyright (c) 1998-2022 Erez Zadok 6 * Copyright (c) 2009 Shrikar Archak 7 * Copyright (c) 2003-2022 Stony Brook University 8 * Copyright (c) 2003-2022 The Research Foundation of SUNY 9 * Copyright (c) 2023 Huawei Device Co., Ltd. 10 */ 11 12#include "sharefs.h" 13#include "authentication.h" 14 15/* The dentry cache is just so we have properly sized dentries */ 16static struct kmem_cache *sharefs_dentry_cachep; 17 18int sharefs_init_dentry_cache(void) 19{ 20 sharefs_dentry_cachep = 21 kmem_cache_create("sharefs_dentry", 22 sizeof(struct sharefs_dentry_info), 23 0, SLAB_RECLAIM_ACCOUNT, NULL); 24 25 return sharefs_dentry_cachep ? 0 : -ENOMEM; 26} 27 28void sharefs_destroy_dentry_cache(void) 29{ 30 if (sharefs_dentry_cachep) 31 kmem_cache_destroy(sharefs_dentry_cachep); 32} 33 34void free_dentry_private_data(struct dentry *dentry) 35{ 36 if (!dentry || !dentry->d_fsdata) 37 return; 38 kmem_cache_free(sharefs_dentry_cachep, dentry->d_fsdata); 39 dentry->d_fsdata = NULL; 40} 41 42/* allocate new dentry private data */ 43int new_dentry_private_data(struct dentry *dentry) 44{ 45 struct sharefs_dentry_info *info = SHAREFS_D(dentry); 46 47 /* use zalloc to init dentry_info.lower_path */ 48 info = kmem_cache_zalloc(sharefs_dentry_cachep, GFP_ATOMIC); 49 if (!info) 50 return -ENOMEM; 51 52 spin_lock_init(&info->lock); 53 dentry->d_fsdata = info; 54 55 return 0; 56} 57 58static int sharefs_inode_test(struct inode *inode, void *candidate_lower_inode) 59{ 60 struct inode *current_lower_inode = sharefs_lower_inode(inode); 61 if (current_lower_inode == (struct inode *)candidate_lower_inode) 62 return 1; /* found a match */ 63 else 64 return 0; /* no match */ 65} 66 67static int sharefs_inode_set(struct inode *inode, void *lower_inode) 68{ 69 /* we do actual inode initialization in sharefs_iget */ 70 return 0; 71} 72 73struct inode *sharefs_iget(struct super_block *sb, struct inode *lower_inode) 74{ 75 struct inode *inode; /* the new inode to return */ 76 77 if (!igrab(lower_inode)) 78 return ERR_PTR(-ESTALE); 79 inode = iget5_locked(sb, /* our superblock */ 80 /* 81 * hashval: we use inode number, but we can 82 * also use "(unsigned long)lower_inode" 83 * instead. 84 */ 85 lower_inode->i_ino, /* hashval */ 86 sharefs_inode_test, /* inode comparison function */ 87 sharefs_inode_set, /* inode init function */ 88 lower_inode); /* data passed to test+set fxns */ 89 if (!inode) { 90 iput(lower_inode); 91 return ERR_PTR(-ENOMEM); 92 } 93 94 if (lower_inode->i_nlink == 0) { 95 iput(lower_inode); 96 iput(inode); 97 return ERR_PTR(-ENOENT); 98 } 99 100 /* if found a cached inode, then just return it (after iput) */ 101 if (!(inode->i_state & I_NEW)) { 102 iput(lower_inode); 103 return inode; 104 } 105 106 /* initialize new inode */ 107 inode->i_ino = lower_inode->i_ino; 108 sharefs_set_lower_inode(inode, lower_inode); 109 110 atomic64_inc(&inode->i_version); 111 112 /* use different set of inode ops for symlinks & directories */ 113 if (S_ISDIR(lower_inode->i_mode)) 114 inode->i_op = &sharefs_dir_iops; 115 else if (S_ISLNK(lower_inode->i_mode)) 116 inode->i_op = &sharefs_symlink_iops; 117 else 118 inode->i_op = &sharefs_main_iops; 119 120 /* use different set of file ops for directories */ 121 if (S_ISDIR(lower_inode->i_mode)) 122 inode->i_fop = &sharefs_dir_fops; 123 else 124 inode->i_fop = &sharefs_main_fops; 125 126 inode->i_atime.tv_sec = 0; 127 inode->i_atime.tv_nsec = 0; 128 inode->i_mtime.tv_sec = 0; 129 inode->i_mtime.tv_nsec = 0; 130 inode->i_ctime.tv_sec = 0; 131 inode->i_ctime.tv_nsec = 0; 132 133 /* properly initialize special inodes */ 134 if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || 135 S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) 136 init_special_inode(inode, lower_inode->i_mode, 137 lower_inode->i_rdev); 138 139 /* all well, copy inode attributes */ 140 fsstack_copy_attr_all(inode, lower_inode); 141 fsstack_copy_inode_size(inode, lower_inode); 142 143 unlock_new_inode(inode); 144 return inode; 145} 146 147/* 148 * Helper interpose routine, called directly by ->lookup to handle 149 * spliced dentries. 150 */ 151static struct dentry *__sharefs_interpose(struct dentry *dentry, 152 struct super_block *sb, 153 struct path *lower_path) 154{ 155 struct inode *inode; 156 struct inode *lower_inode = d_inode(lower_path->dentry); 157 struct dentry *ret_dentry; 158 159 /* 160 * We allocate our new inode below by calling sharefs_iget, 161 * which will initialize some of the new inode's fields 162 */ 163 164 /* inherit lower inode number for sharefs's inode */ 165 inode = sharefs_iget(sb, lower_inode); 166 if (IS_ERR(inode)) { 167 ret_dentry = ERR_PTR(PTR_ERR(inode)); 168 goto out; 169 } 170 171 ret_dentry = d_splice_alias(inode, dentry); 172 173out: 174 return ret_dentry; 175} 176 177/* 178 * Connect a sharefs inode dentry/inode with several lower ones. This is 179 * the classic stackable file system "vnode interposition" action. 180 * 181 * @dentry: sharefs's dentry which interposes on lower one 182 * @sb: sharefs's super_block 183 * @lower_path: the lower path (caller does path_get/put) 184 */ 185int sharefs_interpose(struct dentry *dentry, struct super_block *sb, 186 struct path *lower_path) 187{ 188 struct dentry *ret_dentry; 189 190 ret_dentry = __sharefs_interpose(dentry, sb, lower_path); 191 return PTR_ERR(ret_dentry); 192} 193 194/* 195 * Main driver function for sharefs's lookup. 196 * 197 * Returns: NULL (ok), ERR_PTR if an error occurred. 198 * Fills in lower_parent_path with <dentry,mnt> on success. 199 */ 200static struct dentry *__sharefs_lookup(struct dentry *dentry, 201 unsigned int flags, 202 struct path *lower_parent_path) 203{ 204 int err = 0; 205 struct vfsmount *lower_dir_mnt; 206 struct dentry *lower_dir_dentry = NULL; 207 struct dentry *lower_dentry; 208 const char *name; 209 struct path lower_path; 210 struct qstr this; 211 struct dentry *ret_dentry = NULL; 212 213 /* must initialize dentry operations */ 214 d_set_d_op(dentry, &sharefs_dops); 215 216 if (IS_ROOT(dentry)) 217 goto out; 218 219 name = dentry->d_name.name; 220 221 /* now start the actual lookup procedure */ 222 lower_dir_dentry = lower_parent_path->dentry; 223 lower_dir_mnt = lower_parent_path->mnt; 224 225 /* Use vfs_path_lookup to check if the dentry exists or not */ 226 err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, 227 &lower_path); 228 /* no error: handle positive dentries */ 229 if (!err) { 230 sharefs_set_lower_path(dentry, &lower_path); 231 ret_dentry = 232 __sharefs_interpose(dentry, dentry->d_sb, &lower_path); 233 if (IS_ERR(ret_dentry)) { 234 err = PTR_ERR(ret_dentry); 235 /* path_put underlying path on error */ 236 sharefs_put_reset_lower_path(dentry); 237 } 238 goto out; 239 } 240 /* 241 * We don't consider ENOENT an error, and we want to return a 242 * negative dentry. 243 */ 244 if (err && err != -ENOENT) 245 goto out; 246 247 /* instantiate a new negative dentry */ 248 this.name = name; 249 this.len = strlen(name); 250 this.hash = full_name_hash(lower_dir_dentry, this.name, this.len); 251 lower_dentry = d_lookup(lower_dir_dentry, &this); 252 if (lower_dentry) 253 goto setup_lower; 254 255 lower_dentry = d_alloc(lower_dir_dentry, &this); 256 if (!lower_dentry) { 257 err = -ENOMEM; 258 goto out; 259 } 260 261 /* 262 * Calling ->lookup instead of d_add will give the lower fs a chance 263 * to allocate the d_fsdata field but will still instantiate and hash the 264 * lower_dentry. Without this, sharefs could not stack on top of itself. 265 */ 266 d_inode(lower_dir_dentry)->i_op->lookup(d_inode(lower_dir_dentry), 267 lower_dentry, flags); 268 269setup_lower: 270 lower_path.dentry = lower_dentry; 271 lower_path.mnt = mntget(lower_dir_mnt); 272 sharefs_set_lower_path(dentry, &lower_path); 273 274 /* 275 * If the intent is to create a file, then don't return an error, so 276 * the VFS will continue the process of making this negative dentry 277 * into a positive one. 278 */ 279 if (err == -ENOENT || (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET))) 280 err = 0; 281 282out: 283 if (err) 284 return ERR_PTR(err); 285 return ret_dentry; 286} 287 288struct dentry *sharefs_lookup(struct inode *dir, struct dentry *dentry, 289 unsigned int flags) 290{ 291 int err; 292 struct dentry *ret, *parent; 293 struct path lower_parent_path; 294#ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE 295 const struct cred *saved_cred = NULL; 296 __u16 permission; 297#endif 298 299 parent = dget_parent(dentry); 300 sharefs_get_lower_path(parent, &lower_parent_path); 301#ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE 302 saved_cred = sharefs_override_file_fsids(dir, &permission); 303 if (!saved_cred) { 304 ret = ERR_PTR(-ENOMEM); 305 goto out_err; 306 } 307#endif 308 309 /* allocate dentry private data. We free it in ->d_release */ 310 err = new_dentry_private_data(dentry); 311 if (err) { 312 ret = ERR_PTR(err); 313 goto out; 314 } 315 ret = __sharefs_lookup(dentry, flags, &lower_parent_path); 316 if (IS_ERR(ret)) { 317 sharefs_err("sharefs_lookup error!"); 318 goto out; 319 } 320 321 if (ret) 322 dentry = ret; 323 if (d_inode(dentry)) 324 fsstack_copy_attr_times(d_inode(dentry), 325 sharefs_lower_inode(d_inode(dentry))); 326 /* update parent directory's atime */ 327 fsstack_copy_attr_atime(d_inode(parent), 328 sharefs_lower_inode(d_inode(parent))); 329 fixup_perm_from_level(d_inode(parent), dentry); 330out: 331#ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE 332 sharefs_revert_fsids(saved_cred); 333out_err: 334#endif 335 sharefs_put_lower_path(parent, &lower_parent_path); 336 dput(parent); 337 return ret; 338} 339