diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-12-14 14:09:05 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-12-14 14:09:05 -0500 |
| commit | 5111711d3ed8f4f1012cac3ec3f2b463b549fbfd (patch) | |
| tree | dc44d88bc66d3e7ec4d1c9180d6d4289fe7c5901 | |
| parent | e13cf63f2bbd38721af557f0205da994ea068427 (diff) | |
| parent | c1ac3ffcd0bc7e9617f62be8c7043d53ab84deac (diff) | |
Merge branch 'for-2.6.37' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.37' of git://linux-nfs.org/~bfields/linux:
nfsd: Fix possible BUG_ON firing in set_change_info
sunrpc: prevent use-after-free on clearing XPT_BUSY
| -rw-r--r-- | fs/nfsd/nfs3xdr.c | 6 | ||||
| -rw-r--r-- | fs/nfsd/xdr4.h | 21 | ||||
| -rw-r--r-- | net/sunrpc/svc_xprt.c | 9 |
3 files changed, 22 insertions, 14 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 2a533a0af2a9..7e84a852cdae 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
| @@ -260,9 +260,11 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
| 260 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, | 260 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, |
| 261 | &fhp->fh_post_attr); | 261 | &fhp->fh_post_attr); |
| 262 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; | 262 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; |
| 263 | if (err) | 263 | if (err) { |
| 264 | fhp->fh_post_saved = 0; | 264 | fhp->fh_post_saved = 0; |
| 265 | else | 265 | /* Grab the ctime anyway - set_change_info might use it */ |
| 266 | fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime; | ||
| 267 | } else | ||
| 266 | fhp->fh_post_saved = 1; | 268 | fhp->fh_post_saved = 1; |
| 267 | } | 269 | } |
| 268 | 270 | ||
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 4d476ff08ae6..60fce3dc5cb5 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
| @@ -484,18 +484,17 @@ static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) | |||
| 484 | static inline void | 484 | static inline void |
| 485 | set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) | 485 | set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) |
| 486 | { | 486 | { |
| 487 | BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved); | 487 | BUG_ON(!fhp->fh_pre_saved); |
| 488 | cinfo->atomic = 1; | 488 | cinfo->atomic = fhp->fh_post_saved; |
| 489 | cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); | 489 | cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); |
| 490 | if (cinfo->change_supported) { | 490 | |
| 491 | cinfo->before_change = fhp->fh_pre_change; | 491 | cinfo->before_change = fhp->fh_pre_change; |
| 492 | cinfo->after_change = fhp->fh_post_change; | 492 | cinfo->after_change = fhp->fh_post_change; |
| 493 | } else { | 493 | cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; |
| 494 | cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; | 494 | cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; |
| 495 | cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; | 495 | cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; |
| 496 | cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; | 496 | cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; |
| 497 | cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; | 497 | |
| 498 | } | ||
| 499 | } | 498 | } |
| 500 | 499 | ||
| 501 | int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); | 500 | int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index ea2ff78dcf7b..3f2c5559ca1a 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
| @@ -212,6 +212,7 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, | |||
| 212 | spin_lock(&svc_xprt_class_lock); | 212 | spin_lock(&svc_xprt_class_lock); |
| 213 | list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) { | 213 | list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) { |
| 214 | struct svc_xprt *newxprt; | 214 | struct svc_xprt *newxprt; |
| 215 | unsigned short newport; | ||
| 215 | 216 | ||
| 216 | if (strcmp(xprt_name, xcl->xcl_name)) | 217 | if (strcmp(xprt_name, xcl->xcl_name)) |
| 217 | continue; | 218 | continue; |
| @@ -230,8 +231,9 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, | |||
| 230 | spin_lock_bh(&serv->sv_lock); | 231 | spin_lock_bh(&serv->sv_lock); |
| 231 | list_add(&newxprt->xpt_list, &serv->sv_permsocks); | 232 | list_add(&newxprt->xpt_list, &serv->sv_permsocks); |
| 232 | spin_unlock_bh(&serv->sv_lock); | 233 | spin_unlock_bh(&serv->sv_lock); |
| 234 | newport = svc_xprt_local_port(newxprt); | ||
| 233 | clear_bit(XPT_BUSY, &newxprt->xpt_flags); | 235 | clear_bit(XPT_BUSY, &newxprt->xpt_flags); |
| 234 | return svc_xprt_local_port(newxprt); | 236 | return newport; |
| 235 | } | 237 | } |
| 236 | err: | 238 | err: |
| 237 | spin_unlock(&svc_xprt_class_lock); | 239 | spin_unlock(&svc_xprt_class_lock); |
| @@ -425,8 +427,13 @@ void svc_xprt_received(struct svc_xprt *xprt) | |||
| 425 | { | 427 | { |
| 426 | BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); | 428 | BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); |
| 427 | xprt->xpt_pool = NULL; | 429 | xprt->xpt_pool = NULL; |
| 430 | /* As soon as we clear busy, the xprt could be closed and | ||
| 431 | * 'put', so we need a reference to call svc_xprt_enqueue with: | ||
| 432 | */ | ||
| 433 | svc_xprt_get(xprt); | ||
| 428 | clear_bit(XPT_BUSY, &xprt->xpt_flags); | 434 | clear_bit(XPT_BUSY, &xprt->xpt_flags); |
| 429 | svc_xprt_enqueue(xprt); | 435 | svc_xprt_enqueue(xprt); |
| 436 | svc_xprt_put(xprt); | ||
| 430 | } | 437 | } |
| 431 | EXPORT_SYMBOL_GPL(svc_xprt_received); | 438 | EXPORT_SYMBOL_GPL(svc_xprt_received); |
| 432 | 439 | ||
