@@ -80,6 +80,7 @@ static u64 current_sessionid = 1;
8080static bool check_for_locks (struct nfs4_file * fp , struct nfs4_lockowner * lowner );
8181static void nfs4_free_ol_stateid (struct nfs4_stid * stid );
8282void 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,
56005663out :
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
56085689nfs4_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 );
56585740out :
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
0 commit comments