diff options
author | Sage Weil <sage@newdream.net> | 2009-09-29 18:38:44 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-09-29 18:38:44 -0400 |
commit | 1ab86aedbc7845a946b4ba4edf37762629970708 (patch) | |
tree | 1a3ad19d12a807d76d5700abc6415e1535c88312 | |
parent | 3baf0bed0a5adab95c7599d2f27124c74692ef28 (diff) |
Btrfs: fix error cases for ioctl transactions
Fix leak of vfsmount write reference and open_ioctl_trans reference on
ENOMEM. Clean up the error paths while we're at it.
Signed-off-by: Sage Weil <sage@newdream.net>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ioctl.c | 41 |
1 files changed, 22 insertions, 19 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 4de7ef6f8603..9a780c8d0ac8 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1232,15 +1232,15 @@ static long btrfs_ioctl_trans_start(struct file *file) | |||
1232 | struct inode *inode = fdentry(file)->d_inode; | 1232 | struct inode *inode = fdentry(file)->d_inode; |
1233 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1233 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1234 | struct btrfs_trans_handle *trans; | 1234 | struct btrfs_trans_handle *trans; |
1235 | int ret = 0; | 1235 | int ret; |
1236 | 1236 | ||
1237 | ret = -EPERM; | ||
1237 | if (!capable(CAP_SYS_ADMIN)) | 1238 | if (!capable(CAP_SYS_ADMIN)) |
1238 | return -EPERM; | 1239 | goto out; |
1239 | 1240 | ||
1240 | if (file->private_data) { | 1241 | ret = -EINPROGRESS; |
1241 | ret = -EINPROGRESS; | 1242 | if (file->private_data) |
1242 | goto out; | 1243 | goto out; |
1243 | } | ||
1244 | 1244 | ||
1245 | ret = mnt_want_write(file->f_path.mnt); | 1245 | ret = mnt_want_write(file->f_path.mnt); |
1246 | if (ret) | 1246 | if (ret) |
@@ -1250,12 +1250,19 @@ static long btrfs_ioctl_trans_start(struct file *file) | |||
1250 | root->fs_info->open_ioctl_trans++; | 1250 | root->fs_info->open_ioctl_trans++; |
1251 | mutex_unlock(&root->fs_info->trans_mutex); | 1251 | mutex_unlock(&root->fs_info->trans_mutex); |
1252 | 1252 | ||
1253 | ret = -ENOMEM; | ||
1253 | trans = btrfs_start_ioctl_transaction(root, 0); | 1254 | trans = btrfs_start_ioctl_transaction(root, 0); |
1254 | if (trans) | 1255 | if (!trans) |
1255 | file->private_data = trans; | 1256 | goto out_drop; |
1256 | else | 1257 | |
1257 | ret = -ENOMEM; | 1258 | file->private_data = trans; |
1258 | /*printk(KERN_INFO "btrfs_ioctl_trans_start on %p\n", file);*/ | 1259 | return 0; |
1260 | |||
1261 | out_drop: | ||
1262 | mutex_lock(&root->fs_info->trans_mutex); | ||
1263 | root->fs_info->open_ioctl_trans--; | ||
1264 | mutex_unlock(&root->fs_info->trans_mutex); | ||
1265 | mnt_drop_write(file->f_path.mnt); | ||
1259 | out: | 1266 | out: |
1260 | return ret; | 1267 | return ret; |
1261 | } | 1268 | } |
@@ -1271,24 +1278,20 @@ long btrfs_ioctl_trans_end(struct file *file) | |||
1271 | struct inode *inode = fdentry(file)->d_inode; | 1278 | struct inode *inode = fdentry(file)->d_inode; |
1272 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1279 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1273 | struct btrfs_trans_handle *trans; | 1280 | struct btrfs_trans_handle *trans; |
1274 | int ret = 0; | ||
1275 | 1281 | ||
1276 | trans = file->private_data; | 1282 | trans = file->private_data; |
1277 | if (!trans) { | 1283 | if (!trans) |
1278 | ret = -EINVAL; | 1284 | return -EINVAL; |
1279 | goto out; | ||
1280 | } | ||
1281 | btrfs_end_transaction(trans, root); | ||
1282 | file->private_data = NULL; | 1285 | file->private_data = NULL; |
1283 | 1286 | ||
1287 | btrfs_end_transaction(trans, root); | ||
1288 | |||
1284 | mutex_lock(&root->fs_info->trans_mutex); | 1289 | mutex_lock(&root->fs_info->trans_mutex); |
1285 | root->fs_info->open_ioctl_trans--; | 1290 | root->fs_info->open_ioctl_trans--; |
1286 | mutex_unlock(&root->fs_info->trans_mutex); | 1291 | mutex_unlock(&root->fs_info->trans_mutex); |
1287 | 1292 | ||
1288 | mnt_drop_write(file->f_path.mnt); | 1293 | mnt_drop_write(file->f_path.mnt); |
1289 | 1294 | return 0; | |
1290 | out: | ||
1291 | return ret; | ||
1292 | } | 1295 | } |
1293 | 1296 | ||
1294 | long btrfs_ioctl(struct file *file, unsigned int | 1297 | long btrfs_ioctl(struct file *file, unsigned int |