diff options
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r-- | fs/nfs/nfs4state.c | 128 |
1 files changed, 6 insertions, 122 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index fa51a7d4c022..058811e39555 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -50,12 +50,12 @@ | |||
50 | #include "nfs4_fs.h" | 50 | #include "nfs4_fs.h" |
51 | #include "callback.h" | 51 | #include "callback.h" |
52 | #include "delegation.h" | 52 | #include "delegation.h" |
53 | #include "internal.h" | ||
53 | 54 | ||
54 | #define OPENOWNER_POOL_SIZE 8 | 55 | #define OPENOWNER_POOL_SIZE 8 |
55 | 56 | ||
56 | const nfs4_stateid zero_stateid; | 57 | const nfs4_stateid zero_stateid; |
57 | 58 | ||
58 | static DEFINE_SPINLOCK(state_spinlock); | ||
59 | static LIST_HEAD(nfs4_clientid_list); | 59 | static LIST_HEAD(nfs4_clientid_list); |
60 | 60 | ||
61 | void | 61 | void |
@@ -71,127 +71,11 @@ destroy_nfsv4_state(struct nfs_server *server) | |||
71 | kfree(server->mnt_path); | 71 | kfree(server->mnt_path); |
72 | server->mnt_path = NULL; | 72 | server->mnt_path = NULL; |
73 | if (server->nfs_client) { | 73 | if (server->nfs_client) { |
74 | nfs4_put_client(server->nfs_client); | 74 | nfs_put_client(server->nfs_client); |
75 | server->nfs_client = NULL; | 75 | server->nfs_client = NULL; |
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | /* | ||
80 | * nfs4_get_client(): returns an empty client structure | ||
81 | * nfs4_put_client(): drops reference to client structure | ||
82 | * | ||
83 | * Since these are allocated/deallocated very rarely, we don't | ||
84 | * bother putting them in a slab cache... | ||
85 | */ | ||
86 | static struct nfs_client * | ||
87 | nfs4_alloc_client(struct in_addr *addr) | ||
88 | { | ||
89 | struct nfs_client *clp; | ||
90 | |||
91 | if (nfs_callback_up() < 0) | ||
92 | return NULL; | ||
93 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) { | ||
94 | nfs_callback_down(); | ||
95 | return NULL; | ||
96 | } | ||
97 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | ||
98 | init_rwsem(&clp->cl_sem); | ||
99 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
100 | INIT_LIST_HEAD(&clp->cl_state_owners); | ||
101 | INIT_LIST_HEAD(&clp->cl_unused); | ||
102 | spin_lock_init(&clp->cl_lock); | ||
103 | atomic_set(&clp->cl_count, 1); | ||
104 | INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); | ||
105 | INIT_LIST_HEAD(&clp->cl_superblocks); | ||
106 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); | ||
107 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
108 | clp->cl_boot_time = CURRENT_TIME; | ||
109 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | ||
110 | return clp; | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | nfs4_free_client(struct nfs_client *clp) | ||
115 | { | ||
116 | struct nfs4_state_owner *sp; | ||
117 | |||
118 | while (!list_empty(&clp->cl_unused)) { | ||
119 | sp = list_entry(clp->cl_unused.next, | ||
120 | struct nfs4_state_owner, | ||
121 | so_list); | ||
122 | list_del(&sp->so_list); | ||
123 | kfree(sp); | ||
124 | } | ||
125 | BUG_ON(!list_empty(&clp->cl_state_owners)); | ||
126 | nfs_idmap_delete(clp); | ||
127 | if (!IS_ERR(clp->cl_rpcclient)) | ||
128 | rpc_shutdown_client(clp->cl_rpcclient); | ||
129 | kfree(clp); | ||
130 | nfs_callback_down(); | ||
131 | } | ||
132 | |||
133 | static struct nfs_client *__nfs4_find_client(struct in_addr *addr) | ||
134 | { | ||
135 | struct nfs_client *clp; | ||
136 | list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) { | ||
137 | if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) { | ||
138 | atomic_inc(&clp->cl_count); | ||
139 | return clp; | ||
140 | } | ||
141 | } | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | struct nfs_client *nfs4_find_client(struct in_addr *addr) | ||
146 | { | ||
147 | struct nfs_client *clp; | ||
148 | spin_lock(&state_spinlock); | ||
149 | clp = __nfs4_find_client(addr); | ||
150 | spin_unlock(&state_spinlock); | ||
151 | return clp; | ||
152 | } | ||
153 | |||
154 | struct nfs_client * | ||
155 | nfs4_get_client(struct in_addr *addr) | ||
156 | { | ||
157 | struct nfs_client *clp, *new = NULL; | ||
158 | |||
159 | spin_lock(&state_spinlock); | ||
160 | for (;;) { | ||
161 | clp = __nfs4_find_client(addr); | ||
162 | if (clp != NULL) | ||
163 | break; | ||
164 | clp = new; | ||
165 | if (clp != NULL) { | ||
166 | list_add(&clp->cl_servers, &nfs4_clientid_list); | ||
167 | new = NULL; | ||
168 | break; | ||
169 | } | ||
170 | spin_unlock(&state_spinlock); | ||
171 | new = nfs4_alloc_client(addr); | ||
172 | spin_lock(&state_spinlock); | ||
173 | if (new == NULL) | ||
174 | break; | ||
175 | } | ||
176 | spin_unlock(&state_spinlock); | ||
177 | if (new) | ||
178 | nfs4_free_client(new); | ||
179 | return clp; | ||
180 | } | ||
181 | |||
182 | void | ||
183 | nfs4_put_client(struct nfs_client *clp) | ||
184 | { | ||
185 | if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock)) | ||
186 | return; | ||
187 | list_del(&clp->cl_servers); | ||
188 | spin_unlock(&state_spinlock); | ||
189 | BUG_ON(!list_empty(&clp->cl_superblocks)); | ||
190 | rpc_wake_up(&clp->cl_rpcwaitq); | ||
191 | nfs4_kill_renewd(clp); | ||
192 | nfs4_free_client(clp); | ||
193 | } | ||
194 | |||
195 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | 79 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) |
196 | { | 80 | { |
197 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, | 81 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, |
@@ -771,11 +655,11 @@ static void nfs4_recover_state(struct nfs_client *clp) | |||
771 | __module_get(THIS_MODULE); | 655 | __module_get(THIS_MODULE); |
772 | atomic_inc(&clp->cl_count); | 656 | atomic_inc(&clp->cl_count); |
773 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", | 657 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", |
774 | NIPQUAD(clp->cl_addr)); | 658 | NIPQUAD(clp->cl_addr.sin_addr)); |
775 | if (!IS_ERR(task)) | 659 | if (!IS_ERR(task)) |
776 | return; | 660 | return; |
777 | nfs4_clear_recover_bit(clp); | 661 | nfs4_clear_recover_bit(clp); |
778 | nfs4_put_client(clp); | 662 | nfs_put_client(clp); |
779 | module_put(THIS_MODULE); | 663 | module_put(THIS_MODULE); |
780 | } | 664 | } |
781 | 665 | ||
@@ -970,12 +854,12 @@ out: | |||
970 | if (status == -NFS4ERR_CB_PATH_DOWN) | 854 | if (status == -NFS4ERR_CB_PATH_DOWN) |
971 | nfs_handle_cb_pathdown(clp); | 855 | nfs_handle_cb_pathdown(clp); |
972 | nfs4_clear_recover_bit(clp); | 856 | nfs4_clear_recover_bit(clp); |
973 | nfs4_put_client(clp); | 857 | nfs_put_client(clp); |
974 | module_put_and_exit(0); | 858 | module_put_and_exit(0); |
975 | return 0; | 859 | return 0; |
976 | out_error: | 860 | out_error: |
977 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", | 861 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", |
978 | NIPQUAD(clp->cl_addr.s_addr), -status); | 862 | NIPQUAD(clp->cl_addr.sin_addr), -status); |
979 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 863 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
980 | goto out; | 864 | goto out; |
981 | } | 865 | } |