diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-29 13:23:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-29 13:23:44 -0400 |
commit | 27fb8d7b1fe7c2fa2d7c1f243b899793e1b080e0 (patch) | |
tree | 25a8ca59a3743459bbd48674731becea89a16318 | |
parent | f80a0ca6ad8f2800453e819dafa09a0ed9e56850 (diff) | |
parent | 9699eda6bc1f708a28acb716e1477aa351362fe2 (diff) |
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
nfs: fix memory leak in nfs_get_sb with CONFIG_NFS_V4
nfs: fix some issues in nfs41_proc_reclaim_complete()
NFS: Ensure that nfs_wb_page() waits for Pg_writeback to clear
NFS: Fix an unstable write data integrity race
nfs: testing for null instead of ERR_PTR()
NFS: rsize and wsize settings ignored on v4 mounts
NFSv4: Don't attempt an atomic open if the file is a mountpoint
SUNRPC: Fix a bug in rpcauth_prune_expired
-rw-r--r-- | fs/nfs/client.c | 2 | ||||
-rw-r--r-- | fs/nfs/dir.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 5 | ||||
-rw-r--r-- | fs/nfs/super.c | 3 | ||||
-rw-r--r-- | fs/nfs/write.c | 55 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 1 | ||||
-rw-r--r-- | net/sunrpc/auth.c | 2 |
7 files changed, 47 insertions, 23 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index a8766c4ef2e0..acc9c4943b84 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -966,6 +966,8 @@ out_error: | |||
966 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) | 966 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) |
967 | { | 967 | { |
968 | target->flags = source->flags; | 968 | target->flags = source->flags; |
969 | target->rsize = source->rsize; | ||
970 | target->wsize = source->wsize; | ||
969 | target->acregmin = source->acregmin; | 971 | target->acregmin = source->acregmin; |
970 | target->acregmax = source->acregmax; | 972 | target->acregmax = source->acregmax; |
971 | target->acdirmin = source->acdirmin; | 973 | target->acdirmin = source->acdirmin; |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index db3ad849a289..a7bb5c694aa3 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1052,7 +1052,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1052 | struct inode *dir; | 1052 | struct inode *dir; |
1053 | int openflags, ret = 0; | 1053 | int openflags, ret = 0; |
1054 | 1054 | ||
1055 | if (!is_atomic_open(nd)) | 1055 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) |
1056 | goto no_open; | 1056 | goto no_open; |
1057 | parent = dget_parent(dentry); | 1057 | parent = dget_parent(dentry); |
1058 | dir = parent->d_inode; | 1058 | dir = parent->d_inode; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 638067007c65..071fcedd517c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -5218,9 +5218,12 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
5218 | msg.rpc_resp = &calldata->res; | 5218 | msg.rpc_resp = &calldata->res; |
5219 | task_setup_data.callback_data = calldata; | 5219 | task_setup_data.callback_data = calldata; |
5220 | task = rpc_run_task(&task_setup_data); | 5220 | task = rpc_run_task(&task_setup_data); |
5221 | if (IS_ERR(task)) | 5221 | if (IS_ERR(task)) { |
5222 | status = PTR_ERR(task); | 5222 | status = PTR_ERR(task); |
5223 | goto out; | ||
5224 | } | ||
5223 | rpc_put_task(task); | 5225 | rpc_put_task(task); |
5226 | return 0; | ||
5224 | out: | 5227 | out: |
5225 | dprintk("<-- %s status=%d\n", __func__, status); | 5228 | dprintk("<-- %s status=%d\n", __func__, status); |
5226 | return status; | 5229 | return status; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e01637240eeb..b4148fc00f9f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -2187,6 +2187,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2187 | if (data->version == 4) { | 2187 | if (data->version == 4) { |
2188 | error = nfs4_try_mount(flags, dev_name, data, mnt); | 2188 | error = nfs4_try_mount(flags, dev_name, data, mnt); |
2189 | kfree(data->client_address); | 2189 | kfree(data->client_address); |
2190 | kfree(data->nfs_server.export_path); | ||
2190 | goto out; | 2191 | goto out; |
2191 | } | 2192 | } |
2192 | #endif /* CONFIG_NFS_V4 */ | 2193 | #endif /* CONFIG_NFS_V4 */ |
@@ -2657,7 +2658,7 @@ static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | |||
2657 | devname = nfs_path(path->mnt->mnt_devname, | 2658 | devname = nfs_path(path->mnt->mnt_devname, |
2658 | path->mnt->mnt_root, path->dentry, | 2659 | path->mnt->mnt_root, path->dentry, |
2659 | page, PAGE_SIZE); | 2660 | page, PAGE_SIZE); |
2660 | if (devname == NULL) | 2661 | if (IS_ERR(devname)) |
2661 | goto out_freepage; | 2662 | goto out_freepage; |
2662 | tmp = kstrdup(devname, GFP_KERNEL); | 2663 | tmp = kstrdup(devname, GFP_KERNEL); |
2663 | if (tmp == NULL) | 2664 | if (tmp == NULL) |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index de38d63aa920..3aea3ca98ab7 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 | ||
@@ -1444,6 +1472,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) | |||
1444 | 1472 | ||
1445 | BUG_ON(!PageLocked(page)); | 1473 | BUG_ON(!PageLocked(page)); |
1446 | for (;;) { | 1474 | for (;;) { |
1475 | wait_on_page_writeback(page); | ||
1447 | req = nfs_page_find_request(page); | 1476 | req = nfs_page_find_request(page); |
1448 | if (req == NULL) | 1477 | if (req == NULL) |
1449 | break; | 1478 | break; |
@@ -1478,30 +1507,18 @@ int nfs_wb_page(struct inode *inode, struct page *page) | |||
1478 | .range_start = range_start, | 1507 | .range_start = range_start, |
1479 | .range_end = range_end, | 1508 | .range_end = range_end, |
1480 | }; | 1509 | }; |
1481 | struct nfs_page *req; | ||
1482 | int need_commit; | ||
1483 | int ret; | 1510 | int ret; |
1484 | 1511 | ||
1485 | while(PagePrivate(page)) { | 1512 | while(PagePrivate(page)) { |
1513 | wait_on_page_writeback(page); | ||
1486 | if (clear_page_dirty_for_io(page)) { | 1514 | if (clear_page_dirty_for_io(page)) { |
1487 | ret = nfs_writepage_locked(page, &wbc); | 1515 | ret = nfs_writepage_locked(page, &wbc); |
1488 | if (ret < 0) | 1516 | if (ret < 0) |
1489 | goto out_error; | 1517 | goto out_error; |
1490 | } | 1518 | } |
1491 | req = nfs_find_and_lock_request(page); | 1519 | ret = sync_inode(inode, &wbc); |
1492 | if (!req) | 1520 | if (ret < 0) |
1493 | break; | ||
1494 | if (IS_ERR(req)) { | ||
1495 | ret = PTR_ERR(req); | ||
1496 | goto out_error; | 1521 | goto out_error; |
1497 | } | ||
1498 | need_commit = test_bit(PG_CLEAN, &req->wb_flags); | ||
1499 | nfs_clear_page_tag_locked(req); | ||
1500 | if (need_commit) { | ||
1501 | ret = nfs_commit_inode(inode, FLUSH_SYNC); | ||
1502 | if (ret < 0) | ||
1503 | goto out_error; | ||
1504 | } | ||
1505 | } | 1522 | } |
1506 | return 0; | 1523 | return 0; |
1507 | out_error: | 1524 | out_error: |
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 | { |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index f394fc190a49..95afe79dd9d7 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -237,7 +237,7 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
237 | list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { | 237 | list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { |
238 | 238 | ||
239 | /* Enforce a 60 second garbage collection moratorium */ | 239 | /* Enforce a 60 second garbage collection moratorium */ |
240 | if (time_in_range_open(cred->cr_expire, expired, jiffies) && | 240 | if (time_in_range(cred->cr_expire, expired, jiffies) && |
241 | test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) | 241 | test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) |
242 | continue; | 242 | continue; |
243 | 243 | ||