ovl: encode pure upper file handles
[linux-block.git] / fs / overlayfs / export.c
CommitLineData
8ed5eec9
AG
1/*
2 * Overlayfs NFS export support.
3 *
4 * Amir Goldstein <amir73il@gmail.com>
5 *
6 * Copyright (C) 2017-2018 CTERA Networks. All Rights Reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 */
12
13#include <linux/fs.h>
14#include <linux/cred.h>
15#include <linux/mount.h>
16#include <linux/namei.h>
17#include <linux/xattr.h>
18#include <linux/exportfs.h>
19#include <linux/ratelimit.h>
20#include "overlayfs.h"
21
22static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
23{
24 struct dentry *upper = ovl_dentry_upper(dentry);
25 struct dentry *origin = ovl_dentry_lower(dentry);
26 struct ovl_fh *fh = NULL;
27 int err;
28
29 /*
30 * On overlay with an upper layer, overlay root inode is encoded as
31 * an upper file handle, because upper root dir is not indexed.
32 */
33 if (dentry == dentry->d_sb->s_root && upper)
34 origin = NULL;
35
36 err = -EACCES;
37 if (!upper || origin)
38 goto fail;
39
40 /* TODO: encode non pure-upper by origin */
41 fh = ovl_encode_fh(upper, true);
42
43 err = -EOVERFLOW;
44 if (fh->len > buflen)
45 goto fail;
46
47 memcpy(buf, (char *)fh, fh->len);
48 err = fh->len;
49
50out:
51 kfree(fh);
52 return err;
53
54fail:
55 pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n",
56 dentry, err, buflen, fh ? (int)fh->len : 0,
57 fh ? fh->type : 0);
58 goto out;
59}
60
61static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len)
62{
63 int res, len = *max_len << 2;
64
65 res = ovl_d_to_fh(dentry, (char *)fid, len);
66 if (res <= 0)
67 return FILEID_INVALID;
68
69 len = res;
70
71 /* Round up to dwords */
72 *max_len = (len + 3) >> 2;
73 return OVL_FILEID;
74}
75
76static int ovl_encode_inode_fh(struct inode *inode, u32 *fid, int *max_len,
77 struct inode *parent)
78{
79 struct dentry *dentry;
80 int type;
81
82 /* TODO: encode connectable file handles */
83 if (parent)
84 return FILEID_INVALID;
85
86 dentry = d_find_any_alias(inode);
87 if (WARN_ON(!dentry))
88 return FILEID_INVALID;
89
90 type = ovl_dentry_to_fh(dentry, fid, max_len);
91
92 dput(dentry);
93 return type;
94}
95
96const struct export_operations ovl_export_operations = {
97 .encode_fh = ovl_encode_inode_fh,
98};