Skip to content

Commit 624322f

Browse files
Olga KornievskaiaJ. Bruce Fields
authored andcommitted
NFSD add COPY_NOTIFY operation
Introducing the COPY_NOTIFY operation. Create a new unique stateid that will keep track of the copy state and the upcoming READs that will use that stateid. Each associated parent stateid has a list of copy notify stateids. A copy notify structure makes a copy of the parent stateid and a clientid and will use it to look up the parent stateid during the READ request (suggested by Trond Myklebust <trond.myklebust@hammerspace.com>). At nfs4_put_stid() time, we walk the list of the associated copy notify stateids and delete them. Laundromat thread will traverse globally stored copy notify stateid in idr and notice if any haven't been referenced in the lease period, if so, it'll remove them. Return single netaddr to advertise to the copy. Suggested-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Olga Kornievskaia <kolga@netapp.com> Signed-off-by: Andy Adamson <andros@netapp.com>
1 parent 5191186 commit 624322f

File tree

4 files changed

+173
-24
lines changed

4 files changed

+173
-24
lines changed

fs/nfsd/nfs4proc.c

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/falloc.h>
3838
#include <linux/slab.h>
3939
#include <linux/kthread.h>
40+
#include <linux/sunrpc/addr.h>
4041

4142
#include "idmap.h"
4243
#include "cache.h"
@@ -776,7 +777,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
776777
/* check stateid */
777778
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
778779
&read->rd_stateid, RD_STATE,
779-
&read->rd_nf);
780+
&read->rd_nf, NULL);
780781
if (status) {
781782
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
782783
goto out;
@@ -948,7 +949,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
948949
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
949950
status = nfs4_preprocess_stateid_op(rqstp, cstate,
950951
&cstate->current_fh, &setattr->sa_stateid,
951-
WR_STATE, NULL);
952+
WR_STATE, NULL, NULL);
952953
if (status) {
953954
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
954955
return status;
@@ -999,7 +1000,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
9991000
trace_nfsd_write_start(rqstp, &cstate->current_fh,
10001001
write->wr_offset, cnt);
10011002
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1002-
stateid, WR_STATE, &nf);
1003+
stateid, WR_STATE, &nf, NULL);
10031004
if (status) {
10041005
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
10051006
return status;
@@ -1034,14 +1035,14 @@ nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
10341035
return nfserr_nofilehandle;
10351036

10361037
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
1037-
src_stateid, RD_STATE, src);
1038+
src_stateid, RD_STATE, src, NULL);
10381039
if (status) {
10391040
dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
10401041
goto out;
10411042
}
10421043

10431044
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1044-
dst_stateid, WR_STATE, dst);
1045+
dst_stateid, WR_STATE, dst, NULL);
10451046
if (status) {
10461047
dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
10471048
goto out_put_src;
@@ -1221,7 +1222,7 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
12211222

12221223
static void cleanup_async_copy(struct nfsd4_copy *copy)
12231224
{
1224-
nfs4_free_cp_state(copy);
1225+
nfs4_free_copy_state(copy);
12251226
nfsd_file_put(copy->nf_dst);
12261227
nfsd_file_put(copy->nf_src);
12271228
spin_lock(&copy->cp_clp->async_lock);
@@ -1275,7 +1276,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
12751276
async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
12761277
if (!async_copy)
12771278
goto out;
1278-
if (!nfs4_init_cp_state(nn, copy)) {
1279+
if (!nfs4_init_copy_state(nn, copy)) {
12791280
kfree(async_copy);
12801281
goto out;
12811282
}
@@ -1343,7 +1344,44 @@ static __be32
13431344
nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
13441345
union nfsd4_op_u *u)
13451346
{
1346-
return nfserr_notsupp;
1347+
struct nfsd4_copy_notify *cn = &u->copy_notify;
1348+
__be32 status;
1349+
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1350+
struct nfs4_stid *stid;
1351+
struct nfs4_cpntf_state *cps;
1352+
struct nfs4_client *clp = cstate->clp;
1353+
1354+
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1355+
&cn->cpn_src_stateid, RD_STATE, NULL,
1356+
&stid);
1357+
if (status)
1358+
return status;
1359+
1360+
cn->cpn_sec = nn->nfsd4_lease;
1361+
cn->cpn_nsec = 0;
1362+
1363+
status = nfserrno(-ENOMEM);
1364+
cps = nfs4_alloc_init_cpntf_state(nn, stid);
1365+
if (!cps)
1366+
goto out;
1367+
memcpy(&cn->cpn_cnr_stateid, &cps->cp_stateid.stid, sizeof(stateid_t));
1368+
memcpy(&cps->cp_p_stateid, &stid->sc_stateid, sizeof(stateid_t));
1369+
memcpy(&cps->cp_p_clid, &clp->cl_clientid, sizeof(clientid_t));
1370+
1371+
/* For now, only return one server address in cpn_src, the
1372+
* address used by the client to connect to this server.
1373+
*/
1374+
cn->cpn_src.nl4_type = NL4_NETADDR;
1375+
status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr,
1376+
&cn->cpn_src.u.nl4_addr);
1377+
WARN_ON_ONCE(status);
1378+
if (status) {
1379+
nfs4_put_cpntf_state(nn, cps);
1380+
goto out;
1381+
}
1382+
out:
1383+
nfs4_put_stid(stid);
1384+
return status;
13471385
}
13481386

