aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/callback_proc.c56
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
111static 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 */
120static 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
141static 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
154static 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,