diff options
-rw-r--r-- | fs/nfs/callback_proc.c | 56 |
1 files changed, 38 insertions, 18 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 54cea8ad5a76..0e6e63f55db4 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -108,42 +108,62 @@ int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nf | |||
108 | 108 | ||
109 | #if defined(CONFIG_NFS_V4_1) | 109 | #if defined(CONFIG_NFS_V4_1) |
110 | 110 | ||
111 | static u32 initiate_file_draining(struct nfs_client *clp, | 111 | /* |
112 | struct cb_layoutrecallargs *args) | 112 | * Lookup a layout by filehandle. |
113 | * | ||
114 | * Note: gets a refcount on the layout hdr and on its respective inode. | ||
115 | * Caller must put the layout hdr and the inode. | ||
116 | * | ||
117 | * TODO: keep track of all layouts (and delegations) in a hash table | ||
118 | * hashed by filehandle. | ||
119 | */ | ||
120 | static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh) | ||
113 | { | 121 | { |
114 | struct nfs_server *server; | 122 | struct nfs_server *server; |
115 | struct pnfs_layout_hdr *lo; | ||
116 | struct inode *ino; | 123 | struct inode *ino; |
117 | bool found = false; | 124 | struct pnfs_layout_hdr *lo; |
118 | u32 rv = NFS4ERR_NOMATCHING_LAYOUT; | ||
119 | LIST_HEAD(free_me_list); | ||
120 | 125 | ||
121 | spin_lock(&clp->cl_lock); | ||
122 | rcu_read_lock(); | ||
123 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 126 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
124 | list_for_each_entry(lo, &server->layouts, plh_layouts) { | 127 | list_for_each_entry(lo, &server->layouts, plh_layouts) { |
125 | if (nfs_compare_fh(&args->cbl_fh, | 128 | if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh)) |
126 | &NFS_I(lo->plh_inode)->fh)) | ||
127 | continue; | 129 | continue; |
128 | ino = igrab(lo->plh_inode); | 130 | ino = igrab(lo->plh_inode); |
129 | if (!ino) | 131 | if (!ino) |
130 | continue; | 132 | continue; |
131 | found = true; | ||
132 | /* Without this, layout can be freed as soon | ||
133 | * as we release cl_lock. | ||
134 | */ | ||
135 | get_layout_hdr(lo); | 133 | get_layout_hdr(lo); |
136 | break; | 134 | return lo; |
137 | } | 135 | } |
138 | if (found) | ||
139 | break; | ||
140 | } | 136 | } |
137 | |||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh) | ||
142 | { | ||
143 | struct pnfs_layout_hdr *lo; | ||
144 | |||
145 | spin_lock(&clp->cl_lock); | ||
146 | rcu_read_lock(); | ||
147 | lo = get_layout_by_fh_locked(clp, fh); | ||
141 | rcu_read_unlock(); | 148 | rcu_read_unlock(); |
142 | spin_unlock(&clp->cl_lock); | 149 | spin_unlock(&clp->cl_lock); |
143 | 150 | ||
144 | if (!found) | 151 | return lo; |
152 | } | ||
153 | |||
154 | static u32 initiate_file_draining(struct nfs_client *clp, | ||
155 | struct cb_layoutrecallargs *args) | ||
156 | { | ||
157 | struct inode *ino; | ||
158 | struct pnfs_layout_hdr *lo; | ||
159 | u32 rv = NFS4ERR_NOMATCHING_LAYOUT; | ||
160 | LIST_HEAD(free_me_list); | ||
161 | |||
162 | lo = get_layout_by_fh(clp, &args->cbl_fh); | ||
163 | if (!lo) | ||
145 | return NFS4ERR_NOMATCHING_LAYOUT; | 164 | return NFS4ERR_NOMATCHING_LAYOUT; |
146 | 165 | ||
166 | ino = lo->plh_inode; | ||
147 | spin_lock(&ino->i_lock); | 167 | spin_lock(&ino->i_lock); |
148 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || | 168 | if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || |
149 | mark_matching_lsegs_invalid(lo, &free_me_list, | 169 | mark_matching_lsegs_invalid(lo, &free_me_list, |