18ed5eec9SAmir Goldstein /* 28ed5eec9SAmir Goldstein * Overlayfs NFS export support. 38ed5eec9SAmir Goldstein * 48ed5eec9SAmir Goldstein * Amir Goldstein <amir73il@gmail.com> 58ed5eec9SAmir Goldstein * 68ed5eec9SAmir Goldstein * Copyright (C) 2017-2018 CTERA Networks. All Rights Reserved. 78ed5eec9SAmir Goldstein * 88ed5eec9SAmir Goldstein * This program is free software; you can redistribute it and/or modify it 98ed5eec9SAmir Goldstein * under the terms of the GNU General Public License version 2 as published by 108ed5eec9SAmir Goldstein * the Free Software Foundation. 118ed5eec9SAmir Goldstein */ 128ed5eec9SAmir Goldstein 138ed5eec9SAmir Goldstein #include <linux/fs.h> 148ed5eec9SAmir Goldstein #include <linux/cred.h> 158ed5eec9SAmir Goldstein #include <linux/mount.h> 168ed5eec9SAmir Goldstein #include <linux/namei.h> 178ed5eec9SAmir Goldstein #include <linux/xattr.h> 188ed5eec9SAmir Goldstein #include <linux/exportfs.h> 198ed5eec9SAmir Goldstein #include <linux/ratelimit.h> 208ed5eec9SAmir Goldstein #include "overlayfs.h" 218ed5eec9SAmir Goldstein 228ed5eec9SAmir Goldstein static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen) 238ed5eec9SAmir Goldstein { 248ed5eec9SAmir Goldstein struct dentry *upper = ovl_dentry_upper(dentry); 258ed5eec9SAmir Goldstein struct dentry *origin = ovl_dentry_lower(dentry); 268ed5eec9SAmir Goldstein struct ovl_fh *fh = NULL; 278ed5eec9SAmir Goldstein int err; 288ed5eec9SAmir Goldstein 298ed5eec9SAmir Goldstein /* 308ed5eec9SAmir Goldstein * On overlay with an upper layer, overlay root inode is encoded as 318ed5eec9SAmir Goldstein * an upper file handle, because upper root dir is not indexed. 328ed5eec9SAmir Goldstein */ 338ed5eec9SAmir Goldstein if (dentry == dentry->d_sb->s_root && upper) 348ed5eec9SAmir Goldstein origin = NULL; 358ed5eec9SAmir Goldstein 368ed5eec9SAmir Goldstein err = -EACCES; 378ed5eec9SAmir Goldstein if (!upper || origin) 388ed5eec9SAmir Goldstein goto fail; 398ed5eec9SAmir Goldstein 408ed5eec9SAmir Goldstein /* TODO: encode non pure-upper by origin */ 418ed5eec9SAmir Goldstein fh = ovl_encode_fh(upper, true); 428ed5eec9SAmir Goldstein 438ed5eec9SAmir Goldstein err = -EOVERFLOW; 448ed5eec9SAmir Goldstein if (fh->len > buflen) 458ed5eec9SAmir Goldstein goto fail; 468ed5eec9SAmir Goldstein 478ed5eec9SAmir Goldstein memcpy(buf, (char *)fh, fh->len); 488ed5eec9SAmir Goldstein err = fh->len; 498ed5eec9SAmir Goldstein 508ed5eec9SAmir Goldstein out: 518ed5eec9SAmir Goldstein kfree(fh); 528ed5eec9SAmir Goldstein return err; 538ed5eec9SAmir Goldstein 548ed5eec9SAmir Goldstein fail: 558ed5eec9SAmir Goldstein pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n", 568ed5eec9SAmir Goldstein dentry, err, buflen, fh ? (int)fh->len : 0, 578ed5eec9SAmir Goldstein fh ? fh->type : 0); 588ed5eec9SAmir Goldstein goto out; 598ed5eec9SAmir Goldstein } 608ed5eec9SAmir Goldstein 618ed5eec9SAmir Goldstein static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len) 628ed5eec9SAmir Goldstein { 638ed5eec9SAmir Goldstein int res, len = *max_len << 2; 648ed5eec9SAmir Goldstein 658ed5eec9SAmir Goldstein res = ovl_d_to_fh(dentry, (char *)fid, len); 668ed5eec9SAmir Goldstein if (res <= 0) 678ed5eec9SAmir Goldstein return FILEID_INVALID; 688ed5eec9SAmir Goldstein 698ed5eec9SAmir Goldstein len = res; 708ed5eec9SAmir Goldstein 718ed5eec9SAmir Goldstein /* Round up to dwords */ 728ed5eec9SAmir Goldstein *max_len = (len + 3) >> 2; 738ed5eec9SAmir Goldstein return OVL_FILEID; 748ed5eec9SAmir Goldstein } 758ed5eec9SAmir Goldstein 768ed5eec9SAmir Goldstein static int ovl_encode_inode_fh(struct inode *inode, u32 *fid, int *max_len, 778ed5eec9SAmir Goldstein struct inode *parent) 788ed5eec9SAmir Goldstein { 798ed5eec9SAmir Goldstein struct dentry *dentry; 808ed5eec9SAmir Goldstein int type; 818ed5eec9SAmir Goldstein 828ed5eec9SAmir Goldstein /* TODO: encode connectable file handles */ 838ed5eec9SAmir Goldstein if (parent) 848ed5eec9SAmir Goldstein return FILEID_INVALID; 858ed5eec9SAmir Goldstein 868ed5eec9SAmir Goldstein dentry = d_find_any_alias(inode); 878ed5eec9SAmir Goldstein if (WARN_ON(!dentry)) 888ed5eec9SAmir Goldstein return FILEID_INVALID; 898ed5eec9SAmir Goldstein 908ed5eec9SAmir Goldstein type = ovl_dentry_to_fh(dentry, fid, max_len); 918ed5eec9SAmir Goldstein 928ed5eec9SAmir Goldstein dput(dentry); 938ed5eec9SAmir Goldstein return type; 948ed5eec9SAmir Goldstein } 958ed5eec9SAmir Goldstein 968556a420SAmir Goldstein /* 978556a420SAmir Goldstein * Find or instantiate an overlay dentry from real dentries. 988556a420SAmir Goldstein */ 998556a420SAmir Goldstein static struct dentry *ovl_obtain_alias(struct super_block *sb, 1008556a420SAmir Goldstein struct dentry *upper, 1018556a420SAmir Goldstein struct ovl_path *lowerpath) 1028556a420SAmir Goldstein { 1038556a420SAmir Goldstein struct inode *inode; 1048556a420SAmir Goldstein struct dentry *dentry; 1058556a420SAmir Goldstein struct ovl_entry *oe; 1068556a420SAmir Goldstein void *fsdata = &oe; 1078556a420SAmir Goldstein 1088556a420SAmir Goldstein /* TODO: obtain non pure-upper */ 1098556a420SAmir Goldstein if (lowerpath) 1108556a420SAmir Goldstein return ERR_PTR(-EIO); 1118556a420SAmir Goldstein 1128556a420SAmir Goldstein inode = ovl_get_inode(sb, dget(upper), NULL, NULL, 0); 1138556a420SAmir Goldstein if (IS_ERR(inode)) { 1148556a420SAmir Goldstein dput(upper); 1158556a420SAmir Goldstein return ERR_CAST(inode); 1168556a420SAmir Goldstein } 1178556a420SAmir Goldstein 1188556a420SAmir Goldstein dentry = d_find_any_alias(inode); 1198556a420SAmir Goldstein if (!dentry) { 1208556a420SAmir Goldstein dentry = d_alloc_anon(inode->i_sb); 1218556a420SAmir Goldstein if (!dentry) 1228556a420SAmir Goldstein goto nomem; 1238556a420SAmir Goldstein oe = ovl_alloc_entry(0); 1248556a420SAmir Goldstein if (!oe) 1258556a420SAmir Goldstein goto nomem; 1268556a420SAmir Goldstein 1278556a420SAmir Goldstein dentry->d_fsdata = oe; 1288556a420SAmir Goldstein ovl_dentry_set_upper_alias(dentry); 1298556a420SAmir Goldstein } 1308556a420SAmir Goldstein 1318556a420SAmir Goldstein return d_instantiate_anon(dentry, inode); 1328556a420SAmir Goldstein 1338556a420SAmir Goldstein nomem: 1348556a420SAmir Goldstein iput(inode); 1358556a420SAmir Goldstein dput(dentry); 1368556a420SAmir Goldstein return ERR_PTR(-ENOMEM); 1378556a420SAmir Goldstein } 1388556a420SAmir Goldstein 1393985b70aSAmir Goldstein /* 1403985b70aSAmir Goldstein * Lookup a child overlay dentry to get a connected overlay dentry whose real 1413985b70aSAmir Goldstein * dentry is @real. If @real is on upper layer, we lookup a child overlay 1423985b70aSAmir Goldstein * dentry with the same name as the real dentry. Otherwise, we need to consult 1433985b70aSAmir Goldstein * index for lookup. 1443985b70aSAmir Goldstein */ 1453985b70aSAmir Goldstein static struct dentry *ovl_lookup_real_one(struct dentry *connected, 1463985b70aSAmir Goldstein struct dentry *real, 1473985b70aSAmir Goldstein struct ovl_layer *layer) 1483985b70aSAmir Goldstein { 1493985b70aSAmir Goldstein struct inode *dir = d_inode(connected); 1503985b70aSAmir Goldstein struct dentry *this, *parent = NULL; 1513985b70aSAmir Goldstein struct name_snapshot name; 1523985b70aSAmir Goldstein int err; 1533985b70aSAmir Goldstein 1543985b70aSAmir Goldstein /* TODO: lookup by lower real dentry */ 1553985b70aSAmir Goldstein if (layer->idx) 1563985b70aSAmir Goldstein return ERR_PTR(-EACCES); 1573985b70aSAmir Goldstein 1583985b70aSAmir Goldstein /* 1593985b70aSAmir Goldstein * Lookup child overlay dentry by real name. The dir mutex protects us 1603985b70aSAmir Goldstein * from racing with overlay rename. If the overlay dentry that is above 1613985b70aSAmir Goldstein * real has already been moved to a parent that is not under the 1623985b70aSAmir Goldstein * connected overlay dir, we return -ECHILD and restart the lookup of 1633985b70aSAmir Goldstein * connected real path from the top. 1643985b70aSAmir Goldstein */ 1653985b70aSAmir Goldstein inode_lock_nested(dir, I_MUTEX_PARENT); 1663985b70aSAmir Goldstein err = -ECHILD; 1673985b70aSAmir Goldstein parent = dget_parent(real); 1683985b70aSAmir Goldstein if (ovl_dentry_upper(connected) != parent) 1693985b70aSAmir Goldstein goto fail; 1703985b70aSAmir Goldstein 1713985b70aSAmir Goldstein /* 1723985b70aSAmir Goldstein * We also need to take a snapshot of real dentry name to protect us 1733985b70aSAmir Goldstein * from racing with underlying layer rename. In this case, we don't 1743985b70aSAmir Goldstein * care about returning ESTALE, only from dereferencing a free name 1753985b70aSAmir Goldstein * pointer because we hold no lock on the real dentry. 1763985b70aSAmir Goldstein */ 1773985b70aSAmir Goldstein take_dentry_name_snapshot(&name, real); 1783985b70aSAmir Goldstein this = lookup_one_len(name.name, connected, strlen(name.name)); 1793985b70aSAmir Goldstein err = PTR_ERR(this); 1803985b70aSAmir Goldstein if (IS_ERR(this)) { 1813985b70aSAmir Goldstein goto fail; 1823985b70aSAmir Goldstein } else if (!this || !this->d_inode) { 1833985b70aSAmir Goldstein dput(this); 1843985b70aSAmir Goldstein err = -ENOENT; 1853985b70aSAmir Goldstein goto fail; 1863985b70aSAmir Goldstein } else if (ovl_dentry_upper(this) != real) { 1873985b70aSAmir Goldstein dput(this); 1883985b70aSAmir Goldstein err = -ESTALE; 1893985b70aSAmir Goldstein goto fail; 1903985b70aSAmir Goldstein } 1913985b70aSAmir Goldstein 1923985b70aSAmir Goldstein out: 1933985b70aSAmir Goldstein release_dentry_name_snapshot(&name); 1943985b70aSAmir Goldstein dput(parent); 1953985b70aSAmir Goldstein inode_unlock(dir); 1963985b70aSAmir Goldstein return this; 1973985b70aSAmir Goldstein 1983985b70aSAmir Goldstein fail: 1993985b70aSAmir Goldstein pr_warn_ratelimited("overlayfs: failed to lookup one by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", 2003985b70aSAmir Goldstein real, layer->idx, connected, err); 2013985b70aSAmir Goldstein this = ERR_PTR(err); 2023985b70aSAmir Goldstein goto out; 2033985b70aSAmir Goldstein } 2043985b70aSAmir Goldstein 2053985b70aSAmir Goldstein /* 2063985b70aSAmir Goldstein * Lookup a connected overlay dentry whose real dentry is @real. 2073985b70aSAmir Goldstein * If @real is on upper layer, we lookup a child overlay dentry with the same 2083985b70aSAmir Goldstein * path the real dentry. Otherwise, we need to consult index for lookup. 2093985b70aSAmir Goldstein */ 2103985b70aSAmir Goldstein static struct dentry *ovl_lookup_real(struct super_block *sb, 2113985b70aSAmir Goldstein struct dentry *real, 2123985b70aSAmir Goldstein struct ovl_layer *layer) 2133985b70aSAmir Goldstein { 2143985b70aSAmir Goldstein struct dentry *connected; 2153985b70aSAmir Goldstein int err = 0; 2163985b70aSAmir Goldstein 2173985b70aSAmir Goldstein /* TODO: use index when looking up by lower real dentry */ 2183985b70aSAmir Goldstein if (layer->idx) 2193985b70aSAmir Goldstein return ERR_PTR(-EACCES); 2203985b70aSAmir Goldstein 2213985b70aSAmir Goldstein connected = dget(sb->s_root); 2223985b70aSAmir Goldstein while (!err) { 2233985b70aSAmir Goldstein struct dentry *next, *this; 2243985b70aSAmir Goldstein struct dentry *parent = NULL; 2253985b70aSAmir Goldstein struct dentry *real_connected = ovl_dentry_upper(connected); 2263985b70aSAmir Goldstein 2273985b70aSAmir Goldstein if (real_connected == real) 2283985b70aSAmir Goldstein break; 2293985b70aSAmir Goldstein 2303985b70aSAmir Goldstein /* Find the topmost dentry not yet connected */ 2313985b70aSAmir Goldstein next = dget(real); 2323985b70aSAmir Goldstein for (;;) { 2333985b70aSAmir Goldstein parent = dget_parent(next); 2343985b70aSAmir Goldstein 2353985b70aSAmir Goldstein if (parent == real_connected) 2363985b70aSAmir Goldstein break; 2373985b70aSAmir Goldstein 2383985b70aSAmir Goldstein /* 2393985b70aSAmir Goldstein * If real has been moved out of 'real_connected', 2403985b70aSAmir Goldstein * we will not find 'real_connected' and hit the layer 2413985b70aSAmir Goldstein * root. In that case, we need to restart connecting. 2423985b70aSAmir Goldstein * This game can go on forever in the worst case. We 2433985b70aSAmir Goldstein * may want to consider taking s_vfs_rename_mutex if 2443985b70aSAmir Goldstein * this happens more than once. 2453985b70aSAmir Goldstein */ 2463985b70aSAmir Goldstein if (parent == layer->mnt->mnt_root) { 2473985b70aSAmir Goldstein dput(connected); 2483985b70aSAmir Goldstein connected = dget(sb->s_root); 2493985b70aSAmir Goldstein break; 2503985b70aSAmir Goldstein } 2513985b70aSAmir Goldstein 2523985b70aSAmir Goldstein /* 2533985b70aSAmir Goldstein * If real file has been moved out of the layer root 2543985b70aSAmir Goldstein * directory, we will eventully hit the real fs root. 2553985b70aSAmir Goldstein * This cannot happen by legit overlay rename, so we 2563985b70aSAmir Goldstein * return error in that case. 2573985b70aSAmir Goldstein */ 2583985b70aSAmir Goldstein if (parent == next) { 2593985b70aSAmir Goldstein err = -EXDEV; 2603985b70aSAmir Goldstein break; 2613985b70aSAmir Goldstein } 2623985b70aSAmir Goldstein 2633985b70aSAmir Goldstein dput(next); 2643985b70aSAmir Goldstein next = parent; 2653985b70aSAmir Goldstein } 2663985b70aSAmir Goldstein 2673985b70aSAmir Goldstein if (!err) { 2683985b70aSAmir Goldstein this = ovl_lookup_real_one(connected, next, layer); 2693985b70aSAmir Goldstein if (IS_ERR(this)) 2703985b70aSAmir Goldstein err = PTR_ERR(this); 2713985b70aSAmir Goldstein 2723985b70aSAmir Goldstein /* 2733985b70aSAmir Goldstein * Lookup of child in overlay can fail when racing with 2743985b70aSAmir Goldstein * overlay rename of child away from 'connected' parent. 2753985b70aSAmir Goldstein * In this case, we need to restart the lookup from the 2763985b70aSAmir Goldstein * top, because we cannot trust that 'real_connected' is 2773985b70aSAmir Goldstein * still an ancestor of 'real'. 2783985b70aSAmir Goldstein */ 2793985b70aSAmir Goldstein if (err == -ECHILD) { 2803985b70aSAmir Goldstein this = dget(sb->s_root); 2813985b70aSAmir Goldstein err = 0; 2823985b70aSAmir Goldstein } 2833985b70aSAmir Goldstein if (!err) { 2843985b70aSAmir Goldstein dput(connected); 2853985b70aSAmir Goldstein connected = this; 2863985b70aSAmir Goldstein } 2873985b70aSAmir Goldstein } 2883985b70aSAmir Goldstein 2893985b70aSAmir Goldstein dput(parent); 2903985b70aSAmir Goldstein dput(next); 2913985b70aSAmir Goldstein } 2923985b70aSAmir Goldstein 2933985b70aSAmir Goldstein if (err) 2943985b70aSAmir Goldstein goto fail; 2953985b70aSAmir Goldstein 2963985b70aSAmir Goldstein return connected; 2973985b70aSAmir Goldstein 2983985b70aSAmir Goldstein fail: 2993985b70aSAmir Goldstein pr_warn_ratelimited("overlayfs: failed to lookup by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", 3003985b70aSAmir Goldstein real, layer->idx, connected, err); 3013985b70aSAmir Goldstein dput(connected); 3023985b70aSAmir Goldstein return ERR_PTR(err); 3033985b70aSAmir Goldstein } 3043985b70aSAmir Goldstein 3053985b70aSAmir Goldstein /* 3063985b70aSAmir Goldstein * Get an overlay dentry from upper/lower real dentries. 3073985b70aSAmir Goldstein */ 3083985b70aSAmir Goldstein static struct dentry *ovl_get_dentry(struct super_block *sb, 3093985b70aSAmir Goldstein struct dentry *upper, 3103985b70aSAmir Goldstein struct ovl_path *lowerpath) 3113985b70aSAmir Goldstein { 3123985b70aSAmir Goldstein struct ovl_fs *ofs = sb->s_fs_info; 3133985b70aSAmir Goldstein struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; 3143985b70aSAmir Goldstein 3153985b70aSAmir Goldstein /* TODO: get non-upper dentry */ 3163985b70aSAmir Goldstein if (!upper) 3173985b70aSAmir Goldstein return ERR_PTR(-EACCES); 3183985b70aSAmir Goldstein 3193985b70aSAmir Goldstein /* 3203985b70aSAmir Goldstein * Obtain a disconnected overlay dentry from a non-dir real upper 3213985b70aSAmir Goldstein * dentry. 3223985b70aSAmir Goldstein */ 3233985b70aSAmir Goldstein if (!d_is_dir(upper)) 3243985b70aSAmir Goldstein return ovl_obtain_alias(sb, upper, NULL); 3253985b70aSAmir Goldstein 3263985b70aSAmir Goldstein /* Removed empty directory? */ 3273985b70aSAmir Goldstein if ((upper->d_flags & DCACHE_DISCONNECTED) || d_unhashed(upper)) 3283985b70aSAmir Goldstein return ERR_PTR(-ENOENT); 3293985b70aSAmir Goldstein 3303985b70aSAmir Goldstein /* 3313985b70aSAmir Goldstein * If real upper dentry is connected and hashed, get a connected 3323985b70aSAmir Goldstein * overlay dentry with the same path as the real upper dentry. 3333985b70aSAmir Goldstein */ 3343985b70aSAmir Goldstein return ovl_lookup_real(sb, upper, &upper_layer); 3353985b70aSAmir Goldstein } 3363985b70aSAmir Goldstein 3378556a420SAmir Goldstein static struct dentry *ovl_upper_fh_to_d(struct super_block *sb, 3388556a420SAmir Goldstein struct ovl_fh *fh) 3398556a420SAmir Goldstein { 3408556a420SAmir Goldstein struct ovl_fs *ofs = sb->s_fs_info; 3418556a420SAmir Goldstein struct dentry *dentry; 3428556a420SAmir Goldstein struct dentry *upper; 3438556a420SAmir Goldstein 3448556a420SAmir Goldstein if (!ofs->upper_mnt) 3458556a420SAmir Goldstein return ERR_PTR(-EACCES); 3468556a420SAmir Goldstein 3478556a420SAmir Goldstein upper = ovl_decode_fh(fh, ofs->upper_mnt); 3488556a420SAmir Goldstein if (IS_ERR_OR_NULL(upper)) 3498556a420SAmir Goldstein return upper; 3508556a420SAmir Goldstein 3513985b70aSAmir Goldstein dentry = ovl_get_dentry(sb, upper, NULL); 3528556a420SAmir Goldstein dput(upper); 3538556a420SAmir Goldstein 3548556a420SAmir Goldstein return dentry; 3558556a420SAmir Goldstein } 3568556a420SAmir Goldstein 3578556a420SAmir Goldstein static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, 3588556a420SAmir Goldstein int fh_len, int fh_type) 3598556a420SAmir Goldstein { 3608556a420SAmir Goldstein struct dentry *dentry = NULL; 3618556a420SAmir Goldstein struct ovl_fh *fh = (struct ovl_fh *) fid; 3628556a420SAmir Goldstein int len = fh_len << 2; 3638556a420SAmir Goldstein unsigned int flags = 0; 3648556a420SAmir Goldstein int err; 3658556a420SAmir Goldstein 3668556a420SAmir Goldstein err = -EINVAL; 3678556a420SAmir Goldstein if (fh_type != OVL_FILEID) 3688556a420SAmir Goldstein goto out_err; 3698556a420SAmir Goldstein 3708556a420SAmir Goldstein err = ovl_check_fh_len(fh, len); 3718556a420SAmir Goldstein if (err) 3728556a420SAmir Goldstein goto out_err; 3738556a420SAmir Goldstein 3748556a420SAmir Goldstein /* TODO: decode non-upper */ 3758556a420SAmir Goldstein flags = fh->flags; 3768556a420SAmir Goldstein if (flags & OVL_FH_FLAG_PATH_UPPER) 3778556a420SAmir Goldstein dentry = ovl_upper_fh_to_d(sb, fh); 3788556a420SAmir Goldstein err = PTR_ERR(dentry); 3798556a420SAmir Goldstein if (IS_ERR(dentry) && err != -ESTALE) 3808556a420SAmir Goldstein goto out_err; 3818556a420SAmir Goldstein 3828556a420SAmir Goldstein return dentry; 3838556a420SAmir Goldstein 3848556a420SAmir Goldstein out_err: 3858556a420SAmir Goldstein pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n", 3868556a420SAmir Goldstein len, fh_type, flags, err); 3878556a420SAmir Goldstein return ERR_PTR(err); 3888556a420SAmir Goldstein } 3898556a420SAmir Goldstein 3903985b70aSAmir Goldstein static struct dentry *ovl_fh_to_parent(struct super_block *sb, struct fid *fid, 3913985b70aSAmir Goldstein int fh_len, int fh_type) 3923985b70aSAmir Goldstein { 3933985b70aSAmir Goldstein pr_warn_ratelimited("overlayfs: connectable file handles not supported; use 'no_subtree_check' exportfs option.\n"); 3943985b70aSAmir Goldstein return ERR_PTR(-EACCES); 3953985b70aSAmir Goldstein } 3963985b70aSAmir Goldstein 3973985b70aSAmir Goldstein static int ovl_get_name(struct dentry *parent, char *name, 3983985b70aSAmir Goldstein struct dentry *child) 3993985b70aSAmir Goldstein { 4003985b70aSAmir Goldstein /* 4013985b70aSAmir Goldstein * ovl_fh_to_dentry() returns connected dir overlay dentries and 4023985b70aSAmir Goldstein * ovl_fh_to_parent() is not implemented, so we should not get here. 4033985b70aSAmir Goldstein */ 4043985b70aSAmir Goldstein WARN_ON_ONCE(1); 4053985b70aSAmir Goldstein return -EIO; 4063985b70aSAmir Goldstein } 4073985b70aSAmir Goldstein 4083985b70aSAmir Goldstein static struct dentry *ovl_get_parent(struct dentry *dentry) 4093985b70aSAmir Goldstein { 4103985b70aSAmir Goldstein /* 4113985b70aSAmir Goldstein * ovl_fh_to_dentry() returns connected dir overlay dentries, so we 4123985b70aSAmir Goldstein * should not get here. 4133985b70aSAmir Goldstein */ 4143985b70aSAmir Goldstein WARN_ON_ONCE(1); 4153985b70aSAmir Goldstein return ERR_PTR(-EIO); 4163985b70aSAmir Goldstein } 4173985b70aSAmir Goldstein 4188ed5eec9SAmir Goldstein const struct export_operations ovl_export_operations = { 4198ed5eec9SAmir Goldstein .encode_fh = ovl_encode_inode_fh, 4208556a420SAmir Goldstein .fh_to_dentry = ovl_fh_to_dentry, 4213985b70aSAmir Goldstein .fh_to_parent = ovl_fh_to_parent, 4223985b70aSAmir Goldstein .get_name = ovl_get_name, 4233985b70aSAmir Goldstein .get_parent = ovl_get_parent, 4248ed5eec9SAmir Goldstein }; 425