13491387
static __be32
@@ -1355,7 +1393,7 @@ nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
13551393

13561394
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
13571395
&fallocate->falloc_stateid,
1358-
WR_STATE, &nf);
1396+
WR_STATE, &nf, NULL);
13591397
if (status != nfs_ok) {
13601398
dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
13611399
return status;
@@ -1414,7 +1452,7 @@ nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
14141452

14151453
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
14161454
&seek->seek_stateid,
1417-
RD_STATE, &nf);
1455+
RD_STATE, &nf, NULL);
14181456
if (status) {
14191457
dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n");
14201458
return status;

fs/nfsd/nfs4state.c

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static u64 current_sessionid = 1;
8080
static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
8181
static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
8282
void nfsd4_end_grace(struct nfsd_net *nn);
83+
static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps);
8384

8485
/* Locking: */
8586

@@ -722,6 +723,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla
722723
/* Will be incremented before return to client: */
723724
refcount_set(&stid->sc_count, 1);
724725
spin_lock_init(&stid->sc_lock);
726+
INIT_LIST_HEAD(&stid->sc_cp_list);
725727

726728
/*
727729
* It shouldn't be a problem to reuse an opaque stateid value.
@@ -741,30 +743,76 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla
741743
/*
742744
* Create a unique stateid_t to represent each COPY.
743745
*/
744-
int nfs4_init_cp_state(struct nfsd_net *nn, struct nfsd4_copy *copy)
746+
static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid,
747+
unsigned char sc_type)
745748
{
746749
int new_id;
747750

751+
stid->stid.si_opaque.so_clid.cl_boot = nn->boot_time;
752+
stid->stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id;
753+
stid->sc_type = sc_type;
754+
748755
idr_preload(GFP_KERNEL);
749756
spin_lock(&nn->s2s_cp_lock);
750-
new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, copy, 0, 0, GFP_NOWAIT);
757+
new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT);
758+
stid->stid.si_opaque.so_id = new_id;
751759
spin_unlock(&nn->s2s_cp_lock);
752760
idr_preload_end();
753761
if (new_id < 0)
754762
return 0;
755-
copy->cp_stateid.si_opaque.so_id = new_id;
756-
copy->cp_stateid.si_opaque.so_clid.cl_boot = nn->boot_time;
757-
copy->cp_stateid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id;
758763
return 1;
759764
}
760765

