Merge branch 'for-2.6.38' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.38' of git://linux-nfs.org/~bfields/linux: nfsd: break lease on unlink due to rename nfsd4: acquire only one lease per file nfsd4: modify fi_delegations under recall_lock nfsd4: remove unused deleg dprintk's. nfsd4: split lease setting into separate function nfsd4: fix leak on allocation error nfsd4: add helper function for lease setup nfsd4: split up nfsd_break_deleg_cb NFSD: memory corruption due to writing beyond the stat array NFSD: use nfserr for status after decode_cb_op_status nfsd: don't leak dentry count on mnt_want_write failure
This commit is contained in:
@@ -484,7 +484,7 @@ static int decode_cb_sequence4res(struct xdr_stream *xdr,
|
|||||||
out:
|
out:
|
||||||
return status;
|
return status;
|
||||||
out_default:
|
out_default:
|
||||||
return nfs_cb_stat_to_errno(status);
|
return nfs_cb_stat_to_errno(nfserr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -564,11 +564,9 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
|
|||||||
if (unlikely(status))
|
if (unlikely(status))
|
||||||
goto out;
|
goto out;
|
||||||
if (unlikely(nfserr != NFS4_OK))
|
if (unlikely(nfserr != NFS4_OK))
|
||||||
goto out_default;
|
status = nfs_cb_stat_to_errno(nfserr);
|
||||||
out:
|
out:
|
||||||
return status;
|
return status;
|
||||||
out_default:
|
|
||||||
return nfs_cb_stat_to_errno(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -230,9 +230,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
|
|||||||
dp->dl_client = clp;
|
dp->dl_client = clp;
|
||||||
get_nfs4_file(fp);
|
get_nfs4_file(fp);
|
||||||
dp->dl_file = fp;
|
dp->dl_file = fp;
|
||||||
dp->dl_vfs_file = find_readable_file(fp);
|
|
||||||
get_file(dp->dl_vfs_file);
|
|
||||||
dp->dl_flock = NULL;
|
|
||||||
dp->dl_type = type;
|
dp->dl_type = type;
|
||||||
dp->dl_stateid.si_boot = boot_time;
|
dp->dl_stateid.si_boot = boot_time;
|
||||||
dp->dl_stateid.si_stateownerid = current_delegid++;
|
dp->dl_stateid.si_stateownerid = current_delegid++;
|
||||||
@@ -241,8 +238,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
|
|||||||
fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle);
|
fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle);
|
||||||
dp->dl_time = 0;
|
dp->dl_time = 0;
|
||||||
atomic_set(&dp->dl_count, 1);
|
atomic_set(&dp->dl_count, 1);
|
||||||
list_add(&dp->dl_perfile, &fp->fi_delegations);
|
|
||||||
list_add(&dp->dl_perclnt, &clp->cl_delegations);
|
|
||||||
INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
|
INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
|
||||||
return dp;
|
return dp;
|
||||||
}
|
}
|
||||||
@@ -253,36 +248,30 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
|
|||||||
if (atomic_dec_and_test(&dp->dl_count)) {
|
if (atomic_dec_and_test(&dp->dl_count)) {
|
||||||
dprintk("NFSD: freeing dp %p\n",dp);
|
dprintk("NFSD: freeing dp %p\n",dp);
|
||||||
put_nfs4_file(dp->dl_file);
|
put_nfs4_file(dp->dl_file);
|
||||||
fput(dp->dl_vfs_file);
|
|
||||||
kmem_cache_free(deleg_slab, dp);
|
kmem_cache_free(deleg_slab, dp);
|
||||||
num_delegations--;
|
num_delegations--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove the associated file_lock first, then remove the delegation.
|
static void nfs4_put_deleg_lease(struct nfs4_file *fp)
|
||||||
* lease_modify() is called to remove the FS_LEASE file_lock from
|
|
||||||
* the i_flock list, eventually calling nfsd's lock_manager
|
|
||||||
* fl_release_callback.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
nfs4_close_delegation(struct nfs4_delegation *dp)
|
|
||||||
{
|
{
|
||||||
dprintk("NFSD: close_delegation dp %p\n",dp);
|
if (atomic_dec_and_test(&fp->fi_delegees)) {
|
||||||
/* XXX: do we even need this check?: */
|
vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
|
||||||
if (dp->dl_flock)
|
fp->fi_lease = NULL;
|
||||||
vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock);
|
fp->fi_deleg_file = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called under the state lock. */
|
/* Called under the state lock. */
|
||||||
static void
|
static void
|
||||||
unhash_delegation(struct nfs4_delegation *dp)
|
unhash_delegation(struct nfs4_delegation *dp)
|
||||||
{
|
{
|
||||||
list_del_init(&dp->dl_perfile);
|
|
||||||
list_del_init(&dp->dl_perclnt);
|
list_del_init(&dp->dl_perclnt);
|
||||||
spin_lock(&recall_lock);
|
spin_lock(&recall_lock);
|
||||||
|
list_del_init(&dp->dl_perfile);
|
||||||
list_del_init(&dp->dl_recall_lru);
|
list_del_init(&dp->dl_recall_lru);
|
||||||
spin_unlock(&recall_lock);
|
spin_unlock(&recall_lock);
|
||||||
nfs4_close_delegation(dp);
|
nfs4_put_deleg_lease(dp->dl_file);
|
||||||
nfs4_put_delegation(dp);
|
nfs4_put_delegation(dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -958,8 +947,6 @@ expire_client(struct nfs4_client *clp)
|
|||||||
spin_lock(&recall_lock);
|
spin_lock(&recall_lock);
|
||||||
while (!list_empty(&clp->cl_delegations)) {
|
while (!list_empty(&clp->cl_delegations)) {
|
||||||
dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
|
dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
|
||||||
dprintk("NFSD: expire client. dp %p, fp %p\n", dp,
|
|
||||||
dp->dl_flock);
|
|
||||||
list_del_init(&dp->dl_perclnt);
|
list_del_init(&dp->dl_perclnt);
|
||||||
list_move(&dp->dl_recall_lru, &reaplist);
|
list_move(&dp->dl_recall_lru, &reaplist);
|
||||||
}
|
}
|
||||||
@@ -2078,6 +2065,7 @@ alloc_init_file(struct inode *ino)
|
|||||||
fp->fi_inode = igrab(ino);
|
fp->fi_inode = igrab(ino);
|
||||||
fp->fi_id = current_fileid++;
|
fp->fi_id = current_fileid++;
|
||||||
fp->fi_had_conflict = false;
|
fp->fi_had_conflict = false;
|
||||||
|
fp->fi_lease = NULL;
|
||||||
memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
|
memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
|
||||||
memset(fp->fi_access, 0, sizeof(fp->fi_access));
|
memset(fp->fi_access, 0, sizeof(fp->fi_access));
|
||||||
spin_lock(&recall_lock);
|
spin_lock(&recall_lock);
|
||||||
@@ -2329,23 +2317,8 @@ nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
|
|||||||
nfs4_file_put_access(fp, O_RDONLY);
|
nfs4_file_put_access(fp, O_RDONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
|
||||||
* Spawn a thread to perform a recall on the delegation represented
|
|
||||||
* by the lease (file_lock)
|
|
||||||
*
|
|
||||||
* Called from break_lease() with lock_flocks() held.
|
|
||||||
* Note: we assume break_lease will only call this *once* for any given
|
|
||||||
* lease.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
void nfsd_break_deleg_cb(struct file_lock *fl)
|
|
||||||
{
|
{
|
||||||
struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
|
|
||||||
|
|
||||||
dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl);
|
|
||||||
if (!dp)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* We're assuming the state code never drops its reference
|
/* We're assuming the state code never drops its reference
|
||||||
* without first removing the lease. Since we're in this lease
|
* without first removing the lease. Since we're in this lease
|
||||||
* callback (and since the lease code is serialized by the kernel
|
* callback (and since the lease code is serialized by the kernel
|
||||||
@@ -2353,22 +2326,35 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
|
|||||||
* it's safe to take a reference: */
|
* it's safe to take a reference: */
|
||||||
atomic_inc(&dp->dl_count);
|
atomic_inc(&dp->dl_count);
|
||||||
|
|
||||||
spin_lock(&recall_lock);
|
|
||||||
list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
|
list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
|
||||||
spin_unlock(&recall_lock);
|
|
||||||
|
|
||||||
/* only place dl_time is set. protected by lock_flocks*/
|
/* only place dl_time is set. protected by lock_flocks*/
|
||||||
dp->dl_time = get_seconds();
|
dp->dl_time = get_seconds();
|
||||||
|
|
||||||
|
nfsd4_cb_recall(dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called from break_lease() with lock_flocks() held. */
|
||||||
|
static void nfsd_break_deleg_cb(struct file_lock *fl)
|
||||||
|
{
|
||||||
|
struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
|
||||||
|
struct nfs4_delegation *dp;
|
||||||
|
|
||||||
|
BUG_ON(!fp);
|
||||||
|
/* We assume break_lease is only called once per lease: */
|
||||||
|
BUG_ON(fp->fi_had_conflict);
|
||||||
/*
|
/*
|
||||||
* We don't want the locks code to timeout the lease for us;
|
* We don't want the locks code to timeout the lease for us;
|
||||||
* we'll remove it ourself if the delegation isn't returned
|
* we'll remove it ourself if a delegation isn't returned
|
||||||
* in time.
|
* in time:
|
||||||
*/
|
*/
|
||||||
fl->fl_break_time = 0;
|
fl->fl_break_time = 0;
|
||||||
|
|
||||||
dp->dl_file->fi_had_conflict = true;
|
spin_lock(&recall_lock);
|
||||||
nfsd4_cb_recall(dp);
|
fp->fi_had_conflict = true;
|
||||||
|
list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
|
||||||
|
nfsd_break_one_deleg(dp);
|
||||||
|
spin_unlock(&recall_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -2459,13 +2445,15 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
|
|||||||
static struct nfs4_delegation *
|
static struct nfs4_delegation *
|
||||||
find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
|
find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
|
||||||
{
|
{
|
||||||
struct nfs4_delegation *dp;
|
struct nfs4_delegation *dp = NULL;
|
||||||
|
|
||||||
|
spin_lock(&recall_lock);
|
||||||
list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {
|
list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {
|
||||||
if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
|
if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
|
||||||
return dp;
|
break;
|
||||||
}
|
}
|
||||||
return NULL;
|
spin_unlock(&recall_lock);
|
||||||
|
return dp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int share_access_to_flags(u32 share_access)
|
int share_access_to_flags(u32 share_access)
|
||||||
@@ -2641,6 +2629,66 @@ static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
|
|||||||
return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
|
return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag)
|
||||||
|
{
|
||||||
|
struct file_lock *fl;
|
||||||
|
|
||||||
|
fl = locks_alloc_lock();
|
||||||
|
if (!fl)
|
||||||
|
return NULL;
|
||||||
|
locks_init_lock(fl);
|
||||||
|
fl->fl_lmops = &nfsd_lease_mng_ops;
|
||||||
|
fl->fl_flags = FL_LEASE;
|
||||||
|
fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
|
||||||
|
fl->fl_end = OFFSET_MAX;
|
||||||
|
fl->fl_owner = (fl_owner_t)(dp->dl_file);
|
||||||
|
fl->fl_pid = current->tgid;
|
||||||
|
return fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
|
||||||
|
{
|
||||||
|
struct nfs4_file *fp = dp->dl_file;
|
||||||
|
struct file_lock *fl;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
fl = nfs4_alloc_init_lease(dp, flag);
|
||||||
|
if (!fl)
|
||||||
|
return -ENOMEM;
|
||||||
|
fl->fl_file = find_readable_file(fp);
|
||||||
|
list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
|
||||||
|
status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
|
||||||
|
if (status) {
|
||||||
|
list_del_init(&dp->dl_perclnt);
|
||||||
|
locks_free_lock(fl);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
fp->fi_lease = fl;
|
||||||
|
fp->fi_deleg_file = fl->fl_file;
|
||||||
|
get_file(fp->fi_deleg_file);
|
||||||
|
atomic_set(&fp->fi_delegees, 1);
|
||||||
|
list_add(&dp->dl_perfile, &fp->fi_delegations);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
|
||||||
|
{
|
||||||
|
struct nfs4_file *fp = dp->dl_file;
|
||||||
|
|
||||||
|
if (!fp->fi_lease)
|
||||||
|
return nfs4_setlease(dp, flag);
|
||||||
|
spin_lock(&recall_lock);
|
||||||
|
if (fp->fi_had_conflict) {
|
||||||
|
spin_unlock(&recall_lock);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
atomic_inc(&fp->fi_delegees);
|
||||||
|
list_add(&dp->dl_perfile, &fp->fi_delegations);
|
||||||
|
spin_unlock(&recall_lock);
|
||||||
|
list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempt to hand out a delegation.
|
* Attempt to hand out a delegation.
|
||||||
*/
|
*/
|
||||||
@@ -2650,7 +2698,6 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
|||||||
struct nfs4_delegation *dp;
|
struct nfs4_delegation *dp;
|
||||||
struct nfs4_stateowner *sop = stp->st_stateowner;
|
struct nfs4_stateowner *sop = stp->st_stateowner;
|
||||||
int cb_up;
|
int cb_up;
|
||||||
struct file_lock *fl;
|
|
||||||
int status, flag = 0;
|
int status, flag = 0;
|
||||||
|
|
||||||
cb_up = nfsd4_cb_channel_good(sop->so_client);
|
cb_up = nfsd4_cb_channel_good(sop->so_client);
|
||||||
@@ -2681,36 +2728,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
|
dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
|
||||||
if (dp == NULL) {
|
if (dp == NULL)
|
||||||
flag = NFS4_OPEN_DELEGATE_NONE;
|
goto out_no_deleg;
|
||||||
goto out;
|
status = nfs4_set_delegation(dp, flag);
|
||||||
}
|
if (status)
|
||||||
status = -ENOMEM;
|
goto out_free;
|
||||||
fl = locks_alloc_lock();
|
|
||||||
if (!fl)
|
|
||||||
goto out;
|
|
||||||
locks_init_lock(fl);
|
|
||||||
fl->fl_lmops = &nfsd_lease_mng_ops;
|
|
||||||
fl->fl_flags = FL_LEASE;
|
|
||||||
fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
|
|
||||||
fl->fl_end = OFFSET_MAX;
|
|
||||||
fl->fl_owner = (fl_owner_t)dp;
|
|
||||||
fl->fl_file = find_readable_file(stp->st_file);
|
|
||||||
BUG_ON(!fl->fl_file);
|
|
||||||
fl->fl_pid = current->tgid;
|
|
||||||
dp->dl_flock = fl;
|
|
||||||
|
|
||||||
/* vfs_setlease checks to see if delegation should be handed out.
|
|
||||||
* the lock_manager callback fl_change is used
|
|
||||||
*/
|
|
||||||
if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
|
|
||||||
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
|
|
||||||
dp->dl_flock = NULL;
|
|
||||||
locks_free_lock(fl);
|
|
||||||
unhash_delegation(dp);
|
|
||||||
flag = NFS4_OPEN_DELEGATE_NONE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));
|
memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));
|
||||||
|
|
||||||
@@ -2722,6 +2744,12 @@ out:
|
|||||||
&& open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
|
&& open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
|
||||||
dprintk("NFSD: WARNING: refusing delegation reclaim\n");
|
dprintk("NFSD: WARNING: refusing delegation reclaim\n");
|
||||||
open->op_delegate_type = flag;
|
open->op_delegate_type = flag;
|
||||||
|
return;
|
||||||
|
out_free:
|
||||||
|
nfs4_put_delegation(dp);
|
||||||
|
out_no_deleg:
|
||||||
|
flag = NFS4_OPEN_DELEGATE_NONE;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2916,8 +2944,6 @@ nfs4_laundromat(void)
|
|||||||
test_val = u;
|
test_val = u;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dprintk("NFSD: purging unused delegation dp %p, fp %p\n",
|
|
||||||
dp, dp->dl_flock);
|
|
||||||
list_move(&dp->dl_recall_lru, &reaplist);
|
list_move(&dp->dl_recall_lru, &reaplist);
|
||||||
}
|
}
|
||||||
spin_unlock(&recall_lock);
|
spin_unlock(&recall_lock);
|
||||||
@@ -3128,7 +3154,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
|
|||||||
goto out;
|
goto out;
|
||||||
renew_client(dp->dl_client);
|
renew_client(dp->dl_client);
|
||||||
if (filpp) {
|
if (filpp) {
|
||||||
*filpp = find_readable_file(dp->dl_file);
|
*filpp = dp->dl_file->fi_deleg_file;
|
||||||
BUG_ON(!*filpp);
|
BUG_ON(!*filpp);
|
||||||
}
|
}
|
||||||
} else { /* open or lock stateid */
|
} else { /* open or lock stateid */
|
||||||
|
@@ -83,8 +83,6 @@ struct nfs4_delegation {
|
|||||||
atomic_t dl_count; /* ref count */
|
atomic_t dl_count; /* ref count */
|
||||||
struct nfs4_client *dl_client;
|
struct nfs4_client *dl_client;
|
||||||
struct nfs4_file *dl_file;
|
struct nfs4_file *dl_file;
|
||||||
struct file *dl_vfs_file;
|
|
||||||
struct file_lock *dl_flock;
|
|
||||||
u32 dl_type;
|
u32 dl_type;
|
||||||
time_t dl_time;
|
time_t dl_time;
|
||||||
/* For recall: */
|
/* For recall: */
|
||||||
@@ -379,6 +377,9 @@ struct nfs4_file {
|
|||||||
*/
|
*/
|
||||||
atomic_t fi_readers;
|
atomic_t fi_readers;
|
||||||
atomic_t fi_writers;
|
atomic_t fi_writers;
|
||||||
|
struct file *fi_deleg_file;
|
||||||
|
struct file_lock *fi_lease;
|
||||||
|
atomic_t fi_delegees;
|
||||||
struct inode *fi_inode;
|
struct inode *fi_inode;
|
||||||
u32 fi_id; /* used with stateowner->so_id
|
u32 fi_id; /* used with stateowner->so_id
|
||||||
* for stateid_hashtbl hash */
|
* for stateid_hashtbl hash */
|
||||||
|
@@ -808,7 +808,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
|
|||||||
if (ra->p_count == 0)
|
if (ra->p_count == 0)
|
||||||
frap = rap;
|
frap = rap;
|
||||||
}
|
}
|
||||||
depth = nfsdstats.ra_size*11/10;
|
depth = nfsdstats.ra_size;
|
||||||
if (!frap) {
|
if (!frap) {
|
||||||
spin_unlock(&rab->pb_lock);
|
spin_unlock(&rab->pb_lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1742,6 +1742,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
|||||||
goto out_dput_new;
|
goto out_dput_new;
|
||||||
|
|
||||||
host_err = nfsd_break_lease(odentry->d_inode);
|
host_err = nfsd_break_lease(odentry->d_inode);
|
||||||
|
if (host_err)
|
||||||
|
goto out_drop_write;
|
||||||
|
if (ndentry->d_inode) {
|
||||||
|
host_err = nfsd_break_lease(ndentry->d_inode);
|
||||||
|
if (host_err)
|
||||||
|
goto out_drop_write;
|
||||||
|
}
|
||||||
if (host_err)
|
if (host_err)
|
||||||
goto out_drop_write;
|
goto out_drop_write;
|
||||||
host_err = vfs_rename(fdir, odentry, tdir, ndentry);
|
host_err = vfs_rename(fdir, odentry, tdir, ndentry);
|
||||||
@@ -1812,22 +1819,22 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
|||||||
|
|
||||||
host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
|
host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
|
||||||
if (host_err)
|
if (host_err)
|
||||||
goto out_nfserr;
|
goto out_put;
|
||||||
|
|
||||||
host_err = nfsd_break_lease(rdentry->d_inode);
|
host_err = nfsd_break_lease(rdentry->d_inode);
|
||||||
if (host_err)
|
if (host_err)
|
||||||
goto out_put;
|
goto out_drop_write;
|
||||||
if (type != S_IFDIR)
|
if (type != S_IFDIR)
|
||||||
host_err = vfs_unlink(dirp, rdentry);
|
host_err = vfs_unlink(dirp, rdentry);
|
||||||
else
|
else
|
||||||
host_err = vfs_rmdir(dirp, rdentry);
|
host_err = vfs_rmdir(dirp, rdentry);
|
||||||
|
if (!host_err)
|
||||||
|
host_err = commit_metadata(fhp);
|
||||||
|
out_drop_write:
|
||||||
|
mnt_drop_write(fhp->fh_export->ex_path.mnt);
|
||||||
out_put:
|
out_put:
|
||||||
dput(rdentry);
|
dput(rdentry);
|
||||||
|
|
||||||
if (!host_err)
|
|
||||||
host_err = commit_metadata(fhp);
|
|
||||||
|
|
||||||
mnt_drop_write(fhp->fh_export->ex_path.mnt);
|
|
||||||
out_nfserr:
|
out_nfserr:
|
||||||
err = nfserrno(host_err);
|
err = nfserrno(host_err);
|
||||||
out:
|
out:
|
||||||
|
Reference in New Issue
Block a user