nfsd: don't fail unchecked creates of non-special files
[pandora-kernel.git] / fs / nfsd / state.h
index 4eefaf1..a3cf384 100644 (file)
@@ -35,6 +35,7 @@
 #ifndef _NFSD4_STATE_H
 #define _NFSD4_STATE_H
 
+#include <linux/idr.h>
 #include <linux/sunrpc/svc_xprt.h>
 #include <linux/nfsd/nfsfh.h>
 #include "nfsfh.h"
@@ -45,24 +46,20 @@ typedef struct {
 } clientid_t;
 
 typedef struct {
-       u32             so_boot;
-       u32             so_stateownerid;
-       u32             so_fileid;
+       clientid_t      so_clid;
+       u32             so_id;
 } stateid_opaque_t;
 
 typedef struct {
        u32                     si_generation;
        stateid_opaque_t        si_opaque;
 } stateid_t;
-#define si_boot           si_opaque.so_boot
-#define si_stateownerid   si_opaque.so_stateownerid
-#define si_fileid         si_opaque.so_fileid
 
 #define STATEID_FMT    "(%08x/%08x/%08x/%08x)"
 #define STATEID_VAL(s) \
-       (s)->si_boot, \
-       (s)->si_stateownerid, \
-       (s)->si_fileid, \
+       (s)->si_opaque.so_clid.cl_boot, \
+       (s)->si_opaque.so_clid.cl_id, \
+       (s)->si_opaque.so_id, \
        (s)->si_generation
 
 struct nfsd4_callback {
@@ -76,17 +73,27 @@ struct nfsd4_callback {
        bool cb_done;
 };
 
+struct nfs4_stid {
+#define NFS4_OPEN_STID 1
+#define NFS4_LOCK_STID 2
+#define NFS4_DELEG_STID 4
+/* For an open stateid kept around *only* to process close replays: */
+#define NFS4_CLOSED_STID 8
+       unsigned char sc_type;
+       stateid_t sc_stateid;
+       struct nfs4_client *sc_client;
+};
+
 struct nfs4_delegation {
+       struct nfs4_stid        dl_stid; /* must be first field */
        struct list_head        dl_perfile;
        struct list_head        dl_perclnt;
        struct list_head        dl_recall_lru;  /* delegation recalled */
        atomic_t                dl_count;       /* ref count */
-       struct nfs4_client      *dl_client;
        struct nfs4_file        *dl_file;
        u32                     dl_type;
        time_t                  dl_time;
 /* For recall: */
-       stateid_t               dl_stateid;
        struct knfsd_fh         dl_fh;
        int                     dl_retries;
        struct nfsd4_callback   dl_recall;
@@ -104,6 +111,11 @@ struct nfs4_cb_conn {
        struct svc_xprt         *cb_xprt;       /* minorversion 1 only */
 };
 
+static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s)
+{
+       return container_of(s, struct nfs4_delegation, dl_stid);
+}
+
 /* Maximum number of slots per session. 160 is useful for long haul TCP */
 #define NFSD_MAX_SLOTS_PER_SESSION     160
 /* Maximum number of operations per session compound */
@@ -220,6 +232,7 @@ struct nfs4_client {
        struct list_head        cl_idhash;      /* hash by cl_clientid.id */
        struct list_head        cl_strhash;     /* hash by cl_name */
        struct list_head        cl_openowners;
+       struct idr              cl_stateids;    /* stateid lookup */
        struct list_head        cl_delegations;
        struct list_head        cl_lru;         /* tail queue */
        struct xdr_netobj       cl_name;        /* id generated by client */
@@ -245,6 +258,7 @@ struct nfs4_client {
 #define NFSD4_CB_UP            0
 #define NFSD4_CB_UNKNOWN       1
 #define NFSD4_CB_DOWN          2
+#define NFSD4_CB_FAULT         3
        int                     cl_cb_state;
        struct nfsd4_callback   cl_cb_null;
        struct nfsd4_session    *cl_cb_session;
@@ -293,6 +307,9 @@ static inline void
 update_stateid(stateid_t *stateid)
 {
        stateid->si_generation++;
+       /* Wraparound recommendation from 3530bis-13 9.1.3.2: */
+       if (stateid->si_generation == 0)
+               stateid->si_generation = 1;
 }
 
 /* A reasonable value for REPLAY_ISIZE was estimated as follows:  
@@ -312,49 +329,57 @@ struct nfs4_replay {
        __be32                  rp_status;
        unsigned int            rp_buflen;
        char                    *rp_buf;
-       unsigned                intrp_allocated;
        struct knfsd_fh         rp_openfh;
        char                    rp_ibuf[NFSD4_REPLAY_ISIZE];
 };
 
-/*
-* nfs4_stateowner can either be an open_owner, or a lock_owner
-*
-*    so_idhash:  stateid_hashtbl[] for open owner, lockstateid_hashtbl[]
-*         for lock_owner
-*    so_strhash: ownerstr_hashtbl[] for open_owner, lock_ownerstr_hashtbl[]
-*         for lock_owner
-*    so_perclient: nfs4_client->cl_perclient entry - used when nfs4_client
-*         struct is reaped.
-*    so_perfilestate: heads the list of nfs4_stateid (either open or lock) 
-*         and is used to ensure no dangling nfs4_stateid references when we 
-*         release a stateowner.
-*    so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when
-*         close is called to reap associated byte-range locks
-*    so_close_lru: (open) stateowner is placed on this list instead of being
-*         reaped (when so_perfilestate is empty) to hold the last close replay.
-*         reaped by laundramat thread after lease period.
-*/
 struct nfs4_stateowner {
-       struct kref             so_ref;
-       struct list_head        so_idhash;   /* hash by so_id */
        struct list_head        so_strhash;   /* hash by op_name */
-       struct list_head        so_perclient;
        struct list_head        so_stateids;
-       struct list_head        so_perstateid; /* for lockowners only */
-       struct list_head        so_close_lru; /* tail queue */
-       time_t                  so_time; /* time of placement on so_close_lru */
-       int                     so_is_open_owner; /* 1=openowner,0=lockowner */
-       u32                     so_id;
        struct nfs4_client *    so_client;
        /* after increment in ENCODE_SEQID_OP_TAIL, represents the next
         * sequence id expected from the client: */
        u32                     so_seqid;
        struct xdr_netobj       so_owner;     /* open owner name */
-       int                     so_confirmed; /* successful OPEN_CONFIRM? */
        struct nfs4_replay      so_replay;
+       bool                    so_is_open_owner;
 };
 
+struct nfs4_openowner {
+       struct nfs4_stateowner  oo_owner; /* must be first field */
+       struct list_head        oo_perclient;
+       /*
+        * We keep around openowners a little while after last close,
+        * which saves clients from having to confirm, and allows us to
+        * handle close replays if they come soon enough.  The close_lru
+        * is a list of such openowners, to be reaped by the laundromat
+        * thread eventually if they remain unused:
+        */
+       struct list_head        oo_close_lru;
+       struct nfs4_ol_stateid *oo_last_closed_stid;
+       time_t                  oo_time; /* time of placement on so_close_lru */
+#define NFS4_OO_CONFIRMED   1
+#define NFS4_OO_PURGE_CLOSE 2
+#define NFS4_OO_NEW         4
+       unsigned char           oo_flags;
+};
+
+struct nfs4_lockowner {
+       struct nfs4_stateowner  lo_owner; /* must be first element */
+       struct list_head        lo_perstateid; /* for lockowners only */
+       struct list_head        lo_list; /* for temporary uses */
+};
+
+static inline struct nfs4_openowner * openowner(struct nfs4_stateowner *so)
+{
+       return container_of(so, struct nfs4_openowner, oo_owner);
+}
+
+static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
+{
+       return container_of(so, struct nfs4_lockowner, lo_owner);
+}
+
 /*
 *  nfs4_file: a file opened by some number of (open) nfs4_stateowners.
 *    o fi_perfile list is used to search for conflicting 
@@ -368,17 +393,17 @@ struct nfs4_file {
        /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
        struct file *           fi_fds[3];
        /*
-        * Each open or lock stateid contributes 1 to either
-        * fi_access[O_RDONLY], fi_access[O_WRONLY], or both, depending
-        * on open or lock mode:
+        * Each open or lock stateid contributes 0-4 to the counts
+        * below depending on which bits are set in st_access_bitmap:
+        *     1 to fi_access[O_RDONLY] if NFS4_SHARE_ACCES_READ is set
+        *   + 1 to fi_access[O_WRONLY] if NFS4_SHARE_ACCESS_WRITE is set
+        *   + 1 to both of the above if NFS4_SHARE_ACCESS_BOTH is set.
         */
        atomic_t                fi_access[2];
        struct file             *fi_deleg_file;
        struct file_lock        *fi_lease;
        atomic_t                fi_delegees;
        struct inode            *fi_inode;
-       u32                     fi_id;      /* used with stateowner->so_id 
-                                            * for stateid_hashtbl hash */
        bool                    fi_had_conflict;
 };
 
@@ -408,50 +433,27 @@ static inline struct file *find_any_file(struct nfs4_file *f)
                return f->fi_fds[O_RDONLY];
 }
 
-/*
-* nfs4_stateid can either be an open stateid or (eventually) a lock stateid
-*
-* (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file
-*
-*      st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry
-*      st_perfile: file_hashtbl[] entry.
-*      st_perfile_state: nfs4_stateowner->so_perfilestate
-*       st_perlockowner: (open stateid) list of lock nfs4_stateowners
-*      st_access_bmap: used only for open stateid
-*      st_deny_bmap: used only for open stateid
-*      st_openstp: open stateid lock stateid was derived from
-*
-* XXX: open stateids and lock stateids have diverged sufficiently that
-* we should consider defining separate structs for the two cases.
-*/
-
-struct nfs4_stateid {
-       struct list_head              st_hash; 
+/* "ol" stands for "Open or Lock".  Better suggestions welcome. */
+struct nfs4_ol_stateid {
+       struct nfs4_stid    st_stid; /* must be first field */
        struct list_head              st_perfile;
        struct list_head              st_perstateowner;
        struct list_head              st_lockowners;
        struct nfs4_stateowner      * st_stateowner;
        struct nfs4_file            * st_file;
-       stateid_t                     st_stateid;
        unsigned long                 st_access_bmap;
        unsigned long                 st_deny_bmap;
-       struct nfs4_stateid         * st_openstp;
+       struct nfs4_ol_stateid         * st_openstp;
 };
 
+static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)
+{
+       return container_of(s, struct nfs4_ol_stateid, st_stid);
+}
+
 /* flags for preprocess_seqid_op() */
-#define HAS_SESSION             0x00000001
-#define CONFIRM                 0x00000002
-#define OPEN_STATE              0x00000004
-#define LOCK_STATE              0x00000008
 #define RD_STATE               0x00000010
 #define WR_STATE               0x00000020
-#define CLOSE_STATE             0x00000040
-
-#define seqid_mutating_err(err)                       \
-       (((err) != nfserr_stale_clientid) &&    \
-       ((err) != nfserr_bad_seqid) &&          \
-       ((err) != nfserr_stale_stateid) &&      \
-       ((err) != nfserr_bad_stateid))
 
 struct nfsd4_compound_state;
 
@@ -461,7 +463,8 @@ extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
 extern int nfs4_in_grace(void);
 extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
-extern void nfs4_free_stateowner(struct kref *kref);
+extern void nfs4_free_openowner(struct nfs4_openowner *);
+extern void nfs4_free_lockowner(struct nfs4_lockowner *);
 extern int set_callback_cred(void);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
@@ -473,7 +476,7 @@ extern void nfsd4_destroy_callback_queue(void);
 extern void nfsd4_shutdown_callback(struct nfs4_client *);
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
-extern void nfsd4_init_recdir(char *recdir_name);
+extern void nfsd4_init_recdir(void);
 extern int nfsd4_recdir_load(void);
 extern void nfsd4_shutdown_recdir(void);
 extern int nfs4_client_to_reclaim(const char *name);
@@ -482,18 +485,7 @@ extern void nfsd4_recdir_purge_old(void);
 extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
 extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
 extern void release_session_client(struct nfsd4_session *);
-extern __be32 nfs4_validate_stateid(stateid_t *, int);
-
-static inline void
-nfs4_put_stateowner(struct nfs4_stateowner *so)
-{
-       kref_put(&so->so_ref, nfs4_free_stateowner);
-}
-
-static inline void
-nfs4_get_stateowner(struct nfs4_stateowner *so)
-{
-       kref_get(&so->so_ref);
-}
+extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
+extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
 
 #endif   /* NFSD4_STATE_H */