@@ -553,7 +553,7 @@ bl_layoutreturn(struct inode *i,
}
int
-bl_layoutrecall(struct inode *inode, int type, u64 offset, u64 len)
+bl_layoutrecall(struct inode *inode, int type, u64 offset, u64 len, bool with_nfs4_state_lock)
{
struct super_block *sb;
struct nfsd4_pnfs_cb_layout lr;
@@ -624,7 +624,7 @@ restart:
* same thread which will cause a deadlock.
*/
spin_unlock(&r->blr_lock);
- nfsd_layout_recall_cb(sb, inode, &lr);
+ _nfsd_layout_recall_cb(sb, inode, &lr, with_nfs4_state_lock);
adj = MIN(b->bll_len - (offset - b->bll_foff),
len);
offset += adj;
@@ -1581,8 +1581,9 @@ spawn_layout_recall(struct super_block *sb, struct list_head *todolist,
* Spawn a thread to perform a recall layout
*
*/
-int nfsd_layout_recall_cb(struct super_block *sb, struct inode *inode,
- struct nfsd4_pnfs_cb_layout *cbl)
+int
+_nfsd_layout_recall_cb(struct super_block *sb, struct inode *inode,
+ struct nfsd4_pnfs_cb_layout *cbl, bool with_nfs4_state_lock)
{
int status;
struct nfs4_file *lrfile = NULL;
@@ -1604,7 +1605,8 @@ int nfsd_layout_recall_cb(struct super_block *sb, struct inode *inode,
return -ENOENT;
}
- nfs4_lock_state();
+ if (!with_nfs4_state_lock)
+ nfs4_lock_state();
status = -ENOENT;
if (inode) {
lrfile = find_file(inode);
@@ -1635,12 +1637,20 @@ int nfsd_layout_recall_cb(struct super_block *sb, struct inode *inode,
}
err:
- nfs4_unlock_state();
+ if (!with_nfs4_state_lock)
+ nfs4_unlock_state();
if (lrfile)
put_nfs4_file(lrfile);
return (todo_len && status) ? -EAGAIN : status;
}
+int
+nfsd_layout_recall_cb(struct super_block *sb, struct inode *inode,
+ struct nfsd4_pnfs_cb_layout *cbl)
+{
+ return _nfsd_layout_recall_cb(sb, inode, cbl, false);
+}
+
struct create_device_notify_list_arg {
struct list_head *todolist;
struct nfsd4_pnfs_cb_dev_list *ndl;
@@ -913,7 +913,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
#if defined(CONFIG_SPNFS_BLOCK)
if (pnfs_block_enabled(cstate->current_fh.fh_dentry->d_inode, 0)) {
status = bl_layoutrecall(cstate->current_fh.fh_dentry->d_inode,
- RETURN_FILE, write->wr_offset, write->wr_buflen);
+ RETURN_FILE, write->wr_offset, write->wr_buflen, false);
if (!status) {
status = nfsd_write(rqstp, &cstate->current_fh, filp,
write->wr_offset, rqstp->rq_vec, write->wr_vlen,
@@ -2707,7 +2707,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
return 0;
if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
return nfserr_inval;
- return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
+ return nfsd_setattr_locked(rqstp, fh, &iattr, 0, (time_t)0);
}
static __be32
@@ -128,6 +128,9 @@ void nomatching_layout(struct nfs4_layoutrecall *);
void pnfs_roc(struct nfs4_client *clp, struct nfs4_file *fp);
void *layoutrecall_done(struct nfs4_layoutrecall *);
void nfsd4_cb_layout(struct nfs4_layoutrecall *);
+int _nfsd_layout_recall_cb(struct super_block *, struct inode *,
+ struct nfsd4_pnfs_cb_layout *,
+ bool with_nfs4_state_lock);
int nfsd_layout_recall_cb(struct super_block *, struct inode *,
struct nfsd4_pnfs_cb_layout *);
int nfsd_device_notify_cb(struct super_block *,
@@ -142,7 +145,7 @@ extern size_t pnfs_lexp_addr_len;
extern void pnfsd_lexp_init(struct inode *);
extern bool is_inode_pnfsd_lexp(struct inode *);
-extern int pnfsd_lexp_recall_layout(struct inode *);
+extern int pnfsd_lexp_recall_layout(struct inode *, bool with_nfs4_state_lock);
#endif /* CONFIG_PNFSD_LOCAL_EXPORT */
#endif /* LINUX_NFSD_PNFSD_H */
@@ -258,7 +258,7 @@ has_layout(struct nfs4_file *fp)
* recalls the layout if needed and waits synchronously for its return
*/
int
-pnfsd_lexp_recall_layout(struct inode *inode)
+pnfsd_lexp_recall_layout(struct inode *inode, bool with_nfs4_state_lock)
{
struct nfs4_file *fp;
struct nfsd4_pnfs_cb_layout cbl;
@@ -281,7 +281,7 @@ pnfsd_lexp_recall_layout(struct inode *inode)
while (has_layout(fp)) {
dprintk("%s: recalling layout\n", __func__);
- status = nfsd_layout_recall_cb(inode->i_sb, inode, &cbl);
+ status = _nfsd_layout_recall_cb(inode->i_sb, inode, &cbl, with_nfs4_state_lock);
switch (status) {
case 0:
@@ -304,8 +304,8 @@ commit_metadata(struct svc_fh *fhp)
* N.B. After this call fhp needs an fh_put
*/
__be32
-nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
- int check_guard, time_t guardtime)
+_nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
+ int check_guard, time_t guardtime, bool with_nfs4_state_lock)
{
struct dentry *dentry;
struct inode *inode;
@@ -384,12 +384,13 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
goto out;
#if defined(CONFIG_PNFSD_LOCAL_EXPORT)
if (is_inode_pnfsd_lexp(inode))
- pnfsd_lexp_recall_layout(inode);
+ pnfsd_lexp_recall_layout(inode, with_nfs4_state_lock);
#endif /* CONFIG_PNFSD_LOCAL_EXPORT */
#if defined(CONFIG_SPNFS_BLOCK)
if (pnfs_block_enabled(inode, 0)) {
err = bl_layoutrecall(inode, RETURN_FILE,
- iap->ia_size, inode->i_size - iap->ia_size);
+ iap->ia_size, inode->i_size - iap->ia_size,
+ with_nfs4_state_lock);
}
#endif /* CONFIG_SPNFS_BLOCK */
}
@@ -45,8 +45,26 @@ __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
const char *, unsigned int,
struct svc_export **, struct dentry **);
-__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
- struct iattr *, int, time_t);
+__be32 _nfsd_setattr(struct svc_rqst *, struct svc_fh *,
+ struct iattr *, int, time_t,
+ bool with_nfs4_state_lock);
+
+/* call when nfs4_lock_state has not been taken */
+static inline __be32
+nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct iattr *iap, int check_guard, time_t guardtime)
+{
+ return _nfsd_setattr(rqstp, fhp, iap, check_guard, guardtime, false);
+}
+
+/* call when nfs4_lock_state is taken */
+static inline __be32
+nfsd_setattr_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct iattr *iap, int check_guard, time_t guardtime)
+{
+ return _nfsd_setattr(rqstp, fhp, iap, check_guard, guardtime, true);
+}
+
int nfsd_mountpoint(struct dentry *, struct svc_export *);
#ifdef CONFIG_NFSD_V4
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,