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 | |
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')
-rw-r--r-- | fs/xfs/Makefile | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_format.h | 42 | ||||
-rw-r--r-- | fs/xfs/xfs_symlink.c | 172 | ||||
-rw-r--r-- | fs/xfs/xfs_symlink.h | 42 | ||||
-rw-r--r-- | fs/xfs/xfs_symlink_remote.c | 199 |
5 files changed, 244 insertions, 214 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index a73af1c8f978..20b1d949b090 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile | |||
@@ -50,6 +50,7 @@ xfs-y += xfs_aops.o \ | |||
50 | xfs_mru_cache.o \ | 50 | xfs_mru_cache.o \ |
51 | xfs_rename.o \ | 51 | xfs_rename.o \ |
52 | xfs_super.o \ | 52 | xfs_super.o \ |
53 | xfs_symlink.o \ | ||
53 | xfs_trans.o \ | 54 | xfs_trans.o \ |
54 | xfs_utils.o \ | 55 | xfs_utils.o \ |
55 | xfs_vnodeops.o \ | 56 | xfs_vnodeops.o \ |
@@ -81,7 +82,7 @@ xfs-y += xfs_alloc.o \ | |||
81 | xfs_inode_buf.o \ | 82 | xfs_inode_buf.o \ |
82 | xfs_log_recover.o \ | 83 | xfs_log_recover.o \ |
83 | xfs_mount.o \ | 84 | xfs_mount.o \ |
84 | xfs_symlink.o \ | 85 | xfs_symlink_remote.o \ |
85 | xfs_trans_resv.o | 86 | xfs_trans_resv.o |
86 | 87 | ||
87 | # low-level transaction/log code | 88 | # low-level transaction/log code |
diff --git a/fs/xfs/xfs_format.h b/fs/xfs/xfs_format.h index 62053744a0a6..35c08ff54ca0 100644 --- a/fs/xfs/xfs_format.h +++ b/fs/xfs/xfs_format.h | |||
@@ -27,6 +27,12 @@ | |||
27 | * xfs_log_format.h. Everything else goes here. | 27 | * xfs_log_format.h. Everything else goes here. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | struct xfs_mount; | ||
31 | struct xfs_trans; | ||
32 | struct xfs_inode; | ||
33 | struct xfs_buf; | ||
34 | struct xfs_ifork; | ||
35 | |||
30 | /* | 36 | /* |
31 | * RealTime Device format definitions | 37 | * RealTime Device format definitions |
32 | */ | 38 | */ |
@@ -123,5 +129,41 @@ typedef struct xfs_dqblk { | |||
123 | 129 | ||
124 | #define XFS_DQUOT_CRC_OFF offsetof(struct xfs_dqblk, dd_crc) | 130 | #define XFS_DQUOT_CRC_OFF offsetof(struct xfs_dqblk, dd_crc) |
125 | 131 | ||
132 | /* | ||
133 | * Remote symlink format and access functions. | ||
134 | */ | ||
135 | #define XFS_SYMLINK_MAGIC 0x58534c4d /* XSLM */ | ||
136 | |||
137 | struct xfs_dsymlink_hdr { | ||
138 | __be32 sl_magic; | ||
139 | __be32 sl_offset; | ||
140 | __be32 sl_bytes; | ||
141 | __be32 sl_crc; | ||
142 | uuid_t sl_uuid; | ||
143 | __be64 sl_owner; | ||
144 | __be64 sl_blkno; | ||
145 | __be64 sl_lsn; | ||
146 | }; | ||
147 | |||
148 | /* | ||
149 | * The maximum pathlen is 1024 bytes. Since the minimum file system | ||
150 | * blocksize is 512 bytes, we can get a max of 3 extents back from | ||
151 | * bmapi when crc headers are taken into account. | ||
152 | */ | ||
153 | #define XFS_SYMLINK_MAPS 3 | ||
154 | |||
155 | #define XFS_SYMLINK_BUF_SPACE(mp, bufsize) \ | ||
156 | ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ | ||
157 | sizeof(struct xfs_dsymlink_hdr) : 0)) | ||
158 | |||
159 | int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen); | ||
160 | int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, | ||
161 | uint32_t size, struct xfs_buf *bp); | ||
162 | bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, | ||
163 | uint32_t size, struct xfs_buf *bp); | ||
164 | void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, | ||
165 | struct xfs_inode *ip, struct xfs_ifork *ifp); | ||
166 | |||
167 | extern const struct xfs_buf_ops xfs_symlink_buf_ops; | ||
126 | 168 | ||
127 | #endif /* __XFS_FORMAT_H__ */ | 169 | #endif /* __XFS_FORMAT_H__ */ |
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index dd7c0991fdb9..18f24de4dc2a 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c | |||
@@ -32,8 +32,6 @@ | |||
32 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
33 | #include "xfs_dinode.h" | 33 | #include "xfs_dinode.h" |
34 | #include "xfs_inode.h" | 34 | #include "xfs_inode.h" |
35 | #include "xfs_inode_item.h" | ||
36 | #include "xfs_itable.h" | ||
37 | #include "xfs_ialloc.h" | 35 | #include "xfs_ialloc.h" |
38 | #include "xfs_alloc.h" | 36 | #include "xfs_alloc.h" |
39 | #include "xfs_bmap.h" | 37 | #include "xfs_bmap.h" |
@@ -41,178 +39,8 @@ | |||
41 | #include "xfs_quota.h" | 39 | #include "xfs_quota.h" |
42 | #include "xfs_utils.h" | 40 | #include "xfs_utils.h" |
43 | #include "xfs_trans_space.h" | 41 | #include "xfs_trans_space.h" |
44 | #include "xfs_log_priv.h" | ||
45 | #include "xfs_trace.h" | 42 | #include "xfs_trace.h" |
46 | #include "xfs_symlink.h" | 43 | #include "xfs_symlink.h" |
47 | #include "xfs_cksum.h" | ||
48 | #include "xfs_buf_item.h" | ||
49 | |||
50 | |||
51 | /* | ||
52 | * Each contiguous block has a header, so it is not just a simple pathlen | ||
53 | * to FSB conversion. | ||
54 | */ | ||
55 | int | ||
56 | xfs_symlink_blocks( | ||
57 | struct xfs_mount *mp, | ||
58 | int pathlen) | ||
59 | { | ||
60 | int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize); | ||
61 | |||
62 | return (pathlen + buflen - 1) / buflen; | ||
63 | } | ||
64 | |||
65 | static int | ||
66 | xfs_symlink_hdr_set( | ||
67 | struct xfs_mount *mp, | ||
68 | xfs_ino_t ino, | ||
69 | uint32_t offset, | ||
70 | uint32_t size, | ||
71 | struct xfs_buf *bp) | ||
72 | { | ||
73 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
74 | |||
75 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
76 | return 0; | ||
77 | |||
78 | dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC); | ||
79 | dsl->sl_offset = cpu_to_be32(offset); | ||
80 | dsl->sl_bytes = cpu_to_be32(size); | ||
81 | uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid); | ||
82 | dsl->sl_owner = cpu_to_be64(ino); | ||
83 | dsl->sl_blkno = cpu_to_be64(bp->b_bn); | ||
84 | bp->b_ops = &xfs_symlink_buf_ops; | ||
85 | |||
86 | return sizeof(struct xfs_dsymlink_hdr); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Checking of the symlink header is split into two parts. the verifier does | ||
91 | * CRC, location and bounds checking, the unpacking function checks the path | ||
92 | * parameters and owner. | ||
93 | */ | ||
94 | bool | ||
95 | xfs_symlink_hdr_ok( | ||
96 | struct xfs_mount *mp, | ||
97 | xfs_ino_t ino, | ||
98 | uint32_t offset, | ||
99 | uint32_t size, | ||
100 | struct xfs_buf *bp) | ||
101 | { | ||
102 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
103 | |||
104 | if (offset != be32_to_cpu(dsl->sl_offset)) | ||
105 | return false; | ||
106 | if (size != be32_to_cpu(dsl->sl_bytes)) | ||
107 | return false; | ||
108 | if (ino != be64_to_cpu(dsl->sl_owner)) | ||
109 | return false; | ||
110 | |||
111 | /* ok */ | ||
112 | return true; | ||
113 | } | ||
114 | |||
115 | static bool | ||
116 | xfs_symlink_verify( | ||
117 | struct xfs_buf *bp) | ||
118 | { | ||
119 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
120 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
121 | |||
122 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
123 | return false; | ||
124 | if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC)) | ||
125 | return false; | ||
126 | if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid)) | ||
127 | return false; | ||
128 | if (bp->b_bn != be64_to_cpu(dsl->sl_blkno)) | ||
129 | return false; | ||
130 | if (be32_to_cpu(dsl->sl_offset) + | ||
131 | be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN) | ||
132 | return false; | ||
133 | if (dsl->sl_owner == 0) | ||
134 | return false; | ||
135 | |||
136 | return true; | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | xfs_symlink_read_verify( | ||
141 | struct xfs_buf *bp) | ||
142 | { | ||
143 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
144 | |||
145 | /* no verification of non-crc buffers */ | ||
146 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
147 | return; | ||
148 | |||
149 | if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
150 | offsetof(struct xfs_dsymlink_hdr, sl_crc)) || | ||
151 | !xfs_symlink_verify(bp)) { | ||
152 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
153 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static void | ||
158 | xfs_symlink_write_verify( | ||
159 | struct xfs_buf *bp) | ||
160 | { | ||
161 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
162 | struct xfs_buf_log_item *bip = bp->b_fspriv; | ||
163 | |||
164 | /* no verification of non-crc buffers */ | ||
165 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
166 | return; | ||
167 | |||
168 | if (!xfs_symlink_verify(bp)) { | ||
169 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
170 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
171 | return; | ||
172 | } | ||
173 | |||
174 | if (bip) { | ||
175 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
176 | dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn); | ||
177 | } | ||
178 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
179 | offsetof(struct xfs_dsymlink_hdr, sl_crc)); | ||
180 | } | ||
181 | |||
182 | const struct xfs_buf_ops xfs_symlink_buf_ops = { | ||
183 | .verify_read = xfs_symlink_read_verify, | ||
184 | .verify_write = xfs_symlink_write_verify, | ||
185 | }; | ||
186 | |||
187 | void | ||
188 | xfs_symlink_local_to_remote( | ||
189 | struct xfs_trans *tp, | ||
190 | struct xfs_buf *bp, | ||
191 | struct xfs_inode *ip, | ||
192 | struct xfs_ifork *ifp) | ||
193 | { | ||
194 | struct xfs_mount *mp = ip->i_mount; | ||
195 | char *buf; | ||
196 | |||
197 | if (!xfs_sb_version_hascrc(&mp->m_sb)) { | ||
198 | bp->b_ops = NULL; | ||
199 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | ||
200 | return; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * As this symlink fits in an inode literal area, it must also fit in | ||
205 | * the smallest buffer the filesystem supports. | ||
206 | */ | ||
207 | ASSERT(BBTOB(bp->b_length) >= | ||
208 | ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr)); | ||
209 | |||
210 | bp->b_ops = &xfs_symlink_buf_ops; | ||
211 | |||
212 | buf = bp->b_addr; | ||
213 | buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); | ||
214 | memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); | ||
215 | } | ||
216 | 44 | ||
217 | /* ----- Kernel only functions below ----- */ | 45 | /* ----- Kernel only functions below ----- */ |
218 | STATIC int | 46 | STATIC int |
diff --git a/fs/xfs/xfs_symlink.h b/fs/xfs/xfs_symlink.h index c8e3a02f0344..99338ba666ac 100644 --- a/fs/xfs/xfs_symlink.h +++ b/fs/xfs/xfs_symlink.h | |||
@@ -17,51 +17,11 @@ | |||
17 | #ifndef __XFS_SYMLINK_H | 17 | #ifndef __XFS_SYMLINK_H |
18 | #define __XFS_SYMLINK_H 1 | 18 | #define __XFS_SYMLINK_H 1 |
19 | 19 | ||
20 | struct xfs_mount; | 20 | /* Kernel only symlink defintions */ |
21 | struct xfs_trans; | ||
22 | struct xfs_inode; | ||
23 | struct xfs_buf; | ||
24 | struct xfs_ifork; | ||
25 | struct xfs_name; | ||
26 | |||
27 | #define XFS_SYMLINK_MAGIC 0x58534c4d /* XSLM */ | ||
28 | |||
29 | struct xfs_dsymlink_hdr { | ||
30 | __be32 sl_magic; | ||
31 | __be32 sl_offset; | ||
32 | __be32 sl_bytes; | ||
33 | __be32 sl_crc; | ||
34 | uuid_t sl_uuid; | ||
35 | __be64 sl_owner; | ||
36 | __be64 sl_blkno; | ||
37 | __be64 sl_lsn; | ||
38 | }; | ||
39 | |||
40 | /* | ||
41 | * The maximum pathlen is 1024 bytes. Since the minimum file system | ||
42 | * blocksize is 512 bytes, we can get a max of 3 extents back from | ||
43 | * bmapi when crc headers are taken into account. | ||
44 | */ | ||
45 | #define XFS_SYMLINK_MAPS 3 | ||
46 | |||
47 | #define XFS_SYMLINK_BUF_SPACE(mp, bufsize) \ | ||
48 | ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ | ||
49 | sizeof(struct xfs_dsymlink_hdr) : 0)) | ||
50 | |||
51 | int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen); | ||
52 | bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, | ||
53 | uint32_t size, struct xfs_buf *bp); | ||
54 | void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, | ||
55 | struct xfs_inode *ip, struct xfs_ifork *ifp); | ||
56 | |||
57 | extern const struct xfs_buf_ops xfs_symlink_buf_ops; | ||
58 | |||
59 | #ifdef __KERNEL__ | ||
60 | 21 | ||
61 | int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, | 22 | int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, |
62 | const char *target_path, umode_t mode, struct xfs_inode **ipp); | 23 | const char *target_path, umode_t mode, struct xfs_inode **ipp); |
63 | int xfs_readlink(struct xfs_inode *ip, char *link); | 24 | int xfs_readlink(struct xfs_inode *ip, char *link); |
64 | int xfs_inactive_symlink(struct xfs_inode *ip, struct xfs_trans **tpp); | 25 | int xfs_inactive_symlink(struct xfs_inode *ip, struct xfs_trans **tpp); |
65 | 26 | ||
66 | #endif /* __KERNEL__ */ | ||
67 | #endif /* __XFS_SYMLINK_H */ | 27 | #endif /* __XFS_SYMLINK_H */ |
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 | } | ||