761-
void nfs4_free_cp_state(struct nfsd4_copy *copy)
766+
int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy)
767+
{
768+
return nfs4_init_cp_state(nn, &copy->cp_stateid, NFS4_COPY_STID);
769+
}
770+
771+
struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
772+
struct nfs4_stid *p_stid)
773+
{
774+
struct nfs4_cpntf_state *cps;
775+
776+
cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL);
777+
if (!cps)
778+
return NULL;
779+
cps->cpntf_time = get_seconds();
780+
refcount_set(&cps->cp_stateid.sc_count, 1);
781+
if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID))
782+
goto out_free;
783+
spin_lock(&nn->s2s_cp_lock);
784+
list_add(&cps->cp_list, &p_stid->sc_cp_list);
785+
spin_unlock(&nn->s2s_cp_lock);
786+
return cps;
787+
out_free:
788+
kfree(cps);
789+
return NULL;
790+
}
791+
792+
void nfs4_free_copy_state(struct nfsd4_copy *copy)
762793
{
763794
struct nfsd_net *nn;
764795

796+
WARN_ON_ONCE(copy->cp_stateid.sc_type != NFS4_COPY_STID);
765797
nn = net_generic(copy->cp_clp->net, nfsd_net_id);
766798
spin_lock(&nn->s2s_cp_lock);
767-
idr_remove(&nn->s2s_cp_stateids, copy->cp_stateid.si_opaque.so_id);
799+
idr_remove(&nn->s2s_cp_stateids,
800+
copy->cp_stateid.stid.si_opaque.so_id);
801+
spin_unlock(&nn->s2s_cp_lock);
802+
}
803+
804+
static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid)
805+
{
806+
struct nfs4_cpntf_state *cps;
807+
struct nfsd_net *nn;
808+
809+
nn = net_generic(net, nfsd_net_id);
810+
spin_lock(&nn->s2s_cp_lock);
811+
while (!list_empty(&stid->sc_cp_list)) {
812+
cps = list_first_entry(&stid->sc_cp_list,
813+
struct nfs4_cpntf_state, cp_list);
814+
_free_cpntf_state_locked(nn, cps);
815+
}
768816
spin_unlock(&nn->s2s_cp_lock);
769817
}
770818

@@ -915,6 +963,7 @@ nfs4_put_stid(struct nfs4_stid *s)
915963
return;
916964
}
917965
idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
966+
nfs4_free_cpntf_statelist(clp->net, s);
918967
spin_unlock(&clp->cl_lock);
919968
s->sc_free(s);
920969
if (fp)
@@ -5215,6 +5264,9 @@ nfs4_laundromat(struct nfsd_net *nn)
52155264
struct list_head *pos, *next, reaplist;
52165265
time_t cutoff = get_seconds() - nn->nfsd4_lease;
52175266
time_t t, new_timeo = nn->nfsd4_lease;
5267+
struct nfs4_cpntf_state *cps;
5268+
copy_stateid_t *cps_t;
5269+
int i;
52185270

52195271
dprintk("NFSD: laundromat service - starting\n");
52205272

@@ -5225,6 +5277,17 @@ nfs4_laundromat(struct nfsd_net *nn)
52255277
dprintk("NFSD: end of grace period\n");
52265278
nfsd4_end_grace(nn);
52275279
INIT_LIST_HEAD(&reaplist);
5280+
5281+
spin_lock(&nn->s2s_cp_lock);
5282+
idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
5283+
cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
5284+
if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
5285+
!time_after((unsigned long)cps->cpntf_time,
5286+
(unsigned long)cutoff))
5287+
_free_cpntf_state_locked(nn, cps);
5288+
}
5289+
spin_unlock(&nn->s2s_cp_lock);
5290+
52285291
spin_lock(&nn->client_lock);
52295292
list_for_each_safe(pos, next, &nn->client_lru) {
52305293
clp = list_entry(pos, struct nfs4_client, cl_lru);
@@ -5600,14 +5663,33 @@ nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s,
56005663
out:
56015664
return status;
56025665
}
5666+
static void
5667+
_free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
5668+
{
5669+
WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID);
5670+
if (!refcount_dec_and_test(&cps->cp_stateid.sc_count))
5671+
return;
5672+
list_del(&cps->cp_list);
5673+
idr_remove(&nn->s2s_cp_stateids,
5674+
cps->cp_stateid.stid.si_opaque.so_id);
5675+
kfree(cps);
5676+
}
5677+
5678+
void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
5679+
{
5680+
spin_lock(&nn->s2s_cp_lock);
5681+
_free_cpntf_state_locked(nn, cps);
5682+
spin_unlock(&nn->s2s_cp_lock);
5683+
}
56035684

