aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-08-12 06:49:40 -0400
committerBen Myers <bpm@sgi.com>2013-08-12 17:43:38 -0400
commit1fb7e48db6810093012873a652062648ace6b5bb (patch)
tree7ca9cf8073d2768fbbb44299299dd222efaf3b48 /fs/xfs
parentfde2227ce12b6d3e1945bd512da2a4a333331a2c (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/Makefile3
-rw-r--r--fs/xfs/xfs_format.h42
-rw-r--r--fs/xfs/xfs_symlink.c172
-rw-r--r--fs/xfs/xfs_symlink.h42
-rw-r--r--fs/xfs/xfs_symlink_remote.c199
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
30struct xfs_mount;
31struct xfs_trans;
32struct xfs_inode;
33struct xfs_buf;
34struct 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
137struct 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
159int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen);
160int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
161 uint32_t size, struct xfs_buf *bp);
162bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
163 uint32_t size, struct xfs_buf *bp);
164void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
165 struct xfs_inode *ip, struct xfs_ifork *ifp);
166
167extern 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 */
55int
56xfs_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
65static int
66xfs_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 */
94bool
95xfs_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
115static bool
116xfs_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
139static void
140xfs_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
157static void
158xfs_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
182const struct xfs_buf_ops xfs_symlink_buf_ops = {
183 .verify_read = xfs_symlink_read_verify,
184 .verify_write = xfs_symlink_write_verify,
185};
186
187void
188xfs_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 ----- */
218STATIC int 46STATIC 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
20struct xfs_mount; 20/* Kernel only symlink defintions */
21struct xfs_trans;
22struct xfs_inode;
23struct xfs_buf;
24struct xfs_ifork;
25struct xfs_name;
26
27#define XFS_SYMLINK_MAGIC 0x58534c4d /* XSLM */
28
29struct 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
51int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen);
52bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
53 uint32_t size, struct xfs_buf *bp);
54void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
55 struct xfs_inode *ip, struct xfs_ifork *ifp);
56
57extern const struct xfs_buf_ops xfs_symlink_buf_ops;
58
59#ifdef __KERNEL__
60 21
61int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, 22int 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);
63int xfs_readlink(struct xfs_inode *ip, char *link); 24int xfs_readlink(struct xfs_inode *ip, char *link);
64int xfs_inactive_symlink(struct xfs_inode *ip, struct xfs_trans **tpp); 25int 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 */
39int
40xfs_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
49int
50xfs_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 */
78bool
79xfs_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
99static bool
100xfs_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
123static void
124xfs_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
141static void
142xfs_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
166const struct xfs_buf_ops xfs_symlink_buf_ops = {
167 .verify_read = xfs_symlink_read_verify,
168 .verify_write = xfs_symlink_write_verify,
169};
170
171void
172xfs_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}