/* SPDX-License-Identifier: GPL-2.0 */
#ifndef LINUX_EXPORTFS_H
#define LINUX_EXPORTFS_H 1

#include <linux/types.h>
#include <linux/path.h>

struct dentry;
struct iattr;
struct inode;
struct iomap;
struct super_block;
struct vfsmount;


#define MAX_HANDLE_SZ 128


enum fid_type {
	
	FILEID_ROOT = 0,

	
	FILEID_INO32_GEN = 1,

	
	FILEID_INO32_GEN_PARENT = 2,

	
	FILEID_BTRFS_WITHOUT_PARENT = 0x4d,

	
	FILEID_BTRFS_WITH_PARENT = 0x4e,

	
	FILEID_BTRFS_WITH_PARENT_ROOT = 0x4f,

	
	FILEID_UDF_WITHOUT_PARENT = 0x51,

	
	FILEID_UDF_WITH_PARENT = 0x52,

	
	FILEID_NILFS_WITHOUT_PARENT = 0x61,

	
	FILEID_NILFS_WITH_PARENT = 0x62,

	
	FILEID_FAT_WITHOUT_PARENT = 0x71,

	
	FILEID_FAT_WITH_PARENT = 0x72,

	
	FILEID_INO64_GEN = 0x81,

	
	FILEID_INO64_GEN_PARENT = 0x82,

	
	FILEID_LUSTRE = 0x97,

	
	FILEID_BCACHEFS_WITHOUT_PARENT = 0xb1,
	FILEID_BCACHEFS_WITH_PARENT = 0xb2,

	
	FILEID_NSFS = 0xf1,

	
	FILEID_KERNFS = 0xfe,

	
	FILEID_INVALID = 0xff,
};

struct fid {
	union {
		struct {
			u32 ino;
			u32 gen;
			u32 parent_ino;
			u32 parent_gen;
		} i32;
		struct {
			u64 ino;
			u32 gen;
		} __packed i64;
		struct {
 			u32 block;
 			u16 partref;
 			u16 parent_partref;
 			u32 generation;
 			u32 parent_block;
 			u32 parent_generation;
 		} udf;
		DECLARE_FLEX_ARRAY(__u32, raw);
	};
};

enum handle_to_path_flags {
	HANDLE_CHECK_PERMS   = (1 << 0),
	HANDLE_CHECK_SUBTREE = (1 << 1),
};

struct handle_to_path_ctx {
	struct path root;
	enum handle_to_path_flags flags;
	unsigned int fh_flags;
};

#define EXPORT_FH_CONNECTABLE	0x1 
#define EXPORT_FH_FID		0x2 
#define EXPORT_FH_DIR_ONLY	0x4 


#define FILEID_USER_FLAGS_MASK	0xffff0000
#define FILEID_USER_FLAGS(type) ((type) & FILEID_USER_FLAGS_MASK)


#define FILEID_IS_CONNECTABLE	0x10000
#define FILEID_IS_DIR		0x20000
#define FILEID_VALID_USER_FLAGS	(FILEID_IS_CONNECTABLE | FILEID_IS_DIR)



struct export_operations {
	int (*encode_fh)(struct inode *inode, __u32 *fh, int *max_len,
			struct inode *parent);
	struct dentry * (*fh_to_dentry)(struct super_block *sb, struct fid *fid,
			int fh_len, int fh_type);
	struct dentry * (*fh_to_parent)(struct super_block *sb, struct fid *fid,
			int fh_len, int fh_type);
	int (*get_name)(struct dentry *parent, char *name,
			struct dentry *child);
	struct dentry * (*get_parent)(struct dentry *child);
	int (*commit_metadata)(struct inode *inode);

	int (*get_uuid)(struct super_block *sb, u8 *buf, u32 *len, u64 *offset);
	int (*map_blocks)(struct inode *inode, loff_t offset,
			  u64 len, struct iomap *iomap,
			  bool write, u32 *device_generation);
	int (*commit_blocks)(struct inode *inode, struct iomap *iomaps,
			     int nr_iomaps, struct iattr *iattr);
	int (*permission)(struct handle_to_path_ctx *ctx, unsigned int oflags);
	struct file * (*open)(const struct path *path, unsigned int oflags);
#define	EXPORT_OP_NOWCC			(0x1) 
#define	EXPORT_OP_NOSUBTREECHK		(0x2) 
#define	EXPORT_OP_CLOSE_BEFORE_UNLINK	(0x4) 
#define EXPORT_OP_REMOTE_FS		(0x8) 
#define EXPORT_OP_NOATOMIC_ATTR		(0x10) 
#define EXPORT_OP_FLUSH_ON_CLOSE	(0x20) 
#define EXPORT_OP_NOLOCKS		(0x40) 
	unsigned long	flags;
};


static inline bool
exportfs_cannot_lock(const struct export_operations *export_ops)
{
	return export_ops->flags & EXPORT_OP_NOLOCKS;
}

extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
				    int *max_len, struct inode *parent,
				    int flags);
extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
			      int *max_len, int flags);

static inline bool exportfs_can_encode_fid(const struct export_operations *nop)
{
	return !nop || nop->encode_fh;
}

static inline bool exportfs_can_decode_fh(const struct export_operations *nop)
{
	return nop && nop->fh_to_dentry;
}

static inline bool exportfs_may_export(const struct export_operations *nop)
{
	
	return exportfs_can_decode_fh(nop) && !nop->open && !nop->permission;
}

static inline bool exportfs_can_encode_fh(const struct export_operations *nop,
					  int fh_flags)
{
	
	if (fh_flags & EXPORT_FH_FID)
		return exportfs_can_encode_fid(nop);

	
	if (!nop)
		return false;

	
	if ((fh_flags & EXPORT_FH_CONNECTABLE) && !nop->fh_to_parent)
		return false;

	
	return exportfs_can_decode_fh(nop);
}

static inline int exportfs_encode_fid(struct inode *inode, struct fid *fid,
				      int *max_len)
{
	return exportfs_encode_inode_fh(inode, fid, max_len, NULL,
					EXPORT_FH_FID);
}

extern struct dentry *exportfs_decode_fh_raw(struct vfsmount *mnt,
					     struct fid *fid, int fh_len,
					     int fileid_type,
					     unsigned int flags,
					     int (*acceptable)(void *, struct dentry *),
					     void *context);
extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
	int fh_len, int fileid_type, int (*acceptable)(void *, struct dentry *),
	void *context);


int generic_encode_ino32_fh(struct inode *inode, __u32 *fh, int *max_len,
			    struct inode *parent);
struct dentry *generic_fh_to_dentry(struct super_block *sb,
	struct fid *fid, int fh_len, int fh_type,
	struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen));
struct dentry *generic_fh_to_parent(struct super_block *sb,
	struct fid *fid, int fh_len, int fh_type,
	struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen));

#endif 
