*/
/* recall_lock protects the del_recall_lru */
-static spinlock_t recall_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(recall_lock);
static struct list_head del_recall_lru;
static void
kref_get(&fi->fi_ref);
}
+static int num_delegations;
+
+/*
+ * Open owner state (share locks)
+ */
+
+/* hash tables for nfs4_stateowner */
+#define OWNER_HASH_BITS 8
+#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
+#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
+
+#define ownerid_hashval(id) \
+ ((id) & OWNER_HASH_MASK)
+#define ownerstr_hashval(clientid, ownername) \
+ (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
+
+static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
+static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
+
+/* hash table for nfs4_file */
+#define FILE_HASH_BITS 8
+#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
+#define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
+/* hash table for (open)nfs4_stateid */
+#define STATEID_HASH_BITS 10
+#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
+#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
+
+#define file_hashval(x) \
+ hash_ptr(x, FILE_HASH_BITS)
+#define stateid_hashval(owner_id, file_id) \
+ (((owner_id) + (file_id)) & STATEID_HASH_MASK)
+
+static struct list_head file_hashtbl[FILE_HASH_SIZE];
+static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
+
static struct nfs4_delegation *
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
{
struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
dprintk("NFSD alloc_init_deleg\n");
+ if (num_delegations > STATEID_HASH_SIZE * 4)
+ return NULL;
dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
if (dp == NULL)
return dp;
+ num_delegations++;
INIT_LIST_HEAD(&dp->dl_perfile);
INIT_LIST_HEAD(&dp->dl_perclnt);
INIT_LIST_HEAD(&dp->dl_recall_lru);
dprintk("NFSD: freeing dp %p\n",dp);
put_nfs4_file(dp->dl_file);
kmem_cache_free(deleg_slab, dp);
+ num_delegations--;
}
}
{
struct nfs4_client *clp;
- if ((clp = kmalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
- memset(clp, 0, sizeof(*clp));
+ if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {
memcpy(clp->cl_name.data, name.data, name.len);
clp->cl_name.len = name.len;
}
static void
+shutdown_callback_client(struct nfs4_client *clp)
+{
+ struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+
+ /* shutdown rpc client, ending any outstanding recall rpcs */
+ if (clnt) {
+ clp->cl_callback.cb_client = NULL;
+ rpc_shutdown_client(clnt);
+ rpciod_down();
+ }
+}
+
+static void
expire_client(struct nfs4_client *clp)
{
struct nfs4_stateowner *sop;
struct nfs4_delegation *dp;
- struct nfs4_callback *cb = &clp->cl_callback;
- struct rpc_clnt *clnt = clp->cl_callback.cb_client;
struct list_head reaplist;
dprintk("NFSD: expire_client cl_count %d\n",
atomic_read(&clp->cl_count));
- /* shutdown rpc client, ending any outstanding recall rpcs */
- if (atomic_read(&cb->cb_set) == 1 && clnt) {
- rpc_shutdown_client(clnt);
- clnt = clp->cl_callback.cb_client = NULL;
- }
+ shutdown_callback_client(clp);
INIT_LIST_HEAD(&reaplist);
spin_lock(&recall_lock);
dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
list_del_init(&clp->cl_strhash);
- list_del_init(&clp->cl_idhash);
- list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
+ list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
strhashval = clientstr_hashval(clp->cl_recdir);
list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
renew_client(clp);
* as described above.
*
*/
-int
+__be32
nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
{
- u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
+ __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
struct xdr_netobj clname = {
.len = setclid->se_namelen,
.data = setclid->se_name,
nfs4_verifier clverifier = setclid->se_verf;
unsigned int strhashval;
struct nfs4_client *conf, *unconf, *new;
- int status;
+ __be32 status;
char dname[HEXDIR_LEN];
if (!check_name(clname))
*
* NOTE: callback information will be processed here in a future patch
*/
-int
+__be32
nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
{
- u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
+ __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
struct nfs4_client *conf, *unconf;
nfs4_verifier confirm = setclientid_confirm->sc_confirm;
clientid_t * clid = &setclientid_confirm->sc_clientid;
- int status;
+ __be32 status;
if (STALE_CLIENTID(clid))
return nfserr_stale_clientid;
return status;
}
-/*
- * Open owner state (share locks)
- */
-
-/* hash tables for nfs4_stateowner */
-#define OWNER_HASH_BITS 8
-#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
-#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
-
-#define ownerid_hashval(id) \
- ((id) & OWNER_HASH_MASK)
-#define ownerstr_hashval(clientid, ownername) \
- (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
-
-static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
-static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
-
-/* hash table for nfs4_file */
-#define FILE_HASH_BITS 8
-#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
-#define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
-/* hash table for (open)nfs4_stateid */
-#define STATEID_HASH_BITS 10
-#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
-#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
-
-#define file_hashval(x) \
- hash_ptr(x, FILE_HASH_BITS)
-#define stateid_hashval(owner_id, file_id) \
- (((owner_id) + (file_id)) & STATEID_HASH_MASK)
-
-static struct list_head file_hashtbl[FILE_HASH_SIZE];
-static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
-
/* OPEN Share state helper functions */
static inline struct nfs4_file *
alloc_init_file(struct inode *ino)
static void
nfsd4_free_slab(kmem_cache_t **slab)
{
- int status;
-
if (*slab == NULL)
return;
- status = kmem_cache_destroy(*slab);
+ kmem_cache_destroy(*slab);
*slab = NULL;
- WARN_ON(status);
}
static void
{
dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
- unhash_stateowner(sop);
- list_add_tail(&sop->so_close_lru, &close_lru);
+ list_move_tail(&sop->so_close_lru, &close_lru);
sop->so_time = get_seconds();
}
return NULL;
}
-#define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0)
-#define TEST_DENY(x) ((x >= 0 || x < 5)?1:0)
+static int access_valid(u32 x)
+{
+ return (x > 0 && x < 4);
+}
+
+static int deny_valid(u32 x)
+{
+ return (x >= 0 && x < 5);
+}
static void
set_access(unsigned int *access, unsigned long bmap) {
* Called to check deny when READ with all zero stateid or
* WRITE with all zero or all one stateid
*/
-static int
+static __be32
nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_file *fp;
struct nfs4_stateid *stp;
- int ret;
+ __be32 ret;
dprintk("NFSD: nfs4_share_conflict\n");
};
-int
+__be32
nfsd4_process_open1(struct nfsd4_open *open)
{
clientid_t *clientid = &open->op_clientid;
}
if (open->op_seqid == sop->so_seqid - 1) {
if (sop->so_replay.rp_buflen)
- return NFSERR_REPLAY_ME;
+ return nfserr_replay_me;
/* The original OPEN failed so spectacularly
* that we don't even have replay data saved!
* Therefore, we have no choice but to continue
return nfs_ok;
}
-static inline int
+static inline __be32
nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
{
if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
return NULL;
}
-static int
+static __be32
nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
struct nfs4_delegation **dp)
{
int flags;
- int status = nfserr_bad_stateid;
+ __be32 status = nfserr_bad_stateid;
*dp = find_delegation_file(fp, &open->op_delegate_stateid);
if (*dp == NULL)
return nfs_ok;
}
-static int
+static __be32
nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
{
struct nfs4_stateid *local;
- int status = nfserr_share_denied;
+ __be32 status = nfserr_share_denied;
struct nfs4_stateowner *sop = open->op_stateowner;
list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
}
-static int
+static __be32
nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
struct nfs4_delegation *dp,
struct svc_fh *cur_fh, int flags)
get_file(dp->dl_vfs_file);
stp->st_vfs_file = dp->dl_vfs_file;
} else {
- int status;
+ __be32 status;
status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
&stp->st_vfs_file);
if (status) {
return 0;
}
-static inline int
+static inline __be32
nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
struct nfsd4_open *open)
{
return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
}
-static int
+static __be32
nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
{
struct file *filp = stp->st_vfs_file;
struct inode *inode = filp->f_dentry->d_inode;
unsigned int share_access, new_writer;
- int status;
+ __be32 status;
set_access(&share_access, stp->st_access_bmap);
new_writer = (~share_access) & open->op_share_access
& NFS4_SHARE_ACCESS_WRITE;
if (new_writer) {
- status = get_write_access(inode);
- if (status)
- return nfserrno(status);
+ int err = get_write_access(inode);
+ if (err)
+ return nfserrno(err);
}
status = nfsd4_truncate(rqstp, cur_fh, open);
if (status) {
/*
* called with nfs4_lock_state() held.
*/
-int
+__be32
nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct nfs4_file *fp = NULL;
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
- int status;
+ __be32 status;
status = nfserr_inval;
- if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
+ if (!access_valid(open->op_share_access)
+ || !deny_valid(open->op_share_deny))
goto out;
/*
* Lookup file; if found, lookup stateid and check open request,
} else {
/* Stateid was not found, this is a new OPEN */
int flags = 0;
+ if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
+ flags |= MAY_READ;
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
- flags = MAY_WRITE;
- else
- flags = MAY_READ;
+ flags |= MAY_WRITE;
status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
if (status)
goto out;
}
static struct workqueue_struct *laundry_wq;
-static struct work_struct laundromat_work;
-static void laundromat_main(void *);
-static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
+static void laundromat_main(struct work_struct *);
+static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
-int
+__be32
nfsd4_renew(clientid_t *clid)
{
struct nfs4_client *clp;
- int status;
+ __be32 status;
nfs4_lock_state();
dprintk("process_renew(%08x/%08x): starting\n",
}
dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
sop->so_id);
- list_del(&sop->so_close_lru);
- nfs4_put_stateowner(sop);
+ release_stateowner(sop);
}
if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
}
void
-laundromat_main(void *not_used)
+laundromat_main(struct work_struct *not_used)
{
time_t t;
}
static
-int nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
+__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
{
- int status = nfserr_openmode;
+ __be32 status = nfserr_openmode;
if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
goto out;
return status;
}
-static inline int
+static inline __be32
check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
{
/* Trying to call delegreturn with a special stateid? Yuch: */
/*
* Checks for stateid operations
*/
-int
+__be32
nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp)
{
struct nfs4_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
stateid_t *stidp;
struct inode *ino = current_fh->fh_dentry->d_inode;
- int status;
+ __be32 status;
dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n",
stateid->si_boot, stateid->si_stateownerid,
if (!stateid->si_fileid) { /* delegation stateid */
if(!(dp = find_delegation_stateid(ino, stateid))) {
dprintk("NFSD: delegation stateid not found\n");
- if (nfs4_in_grace())
- status = nfserr_grace;
goto out;
}
stidp = &dp->dl_stateid;
} else { /* open or lock stateid */
if (!(stp = find_stateid(stateid, flags))) {
dprintk("NFSD: open or lock stateid not found\n");
- if (nfs4_in_grace())
- status = nfserr_grace;
goto out;
}
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp))
/*
* Checks for sequence id mutating operations.
*/
-static int
+static __be32
nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
{
struct nfs4_stateid *stp;
clientid_t *lockclid = &lock->v.new.clientid;
struct nfs4_client *clp = sop->so_client;
int lkflg = 0;
- int status;
+ __be32 status;
lkflg = setlkflg(lock->lk_type);
if (seqid == sop->so_seqid - 1) {
dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
/* indicate replay to calling function */
- return NFSERR_REPLAY_ME;
+ return nfserr_replay_me;
}
printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
sop->so_seqid, seqid);
return nfserr_bad_seqid;
}
-int
+__be32
nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner)
{
- int status;
+ __be32 status;
struct nfs4_stateowner *sop;
struct nfs4_stateid *stp;
(int)current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
- if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0)))
- goto out;
+ status = fh_verify(rqstp, current_fh, S_IFREG, 0);
+ if (status)
+ return status;
nfs4_lock_state();
}
}
-int
+__be32
nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner)
{
- int status;
+ __be32 status;
struct nfs4_stateid *stp;
unsigned int share_access;
(int)current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
- if (!TEST_ACCESS(od->od_share_access) || !TEST_DENY(od->od_share_deny))
+ if (!access_valid(od->od_share_access)
+ || !deny_valid(od->od_share_deny))
return nfserr_inval;
nfs4_lock_state();
/*
* nfs4_unlock_state() called after encode
*/
-int
+__be32
nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner)
{
- int status;
+ __be32 status;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_close on file %.*s\n",
return status;
}
-int
+__be32
nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr)
{
- int status;
+ __be32 status;
if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0)))
goto out;
/*
* LOCK operation
*/
-int
+__be32
nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner)
{
struct nfs4_stateowner *open_sop = NULL;
struct file *filp;
struct file_lock file_lock;
struct file_lock conflock;
- int status = 0;
+ __be32 status = 0;
unsigned int strhashval;
+ int err;
dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
(long long) lock->lk_offset,
* locks_copy_lock: */
conflock.fl_ops = NULL;
conflock.fl_lmops = NULL;
- status = posix_lock_file_conf(filp, &file_lock, &conflock);
+ err = posix_lock_file_conf(filp, &file_lock, &conflock);
dprintk("NFSD: nfsd4_lock: posix_lock_file_conf status %d\n",status);
- switch (-status) {
+ switch (-err) {
case 0: /* success! */
update_stateid(&lock_stp->st_stateid);
memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid,
sizeof(stateid_t));
+ status = 0;
break;
case (EAGAIN): /* conflock holds conflicting lock */
status = nfserr_denied;
status = nfserr_deadlock;
break;
default:
- dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",status);
+ dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",err);
status = nfserr_resource;
break;
}
/*
* LOCKT operation
*/
-int
+__be32
nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt)
{
struct inode *inode;
struct file file;
struct file_lock file_lock;
struct file_lock conflock;
- int status;
+ __be32 status;
if (nfs4_in_grace())
return nfserr_grace;
return status;
}
-int
+__be32
nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner)
{
struct nfs4_stateid *stp;
struct file *filp = NULL;
struct file_lock file_lock;
- int status;
+ __be32 status;
+ int err;
dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
(long long) locku->lu_offset,
/*
* Try to unlock the file in the VFS.
*/
- status = posix_lock_file(filp, &file_lock);
- if (status) {
+ err = posix_lock_file(filp, &file_lock);
+ if (err) {
dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
goto out_nfserr;
}
return status;
out_nfserr:
- status = nfserrno(status);
+ status = nfserrno(err);
goto out;
}
return status;
}
-int
+__be32
nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
{
clientid_t *clid = &rlockowner->rl_clientid;
struct xdr_netobj *owner = &rlockowner->rl_owner;
struct list_head matches;
int i;
- int status;
+ __be32 status;
dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
clid->cl_boot, clid->cl_id);
/*
* Called from OPEN. Look for clientid in reclaim list.
*/
-int
+__be32
nfs4_check_open_reclaim(clientid_t *clid)
{
return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
int i;
struct nfs4_client *clp = NULL;
struct nfs4_delegation *dp = NULL;
- struct nfs4_stateowner *sop = NULL;
struct list_head *pos, *next, reaplist;
- list_for_each_safe(pos, next, &close_lru) {
- sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
- list_del(&sop->so_close_lru);
- nfs4_put_stateowner(sop);
- }
-
for (i = 0; i < CLIENT_HASH_SIZE; i++) {
while (!list_empty(&conf_id_hashtbl[i])) {
clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);