1bbb1e54dSMiklos Szeredi /* 2bbb1e54dSMiklos Szeredi * Copyright (C) 2011 Novell Inc. 3bbb1e54dSMiklos Szeredi * Copyright (C) 2016 Red Hat, Inc. 4bbb1e54dSMiklos Szeredi * 5bbb1e54dSMiklos Szeredi * This program is free software; you can redistribute it and/or modify it 6bbb1e54dSMiklos Szeredi * under the terms of the GNU General Public License version 2 as published by 7bbb1e54dSMiklos Szeredi * the Free Software Foundation. 8bbb1e54dSMiklos Szeredi */ 9bbb1e54dSMiklos Szeredi 10bbb1e54dSMiklos Szeredi #include <linux/fs.h> 11*5b825c3aSIngo Molnar #include <linux/cred.h> 12bbb1e54dSMiklos Szeredi #include <linux/namei.h> 13bbb1e54dSMiklos Szeredi #include <linux/xattr.h> 1402b69b28SMiklos Szeredi #include <linux/ratelimit.h> 15bbb1e54dSMiklos Szeredi #include "overlayfs.h" 16bbb1e54dSMiklos Szeredi #include "ovl_entry.h" 17bbb1e54dSMiklos Szeredi 18e28edc46SMiklos Szeredi struct ovl_lookup_data { 19e28edc46SMiklos Szeredi struct qstr name; 20e28edc46SMiklos Szeredi bool is_dir; 21e28edc46SMiklos Szeredi bool opaque; 22e28edc46SMiklos Szeredi bool stop; 23e28edc46SMiklos Szeredi bool last; 2402b69b28SMiklos Szeredi char *redirect; 25e28edc46SMiklos Szeredi }; 26bbb1e54dSMiklos Szeredi 2702b69b28SMiklos Szeredi static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d, 2802b69b28SMiklos Szeredi size_t prelen, const char *post) 2902b69b28SMiklos Szeredi { 3002b69b28SMiklos Szeredi int res; 3102b69b28SMiklos Szeredi char *s, *next, *buf = NULL; 3202b69b28SMiklos Szeredi 3302b69b28SMiklos Szeredi res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0); 3402b69b28SMiklos Szeredi if (res < 0) { 3502b69b28SMiklos Szeredi if (res == -ENODATA || res == -EOPNOTSUPP) 3602b69b28SMiklos Szeredi return 0; 3702b69b28SMiklos Szeredi goto fail; 3802b69b28SMiklos Szeredi } 3902b69b28SMiklos Szeredi buf = kzalloc(prelen + res + strlen(post) + 1, GFP_TEMPORARY); 4002b69b28SMiklos Szeredi if (!buf) 4102b69b28SMiklos Szeredi return -ENOMEM; 4202b69b28SMiklos Szeredi 4302b69b28SMiklos Szeredi if (res == 0) 4402b69b28SMiklos Szeredi goto invalid; 4502b69b28SMiklos Szeredi 4602b69b28SMiklos Szeredi res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, buf, res); 4702b69b28SMiklos Szeredi if (res < 0) 4802b69b28SMiklos Szeredi goto fail; 4902b69b28SMiklos Szeredi if (res == 0) 5002b69b28SMiklos Szeredi goto invalid; 5102b69b28SMiklos Szeredi if (buf[0] == '/') { 5202b69b28SMiklos Szeredi for (s = buf; *s++ == '/'; s = next) { 5302b69b28SMiklos Szeredi next = strchrnul(s, '/'); 5402b69b28SMiklos Szeredi if (s == next) 5502b69b28SMiklos Szeredi goto invalid; 5602b69b28SMiklos Szeredi } 5702b69b28SMiklos Szeredi } else { 5802b69b28SMiklos Szeredi if (strchr(buf, '/') != NULL) 5902b69b28SMiklos Szeredi goto invalid; 6002b69b28SMiklos Szeredi 6102b69b28SMiklos Szeredi memmove(buf + prelen, buf, res); 6202b69b28SMiklos Szeredi memcpy(buf, d->name.name, prelen); 6302b69b28SMiklos Szeredi } 6402b69b28SMiklos Szeredi 6502b69b28SMiklos Szeredi strcat(buf, post); 6602b69b28SMiklos Szeredi kfree(d->redirect); 6702b69b28SMiklos Szeredi d->redirect = buf; 6802b69b28SMiklos Szeredi d->name.name = d->redirect; 6902b69b28SMiklos Szeredi d->name.len = strlen(d->redirect); 7002b69b28SMiklos Szeredi 7102b69b28SMiklos Szeredi return 0; 7202b69b28SMiklos Szeredi 7302b69b28SMiklos Szeredi err_free: 7402b69b28SMiklos Szeredi kfree(buf); 7502b69b28SMiklos Szeredi return 0; 7602b69b28SMiklos Szeredi fail: 7702b69b28SMiklos Szeredi pr_warn_ratelimited("overlayfs: failed to get redirect (%i)\n", res); 7802b69b28SMiklos Szeredi goto err_free; 7902b69b28SMiklos Szeredi invalid: 8002b69b28SMiklos Szeredi pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf); 8102b69b28SMiklos Szeredi goto err_free; 8202b69b28SMiklos Szeredi } 8302b69b28SMiklos Szeredi 84bbb1e54dSMiklos Szeredi static bool ovl_is_opaquedir(struct dentry *dentry) 85bbb1e54dSMiklos Szeredi { 86bbb1e54dSMiklos Szeredi int res; 87bbb1e54dSMiklos Szeredi char val; 88bbb1e54dSMiklos Szeredi 89bbb1e54dSMiklos Szeredi if (!d_is_dir(dentry)) 90bbb1e54dSMiklos Szeredi return false; 91bbb1e54dSMiklos Szeredi 92bbb1e54dSMiklos Szeredi res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1); 93bbb1e54dSMiklos Szeredi if (res == 1 && val == 'y') 94bbb1e54dSMiklos Szeredi return true; 95bbb1e54dSMiklos Szeredi 96bbb1e54dSMiklos Szeredi return false; 97bbb1e54dSMiklos Szeredi } 98bbb1e54dSMiklos Szeredi 99e28edc46SMiklos Szeredi static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, 100e28edc46SMiklos Szeredi const char *name, unsigned int namelen, 10102b69b28SMiklos Szeredi size_t prelen, const char *post, 102e28edc46SMiklos Szeredi struct dentry **ret) 103e28edc46SMiklos Szeredi { 104e28edc46SMiklos Szeredi struct dentry *this; 105e28edc46SMiklos Szeredi int err; 106e28edc46SMiklos Szeredi 107e28edc46SMiklos Szeredi this = lookup_one_len_unlocked(name, base, namelen); 108e28edc46SMiklos Szeredi if (IS_ERR(this)) { 109e28edc46SMiklos Szeredi err = PTR_ERR(this); 110e28edc46SMiklos Szeredi this = NULL; 111e28edc46SMiklos Szeredi if (err == -ENOENT || err == -ENAMETOOLONG) 112e28edc46SMiklos Szeredi goto out; 113e28edc46SMiklos Szeredi goto out_err; 114e28edc46SMiklos Szeredi } 115e28edc46SMiklos Szeredi if (!this->d_inode) 116e28edc46SMiklos Szeredi goto put_and_out; 117e28edc46SMiklos Szeredi 118e28edc46SMiklos Szeredi if (ovl_dentry_weird(this)) { 119e28edc46SMiklos Szeredi /* Don't support traversing automounts and other weirdness */ 120e28edc46SMiklos Szeredi err = -EREMOTE; 121e28edc46SMiklos Szeredi goto out_err; 122e28edc46SMiklos Szeredi } 123e28edc46SMiklos Szeredi if (ovl_is_whiteout(this)) { 124e28edc46SMiklos Szeredi d->stop = d->opaque = true; 125e28edc46SMiklos Szeredi goto put_and_out; 126e28edc46SMiklos Szeredi } 127e28edc46SMiklos Szeredi if (!d_can_lookup(this)) { 128e28edc46SMiklos Szeredi d->stop = true; 129e28edc46SMiklos Szeredi if (d->is_dir) 130e28edc46SMiklos Szeredi goto put_and_out; 131e28edc46SMiklos Szeredi goto out; 132e28edc46SMiklos Szeredi } 133e28edc46SMiklos Szeredi d->is_dir = true; 134e28edc46SMiklos Szeredi if (!d->last && ovl_is_opaquedir(this)) { 135e28edc46SMiklos Szeredi d->stop = d->opaque = true; 136e28edc46SMiklos Szeredi goto out; 137e28edc46SMiklos Szeredi } 13802b69b28SMiklos Szeredi err = ovl_check_redirect(this, d, prelen, post); 13902b69b28SMiklos Szeredi if (err) 14002b69b28SMiklos Szeredi goto out_err; 141e28edc46SMiklos Szeredi out: 142e28edc46SMiklos Szeredi *ret = this; 143e28edc46SMiklos Szeredi return 0; 144e28edc46SMiklos Szeredi 145e28edc46SMiklos Szeredi put_and_out: 146e28edc46SMiklos Szeredi dput(this); 147e28edc46SMiklos Szeredi this = NULL; 148e28edc46SMiklos Szeredi goto out; 149e28edc46SMiklos Szeredi 150e28edc46SMiklos Szeredi out_err: 151e28edc46SMiklos Szeredi dput(this); 152e28edc46SMiklos Szeredi return err; 153e28edc46SMiklos Szeredi } 154e28edc46SMiklos Szeredi 155e28edc46SMiklos Szeredi static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, 156e28edc46SMiklos Szeredi struct dentry **ret) 157e28edc46SMiklos Szeredi { 1584c7d0c9cSAmir Goldstein /* Counting down from the end, since the prefix can change */ 1594c7d0c9cSAmir Goldstein size_t rem = d->name.len - 1; 16002b69b28SMiklos Szeredi struct dentry *dentry = NULL; 16102b69b28SMiklos Szeredi int err; 16202b69b28SMiklos Szeredi 1634c7d0c9cSAmir Goldstein if (d->name.name[0] != '/') 16402b69b28SMiklos Szeredi return ovl_lookup_single(base, d, d->name.name, d->name.len, 16502b69b28SMiklos Szeredi 0, "", ret); 16602b69b28SMiklos Szeredi 1674c7d0c9cSAmir Goldstein while (!IS_ERR_OR_NULL(base) && d_can_lookup(base)) { 1684c7d0c9cSAmir Goldstein const char *s = d->name.name + d->name.len - rem; 16902b69b28SMiklos Szeredi const char *next = strchrnul(s, '/'); 1704c7d0c9cSAmir Goldstein size_t thislen = next - s; 1714c7d0c9cSAmir Goldstein bool end = !next[0]; 17202b69b28SMiklos Szeredi 1734c7d0c9cSAmir Goldstein /* Verify we did not go off the rails */ 1744c7d0c9cSAmir Goldstein if (WARN_ON(s[-1] != '/')) 17502b69b28SMiklos Szeredi return -EIO; 17602b69b28SMiklos Szeredi 1774c7d0c9cSAmir Goldstein err = ovl_lookup_single(base, d, s, thislen, 1784c7d0c9cSAmir Goldstein d->name.len - rem, next, &base); 17902b69b28SMiklos Szeredi dput(dentry); 18002b69b28SMiklos Szeredi if (err) 18102b69b28SMiklos Szeredi return err; 18202b69b28SMiklos Szeredi dentry = base; 1834c7d0c9cSAmir Goldstein if (end) 1844c7d0c9cSAmir Goldstein break; 1854c7d0c9cSAmir Goldstein 1864c7d0c9cSAmir Goldstein rem -= thislen + 1; 1874c7d0c9cSAmir Goldstein 1884c7d0c9cSAmir Goldstein if (WARN_ON(rem >= d->name.len)) 1894c7d0c9cSAmir Goldstein return -EIO; 19002b69b28SMiklos Szeredi } 19102b69b28SMiklos Szeredi *ret = dentry; 19202b69b28SMiklos Szeredi return 0; 193e28edc46SMiklos Szeredi } 194e28edc46SMiklos Szeredi 195bbb1e54dSMiklos Szeredi /* 196bbb1e54dSMiklos Szeredi * Returns next layer in stack starting from top. 197bbb1e54dSMiklos Szeredi * Returns -1 if this is the last layer. 198bbb1e54dSMiklos Szeredi */ 199bbb1e54dSMiklos Szeredi int ovl_path_next(int idx, struct dentry *dentry, struct path *path) 200bbb1e54dSMiklos Szeredi { 201bbb1e54dSMiklos Szeredi struct ovl_entry *oe = dentry->d_fsdata; 202bbb1e54dSMiklos Szeredi 203bbb1e54dSMiklos Szeredi BUG_ON(idx < 0); 204bbb1e54dSMiklos Szeredi if (idx == 0) { 205bbb1e54dSMiklos Szeredi ovl_path_upper(dentry, path); 206bbb1e54dSMiklos Szeredi if (path->dentry) 207bbb1e54dSMiklos Szeredi return oe->numlower ? 1 : -1; 208bbb1e54dSMiklos Szeredi idx++; 209bbb1e54dSMiklos Szeredi } 210bbb1e54dSMiklos Szeredi BUG_ON(idx > oe->numlower); 211bbb1e54dSMiklos Szeredi *path = oe->lowerstack[idx - 1]; 212bbb1e54dSMiklos Szeredi 213bbb1e54dSMiklos Szeredi return (idx < oe->numlower) ? idx + 1 : -1; 214bbb1e54dSMiklos Szeredi } 215bbb1e54dSMiklos Szeredi 216bbb1e54dSMiklos Szeredi struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, 217bbb1e54dSMiklos Szeredi unsigned int flags) 218bbb1e54dSMiklos Szeredi { 219bbb1e54dSMiklos Szeredi struct ovl_entry *oe; 220bbb1e54dSMiklos Szeredi const struct cred *old_cred; 2216b2d5fe4SMiklos Szeredi struct ovl_fs *ofs = dentry->d_sb->s_fs_info; 222bbb1e54dSMiklos Szeredi struct ovl_entry *poe = dentry->d_parent->d_fsdata; 223bbb1e54dSMiklos Szeredi struct path *stack = NULL; 224bbb1e54dSMiklos Szeredi struct dentry *upperdir, *upperdentry = NULL; 225bbb1e54dSMiklos Szeredi unsigned int ctr = 0; 226bbb1e54dSMiklos Szeredi struct inode *inode = NULL; 227bbb1e54dSMiklos Szeredi bool upperopaque = false; 22802b69b28SMiklos Szeredi char *upperredirect = NULL; 229bbb1e54dSMiklos Szeredi struct dentry *this; 230bbb1e54dSMiklos Szeredi unsigned int i; 231bbb1e54dSMiklos Szeredi int err; 232e28edc46SMiklos Szeredi struct ovl_lookup_data d = { 233e28edc46SMiklos Szeredi .name = dentry->d_name, 234e28edc46SMiklos Szeredi .is_dir = false, 235e28edc46SMiklos Szeredi .opaque = false, 236e28edc46SMiklos Szeredi .stop = false, 237e28edc46SMiklos Szeredi .last = !poe->numlower, 23802b69b28SMiklos Szeredi .redirect = NULL, 239e28edc46SMiklos Szeredi }; 240bbb1e54dSMiklos Szeredi 2416b2d5fe4SMiklos Szeredi if (dentry->d_name.len > ofs->namelen) 2426b2d5fe4SMiklos Szeredi return ERR_PTR(-ENAMETOOLONG); 2436b2d5fe4SMiklos Szeredi 244bbb1e54dSMiklos Szeredi old_cred = ovl_override_creds(dentry->d_sb); 245bbb1e54dSMiklos Szeredi upperdir = ovl_upperdentry_dereference(poe); 246bbb1e54dSMiklos Szeredi if (upperdir) { 247e28edc46SMiklos Szeredi err = ovl_lookup_layer(upperdir, &d, &upperdentry); 248e28edc46SMiklos Szeredi if (err) 249bbb1e54dSMiklos Szeredi goto out; 250bbb1e54dSMiklos Szeredi 251e28edc46SMiklos Szeredi if (upperdentry && unlikely(ovl_dentry_remote(upperdentry))) { 252e28edc46SMiklos Szeredi dput(upperdentry); 253bbb1e54dSMiklos Szeredi err = -EREMOTE; 254bbb1e54dSMiklos Szeredi goto out; 255bbb1e54dSMiklos Szeredi } 25602b69b28SMiklos Szeredi 25702b69b28SMiklos Szeredi if (d.redirect) { 25802b69b28SMiklos Szeredi upperredirect = kstrdup(d.redirect, GFP_KERNEL); 25902b69b28SMiklos Szeredi if (!upperredirect) 26002b69b28SMiklos Szeredi goto out_put_upper; 26102b69b28SMiklos Szeredi if (d.redirect[0] == '/') 26202b69b28SMiklos Szeredi poe = dentry->d_sb->s_root->d_fsdata; 26302b69b28SMiklos Szeredi } 264e28edc46SMiklos Szeredi upperopaque = d.opaque; 265bbb1e54dSMiklos Szeredi } 266bbb1e54dSMiklos Szeredi 267e28edc46SMiklos Szeredi if (!d.stop && poe->numlower) { 268bbb1e54dSMiklos Szeredi err = -ENOMEM; 26902b69b28SMiklos Szeredi stack = kcalloc(ofs->numlower, sizeof(struct path), 270e28edc46SMiklos Szeredi GFP_TEMPORARY); 271bbb1e54dSMiklos Szeredi if (!stack) 272bbb1e54dSMiklos Szeredi goto out_put_upper; 273bbb1e54dSMiklos Szeredi } 274bbb1e54dSMiklos Szeredi 275e28edc46SMiklos Szeredi for (i = 0; !d.stop && i < poe->numlower; i++) { 276bbb1e54dSMiklos Szeredi struct path lowerpath = poe->lowerstack[i]; 277bbb1e54dSMiklos Szeredi 278e28edc46SMiklos Szeredi d.last = i == poe->numlower - 1; 279e28edc46SMiklos Szeredi err = ovl_lookup_layer(lowerpath.dentry, &d, &this); 280e28edc46SMiklos Szeredi if (err) 281bbb1e54dSMiklos Szeredi goto out_put; 2826b2d5fe4SMiklos Szeredi 283bbb1e54dSMiklos Szeredi if (!this) 284bbb1e54dSMiklos Szeredi continue; 285bbb1e54dSMiklos Szeredi 286bbb1e54dSMiklos Szeredi stack[ctr].dentry = this; 287bbb1e54dSMiklos Szeredi stack[ctr].mnt = lowerpath.mnt; 288bbb1e54dSMiklos Szeredi ctr++; 28902b69b28SMiklos Szeredi 29002b69b28SMiklos Szeredi if (d.stop) 29102b69b28SMiklos Szeredi break; 29202b69b28SMiklos Szeredi 29302b69b28SMiklos Szeredi if (d.redirect && 29402b69b28SMiklos Szeredi d.redirect[0] == '/' && 29502b69b28SMiklos Szeredi poe != dentry->d_sb->s_root->d_fsdata) { 29602b69b28SMiklos Szeredi poe = dentry->d_sb->s_root->d_fsdata; 29702b69b28SMiklos Szeredi 29802b69b28SMiklos Szeredi /* Find the current layer on the root dentry */ 29902b69b28SMiklos Szeredi for (i = 0; i < poe->numlower; i++) 30002b69b28SMiklos Szeredi if (poe->lowerstack[i].mnt == lowerpath.mnt) 30102b69b28SMiklos Szeredi break; 30202b69b28SMiklos Szeredi if (WARN_ON(i == poe->numlower)) 30302b69b28SMiklos Szeredi break; 30402b69b28SMiklos Szeredi } 305bbb1e54dSMiklos Szeredi } 306bbb1e54dSMiklos Szeredi 307bbb1e54dSMiklos Szeredi oe = ovl_alloc_entry(ctr); 308bbb1e54dSMiklos Szeredi err = -ENOMEM; 309bbb1e54dSMiklos Szeredi if (!oe) 310bbb1e54dSMiklos Szeredi goto out_put; 311bbb1e54dSMiklos Szeredi 312bbb1e54dSMiklos Szeredi if (upperdentry || ctr) { 313bbb1e54dSMiklos Szeredi struct dentry *realdentry; 314bbb1e54dSMiklos Szeredi struct inode *realinode; 315bbb1e54dSMiklos Szeredi 316bbb1e54dSMiklos Szeredi realdentry = upperdentry ? upperdentry : stack[0].dentry; 317bbb1e54dSMiklos Szeredi realinode = d_inode(realdentry); 318bbb1e54dSMiklos Szeredi 319bbb1e54dSMiklos Szeredi err = -ENOMEM; 320bbb1e54dSMiklos Szeredi if (upperdentry && !d_is_dir(upperdentry)) { 321bbb1e54dSMiklos Szeredi inode = ovl_get_inode(dentry->d_sb, realinode); 322bbb1e54dSMiklos Szeredi } else { 323bbb1e54dSMiklos Szeredi inode = ovl_new_inode(dentry->d_sb, realinode->i_mode, 324bbb1e54dSMiklos Szeredi realinode->i_rdev); 325bbb1e54dSMiklos Szeredi if (inode) 326bbb1e54dSMiklos Szeredi ovl_inode_init(inode, realinode, !!upperdentry); 327bbb1e54dSMiklos Szeredi } 328bbb1e54dSMiklos Szeredi if (!inode) 329bbb1e54dSMiklos Szeredi goto out_free_oe; 330bbb1e54dSMiklos Szeredi ovl_copyattr(realdentry->d_inode, inode); 331bbb1e54dSMiklos Szeredi } 332bbb1e54dSMiklos Szeredi 333bbb1e54dSMiklos Szeredi revert_creds(old_cred); 334bbb1e54dSMiklos Szeredi oe->opaque = upperopaque; 33502b69b28SMiklos Szeredi oe->redirect = upperredirect; 336bbb1e54dSMiklos Szeredi oe->__upperdentry = upperdentry; 337bbb1e54dSMiklos Szeredi memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr); 338bbb1e54dSMiklos Szeredi kfree(stack); 33902b69b28SMiklos Szeredi kfree(d.redirect); 340bbb1e54dSMiklos Szeredi dentry->d_fsdata = oe; 341bbb1e54dSMiklos Szeredi d_add(dentry, inode); 342bbb1e54dSMiklos Szeredi 343bbb1e54dSMiklos Szeredi return NULL; 344bbb1e54dSMiklos Szeredi 345bbb1e54dSMiklos Szeredi out_free_oe: 346bbb1e54dSMiklos Szeredi kfree(oe); 347bbb1e54dSMiklos Szeredi out_put: 348bbb1e54dSMiklos Szeredi for (i = 0; i < ctr; i++) 349bbb1e54dSMiklos Szeredi dput(stack[i].dentry); 350bbb1e54dSMiklos Szeredi kfree(stack); 351bbb1e54dSMiklos Szeredi out_put_upper: 352bbb1e54dSMiklos Szeredi dput(upperdentry); 35302b69b28SMiklos Szeredi kfree(upperredirect); 354bbb1e54dSMiklos Szeredi out: 35502b69b28SMiklos Szeredi kfree(d.redirect); 356bbb1e54dSMiklos Szeredi revert_creds(old_cred); 357bbb1e54dSMiklos Szeredi return ERR_PTR(err); 358bbb1e54dSMiklos Szeredi } 359bbb1e54dSMiklos Szeredi 360bbb1e54dSMiklos Szeredi bool ovl_lower_positive(struct dentry *dentry) 361bbb1e54dSMiklos Szeredi { 362bbb1e54dSMiklos Szeredi struct ovl_entry *oe = dentry->d_fsdata; 363bbb1e54dSMiklos Szeredi struct ovl_entry *poe = dentry->d_parent->d_fsdata; 364bbb1e54dSMiklos Szeredi const struct qstr *name = &dentry->d_name; 365bbb1e54dSMiklos Szeredi unsigned int i; 366bbb1e54dSMiklos Szeredi bool positive = false; 367bbb1e54dSMiklos Szeredi bool done = false; 368bbb1e54dSMiklos Szeredi 369bbb1e54dSMiklos Szeredi /* 370bbb1e54dSMiklos Szeredi * If dentry is negative, then lower is positive iff this is a 371bbb1e54dSMiklos Szeredi * whiteout. 372bbb1e54dSMiklos Szeredi */ 373bbb1e54dSMiklos Szeredi if (!dentry->d_inode) 374bbb1e54dSMiklos Szeredi return oe->opaque; 375bbb1e54dSMiklos Szeredi 376bbb1e54dSMiklos Szeredi /* Negative upper -> positive lower */ 377bbb1e54dSMiklos Szeredi if (!oe->__upperdentry) 378bbb1e54dSMiklos Szeredi return true; 379bbb1e54dSMiklos Szeredi 380bbb1e54dSMiklos Szeredi /* Positive upper -> have to look up lower to see whether it exists */ 381bbb1e54dSMiklos Szeredi for (i = 0; !done && !positive && i < poe->numlower; i++) { 382bbb1e54dSMiklos Szeredi struct dentry *this; 383bbb1e54dSMiklos Szeredi struct dentry *lowerdir = poe->lowerstack[i].dentry; 384bbb1e54dSMiklos Szeredi 385bbb1e54dSMiklos Szeredi this = lookup_one_len_unlocked(name->name, lowerdir, 386bbb1e54dSMiklos Szeredi name->len); 387bbb1e54dSMiklos Szeredi if (IS_ERR(this)) { 388bbb1e54dSMiklos Szeredi switch (PTR_ERR(this)) { 389bbb1e54dSMiklos Szeredi case -ENOENT: 390bbb1e54dSMiklos Szeredi case -ENAMETOOLONG: 391bbb1e54dSMiklos Szeredi break; 392bbb1e54dSMiklos Szeredi 393bbb1e54dSMiklos Szeredi default: 394bbb1e54dSMiklos Szeredi /* 395bbb1e54dSMiklos Szeredi * Assume something is there, we just couldn't 396bbb1e54dSMiklos Szeredi * access it. 397bbb1e54dSMiklos Szeredi */ 398bbb1e54dSMiklos Szeredi positive = true; 399bbb1e54dSMiklos Szeredi break; 400bbb1e54dSMiklos Szeredi } 401bbb1e54dSMiklos Szeredi } else { 402bbb1e54dSMiklos Szeredi if (this->d_inode) { 403bbb1e54dSMiklos Szeredi positive = !ovl_is_whiteout(this); 404bbb1e54dSMiklos Szeredi done = true; 405bbb1e54dSMiklos Szeredi } 406bbb1e54dSMiklos Szeredi dput(this); 407bbb1e54dSMiklos Szeredi } 408bbb1e54dSMiklos Szeredi } 409bbb1e54dSMiklos Szeredi 410bbb1e54dSMiklos Szeredi return positive; 411bbb1e54dSMiklos Szeredi } 412