diff options
| -rw-r--r-- | fs/nfs/write.c | 36 | ||||
| -rw-r--r-- | include/linux/nfs_fs.h | 1 |
2 files changed, 33 insertions, 4 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index de38d63aa920..ccde2aeb3fec 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -1201,6 +1201,25 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 1201 | 1201 | ||
| 1202 | 1202 | ||
| 1203 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1203 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
| 1204 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) | ||
| 1205 | { | ||
| 1206 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) | ||
| 1207 | return 1; | ||
| 1208 | if (may_wait && !out_of_line_wait_on_bit_lock(&nfsi->flags, | ||
| 1209 | NFS_INO_COMMIT, nfs_wait_bit_killable, | ||
| 1210 | TASK_KILLABLE)) | ||
| 1211 | return 1; | ||
| 1212 | return 0; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | static void nfs_commit_clear_lock(struct nfs_inode *nfsi) | ||
| 1216 | { | ||
| 1217 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); | ||
| 1218 | smp_mb__after_clear_bit(); | ||
| 1219 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | |||
| 1204 | static void nfs_commitdata_release(void *data) | 1223 | static void nfs_commitdata_release(void *data) |
| 1205 | { | 1224 | { |
| 1206 | struct nfs_write_data *wdata = data; | 1225 | struct nfs_write_data *wdata = data; |
| @@ -1262,8 +1281,6 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
| 1262 | task = rpc_run_task(&task_setup_data); | 1281 | task = rpc_run_task(&task_setup_data); |
| 1263 | if (IS_ERR(task)) | 1282 | if (IS_ERR(task)) |
| 1264 | return PTR_ERR(task); | 1283 | return PTR_ERR(task); |
| 1265 | if (how & FLUSH_SYNC) | ||
| 1266 | rpc_wait_for_completion_task(task); | ||
| 1267 | rpc_put_task(task); | 1284 | rpc_put_task(task); |
| 1268 | return 0; | 1285 | return 0; |
| 1269 | } | 1286 | } |
| @@ -1294,6 +1311,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
| 1294 | BDI_RECLAIMABLE); | 1311 | BDI_RECLAIMABLE); |
| 1295 | nfs_clear_page_tag_locked(req); | 1312 | nfs_clear_page_tag_locked(req); |
| 1296 | } | 1313 | } |
| 1314 | nfs_commit_clear_lock(NFS_I(inode)); | ||
| 1297 | return -ENOMEM; | 1315 | return -ENOMEM; |
| 1298 | } | 1316 | } |
| 1299 | 1317 | ||
| @@ -1349,6 +1367,7 @@ static void nfs_commit_release(void *calldata) | |||
| 1349 | next: | 1367 | next: |
| 1350 | nfs_clear_page_tag_locked(req); | 1368 | nfs_clear_page_tag_locked(req); |
| 1351 | } | 1369 | } |
| 1370 | nfs_commit_clear_lock(NFS_I(data->inode)); | ||
| 1352 | nfs_commitdata_release(calldata); | 1371 | nfs_commitdata_release(calldata); |
| 1353 | } | 1372 | } |
| 1354 | 1373 | ||
| @@ -1363,8 +1382,11 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
| 1363 | static int nfs_commit_inode(struct inode *inode, int how) | 1382 | static int nfs_commit_inode(struct inode *inode, int how) |
| 1364 | { | 1383 | { |
| 1365 | LIST_HEAD(head); | 1384 | LIST_HEAD(head); |
| 1366 | int res; | 1385 | int may_wait = how & FLUSH_SYNC; |
| 1386 | int res = 0; | ||
| 1367 | 1387 | ||
| 1388 | if (!nfs_commit_set_lock(NFS_I(inode), may_wait)) | ||
| 1389 | goto out; | ||
| 1368 | spin_lock(&inode->i_lock); | 1390 | spin_lock(&inode->i_lock); |
| 1369 | res = nfs_scan_commit(inode, &head, 0, 0); | 1391 | res = nfs_scan_commit(inode, &head, 0, 0); |
| 1370 | spin_unlock(&inode->i_lock); | 1392 | spin_unlock(&inode->i_lock); |
| @@ -1372,7 +1394,13 @@ static int nfs_commit_inode(struct inode *inode, int how) | |||
| 1372 | int error = nfs_commit_list(inode, &head, how); | 1394 | int error = nfs_commit_list(inode, &head, how); |
| 1373 | if (error < 0) | 1395 | if (error < 0) |
| 1374 | return error; | 1396 | return error; |
| 1375 | } | 1397 | if (may_wait) |
| 1398 | wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT, | ||
| 1399 | nfs_wait_bit_killable, | ||
| 1400 | TASK_KILLABLE); | ||
| 1401 | } else | ||
| 1402 | nfs_commit_clear_lock(NFS_I(inode)); | ||
| 1403 | out: | ||
| 1376 | return res; | 1404 | return res; |
| 1377 | } | 1405 | } |
| 1378 | 1406 | ||
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 1a0b85aa151e..07ce4609fe50 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -209,6 +209,7 @@ struct nfs_inode { | |||
| 209 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ | 209 | #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ |
| 210 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ | 210 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ |
| 211 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ | 211 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ |
| 212 | #define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ | ||
| 212 | 213 | ||
| 213 | static inline struct nfs_inode *NFS_I(const struct inode *inode) | 214 | static inline struct nfs_inode *NFS_I(const struct inode *inode) |
| 214 | { | 215 | { |