56045685
/*
56055686
* Checks for stateid operations
56065687
*/
56075688
__be32
56085689
nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
56095690
struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
5610-
stateid_t *stateid, int flags, struct nfsd_file **nfp)
5691+
stateid_t *stateid, int flags, struct nfsd_file **nfp,
5692+
struct nfs4_stid **cstid)
56115693
{
56125694
struct inode *ino = d_inode(fhp->fh_dentry);
56135695
struct net *net = SVC_NET(rqstp);
@@ -5656,8 +5738,12 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
56565738
if (status == nfs_ok && nfp)
56575739
status = nfs4_check_file(rqstp, fhp, s, nfp, flags);
56585740
out:
5659-
if (s)
5660-
nfs4_put_stid(s);
5741+
if (s) {
5742+
if (!status && cstid)
5743+
*cstid = s;
5744+
else
5745+
nfs4_put_stid(s);
5746+
}
56615747
return status;
56625748
}
56635749

fs/nfsd/state.h

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ typedef struct {
5656
stateid_opaque_t si_opaque;
5757
} stateid_t;
5858

59+
typedef struct {
60+
stateid_t stid;
61+
#define NFS4_COPY_STID 1
62+
#define NFS4_COPYNOTIFY_STID 2
63+
unsigned char sc_type;
64+
refcount_t sc_count;
65+
} copy_stateid_t;
66+
5967
#define STATEID_FMT "(%08x/%08x/%08x/%08x)"
6068
#define STATEID_VAL(s) \
6169
(s)->si_opaque.so_clid.cl_boot, \
@@ -96,6 +104,7 @@ struct nfs4_stid {
96104
#define NFS4_REVOKED_DELEG_STID 16
97105
#define NFS4_CLOSED_DELEG_STID 32
98106
#define NFS4_LAYOUT_STID 64
107+
struct list_head sc_cp_list;
99108
unsigned char sc_type;
100109
stateid_t sc_stateid;
101110
spinlock_t sc_lock;
@@ -104,6 +113,17 @@ struct nfs4_stid {
104113
void (*sc_free)(struct nfs4_stid *);
105114
};
106115

116+
/* Keep a list of stateids issued by the COPY_NOTIFY, associate it with the
117+
* parent OPEN/LOCK/DELEG stateid.
118+
*/
119+
struct nfs4_cpntf_state {
120+
copy_stateid_t cp_stateid;
121+
struct list_head cp_list; /* per parent nfs4_stid */
122+
stateid_t cp_p_stateid; /* copy of parent's stateid */
123+
clientid_t cp_p_clid; /* copy of parent's clid */
124+
time_t cpntf_time; /* last time stateid used */
125+
};
126+
107127
/*
108128
* Represents a delegation stateid. The nfs4_client holds references to these
109129
* and they are put when it is being destroyed or when the delegation is
@@ -618,14 +638,17 @@ struct nfsd4_copy;
618638

619639
extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
620640
struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
621-
stateid_t *stateid, int flags, struct nfsd_file **filp);
641+
stateid_t *stateid, int flags, struct nfsd_file **filp,
642+
struct nfs4_stid **cstid);
622643
__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
623644
stateid_t *stateid, unsigned char typemask,
624645
struct nfs4_stid **s, struct nfsd_net *nn);
625646
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
626647
void (*sc_free)(struct nfs4_stid *));
627-
int nfs4_init_cp_state(struct nfsd_net *nn, struct nfsd4_copy *copy);
628-
void nfs4_free_cp_state(struct nfsd4_copy *copy);
648+
int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy);
649+
void nfs4_free_copy_state(struct nfsd4_copy *copy);
650+
struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn,
651+
struct nfs4_stid *p_stid);
629652
void nfs4_unhash_stid(struct nfs4_stid *s);
630653
void nfs4_put_stid(struct nfs4_stid *s);
631654
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
@@ -655,6 +678,8 @@ void put_nfs4_file(struct nfs4_file *fi);
655678
extern void nfs4_put_copy(struct nfsd4_copy *copy);
656679
extern struct nfsd4_copy *
657680
find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
681+
extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
682+
struct nfs4_cpntf_state *cps);
658683
static inline void get_nfs4_file(struct nfs4_file *fi)
659684
{
660685
refcount_inc(&fi->fi_ref);

fs/nfsd/xdr4.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ struct nfsd4_copy {
542542
struct nfsd_file *nf_src;
543543
struct nfsd_file *nf_dst;
544544

545-
stateid_t cp_stateid;
545+
copy_stateid_t cp_stateid;
546546

547547
struct list_head copies;
548548
struct task_struct *copy_task;

0 commit comments

Comments
 (0)