aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-07-29 21:34:41 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-07-31 14:20:30 -0400
commit2c41beb0e5cf22fe3ab4c4adc3cedd5f732b2a7e (patch)
treea55bc78458d534b40e6642ca003a2aeb7de362b1 /fs/nfsd
parentfc5a96c3b70d00c863f69ff4ea7f5dfddbcbc0d8 (diff)
nfsd: reduce cl_lock thrashing in release_openowner
Releasing an openowner is a bit inefficient as it can potentially thrash the cl_lock if you have a lot of stateids attached to it. Once we remove the client_mutex, it'll also potentially be dangerous to do this. Add some functions to make it easier to defer the part of putting a generic stateid reference that needs to be done outside the cl_lock while doing the parts that must be done while holding it under a single lock. First we unhash each open stateid. Then we call put_generic_stateid_locked which will put the reference to an nfs4_ol_stateid. If it turns out to be the last reference, it'll go ahead and remove the stid from the IDR tree and put it onto the reaplist using the st_locks list_head. Then, after dropping the lock we'll call free_ol_stateid_reaplist to walk the list of stateids that are fully unhashed and ready to be freed, and free each of them. This function can sleep, so it must be done outside any spinlocks. Signed-off-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4state.c96
1 files changed, 63 insertions, 33 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9c7dcbb68094..879342bc16b2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -983,6 +983,30 @@ static void nfs4_free_lock_stateid(struct nfs4_stid *stid)
983 nfs4_free_ol_stateid(stid); 983 nfs4_free_ol_stateid(stid);
984} 984}
985 985
986/*
987 * Put the persistent reference to an already unhashed generic stateid, while
988 * holding the cl_lock. If it's the last reference, then put it onto the
989 * reaplist for later destruction.
990 */
991static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
992 struct list_head *reaplist)
993{
994 struct nfs4_stid *s = &stp->st_stid;
995 struct nfs4_client *clp = s->sc_client;
996
997 lockdep_assert_held(&clp->cl_lock);
998
999 WARN_ON_ONCE(!list_empty(&stp->st_locks));
1000
1001 if (!atomic_dec_and_test(&s->sc_count)) {
1002 wake_up_all(&close_wq);
1003 return;
1004 }
1005
1006 idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
1007 list_add(&stp->st_locks, reaplist);
1008}
1009
986static void unhash_lock_stateid(struct nfs4_ol_stateid *stp) 1010static void unhash_lock_stateid(struct nfs4_ol_stateid *stp)
987{ 1011{
988 struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); 1012 struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
@@ -1013,6 +1037,25 @@ static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
1013 list_del_init(&lo->lo_owner.so_strhash); 1037 list_del_init(&lo->lo_owner.so_strhash);
1014} 1038}
1015 1039
1040/*
1041 * Free a list of generic stateids that were collected earlier after being
1042 * fully unhashed.
1043 */
1044static void
1045free_ol_stateid_reaplist(struct list_head *reaplist)
1046{
1047 struct nfs4_ol_stateid *stp;
1048
1049 might_sleep();
1050
1051 while (!list_empty(reaplist)) {
1052 stp = list_first_entry(reaplist, struct nfs4_ol_stateid,
1053 st_locks);
1054 list_del(&stp->st_locks);
1055 stp->st_stid.sc_free(&stp->st_stid);
1056 }
1057}
1058
1016static void release_lockowner(struct nfs4_lockowner *lo) 1059static void release_lockowner(struct nfs4_lockowner *lo)
1017{ 1060{
1018 struct nfs4_client *clp = lo->lo_owner.so_client; 1061 struct nfs4_client *clp = lo->lo_owner.so_client;
@@ -1027,24 +1070,10 @@ static void release_lockowner(struct nfs4_lockowner *lo)
1027 stp = list_first_entry(&lo->lo_owner.so_stateids, 1070 stp = list_first_entry(&lo->lo_owner.so_stateids,
1028 struct nfs4_ol_stateid, st_perstateowner); 1071 struct nfs4_ol_stateid, st_perstateowner);
1029 unhash_lock_stateid(stp); 1072 unhash_lock_stateid(stp);
1030 /* 1073 put_ol_stateid_locked(stp, &reaplist);
1031 * We now know that no new references can be added to the
1032 * stateid. If ours is the last one, finish the unhashing
1033 * and put it on the list to be reaped.
1034 */
1035 if (atomic_dec_and_test(&stp->st_stid.sc_count)) {
1036 idr_remove(&clp->cl_stateids,
1037 stp->st_stid.sc_stateid.si_opaque.so_id);
1038 list_add(&stp->st_locks, &reaplist);
1039 }
1040 } 1074 }
1041 spin_unlock(&clp->cl_lock); 1075 spin_unlock(&clp->cl_lock);
1042 while (!list_empty(&reaplist)) { 1076 free_ol_stateid_reaplist(&reaplist);
1043 stp = list_first_entry(&reaplist, struct nfs4_ol_stateid,
1044 st_locks);
1045 list_del(&stp->st_locks);
1046 stp->st_stid.sc_free(&stp->st_stid);
1047 }
1048 nfs4_put_stateowner(&lo->lo_owner); 1077 nfs4_put_stateowner(&lo->lo_owner);
1049} 1078}
1050 1079
@@ -1065,16 +1094,21 @@ static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp)
1065 1094
1066static void unhash_open_stateid(struct nfs4_ol_stateid *stp) 1095static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
1067{ 1096{
1068 spin_lock(&stp->st_stateowner->so_client->cl_lock); 1097 lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
1098
1069 unhash_generic_stateid(stp); 1099 unhash_generic_stateid(stp);
1070 release_open_stateid_locks(stp); 1100 release_open_stateid_locks(stp);
1071 spin_unlock(&stp->st_stateowner->so_client->cl_lock);
1072} 1101}
1073 1102
1074static void release_open_stateid(struct nfs4_ol_stateid *stp) 1103static void release_open_stateid(struct nfs4_ol_stateid *stp)
1075{ 1104{
1105 LIST_HEAD(reaplist);
1106
1107 spin_lock(&stp->st_stid.sc_client->cl_lock);
1076 unhash_open_stateid(stp); 1108 unhash_open_stateid(stp);
1077 nfs4_put_stid(&stp->st_stid); 1109 put_ol_stateid_locked(stp, &reaplist);
1110 spin_unlock(&stp->st_stid.sc_client->cl_lock);
1111 free_ol_stateid_reaplist(&reaplist);
1078} 1112}
1079 1113
1080static void unhash_openowner_locked(struct nfs4_openowner *oo) 1114static void unhash_openowner_locked(struct nfs4_openowner *oo)
@@ -1098,30 +1132,24 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
1098 } 1132 }
1099} 1133}
1100 1134
1101static void release_openowner_stateids(struct nfs4_openowner *oo) 1135static void release_openowner(struct nfs4_openowner *oo)
1102{ 1136{
1103 struct nfs4_ol_stateid *stp; 1137 struct nfs4_ol_stateid *stp;
1104 struct nfs4_client *clp = oo->oo_owner.so_client; 1138 struct nfs4_client *clp = oo->oo_owner.so_client;
1139 struct list_head reaplist;
1105 1140
1106 lockdep_assert_held(&clp->cl_lock); 1141 INIT_LIST_HEAD(&reaplist);
1107 1142
1143 spin_lock(&clp->cl_lock);
1144 unhash_openowner_locked(oo);
1108 while (!list_empty(&oo->oo_owner.so_stateids)) { 1145 while (!list_empty(&oo->oo_owner.so_stateids)) {
1109 stp = list_first_entry(&oo->oo_owner.so_stateids, 1146 stp = list_first_entry(&oo->oo_owner.so_stateids,
1110 struct nfs4_ol_stateid, st_perstateowner); 1147 struct nfs4_ol_stateid, st_perstateowner);
1111 spin_unlock(&clp->cl_lock); 1148 unhash_open_stateid(stp);
1112 release_open_stateid(stp); 1149 put_ol_stateid_locked(stp, &reaplist);
1113 spin_lock(&clp->cl_lock);
1114 } 1150 }
1115}
1116
1117static void release_openowner(struct nfs4_openowner *oo)
1118{
1119 struct nfs4_client *clp = oo->oo_owner.so_client;
1120
1121 spin_lock(&clp->cl_lock);
1122 unhash_openowner_locked(oo);
1123 release_openowner_stateids(oo);
1124 spin_unlock(&clp->cl_lock); 1151 spin_unlock(&clp->cl_lock);
1152 free_ol_stateid_reaplist(&reaplist);
1125 release_last_closed_stateid(oo); 1153 release_last_closed_stateid(oo);
1126 nfs4_put_stateowner(&oo->oo_owner); 1154 nfs4_put_stateowner(&oo->oo_owner);
1127} 1155}
@@ -4675,7 +4703,9 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
4675 struct nfs4_client *clp = s->st_stid.sc_client; 4703 struct nfs4_client *clp = s->st_stid.sc_client;
4676 4704
4677 s->st_stid.sc_type = NFS4_CLOSED_STID; 4705 s->st_stid.sc_type = NFS4_CLOSED_STID;
4706 spin_lock(&clp->cl_lock);
4678 unhash_open_stateid(s); 4707 unhash_open_stateid(s);
4708 spin_unlock(&clp->cl_lock);
4679 4709
4680 if (clp->cl_minorversion) 4710 if (clp->cl_minorversion)
4681 nfs4_put_stid(&s->st_stid); 4711 nfs4_put_stid(&s->st_stid);