diff options
author | Amir Goldstein <amir73il@gmail.com> | 2017-07-12 07:17:16 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-01-24 05:25:59 -0500 |
commit | 8ed5eec9d6c4c013aa657ebefbd10a1a0d15893d (patch) | |
tree | 634ea6f80f9212f0d81c846145a8b260f2c6d34a | |
parent | a01f64b5c06ca1130b0b72ceb5e2a25e4d37ab08 (diff) |
ovl: encode pure upper file handles
Encode overlay file handles as struct ovl_fh containing the file handle
encoding of the real upper inode.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r-- | fs/overlayfs/Makefile | 3 | ||||
-rw-r--r-- | fs/overlayfs/export.c | 98 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 6 |
3 files changed, 106 insertions, 1 deletions
diff --git a/fs/overlayfs/Makefile b/fs/overlayfs/Makefile index 99373bbc1478..30802347a020 100644 --- a/fs/overlayfs/Makefile +++ b/fs/overlayfs/Makefile | |||
@@ -4,4 +4,5 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_OVERLAY_FS) += overlay.o | 5 | obj-$(CONFIG_OVERLAY_FS) += overlay.o |
6 | 6 | ||
7 | overlay-objs := super.o namei.o util.o inode.o dir.o readdir.o copy_up.o | 7 | overlay-objs := super.o namei.o util.o inode.o dir.o readdir.o copy_up.o \ |
8 | export.o | ||
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c new file mode 100644 index 000000000000..67b907ca9cdc --- /dev/null +++ b/fs/overlayfs/export.c | |||
@@ -0,0 +1,98 @@ | |||
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 | }; | ||
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 2dddcd257eb3..f2baa2ccaacd 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
@@ -68,6 +68,9 @@ enum ovl_entry_flag { | |||
68 | #error Endianness not defined | 68 | #error Endianness not defined |
69 | #endif | 69 | #endif |
70 | 70 | ||
71 | /* The type returned by overlay exportfs ops when encoding an ovl_fh handle */ | ||
72 | #define OVL_FILEID 0xfb | ||
73 | |||
71 | /* On-disk and in-memeory format for redirect by file handle */ | 74 | /* On-disk and in-memeory format for redirect by file handle */ |
72 | struct ovl_fh { | 75 | struct ovl_fh { |
73 | u8 version; /* 0 */ | 76 | u8 version; /* 0 */ |
@@ -351,3 +354,6 @@ int ovl_set_attr(struct dentry *upper, struct kstat *stat); | |||
351 | struct ovl_fh *ovl_encode_fh(struct dentry *real, bool is_upper); | 354 | struct ovl_fh *ovl_encode_fh(struct dentry *real, bool is_upper); |
352 | int ovl_set_origin(struct dentry *dentry, struct dentry *lower, | 355 | int ovl_set_origin(struct dentry *dentry, struct dentry *lower, |
353 | struct dentry *upper); | 356 | struct dentry *upper); |
357 | |||
358 | /* export.c */ | ||
359 | extern const struct export_operations ovl_export_operations; | ||