diff options
Diffstat (limited to 'fs/xfs/xfs_dfrag.c')
-rw-r--r-- | fs/xfs/xfs_dfrag.c | 71 |
1 files changed, 40 insertions, 31 deletions
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 681be5c93af5..8dd7a3923f64 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c | |||
@@ -65,9 +65,9 @@ | |||
65 | */ | 65 | */ |
66 | int | 66 | int |
67 | xfs_swapext( | 67 | xfs_swapext( |
68 | xfs_swapext_t __user *sxp) | 68 | xfs_swapext_t __user *sxu) |
69 | { | 69 | { |
70 | xfs_swapext_t sx; | 70 | xfs_swapext_t *sxp; |
71 | xfs_inode_t *ip=NULL, *tip=NULL, *ips[2]; | 71 | xfs_inode_t *ip=NULL, *tip=NULL, *ips[2]; |
72 | xfs_trans_t *tp; | 72 | xfs_trans_t *tp; |
73 | xfs_mount_t *mp; | 73 | xfs_mount_t *mp; |
@@ -76,20 +76,29 @@ xfs_swapext( | |||
76 | vnode_t *vp, *tvp; | 76 | vnode_t *vp, *tvp; |
77 | bhv_desc_t *bdp, *tbdp; | 77 | bhv_desc_t *bdp, *tbdp; |
78 | vn_bhv_head_t *bhp, *tbhp; | 78 | vn_bhv_head_t *bhp, *tbhp; |
79 | uint lock_flags=0; | 79 | static uint lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; |
80 | int ilf_fields, tilf_fields; | 80 | int ilf_fields, tilf_fields; |
81 | int error = 0; | 81 | int error = 0; |
82 | xfs_ifork_t tempif, *ifp, *tifp; | 82 | xfs_ifork_t *tempifp, *ifp, *tifp; |
83 | __uint64_t tmp; | 83 | __uint64_t tmp; |
84 | int aforkblks = 0; | 84 | int aforkblks = 0; |
85 | int taforkblks = 0; | 85 | int taforkblks = 0; |
86 | int locked = 0; | 86 | char locked = 0; |
87 | 87 | ||
88 | if (copy_from_user(&sx, sxp, sizeof(sx))) | 88 | sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL); |
89 | return XFS_ERROR(EFAULT); | 89 | tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); |
90 | if (!sxp || !tempifp) { | ||
91 | error = XFS_ERROR(ENOMEM); | ||
92 | goto error0; | ||
93 | } | ||
94 | |||
95 | if (copy_from_user(sxp, sxu, sizeof(xfs_swapext_t))) { | ||
96 | error = XFS_ERROR(EFAULT); | ||
97 | goto error0; | ||
98 | } | ||
90 | 99 | ||
91 | /* Pull information for the target fd */ | 100 | /* Pull information for the target fd */ |
92 | if (((fp = fget((int)sx.sx_fdtarget)) == NULL) || | 101 | if (((fp = fget((int)sxp->sx_fdtarget)) == NULL) || |
93 | ((vp = LINVFS_GET_VP(fp->f_dentry->d_inode)) == NULL)) { | 102 | ((vp = LINVFS_GET_VP(fp->f_dentry->d_inode)) == NULL)) { |
94 | error = XFS_ERROR(EINVAL); | 103 | error = XFS_ERROR(EINVAL); |
95 | goto error0; | 104 | goto error0; |
@@ -104,7 +113,7 @@ xfs_swapext( | |||
104 | ip = XFS_BHVTOI(bdp); | 113 | ip = XFS_BHVTOI(bdp); |
105 | } | 114 | } |
106 | 115 | ||
107 | if (((tfp = fget((int)sx.sx_fdtmp)) == NULL) || | 116 | if (((tfp = fget((int)sxp->sx_fdtmp)) == NULL) || |
108 | ((tvp = LINVFS_GET_VP(tfp->f_dentry->d_inode)) == NULL)) { | 117 | ((tvp = LINVFS_GET_VP(tfp->f_dentry->d_inode)) == NULL)) { |
109 | error = XFS_ERROR(EINVAL); | 118 | error = XFS_ERROR(EINVAL); |
110 | goto error0; | 119 | goto error0; |
@@ -131,7 +140,7 @@ xfs_swapext( | |||
131 | 140 | ||
132 | mp = ip->i_mount; | 141 | mp = ip->i_mount; |
133 | 142 | ||
134 | sbp = &sx.sx_stat; | 143 | sbp = &sxp->sx_stat; |
135 | 144 | ||
136 | if (XFS_FORCED_SHUTDOWN(mp)) { | 145 | if (XFS_FORCED_SHUTDOWN(mp)) { |
137 | error = XFS_ERROR(EIO); | 146 | error = XFS_ERROR(EIO); |
@@ -148,7 +157,7 @@ xfs_swapext( | |||
148 | ips[0] = tip; | 157 | ips[0] = tip; |
149 | ips[1] = ip; | 158 | ips[1] = ip; |
150 | } | 159 | } |
151 | lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; | 160 | |
152 | xfs_lock_inodes(ips, 2, 0, lock_flags); | 161 | xfs_lock_inodes(ips, 2, 0, lock_flags); |
153 | 162 | ||
154 | /* Check permissions */ | 163 | /* Check permissions */ |
@@ -192,9 +201,9 @@ xfs_swapext( | |||
192 | } | 201 | } |
193 | 202 | ||
194 | /* Verify all data are being swapped */ | 203 | /* Verify all data are being swapped */ |
195 | if (sx.sx_offset != 0 || | 204 | if (sxp->sx_offset != 0 || |
196 | sx.sx_length != ip->i_d.di_size || | 205 | sxp->sx_length != ip->i_d.di_size || |
197 | sx.sx_length != tip->i_d.di_size) { | 206 | sxp->sx_length != tip->i_d.di_size) { |
198 | error = XFS_ERROR(EFAULT); | 207 | error = XFS_ERROR(EFAULT); |
199 | goto error0; | 208 | goto error0; |
200 | } | 209 | } |
@@ -255,7 +264,8 @@ xfs_swapext( | |||
255 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 264 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
256 | xfs_iunlock(tip, XFS_IOLOCK_EXCL); | 265 | xfs_iunlock(tip, XFS_IOLOCK_EXCL); |
257 | xfs_trans_cancel(tp, 0); | 266 | xfs_trans_cancel(tp, 0); |
258 | return error; | 267 | locked = 0; |
268 | goto error0; | ||
259 | } | 269 | } |
260 | xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); | 270 | xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); |
261 | 271 | ||
@@ -266,10 +276,8 @@ xfs_swapext( | |||
266 | (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { | 276 | (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { |
267 | error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks); | 277 | error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks); |
268 | if (error) { | 278 | if (error) { |
269 | xfs_iunlock(ip, lock_flags); | ||
270 | xfs_iunlock(tip, lock_flags); | ||
271 | xfs_trans_cancel(tp, 0); | 279 | xfs_trans_cancel(tp, 0); |
272 | return error; | 280 | goto error0; |
273 | } | 281 | } |
274 | } | 282 | } |
275 | if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) && | 283 | if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) && |
@@ -277,10 +285,8 @@ xfs_swapext( | |||
277 | error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK, | 285 | error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK, |
278 | &taforkblks); | 286 | &taforkblks); |
279 | if (error) { | 287 | if (error) { |
280 | xfs_iunlock(ip, lock_flags); | ||
281 | xfs_iunlock(tip, lock_flags); | ||
282 | xfs_trans_cancel(tp, 0); | 288 | xfs_trans_cancel(tp, 0); |
283 | return error; | 289 | goto error0; |
284 | } | 290 | } |
285 | } | 291 | } |
286 | 292 | ||
@@ -289,9 +295,9 @@ xfs_swapext( | |||
289 | */ | 295 | */ |
290 | ifp = &ip->i_df; | 296 | ifp = &ip->i_df; |
291 | tifp = &tip->i_df; | 297 | tifp = &tip->i_df; |
292 | tempif = *ifp; /* struct copy */ | 298 | *tempifp = *ifp; /* struct copy */ |
293 | *ifp = *tifp; /* struct copy */ | 299 | *ifp = *tifp; /* struct copy */ |
294 | *tifp = tempif; /* struct copy */ | 300 | *tifp = *tempifp; /* struct copy */ |
295 | 301 | ||
296 | /* | 302 | /* |
297 | * Fix the on-disk inode values | 303 | * Fix the on-disk inode values |
@@ -369,11 +375,7 @@ xfs_swapext( | |||
369 | } | 375 | } |
370 | 376 | ||
371 | error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL); | 377 | error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL); |
372 | 378 | locked = 0; | |
373 | fput(fp); | ||
374 | fput(tfp); | ||
375 | |||
376 | return error; | ||
377 | 379 | ||
378 | error0: | 380 | error0: |
379 | if (locked) { | 381 | if (locked) { |
@@ -381,8 +383,15 @@ xfs_swapext( | |||
381 | xfs_iunlock(tip, lock_flags); | 383 | xfs_iunlock(tip, lock_flags); |
382 | } | 384 | } |
383 | 385 | ||
384 | if (fp != NULL) fput(fp); | 386 | if (fp != NULL) |
385 | if (tfp != NULL) fput(tfp); | 387 | fput(fp); |
388 | if (tfp != NULL) | ||
389 | fput(tfp); | ||
390 | |||
391 | if (sxp != NULL) | ||
392 | kmem_free(sxp, sizeof(xfs_swapext_t)); | ||
393 | if (tempifp != NULL) | ||
394 | kmem_free(tempifp, sizeof(xfs_ifork_t)); | ||
386 | 395 | ||
387 | return error; | 396 | return error; |
388 | } | 397 | } |