ovl: encode pure upper file handles
[linux-2.6-microblaze.git] / fs / overlayfs / export.c
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
22 static 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
50 out:
51         kfree(fh);
52         return err;
53
54 fail:
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
61 static 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
76 static 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
96 const struct export_operations ovl_export_operations = {
97         .encode_fh      = ovl_encode_inode_fh,
98 };