]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/openzfs/module/os/linux/zfs/zpl_export.c
ZFS: MFV 2.0-rc1-ga00c61
[FreeBSD/FreeBSD.git] / sys / contrib / openzfs / module / os / linux / zfs / zpl_export.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2011 Gunnar Beutner
23  * Copyright (c) 2012 Cyril Plisko. All rights reserved.
24  */
25
26
27 #include <sys/zfs_znode.h>
28 #include <sys/zfs_vnops.h>
29 #include <sys/zfs_ctldir.h>
30 #include <sys/zpl.h>
31
32
33 static int
34 #ifdef HAVE_ENCODE_FH_WITH_INODE
35 zpl_encode_fh(struct inode *ip, __u32 *fh, int *max_len, struct inode *parent)
36 {
37 #else
38 zpl_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, int connectable)
39 {
40         /* CSTYLED */
41         struct inode *ip = dentry->d_inode;
42 #endif /* HAVE_ENCODE_FH_WITH_INODE */
43         fstrans_cookie_t cookie;
44         fid_t *fid = (fid_t *)fh;
45         int len_bytes, rc;
46
47         len_bytes = *max_len * sizeof (__u32);
48
49         if (len_bytes < offsetof(fid_t, fid_data))
50                 return (255);
51
52         fid->fid_len = len_bytes - offsetof(fid_t, fid_data);
53         cookie = spl_fstrans_mark();
54
55         if (zfsctl_is_node(ip))
56                 rc = zfsctl_fid(ip, fid);
57         else
58                 rc = zfs_fid(ip, fid);
59
60         spl_fstrans_unmark(cookie);
61         len_bytes = offsetof(fid_t, fid_data) + fid->fid_len;
62         *max_len = roundup(len_bytes, sizeof (__u32)) / sizeof (__u32);
63
64         return (rc == 0 ? FILEID_INO32_GEN : 255);
65 }
66
67 static struct dentry *
68 zpl_fh_to_dentry(struct super_block *sb, struct fid *fh,
69     int fh_len, int fh_type)
70 {
71         fid_t *fid = (fid_t *)fh;
72         fstrans_cookie_t cookie;
73         struct inode *ip;
74         int len_bytes, rc;
75
76         len_bytes = fh_len * sizeof (__u32);
77
78         if (fh_type != FILEID_INO32_GEN ||
79             len_bytes < offsetof(fid_t, fid_data) ||
80             len_bytes < offsetof(fid_t, fid_data) + fid->fid_len)
81                 return (ERR_PTR(-EINVAL));
82
83         cookie = spl_fstrans_mark();
84         rc = zfs_vget(sb, &ip, fid);
85         spl_fstrans_unmark(cookie);
86
87         if (rc) {
88                 /*
89                  * If we see ENOENT it might mean that an NFSv4 * client
90                  * is using a cached inode value in a file handle and
91                  * that the sought after file has had its inode changed
92                  * by a third party.  So change the error to ESTALE
93                  * which will trigger a full lookup by the client and
94                  * will find the new filename/inode pair if it still
95                  * exists.
96                  */
97                 if (rc == ENOENT)
98                         rc = ESTALE;
99
100                 return (ERR_PTR(-rc));
101         }
102
103         ASSERT((ip != NULL) && !IS_ERR(ip));
104
105         return (d_obtain_alias(ip));
106 }
107
108 static struct dentry *
109 zpl_get_parent(struct dentry *child)
110 {
111         cred_t *cr = CRED();
112         fstrans_cookie_t cookie;
113         znode_t *zp;
114         int error;
115
116         crhold(cr);
117         cookie = spl_fstrans_mark();
118         error = -zfs_lookup(ITOZ(child->d_inode), "..", &zp, 0, cr, NULL, NULL);
119         spl_fstrans_unmark(cookie);
120         crfree(cr);
121         ASSERT3S(error, <=, 0);
122
123         if (error)
124                 return (ERR_PTR(error));
125
126         return (d_obtain_alias(ZTOI(zp)));
127 }
128
129 static int
130 zpl_commit_metadata(struct inode *inode)
131 {
132         cred_t *cr = CRED();
133         fstrans_cookie_t cookie;
134         int error;
135
136         if (zfsctl_is_node(inode))
137                 return (0);
138
139         crhold(cr);
140         cookie = spl_fstrans_mark();
141         error = -zfs_fsync(ITOZ(inode), 0, cr);
142         spl_fstrans_unmark(cookie);
143         crfree(cr);
144         ASSERT3S(error, <=, 0);
145
146         return (error);
147 }
148
149 const struct export_operations zpl_export_operations = {
150         .encode_fh              = zpl_encode_fh,
151         .fh_to_dentry           = zpl_fh_to_dentry,
152         .get_parent             = zpl_get_parent,
153         .commit_metadata        = zpl_commit_metadata,
154 };