@@ -1389,8 +1389,7 @@ static inline bool is_btrfs_snap_ioctl(int cmd)
1389
1389
return false;
1390
1390
}
1391
1391
1392
- static int shiftfs_btrfs_ioctl_fd_restore (int cmd , struct fd lfd , int fd ,
1393
- void __user * arg ,
1392
+ static int shiftfs_btrfs_ioctl_fd_restore (int cmd , int fd , void __user * arg ,
1394
1393
struct btrfs_ioctl_vol_args * v1 ,
1395
1394
struct btrfs_ioctl_vol_args_v2 * v2 )
1396
1395
{
@@ -1404,7 +1403,6 @@ static int shiftfs_btrfs_ioctl_fd_restore(int cmd, struct fd lfd, int fd,
1404
1403
else
1405
1404
ret = copy_to_user (arg , v2 , sizeof (* v2 ));
1406
1405
1407
- fdput (lfd );
1408
1406
__close_fd (current -> files , fd );
1409
1407
kfree (v1 );
1410
1408
kfree (v2 );
@@ -1415,11 +1413,11 @@ static int shiftfs_btrfs_ioctl_fd_restore(int cmd, struct fd lfd, int fd,
1415
1413
static int shiftfs_btrfs_ioctl_fd_replace (int cmd , void __user * arg ,
1416
1414
struct btrfs_ioctl_vol_args * * b1 ,
1417
1415
struct btrfs_ioctl_vol_args_v2 * * b2 ,
1418
- struct fd * lfd ,
1419
1416
int * newfd )
1420
1417
{
1421
1418
int oldfd , ret ;
1422
1419
struct fd src ;
1420
+ struct fd lfd = {};
1423
1421
struct btrfs_ioctl_vol_args * v1 = NULL ;
1424
1422
struct btrfs_ioctl_vol_args_v2 * v2 = NULL ;
1425
1423
@@ -1444,18 +1442,28 @@ static int shiftfs_btrfs_ioctl_fd_replace(int cmd, void __user *arg,
1444
1442
if (!src .file )
1445
1443
return - EINVAL ;
1446
1444
1447
- ret = shiftfs_real_fdget (src .file , lfd );
1448
- fdput ( src );
1449
- if ( ret )
1445
+ ret = shiftfs_real_fdget (src .file , & lfd );
1446
+ if ( ret ) {
1447
+ fdput ( src );
1450
1448
return ret ;
1449
+ }
1450
+
1451
+ /*
1452
+ * shiftfs_real_fdget() does not take a reference to lfd.file, so
1453
+ * take a reference here to offset the one which will be put by
1454
+ * __close_fd(), and make sure that reference is put on fdput(lfd).
1455
+ */
1456
+ get_file (lfd .file );
1457
+ lfd .flags |= FDPUT_FPUT ;
1458
+ fdput (src );
1451
1459
1452
- * newfd = get_unused_fd_flags (lfd -> file -> f_flags );
1460
+ * newfd = get_unused_fd_flags (lfd . file -> f_flags );
1453
1461
if (* newfd < 0 ) {
1454
- fdput (* lfd );
1462
+ fdput (lfd );
1455
1463
return * newfd ;
1456
1464
}
1457
1465
1458
- fd_install (* newfd , lfd -> file );
1466
+ fd_install (* newfd , lfd . file );
1459
1467
1460
1468
if (cmd == BTRFS_IOC_SNAP_CREATE ) {
1461
1469
v1 -> fd = * newfd ;
@@ -1468,7 +1476,7 @@ static int shiftfs_btrfs_ioctl_fd_replace(int cmd, void __user *arg,
1468
1476
}
1469
1477
1470
1478
if (ret )
1471
- shiftfs_btrfs_ioctl_fd_restore (cmd , * lfd , * newfd , arg , v1 , v2 );
1479
+ shiftfs_btrfs_ioctl_fd_restore (cmd , * newfd , arg , v1 , v2 );
1472
1480
1473
1481
return ret ;
1474
1482
}
@@ -1482,13 +1490,12 @@ static long shiftfs_real_ioctl(struct file *file, unsigned int cmd,
1482
1490
int newfd = - EBADF ;
1483
1491
long err = 0 , ret = 0 ;
1484
1492
void __user * argp = (void __user * )arg ;
1485
- struct fd btrfs_lfd = {};
1486
1493
struct super_block * sb = file -> f_path .dentry -> d_sb ;
1487
1494
struct btrfs_ioctl_vol_args * btrfs_v1 = NULL ;
1488
1495
struct btrfs_ioctl_vol_args_v2 * btrfs_v2 = NULL ;
1489
1496
1490
1497
ret = shiftfs_btrfs_ioctl_fd_replace (cmd , argp , & btrfs_v1 , & btrfs_v2 ,
1491
- & btrfs_lfd , & newfd );
1498
+ & newfd );
1492
1499
if (ret < 0 )
1493
1500
return ret ;
1494
1501
@@ -1511,7 +1518,7 @@ static long shiftfs_real_ioctl(struct file *file, unsigned int cmd,
1511
1518
fdput (lowerfd );
1512
1519
1513
1520
out_restore :
1514
- err = shiftfs_btrfs_ioctl_fd_restore (cmd , btrfs_lfd , newfd , argp ,
1521
+ err = shiftfs_btrfs_ioctl_fd_restore (cmd , newfd , argp ,
1515
1522
btrfs_v1 , btrfs_v2 );
1516
1523
if (!ret )
1517
1524
ret = err ;
0 commit comments