diff options
| -rw-r--r-- | fs/nfs/client.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 2 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 160 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 14 | ||||
| -rw-r--r-- | include/linux/nfs_fs_sb.h | 1 |
5 files changed, 177 insertions, 4 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index eba0bcc1bab0..e55ad211dbed 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -156,7 +156,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
| 156 | cred = rpc_lookup_machine_cred(); | 156 | cred = rpc_lookup_machine_cred(); |
| 157 | if (!IS_ERR(cred)) | 157 | if (!IS_ERR(cred)) |
| 158 | clp->cl_machine_cred = cred; | 158 | clp->cl_machine_cred = cred; |
| 159 | 159 | #if defined(CONFIG_NFS_V4_1) | |
| 160 | INIT_LIST_HEAD(&clp->cl_layouts); | ||
| 161 | #endif | ||
| 160 | nfs_fscache_get_client_cookie(clp); | 162 | nfs_fscache_get_client_cookie(clp); |
| 161 | 163 | ||
| 162 | return clp; | 164 | return clp; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e0dc06d74b6a..9c81f4d66950 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -54,6 +54,7 @@ | |||
| 54 | #include "callback.h" | 54 | #include "callback.h" |
| 55 | #include "delegation.h" | 55 | #include "delegation.h" |
| 56 | #include "internal.h" | 56 | #include "internal.h" |
| 57 | #include "pnfs.h" | ||
| 57 | 58 | ||
| 58 | #define OPENOWNER_POOL_SIZE 8 | 59 | #define OPENOWNER_POOL_SIZE 8 |
| 59 | 60 | ||
| @@ -1475,6 +1476,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 1475 | } | 1476 | } |
| 1476 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1477 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
| 1477 | set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); | 1478 | set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); |
| 1479 | pnfs_destroy_all_layouts(clp); | ||
| 1478 | } | 1480 | } |
| 1479 | 1481 | ||
| 1480 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { | 1482 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index c0cd954855b9..891a0c36f992 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | */ | 28 | */ |
| 29 | 29 | ||
| 30 | #include <linux/nfs_fs.h> | 30 | #include <linux/nfs_fs.h> |
| 31 | #include "internal.h" | ||
| 31 | #include "pnfs.h" | 32 | #include "pnfs.h" |
| 32 | 33 | ||
| 33 | #define NFSDBG_FACILITY NFSDBG_PNFS | 34 | #define NFSDBG_FACILITY NFSDBG_PNFS |
| @@ -183,38 +184,189 @@ put_layout_hdr_locked(struct pnfs_layout_hdr *lo) | |||
| 183 | lo->refcount--; | 184 | lo->refcount--; |
| 184 | if (!lo->refcount) { | 185 | if (!lo->refcount) { |
| 185 | dprintk("%s: freeing layout cache %p\n", __func__, lo); | 186 | dprintk("%s: freeing layout cache %p\n", __func__, lo); |
| 187 | BUG_ON(!list_empty(&lo->layouts)); | ||
| 186 | NFS_I(lo->inode)->layout = NULL; | 188 | NFS_I(lo->inode)->layout = NULL; |
| 187 | kfree(lo); | 189 | kfree(lo); |
| 188 | } | 190 | } |
| 189 | } | 191 | } |
| 190 | 192 | ||
| 193 | static void | ||
| 194 | put_layout_hdr(struct inode *inode) | ||
| 195 | { | ||
| 196 | spin_lock(&inode->i_lock); | ||
| 197 | put_layout_hdr_locked(NFS_I(inode)->layout); | ||
| 198 | spin_unlock(&inode->i_lock); | ||
| 199 | } | ||
| 200 | |||
| 201 | static void | ||
| 202 | init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg) | ||
| 203 | { | ||
| 204 | INIT_LIST_HEAD(&lseg->fi_list); | ||
| 205 | kref_init(&lseg->kref); | ||
| 206 | lseg->layout = lo; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* Called without i_lock held, as the free_lseg call may sleep */ | ||
| 210 | static void | ||
| 211 | destroy_lseg(struct kref *kref) | ||
| 212 | { | ||
| 213 | struct pnfs_layout_segment *lseg = | ||
| 214 | container_of(kref, struct pnfs_layout_segment, kref); | ||
| 215 | struct inode *ino = lseg->layout->inode; | ||
| 216 | |||
| 217 | dprintk("--> %s\n", __func__); | ||
| 218 | kfree(lseg); | ||
| 219 | /* Matched by get_layout_hdr_locked in pnfs_insert_layout */ | ||
| 220 | put_layout_hdr(ino); | ||
| 221 | } | ||
| 222 | |||
| 223 | static void | ||
| 224 | put_lseg(struct pnfs_layout_segment *lseg) | ||
| 225 | { | ||
| 226 | if (!lseg) | ||
| 227 | return; | ||
| 228 | |||
| 229 | dprintk("%s: lseg %p ref %d\n", __func__, lseg, | ||
| 230 | atomic_read(&lseg->kref.refcount)); | ||
| 231 | kref_put(&lseg->kref, destroy_lseg); | ||
| 232 | } | ||
| 233 | |||
| 234 | static void | ||
| 235 | pnfs_clear_lseg_list(struct pnfs_layout_hdr *lo, struct list_head *tmp_list) | ||
| 236 | { | ||
| 237 | struct pnfs_layout_segment *lseg, *next; | ||
| 238 | struct nfs_client *clp; | ||
| 239 | |||
| 240 | dprintk("%s:Begin lo %p\n", __func__, lo); | ||
| 241 | |||
| 242 | assert_spin_locked(&lo->inode->i_lock); | ||
| 243 | list_for_each_entry_safe(lseg, next, &lo->segs, fi_list) { | ||
| 244 | dprintk("%s: freeing lseg %p\n", __func__, lseg); | ||
| 245 | list_move(&lseg->fi_list, tmp_list); | ||
| 246 | } | ||
| 247 | clp = NFS_SERVER(lo->inode)->nfs_client; | ||
| 248 | spin_lock(&clp->cl_lock); | ||
| 249 | /* List does not take a reference, so no need for put here */ | ||
| 250 | list_del_init(&lo->layouts); | ||
| 251 | spin_unlock(&clp->cl_lock); | ||
| 252 | |||
| 253 | dprintk("%s:Return\n", __func__); | ||
| 254 | } | ||
| 255 | |||
| 256 | static void | ||
| 257 | pnfs_free_lseg_list(struct list_head *tmp_list) | ||
| 258 | { | ||
| 259 | struct pnfs_layout_segment *lseg; | ||
| 260 | |||
| 261 | while (!list_empty(tmp_list)) { | ||
| 262 | lseg = list_entry(tmp_list->next, struct pnfs_layout_segment, | ||
| 263 | fi_list); | ||
| 264 | dprintk("%s calling put_lseg on %p\n", __func__, lseg); | ||
| 265 | list_del(&lseg->fi_list); | ||
| 266 | put_lseg(lseg); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 191 | void | 270 | void |
| 192 | pnfs_destroy_layout(struct nfs_inode *nfsi) | 271 | pnfs_destroy_layout(struct nfs_inode *nfsi) |
| 193 | { | 272 | { |
| 194 | struct pnfs_layout_hdr *lo; | 273 | struct pnfs_layout_hdr *lo; |
| 274 | LIST_HEAD(tmp_list); | ||
| 195 | 275 | ||
| 196 | spin_lock(&nfsi->vfs_inode.i_lock); | 276 | spin_lock(&nfsi->vfs_inode.i_lock); |
| 197 | lo = nfsi->layout; | 277 | lo = nfsi->layout; |
| 198 | if (lo) { | 278 | if (lo) { |
| 279 | pnfs_clear_lseg_list(lo, &tmp_list); | ||
| 199 | /* Matched by refcount set to 1 in alloc_init_layout_hdr */ | 280 | /* Matched by refcount set to 1 in alloc_init_layout_hdr */ |
| 200 | put_layout_hdr_locked(lo); | 281 | put_layout_hdr_locked(lo); |
| 201 | } | 282 | } |
| 202 | spin_unlock(&nfsi->vfs_inode.i_lock); | 283 | spin_unlock(&nfsi->vfs_inode.i_lock); |
| 284 | pnfs_free_lseg_list(&tmp_list); | ||
| 285 | } | ||
| 286 | |||
| 287 | /* | ||
| 288 | * Called by the state manger to remove all layouts established under an | ||
| 289 | * expired lease. | ||
| 290 | */ | ||
| 291 | void | ||
| 292 | pnfs_destroy_all_layouts(struct nfs_client *clp) | ||
| 293 | { | ||
| 294 | struct pnfs_layout_hdr *lo; | ||
| 295 | LIST_HEAD(tmp_list); | ||
| 296 | |||
| 297 | spin_lock(&clp->cl_lock); | ||
| 298 | list_splice_init(&clp->cl_layouts, &tmp_list); | ||
| 299 | spin_unlock(&clp->cl_lock); | ||
| 300 | |||
| 301 | while (!list_empty(&tmp_list)) { | ||
| 302 | lo = list_entry(tmp_list.next, struct pnfs_layout_hdr, | ||
| 303 | layouts); | ||
| 304 | dprintk("%s freeing layout for inode %lu\n", __func__, | ||
| 305 | lo->inode->i_ino); | ||
| 306 | pnfs_destroy_layout(NFS_I(lo->inode)); | ||
| 307 | } | ||
| 203 | } | 308 | } |
| 204 | 309 | ||
| 205 | /* STUB - pretend LAYOUTGET to server failed */ | 310 | static void pnfs_insert_layout(struct pnfs_layout_hdr *lo, |
| 311 | struct pnfs_layout_segment *lseg); | ||
| 312 | |||
| 313 | /* Get layout from server. */ | ||
| 206 | static struct pnfs_layout_segment * | 314 | static struct pnfs_layout_segment * |
| 207 | send_layoutget(struct pnfs_layout_hdr *lo, | 315 | send_layoutget(struct pnfs_layout_hdr *lo, |
| 208 | struct nfs_open_context *ctx, | 316 | struct nfs_open_context *ctx, |
| 209 | u32 iomode) | 317 | u32 iomode) |
| 210 | { | 318 | { |
| 211 | struct inode *ino = lo->inode; | 319 | struct inode *ino = lo->inode; |
| 320 | struct pnfs_layout_segment *lseg; | ||
| 212 | 321 | ||
| 213 | set_bit(lo_fail_bit(iomode), &lo->state); | 322 | /* Lets pretend we sent LAYOUTGET and got a response */ |
| 323 | lseg = kzalloc(sizeof(*lseg), GFP_KERNEL); | ||
| 324 | if (!lseg) { | ||
| 325 | set_bit(lo_fail_bit(iomode), &lo->state); | ||
| 326 | spin_lock(&ino->i_lock); | ||
| 327 | put_layout_hdr_locked(lo); | ||
| 328 | spin_unlock(&ino->i_lock); | ||
| 329 | return NULL; | ||
| 330 | } | ||
| 331 | init_lseg(lo, lseg); | ||
| 332 | lseg->iomode = IOMODE_RW; | ||
| 214 | spin_lock(&ino->i_lock); | 333 | spin_lock(&ino->i_lock); |
| 334 | pnfs_insert_layout(lo, lseg); | ||
| 215 | put_layout_hdr_locked(lo); | 335 | put_layout_hdr_locked(lo); |
| 216 | spin_unlock(&ino->i_lock); | 336 | spin_unlock(&ino->i_lock); |
| 217 | return NULL; | 337 | return lseg; |
| 338 | } | ||
| 339 | |||
| 340 | static void | ||
| 341 | pnfs_insert_layout(struct pnfs_layout_hdr *lo, | ||
| 342 | struct pnfs_layout_segment *lseg) | ||
| 343 | { | ||
| 344 | dprintk("%s:Begin\n", __func__); | ||
| 345 | |||
| 346 | assert_spin_locked(&lo->inode->i_lock); | ||
| 347 | if (list_empty(&lo->segs)) { | ||
| 348 | struct nfs_client *clp = NFS_SERVER(lo->inode)->nfs_client; | ||
| 349 | |||
| 350 | spin_lock(&clp->cl_lock); | ||
| 351 | BUG_ON(!list_empty(&lo->layouts)); | ||
| 352 | list_add_tail(&lo->layouts, &clp->cl_layouts); | ||
| 353 | spin_unlock(&clp->cl_lock); | ||
| 354 | } | ||
| 355 | get_layout_hdr_locked(lo); | ||
| 356 | /* STUB - add the constructed lseg if necessary */ | ||
| 357 | if (list_empty(&lo->segs)) { | ||
| 358 | list_add_tail(&lseg->fi_list, &lo->segs); | ||
| 359 | dprintk("%s: inserted lseg %p iomode %d at tail\n", | ||
| 360 | __func__, lseg, lseg->iomode); | ||
| 361 | } else { | ||
| 362 | /* There is no harm for the moment in calling this | ||
| 363 | * with the lock held, and the call will be removed | ||
| 364 | * with the STUB. | ||
| 365 | */ | ||
| 366 | put_lseg(lseg); | ||
| 367 | } | ||
| 368 | |||
| 369 | dprintk("%s:Return\n", __func__); | ||
| 218 | } | 370 | } |
| 219 | 371 | ||
| 220 | static struct pnfs_layout_hdr * | 372 | static struct pnfs_layout_hdr * |
| @@ -226,6 +378,8 @@ alloc_init_layout_hdr(struct inode *ino) | |||
| 226 | if (!lo) | 378 | if (!lo) |
| 227 | return NULL; | 379 | return NULL; |
| 228 | lo->refcount = 1; | 380 | lo->refcount = 1; |
| 381 | INIT_LIST_HEAD(&lo->layouts); | ||
| 382 | INIT_LIST_HEAD(&lo->segs); | ||
| 229 | lo->inode = ino; | 383 | lo->inode = ino; |
| 230 | return lo; | 384 | return lo; |
| 231 | } | 385 | } |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 4ed1b48c71b1..1c3eb02f4944 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
| @@ -30,6 +30,13 @@ | |||
| 30 | #ifndef FS_NFS_PNFS_H | 30 | #ifndef FS_NFS_PNFS_H |
| 31 | #define FS_NFS_PNFS_H | 31 | #define FS_NFS_PNFS_H |
| 32 | 32 | ||
| 33 | struct pnfs_layout_segment { | ||
| 34 | struct list_head fi_list; | ||
| 35 | u32 iomode; | ||
| 36 | struct kref kref; | ||
| 37 | struct pnfs_layout_hdr *layout; | ||
| 38 | }; | ||
| 39 | |||
| 33 | #ifdef CONFIG_NFS_V4_1 | 40 | #ifdef CONFIG_NFS_V4_1 |
| 34 | 41 | ||
| 35 | #define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4" | 42 | #define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4" |
| @@ -51,6 +58,8 @@ struct pnfs_layoutdriver_type { | |||
| 51 | 58 | ||
| 52 | struct pnfs_layout_hdr { | 59 | struct pnfs_layout_hdr { |
| 53 | unsigned long refcount; | 60 | unsigned long refcount; |
| 61 | struct list_head layouts; /* other client layouts */ | ||
| 62 | struct list_head segs; /* layout segments list */ | ||
| 54 | unsigned long state; | 63 | unsigned long state; |
| 55 | struct inode *inode; | 64 | struct inode *inode; |
| 56 | }; | 65 | }; |
| @@ -64,6 +73,7 @@ pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, | |||
| 64 | void set_pnfs_layoutdriver(struct nfs_server *, u32 id); | 73 | void set_pnfs_layoutdriver(struct nfs_server *, u32 id); |
| 65 | void unset_pnfs_layoutdriver(struct nfs_server *); | 74 | void unset_pnfs_layoutdriver(struct nfs_server *); |
| 66 | void pnfs_destroy_layout(struct nfs_inode *); | 75 | void pnfs_destroy_layout(struct nfs_inode *); |
| 76 | void pnfs_destroy_all_layouts(struct nfs_client *); | ||
| 67 | 77 | ||
| 68 | 78 | ||
| 69 | static inline int lo_fail_bit(u32 iomode) | 79 | static inline int lo_fail_bit(u32 iomode) |
| @@ -80,6 +90,10 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss) | |||
| 80 | 90 | ||
| 81 | #else /* CONFIG_NFS_V4_1 */ | 91 | #else /* CONFIG_NFS_V4_1 */ |
| 82 | 92 | ||
| 93 | static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) | ||
| 94 | { | ||
| 95 | } | ||
| 96 | |||
| 83 | static inline void pnfs_destroy_layout(struct nfs_inode *nfsi) | 97 | static inline void pnfs_destroy_layout(struct nfs_inode *nfsi) |
| 84 | { | 98 | { |
| 85 | } | 99 | } |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index c38619d95a57..4d62f1581ed1 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
| @@ -82,6 +82,7 @@ struct nfs_client { | |||
| 82 | /* The flags used for obtaining the clientid during EXCHANGE_ID */ | 82 | /* The flags used for obtaining the clientid during EXCHANGE_ID */ |
| 83 | u32 cl_exchange_flags; | 83 | u32 cl_exchange_flags; |
| 84 | struct nfs4_session *cl_session; /* sharred session */ | 84 | struct nfs4_session *cl_session; /* sharred session */ |
| 85 | struct list_head cl_layouts; | ||
| 85 | #endif /* CONFIG_NFS_V4_1 */ | 86 | #endif /* CONFIG_NFS_V4_1 */ |
| 86 | 87 | ||
| 87 | #ifdef CONFIG_NFS_FSCACHE | 88 | #ifdef CONFIG_NFS_FSCACHE |
