1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2000-2006 Silicon Graphics, Inc.
4*4882a593Smuzhiyun * Copyright (c) 2012-2013 Red Hat, Inc.
5*4882a593Smuzhiyun * All rights reserved.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include "xfs.h"
8*4882a593Smuzhiyun #include "xfs_shared.h"
9*4882a593Smuzhiyun #include "xfs_fs.h"
10*4882a593Smuzhiyun #include "xfs_format.h"
11*4882a593Smuzhiyun #include "xfs_log_format.h"
12*4882a593Smuzhiyun #include "xfs_trans_resv.h"
13*4882a593Smuzhiyun #include "xfs_bit.h"
14*4882a593Smuzhiyun #include "xfs_mount.h"
15*4882a593Smuzhiyun #include "xfs_dir2.h"
16*4882a593Smuzhiyun #include "xfs_inode.h"
17*4882a593Smuzhiyun #include "xfs_bmap.h"
18*4882a593Smuzhiyun #include "xfs_bmap_btree.h"
19*4882a593Smuzhiyun #include "xfs_quota.h"
20*4882a593Smuzhiyun #include "xfs_symlink.h"
21*4882a593Smuzhiyun #include "xfs_trans_space.h"
22*4882a593Smuzhiyun #include "xfs_trace.h"
23*4882a593Smuzhiyun #include "xfs_trans.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /* ----- Kernel only functions below ----- */
26*4882a593Smuzhiyun int
xfs_readlink_bmap_ilocked(struct xfs_inode * ip,char * link)27*4882a593Smuzhiyun xfs_readlink_bmap_ilocked(
28*4882a593Smuzhiyun struct xfs_inode *ip,
29*4882a593Smuzhiyun char *link)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun struct xfs_mount *mp = ip->i_mount;
32*4882a593Smuzhiyun struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
33*4882a593Smuzhiyun struct xfs_buf *bp;
34*4882a593Smuzhiyun xfs_daddr_t d;
35*4882a593Smuzhiyun char *cur_chunk;
36*4882a593Smuzhiyun int pathlen = ip->i_d.di_size;
37*4882a593Smuzhiyun int nmaps = XFS_SYMLINK_MAPS;
38*4882a593Smuzhiyun int byte_cnt;
39*4882a593Smuzhiyun int n;
40*4882a593Smuzhiyun int error = 0;
41*4882a593Smuzhiyun int fsblocks = 0;
42*4882a593Smuzhiyun int offset;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun fsblocks = xfs_symlink_blocks(mp, pathlen);
47*4882a593Smuzhiyun error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0);
48*4882a593Smuzhiyun if (error)
49*4882a593Smuzhiyun goto out;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun offset = 0;
52*4882a593Smuzhiyun for (n = 0; n < nmaps; n++) {
53*4882a593Smuzhiyun d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
54*4882a593Smuzhiyun byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun error = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0,
57*4882a593Smuzhiyun &bp, &xfs_symlink_buf_ops);
58*4882a593Smuzhiyun if (error)
59*4882a593Smuzhiyun return error;
60*4882a593Smuzhiyun byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
61*4882a593Smuzhiyun if (pathlen < byte_cnt)
62*4882a593Smuzhiyun byte_cnt = pathlen;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun cur_chunk = bp->b_addr;
65*4882a593Smuzhiyun if (xfs_sb_version_hascrc(&mp->m_sb)) {
66*4882a593Smuzhiyun if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
67*4882a593Smuzhiyun byte_cnt, bp)) {
68*4882a593Smuzhiyun error = -EFSCORRUPTED;
69*4882a593Smuzhiyun xfs_alert(mp,
70*4882a593Smuzhiyun "symlink header does not match required off/len/owner (0x%x/Ox%x,0x%llx)",
71*4882a593Smuzhiyun offset, byte_cnt, ip->i_ino);
72*4882a593Smuzhiyun xfs_buf_relse(bp);
73*4882a593Smuzhiyun goto out;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun cur_chunk += sizeof(struct xfs_dsymlink_hdr);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun memcpy(link + offset, cur_chunk, byte_cnt);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun pathlen -= byte_cnt;
83*4882a593Smuzhiyun offset += byte_cnt;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun xfs_buf_relse(bp);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun ASSERT(pathlen == 0);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun link[ip->i_d.di_size] = '\0';
90*4882a593Smuzhiyun error = 0;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun out:
93*4882a593Smuzhiyun return error;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun int
xfs_readlink(struct xfs_inode * ip,char * link)97*4882a593Smuzhiyun xfs_readlink(
98*4882a593Smuzhiyun struct xfs_inode *ip,
99*4882a593Smuzhiyun char *link)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun struct xfs_mount *mp = ip->i_mount;
102*4882a593Smuzhiyun xfs_fsize_t pathlen;
103*4882a593Smuzhiyun int error = 0;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun trace_xfs_readlink(ip);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun ASSERT(!(ip->i_df.if_flags & XFS_IFINLINE));
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if (XFS_FORCED_SHUTDOWN(mp))
110*4882a593Smuzhiyun return -EIO;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun xfs_ilock(ip, XFS_ILOCK_SHARED);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun pathlen = ip->i_d.di_size;
115*4882a593Smuzhiyun if (!pathlen)
116*4882a593Smuzhiyun goto out;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (pathlen < 0 || pathlen > XFS_SYMLINK_MAXLEN) {
119*4882a593Smuzhiyun xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
120*4882a593Smuzhiyun __func__, (unsigned long long) ip->i_ino,
121*4882a593Smuzhiyun (long long) pathlen);
122*4882a593Smuzhiyun ASSERT(0);
123*4882a593Smuzhiyun error = -EFSCORRUPTED;
124*4882a593Smuzhiyun goto out;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun error = xfs_readlink_bmap_ilocked(ip, link);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun out:
131*4882a593Smuzhiyun xfs_iunlock(ip, XFS_ILOCK_SHARED);
132*4882a593Smuzhiyun return error;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun int
xfs_symlink(struct xfs_inode * dp,struct xfs_name * link_name,const char * target_path,umode_t mode,struct xfs_inode ** ipp)136*4882a593Smuzhiyun xfs_symlink(
137*4882a593Smuzhiyun struct xfs_inode *dp,
138*4882a593Smuzhiyun struct xfs_name *link_name,
139*4882a593Smuzhiyun const char *target_path,
140*4882a593Smuzhiyun umode_t mode,
141*4882a593Smuzhiyun struct xfs_inode **ipp)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun struct xfs_mount *mp = dp->i_mount;
144*4882a593Smuzhiyun struct xfs_trans *tp = NULL;
145*4882a593Smuzhiyun struct xfs_inode *ip = NULL;
146*4882a593Smuzhiyun int error = 0;
147*4882a593Smuzhiyun int pathlen;
148*4882a593Smuzhiyun bool unlock_dp_on_error = false;
149*4882a593Smuzhiyun xfs_fileoff_t first_fsb;
150*4882a593Smuzhiyun xfs_filblks_t fs_blocks;
151*4882a593Smuzhiyun int nmaps;
152*4882a593Smuzhiyun struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
153*4882a593Smuzhiyun xfs_daddr_t d;
154*4882a593Smuzhiyun const char *cur_chunk;
155*4882a593Smuzhiyun int byte_cnt;
156*4882a593Smuzhiyun int n;
157*4882a593Smuzhiyun xfs_buf_t *bp;
158*4882a593Smuzhiyun prid_t prid;
159*4882a593Smuzhiyun struct xfs_dquot *udqp = NULL;
160*4882a593Smuzhiyun struct xfs_dquot *gdqp = NULL;
161*4882a593Smuzhiyun struct xfs_dquot *pdqp = NULL;
162*4882a593Smuzhiyun uint resblks;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun *ipp = NULL;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun trace_xfs_symlink(dp, link_name);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun if (XFS_FORCED_SHUTDOWN(mp))
169*4882a593Smuzhiyun return -EIO;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /*
172*4882a593Smuzhiyun * Check component lengths of the target path name.
173*4882a593Smuzhiyun */
174*4882a593Smuzhiyun pathlen = strlen(target_path);
175*4882a593Smuzhiyun if (pathlen >= XFS_SYMLINK_MAXLEN) /* total string too long */
176*4882a593Smuzhiyun return -ENAMETOOLONG;
177*4882a593Smuzhiyun ASSERT(pathlen > 0);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun prid = xfs_get_initial_prid(dp);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /*
182*4882a593Smuzhiyun * Make sure that we have allocated dquot(s) on disk.
183*4882a593Smuzhiyun */
184*4882a593Smuzhiyun error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
185*4882a593Smuzhiyun XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
186*4882a593Smuzhiyun &udqp, &gdqp, &pdqp);
187*4882a593Smuzhiyun if (error)
188*4882a593Smuzhiyun return error;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun * The symlink will fit into the inode data fork?
192*4882a593Smuzhiyun * There can't be any attributes so we get the whole variable part.
193*4882a593Smuzhiyun */
194*4882a593Smuzhiyun if (pathlen <= XFS_LITINO(mp))
195*4882a593Smuzhiyun fs_blocks = 0;
196*4882a593Smuzhiyun else
197*4882a593Smuzhiyun fs_blocks = xfs_symlink_blocks(mp, pathlen);
198*4882a593Smuzhiyun resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, resblks, 0, 0, &tp);
201*4882a593Smuzhiyun if (error)
202*4882a593Smuzhiyun goto out_release_inode;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
205*4882a593Smuzhiyun unlock_dp_on_error = true;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /*
208*4882a593Smuzhiyun * Check whether the directory allows new symlinks or not.
209*4882a593Smuzhiyun */
210*4882a593Smuzhiyun if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) {
211*4882a593Smuzhiyun error = -EPERM;
212*4882a593Smuzhiyun goto out_trans_cancel;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /*
216*4882a593Smuzhiyun * Reserve disk quota : blocks and inode.
217*4882a593Smuzhiyun */
218*4882a593Smuzhiyun error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
219*4882a593Smuzhiyun pdqp, resblks, 1, 0);
220*4882a593Smuzhiyun if (error)
221*4882a593Smuzhiyun goto out_trans_cancel;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /*
224*4882a593Smuzhiyun * Allocate an inode for the symlink.
225*4882a593Smuzhiyun */
226*4882a593Smuzhiyun error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
227*4882a593Smuzhiyun prid, &ip);
228*4882a593Smuzhiyun if (error)
229*4882a593Smuzhiyun goto out_trans_cancel;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /*
232*4882a593Smuzhiyun * Now we join the directory inode to the transaction. We do not do it
233*4882a593Smuzhiyun * earlier because xfs_dir_ialloc might commit the previous transaction
234*4882a593Smuzhiyun * (and release all the locks). An error from here on will result in
235*4882a593Smuzhiyun * the transaction cancel unlocking dp so don't do it explicitly in the
236*4882a593Smuzhiyun * error path.
237*4882a593Smuzhiyun */
238*4882a593Smuzhiyun xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
239*4882a593Smuzhiyun unlock_dp_on_error = false;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun /*
242*4882a593Smuzhiyun * Also attach the dquot(s) to it, if applicable.
243*4882a593Smuzhiyun */
244*4882a593Smuzhiyun xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun resblks -= XFS_IALLOC_SPACE_RES(mp);
247*4882a593Smuzhiyun /*
248*4882a593Smuzhiyun * If the symlink will fit into the inode, write it inline.
249*4882a593Smuzhiyun */
250*4882a593Smuzhiyun if (pathlen <= XFS_IFORK_DSIZE(ip)) {
251*4882a593Smuzhiyun xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun ip->i_d.di_size = pathlen;
254*4882a593Smuzhiyun ip->i_df.if_format = XFS_DINODE_FMT_LOCAL;
255*4882a593Smuzhiyun xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
256*4882a593Smuzhiyun } else {
257*4882a593Smuzhiyun int offset;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun first_fsb = 0;
260*4882a593Smuzhiyun nmaps = XFS_SYMLINK_MAPS;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks,
263*4882a593Smuzhiyun XFS_BMAPI_METADATA, resblks, mval, &nmaps);
264*4882a593Smuzhiyun if (error)
265*4882a593Smuzhiyun goto out_trans_cancel;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun resblks -= fs_blocks;
268*4882a593Smuzhiyun ip->i_d.di_size = pathlen;
269*4882a593Smuzhiyun xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun cur_chunk = target_path;
272*4882a593Smuzhiyun offset = 0;
273*4882a593Smuzhiyun for (n = 0; n < nmaps; n++) {
274*4882a593Smuzhiyun char *buf;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
277*4882a593Smuzhiyun byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
278*4882a593Smuzhiyun error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
279*4882a593Smuzhiyun BTOBB(byte_cnt), 0, &bp);
280*4882a593Smuzhiyun if (error)
281*4882a593Smuzhiyun goto out_trans_cancel;
282*4882a593Smuzhiyun bp->b_ops = &xfs_symlink_buf_ops;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
285*4882a593Smuzhiyun byte_cnt = min(byte_cnt, pathlen);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun buf = bp->b_addr;
288*4882a593Smuzhiyun buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset,
289*4882a593Smuzhiyun byte_cnt, bp);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun memcpy(buf, cur_chunk, byte_cnt);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun cur_chunk += byte_cnt;
294*4882a593Smuzhiyun pathlen -= byte_cnt;
295*4882a593Smuzhiyun offset += byte_cnt;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
298*4882a593Smuzhiyun xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
299*4882a593Smuzhiyun (char *)bp->b_addr);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun ASSERT(pathlen == 0);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun i_size_write(VFS_I(ip), ip->i_d.di_size);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun /*
306*4882a593Smuzhiyun * Create the directory entry for the symlink.
307*4882a593Smuzhiyun */
308*4882a593Smuzhiyun error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, resblks);
309*4882a593Smuzhiyun if (error)
310*4882a593Smuzhiyun goto out_trans_cancel;
311*4882a593Smuzhiyun xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
312*4882a593Smuzhiyun xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /*
315*4882a593Smuzhiyun * If this is a synchronous mount, make sure that the
316*4882a593Smuzhiyun * symlink transaction goes to disk before returning to
317*4882a593Smuzhiyun * the user.
318*4882a593Smuzhiyun */
319*4882a593Smuzhiyun if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
320*4882a593Smuzhiyun xfs_trans_set_sync(tp);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun error = xfs_trans_commit(tp);
324*4882a593Smuzhiyun if (error)
325*4882a593Smuzhiyun goto out_release_inode;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun xfs_qm_dqrele(udqp);
328*4882a593Smuzhiyun xfs_qm_dqrele(gdqp);
329*4882a593Smuzhiyun xfs_qm_dqrele(pdqp);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun *ipp = ip;
332*4882a593Smuzhiyun return 0;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun out_trans_cancel:
335*4882a593Smuzhiyun xfs_trans_cancel(tp);
336*4882a593Smuzhiyun out_release_inode:
337*4882a593Smuzhiyun /*
338*4882a593Smuzhiyun * Wait until after the current transaction is aborted to finish the
339*4882a593Smuzhiyun * setup of the inode and release the inode. This prevents recursive
340*4882a593Smuzhiyun * transactions and deadlocks from xfs_inactive.
341*4882a593Smuzhiyun */
342*4882a593Smuzhiyun if (ip) {
343*4882a593Smuzhiyun xfs_finish_inode_setup(ip);
344*4882a593Smuzhiyun xfs_irele(ip);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun xfs_qm_dqrele(udqp);
348*4882a593Smuzhiyun xfs_qm_dqrele(gdqp);
349*4882a593Smuzhiyun xfs_qm_dqrele(pdqp);
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun if (unlock_dp_on_error)
352*4882a593Smuzhiyun xfs_iunlock(dp, XFS_ILOCK_EXCL);
353*4882a593Smuzhiyun return error;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /*
357*4882a593Smuzhiyun * Free a symlink that has blocks associated with it.
358*4882a593Smuzhiyun *
359*4882a593Smuzhiyun * Note: zero length symlinks are not allowed to exist. When we set the size to
360*4882a593Smuzhiyun * zero, also change it to a regular file so that it does not get written to
361*4882a593Smuzhiyun * disk as a zero length symlink. The inode is on the unlinked list already, so
362*4882a593Smuzhiyun * userspace cannot find this inode anymore, so this change is not user visible
363*4882a593Smuzhiyun * but allows us to catch corrupt zero-length symlinks in the verifiers.
364*4882a593Smuzhiyun */
365*4882a593Smuzhiyun STATIC int
xfs_inactive_symlink_rmt(struct xfs_inode * ip)366*4882a593Smuzhiyun xfs_inactive_symlink_rmt(
367*4882a593Smuzhiyun struct xfs_inode *ip)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun xfs_buf_t *bp;
370*4882a593Smuzhiyun int done;
371*4882a593Smuzhiyun int error;
372*4882a593Smuzhiyun int i;
373*4882a593Smuzhiyun xfs_mount_t *mp;
374*4882a593Smuzhiyun xfs_bmbt_irec_t mval[XFS_SYMLINK_MAPS];
375*4882a593Smuzhiyun int nmaps;
376*4882a593Smuzhiyun int size;
377*4882a593Smuzhiyun xfs_trans_t *tp;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun mp = ip->i_mount;
380*4882a593Smuzhiyun ASSERT(ip->i_df.if_flags & XFS_IFEXTENTS);
381*4882a593Smuzhiyun /*
382*4882a593Smuzhiyun * We're freeing a symlink that has some
383*4882a593Smuzhiyun * blocks allocated to it. Free the
384*4882a593Smuzhiyun * blocks here. We know that we've got
385*4882a593Smuzhiyun * either 1 or 2 extents and that we can
386*4882a593Smuzhiyun * free them all in one bunmapi call.
387*4882a593Smuzhiyun */
388*4882a593Smuzhiyun ASSERT(ip->i_df.if_nextents > 0 && ip->i_df.if_nextents <= 2);
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
391*4882a593Smuzhiyun if (error)
392*4882a593Smuzhiyun return error;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun xfs_ilock(ip, XFS_ILOCK_EXCL);
395*4882a593Smuzhiyun xfs_trans_ijoin(tp, ip, 0);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun /*
398*4882a593Smuzhiyun * Lock the inode, fix the size, turn it into a regular file and join it
399*4882a593Smuzhiyun * to the transaction. Hold it so in the normal path, we still have it
400*4882a593Smuzhiyun * locked for the second transaction. In the error paths we need it
401*4882a593Smuzhiyun * held so the cancel won't rele it, see below.
402*4882a593Smuzhiyun */
403*4882a593Smuzhiyun size = (int)ip->i_d.di_size;
404*4882a593Smuzhiyun ip->i_d.di_size = 0;
405*4882a593Smuzhiyun VFS_I(ip)->i_mode = (VFS_I(ip)->i_mode & ~S_IFMT) | S_IFREG;
406*4882a593Smuzhiyun xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
407*4882a593Smuzhiyun /*
408*4882a593Smuzhiyun * Find the block(s) so we can inval and unmap them.
409*4882a593Smuzhiyun */
410*4882a593Smuzhiyun done = 0;
411*4882a593Smuzhiyun nmaps = ARRAY_SIZE(mval);
412*4882a593Smuzhiyun error = xfs_bmapi_read(ip, 0, xfs_symlink_blocks(mp, size),
413*4882a593Smuzhiyun mval, &nmaps, 0);
414*4882a593Smuzhiyun if (error)
415*4882a593Smuzhiyun goto error_trans_cancel;
416*4882a593Smuzhiyun /*
417*4882a593Smuzhiyun * Invalidate the block(s). No validation is done.
418*4882a593Smuzhiyun */
419*4882a593Smuzhiyun for (i = 0; i < nmaps; i++) {
420*4882a593Smuzhiyun error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
421*4882a593Smuzhiyun XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
422*4882a593Smuzhiyun XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0,
423*4882a593Smuzhiyun &bp);
424*4882a593Smuzhiyun if (error)
425*4882a593Smuzhiyun goto error_trans_cancel;
426*4882a593Smuzhiyun xfs_trans_binval(tp, bp);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun /*
429*4882a593Smuzhiyun * Unmap the dead block(s) to the dfops.
430*4882a593Smuzhiyun */
431*4882a593Smuzhiyun error = xfs_bunmapi(tp, ip, 0, size, 0, nmaps, &done);
432*4882a593Smuzhiyun if (error)
433*4882a593Smuzhiyun goto error_trans_cancel;
434*4882a593Smuzhiyun ASSERT(done);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /*
437*4882a593Smuzhiyun * Commit the transaction. This first logs the EFI and the inode, then
438*4882a593Smuzhiyun * rolls and commits the transaction that frees the extents.
439*4882a593Smuzhiyun */
440*4882a593Smuzhiyun xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
441*4882a593Smuzhiyun error = xfs_trans_commit(tp);
442*4882a593Smuzhiyun if (error) {
443*4882a593Smuzhiyun ASSERT(XFS_FORCED_SHUTDOWN(mp));
444*4882a593Smuzhiyun goto error_unlock;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun /*
448*4882a593Smuzhiyun * Remove the memory for extent descriptions (just bookkeeping).
449*4882a593Smuzhiyun */
450*4882a593Smuzhiyun if (ip->i_df.if_bytes)
451*4882a593Smuzhiyun xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK);
452*4882a593Smuzhiyun ASSERT(ip->i_df.if_bytes == 0);
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun xfs_iunlock(ip, XFS_ILOCK_EXCL);
455*4882a593Smuzhiyun return 0;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun error_trans_cancel:
458*4882a593Smuzhiyun xfs_trans_cancel(tp);
459*4882a593Smuzhiyun error_unlock:
460*4882a593Smuzhiyun xfs_iunlock(ip, XFS_ILOCK_EXCL);
461*4882a593Smuzhiyun return error;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun /*
465*4882a593Smuzhiyun * xfs_inactive_symlink - free a symlink
466*4882a593Smuzhiyun */
467*4882a593Smuzhiyun int
xfs_inactive_symlink(struct xfs_inode * ip)468*4882a593Smuzhiyun xfs_inactive_symlink(
469*4882a593Smuzhiyun struct xfs_inode *ip)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun struct xfs_mount *mp = ip->i_mount;
472*4882a593Smuzhiyun int pathlen;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun trace_xfs_inactive_symlink(ip);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun if (XFS_FORCED_SHUTDOWN(mp))
477*4882a593Smuzhiyun return -EIO;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun xfs_ilock(ip, XFS_ILOCK_EXCL);
480*4882a593Smuzhiyun pathlen = (int)ip->i_d.di_size;
481*4882a593Smuzhiyun ASSERT(pathlen);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun if (pathlen <= 0 || pathlen > XFS_SYMLINK_MAXLEN) {
484*4882a593Smuzhiyun xfs_alert(mp, "%s: inode (0x%llx) bad symlink length (%d)",
485*4882a593Smuzhiyun __func__, (unsigned long long)ip->i_ino, pathlen);
486*4882a593Smuzhiyun xfs_iunlock(ip, XFS_ILOCK_EXCL);
487*4882a593Smuzhiyun ASSERT(0);
488*4882a593Smuzhiyun return -EFSCORRUPTED;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun /*
492*4882a593Smuzhiyun * Inline fork state gets removed by xfs_difree() so we have nothing to
493*4882a593Smuzhiyun * do here in that case.
494*4882a593Smuzhiyun */
495*4882a593Smuzhiyun if (ip->i_df.if_flags & XFS_IFINLINE) {
496*4882a593Smuzhiyun xfs_iunlock(ip, XFS_ILOCK_EXCL);
497*4882a593Smuzhiyun return 0;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun xfs_iunlock(ip, XFS_ILOCK_EXCL);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* remove the remote symlink */
503*4882a593Smuzhiyun return xfs_inactive_symlink_rmt(ip);
504*4882a593Smuzhiyun }
505