diff options
author | Dave Chinner <dchinner@redhat.com> | 2013-08-12 06:49:40 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2013-08-12 17:43:38 -0400 |
commit | 1fb7e48db6810093012873a652062648ace6b5bb (patch) | |
tree | 7ca9cf8073d2768fbbb44299299dd222efaf3b48 /fs/xfs/xfs_symlink_remote.c | |
parent | fde2227ce12b6d3e1945bd512da2a4a333331a2c (diff) |
xfs: split out the remote symlink handling
The remote symlink format definition and manipulation needs to be
shared with userspace, but the in-kernel interfaces do not. Split
the remote symlink format handling out into xfs_symlink_remote.[ch]
fo it can easily be shared with userspace.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_symlink_remote.c')
-rw-r--r-- | fs/xfs/xfs_symlink_remote.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/fs/xfs/xfs_symlink_remote.c b/fs/xfs/xfs_symlink_remote.c new file mode 100644 index 000000000000..a31852471885 --- /dev/null +++ b/fs/xfs/xfs_symlink_remote.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. | ||
3 | * Copyright (c) 2012-2013 Red Hat, Inc. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it would be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write the Free Software Foundation, | ||
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | #include "xfs.h" | ||
20 | #include "xfs_fs.h" | ||
21 | #include "xfs_format.h" | ||
22 | #include "xfs_log.h" | ||
23 | #include "xfs_trans.h" | ||
24 | #include "xfs_sb.h" | ||
25 | #include "xfs_mount.h" | ||
26 | #include "xfs_bmap_btree.h" | ||
27 | #include "xfs_inode.h" | ||
28 | #include "xfs_error.h" | ||
29 | #include "xfs_trace.h" | ||
30 | #include "xfs_symlink.h" | ||
31 | #include "xfs_cksum.h" | ||
32 | #include "xfs_buf_item.h" | ||
33 | |||
34 | |||
35 | /* | ||
36 | * Each contiguous block has a header, so it is not just a simple pathlen | ||
37 | * to FSB conversion. | ||
38 | */ | ||
39 | int | ||
40 | xfs_symlink_blocks( | ||
41 | struct xfs_mount *mp, | ||
42 | int pathlen) | ||
43 | { | ||
44 | int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize); | ||
45 | |||
46 | return (pathlen + buflen - 1) / buflen; | ||
47 | } | ||
48 | |||
49 | int | ||
50 | xfs_symlink_hdr_set( | ||
51 | struct xfs_mount *mp, | ||
52 | xfs_ino_t ino, | ||
53 | uint32_t offset, | ||
54 | uint32_t size, | ||
55 | struct xfs_buf *bp) | ||
56 | { | ||
57 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
58 | |||
59 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
60 | return 0; | ||
61 | |||
62 | dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC); | ||
63 | dsl->sl_offset = cpu_to_be32(offset); | ||
64 | dsl->sl_bytes = cpu_to_be32(size); | ||
65 | uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid); | ||
66 | dsl->sl_owner = cpu_to_be64(ino); | ||
67 | dsl->sl_blkno = cpu_to_be64(bp->b_bn); | ||
68 | bp->b_ops = &xfs_symlink_buf_ops; | ||
69 | |||
70 | return sizeof(struct xfs_dsymlink_hdr); | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Checking of the symlink header is split into two parts. the verifier does | ||
75 | * CRC, location and bounds checking, the unpacking function checks the path | ||
76 | * parameters and owner. | ||
77 | */ | ||
78 | bool | ||
79 | xfs_symlink_hdr_ok( | ||
80 | struct xfs_mount *mp, | ||
81 | xfs_ino_t ino, | ||
82 | uint32_t offset, | ||
83 | uint32_t size, | ||
84 | struct xfs_buf *bp) | ||
85 | { | ||
86 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
87 | |||
88 | if (offset != be32_to_cpu(dsl->sl_offset)) | ||
89 | return false; | ||
90 | if (size != be32_to_cpu(dsl->sl_bytes)) | ||
91 | return false; | ||
92 | if (ino != be64_to_cpu(dsl->sl_owner)) | ||
93 | return false; | ||
94 | |||
95 | /* ok */ | ||
96 | return true; | ||
97 | } | ||
98 | |||
99 | static bool | ||
100 | xfs_symlink_verify( | ||
101 | struct xfs_buf *bp) | ||
102 | { | ||
103 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
104 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
105 | |||
106 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
107 | return false; | ||
108 | if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC)) | ||
109 | return false; | ||
110 | if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid)) | ||
111 | return false; | ||
112 | if (bp->b_bn != be64_to_cpu(dsl->sl_blkno)) | ||
113 | return false; | ||
114 | if (be32_to_cpu(dsl->sl_offset) + | ||
115 | be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN) | ||
116 | return false; | ||
117 | if (dsl->sl_owner == 0) | ||
118 | return false; | ||
119 | |||
120 | return true; | ||
121 | } | ||
122 | |||
123 | static void | ||
124 | xfs_symlink_read_verify( | ||
125 | struct xfs_buf *bp) | ||
126 | { | ||
127 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
128 | |||
129 | /* no verification of non-crc buffers */ | ||
130 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
131 | return; | ||
132 | |||
133 | if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
134 | offsetof(struct xfs_dsymlink_hdr, sl_crc)) || | ||
135 | !xfs_symlink_verify(bp)) { | ||
136 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
137 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | static void | ||
142 | xfs_symlink_write_verify( | ||
143 | struct xfs_buf *bp) | ||
144 | { | ||
145 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
146 | struct xfs_buf_log_item *bip = bp->b_fspriv; | ||
147 | |||
148 | /* no verification of non-crc buffers */ | ||
149 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
150 | return; | ||
151 | |||
152 | if (!xfs_symlink_verify(bp)) { | ||
153 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
154 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | if (bip) { | ||
159 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
160 | dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn); | ||
161 | } | ||
162 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
163 | offsetof(struct xfs_dsymlink_hdr, sl_crc)); | ||
164 | } | ||
165 | |||
166 | const struct xfs_buf_ops xfs_symlink_buf_ops = { | ||
167 | .verify_read = xfs_symlink_read_verify, | ||
168 | .verify_write = xfs_symlink_write_verify, | ||
169 | }; | ||
170 | |||
171 | void | ||
172 | xfs_symlink_local_to_remote( | ||
173 | struct xfs_trans *tp, | ||
174 | struct xfs_buf *bp, | ||
175 | struct xfs_inode *ip, | ||
176 | struct xfs_ifork *ifp) | ||
177 | { | ||
178 | struct xfs_mount *mp = ip->i_mount; | ||
179 | char *buf; | ||
180 | |||
181 | if (!xfs_sb_version_hascrc(&mp->m_sb)) { | ||
182 | bp->b_ops = NULL; | ||
183 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * As this symlink fits in an inode literal area, it must also fit in | ||
189 | * the smallest buffer the filesystem supports. | ||
190 | */ | ||
191 | ASSERT(BBTOB(bp->b_length) >= | ||
192 | ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr)); | ||
193 | |||
194 | bp->b_ops = &xfs_symlink_buf_ops; | ||
195 | |||
196 | buf = bp->b_addr; | ||
197 | buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); | ||
198 | memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); | ||
199 | } | ||