linux/fs/overlayfs/export.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Overlayfs NFS export support.
 *
 * Amir Goldstein <[email protected]>
 *
 * Copyright (C) 2017-2018 CTERA Networks. All Rights Reserved.
 */

#include <linux/fs.h>
#include <linux/cred.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/xattr.h>
#include <linux/exportfs.h>
#include <linux/ratelimit.h>
#include "overlayfs.h"

static int ovl_encode_maybe_copy_up(struct dentry *dentry)
{}

/*
 * Before encoding a non-upper directory file handle from real layer N, we need
 * to check if it will be possible to reconnect an overlay dentry from the real
 * lower decoded dentry. This is done by following the overlay ancestry up to a
 * "layer N connected" ancestor and verifying that all parents along the way are
 * "layer N connectable". If an ancestor that is NOT "layer N connectable" is
 * found, we need to copy up an ancestor, which is "layer N connectable", thus
 * making that ancestor "layer N connected". For example:
 *
 * layer 1: /a
 * layer 2: /a/b/c
 *
 * The overlay dentry /a is NOT "layer 2 connectable", because if dir /a is
 * copied up and renamed, upper dir /a will be indexed by lower dir /a from
 * layer 1. The dir /a from layer 2 will never be indexed, so the algorithm (*)
 * in ovl_lookup_real_ancestor() will not be able to lookup a connected overlay
 * dentry from the connected lower dentry /a/b/c.
 *
 * To avoid this problem on decode time, we need to copy up an ancestor of
 * /a/b/c, which is "layer 2 connectable", on encode time. That ancestor is
 * /a/b. After copy up (and index) of /a/b, it will become "layer 2 connected"
 * and when the time comes to decode the file handle from lower dentry /a/b/c,
 * ovl_lookup_real_ancestor() will find the indexed ancestor /a/b and decoding
 * a connected overlay dentry will be accomplished.
 *
 * (*) the algorithm in ovl_lookup_real_ancestor() can be improved to lookup an
 * entry /a in the lower layers above layer N and find the indexed dir /a from
 * layer 1. If that improvement is made, then the check for "layer N connected"
 * will need to verify there are no redirects in lower layers above N. In the
 * example above, /a will be "layer 2 connectable". However, if layer 2 dir /a
 * is a target of a layer 1 redirect, then /a will NOT be "layer 2 connectable":
 *
 * layer 1: /A (redirect = /a)
 * layer 2: /a/b/c
 */

/* Return the lowest layer for encoding a connectable file handle */
static int ovl_connectable_layer(struct dentry *dentry)
{}

/*
 * @dentry is "connected" if all ancestors up to root or a "connected" ancestor
 * have the same uppermost lower layer as the origin's layer. We may need to
 * copy up a "connectable" ancestor to make it "connected". A "connected" dentry
 * cannot become non "connected", so cache positive result in dentry flags.
 *
 * Return the connected origin layer or < 0 on error.
 */
static int ovl_connect_layer(struct dentry *dentry)
{}

/*
 * We only need to encode origin if there is a chance that the same object was
 * encoded pre copy up and then we need to stay consistent with the same
 * encoding also after copy up. If non-pure upper is not indexed, then it was
 * copied up before NFS export was enabled. In that case we don't need to worry
 * about staying consistent with pre copy up encoding and we encode an upper
 * file handle. Overlay root dentry is a private case of non-indexed upper.
 *
 * The following table summarizes the different file handle encodings used for
 * different overlay object types:
 *
 *  Object type		| Encoding
 * --------------------------------
 *  Pure upper		| U
 *  Non-indexed upper	| U
 *  Indexed upper	| L (*)
 *  Non-upper		| L (*)
 *
 * U = upper file handle
 * L = lower file handle
 *
 * (*) Decoding a connected overlay dir from real lower dentry is not always
 * possible when there are redirects in lower layers and non-indexed merge dirs.
 * To mitigate those case, we may copy up the lower dir ancestor before encode
 * of a decodable file handle for non-upper dir.
 *
 * Return 0 for upper file handle, > 0 for lower file handle or < 0 on error.
 */
static int ovl_check_encode_origin(struct dentry *dentry)
{}

static int ovl_dentry_to_fid(struct ovl_fs *ofs, struct dentry *dentry,
			     u32 *fid, int buflen)
{}

static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len,
			 struct inode *parent)
{}

/*
 * Find or instantiate an overlay dentry from real dentries and index.
 */
static struct dentry *ovl_obtain_alias(struct super_block *sb,
				       struct dentry *upper_alias,
				       struct ovl_path *lowerpath,
				       struct dentry *index)
{}

/* Get the upper or lower dentry in stack whose on layer @idx */
static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
{}

/*
 * Lookup a child overlay dentry to get a connected overlay dentry whose real
 * dentry is @real. If @real is on upper layer, we lookup a child overlay
 * dentry with the same name as the real dentry. Otherwise, we need to consult
 * index for lookup.
 */
static struct dentry *ovl_lookup_real_one(struct dentry *connected,
					  struct dentry *real,
					  const struct ovl_layer *layer)
{}

static struct dentry *ovl_lookup_real(struct super_block *sb,
				      struct dentry *real,
				      const struct ovl_layer *layer);

/*
 * Lookup an indexed or hashed overlay dentry by real inode.
 */
static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
					    struct dentry *real,
					    const struct ovl_layer *layer)
{}

/*
 * Lookup an indexed or hashed overlay dentry, whose real dentry is an
 * ancestor of @real.
 */
static struct dentry *ovl_lookup_real_ancestor(struct super_block *sb,
					       struct dentry *real,
					       const struct ovl_layer *layer)
{}

/*
 * Lookup a connected overlay dentry whose real dentry is @real.
 * If @real is on upper layer, we lookup a child overlay dentry with the same
 * path the real dentry. Otherwise, we need to consult index for lookup.
 */
static struct dentry *ovl_lookup_real(struct super_block *sb,
				      struct dentry *real,
				      const struct ovl_layer *layer)
{}

/*
 * Get an overlay dentry from upper/lower real dentries and index.
 */
static struct dentry *ovl_get_dentry(struct super_block *sb,
				     struct dentry *upper,
				     struct ovl_path *lowerpath,
				     struct dentry *index)
{}

static struct dentry *ovl_upper_fh_to_d(struct super_block *sb,
					struct ovl_fh *fh)
{}

static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
					struct ovl_fh *fh)
{}

static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
{}

static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
				       int fh_len, int fh_type)
{}

static struct dentry *ovl_fh_to_parent(struct super_block *sb, struct fid *fid,
				       int fh_len, int fh_type)
{}

static int ovl_get_name(struct dentry *parent, char *name,
			struct dentry *child)
{}

static struct dentry *ovl_get_parent(struct dentry *dentry)
{}

const struct export_operations ovl_export_operations =;

/* encode_fh() encodes non-decodable file handles with nfs_export=off */
const struct export_operations ovl_export_fid_operations =;