summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/fs/nfsd')
-rw-r--r--ANDROID_3.4.5/fs/nfsd/Kconfig92
-rw-r--r--ANDROID_3.4.5/fs/nfsd/Makefile14
-rw-r--r--ANDROID_3.4.5/fs/nfsd/acl.h59
-rw-r--r--ANDROID_3.4.5/fs/nfsd/auth.c95
-rw-r--r--ANDROID_3.4.5/fs/nfsd/auth.h22
-rw-r--r--ANDROID_3.4.5/fs/nfsd/cache.h83
-rw-r--r--ANDROID_3.4.5/fs/nfsd/current_stateid.h28
-rw-r--r--ANDROID_3.4.5/fs/nfsd/export.c1263
-rw-r--r--ANDROID_3.4.5/fs/nfsd/fault_inject.c91
-rw-r--r--ANDROID_3.4.5/fs/nfsd/fault_inject.h28
-rw-r--r--ANDROID_3.4.5/fs/nfsd/idmap.h62
-rw-r--r--ANDROID_3.4.5/fs/nfsd/lockd.c77
-rw-r--r--ANDROID_3.4.5/fs/nfsd/netns.h34
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs2acl.c356
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs3acl.c267
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs3proc.c896
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs3xdr.c1112
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs4acl.c839
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs4callback.c1037
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs4idmap.c633
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs4proc.c1769
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs4recover.c1046
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs4state.c4889
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfs4xdr.c3671
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfscache.c323
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfsctl.c1218
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfsd.h380
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfsfh.c690
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfsfh.h206
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfsproc.c755
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfssvc.c690
-rw-r--r--ANDROID_3.4.5/fs/nfsd/nfsxdr.c545
-rw-r--r--ANDROID_3.4.5/fs/nfsd/state.h489
-rw-r--r--ANDROID_3.4.5/fs/nfsd/stats.c105
-rw-r--r--ANDROID_3.4.5/fs/nfsd/vfs.c2318
-rw-r--r--ANDROID_3.4.5/fs/nfsd/vfs.h121
-rw-r--r--ANDROID_3.4.5/fs/nfsd/xdr.h173
-rw-r--r--ANDROID_3.4.5/fs/nfsd/xdr3.h344
-rw-r--r--ANDROID_3.4.5/fs/nfsd/xdr4.h621
39 files changed, 0 insertions, 27441 deletions
diff --git a/ANDROID_3.4.5/fs/nfsd/Kconfig b/ANDROID_3.4.5/fs/nfsd/Kconfig
deleted file mode 100644
index 8df1ea4a..00000000
--- a/ANDROID_3.4.5/fs/nfsd/Kconfig
+++ /dev/null
@@ -1,92 +0,0 @@
-config NFSD
- tristate "NFS server support"
- depends on INET
- depends on FILE_LOCKING
- select LOCKD
- select SUNRPC
- select EXPORTFS
- select NFS_ACL_SUPPORT if NFSD_V2_ACL
- help
- Choose Y here if you want to allow other computers to access
- files residing on this system using Sun's Network File System
- protocol. To compile the NFS server support as a module,
- choose M here: the module will be called nfsd.
-
- You may choose to use a user-space NFS server instead, in which
- case you can choose N here.
-
- To export local file systems using NFS, you also need to install
- user space programs which can be found in the Linux nfs-utils
- package, available from http://linux-nfs.org/. More detail about
- the Linux NFS server implementation is available via the
- exports(5) man page.
-
- Below you can choose which versions of the NFS protocol are
- available to clients mounting the NFS server on this system.
- Support for NFS version 2 (RFC 1094) is always available when
- CONFIG_NFSD is selected.
-
- If unsure, say N.
-
-config NFSD_V2_ACL
- bool
- depends on NFSD
-
-config NFSD_V3
- bool "NFS server support for NFS version 3"
- depends on NFSD
- help
- This option enables support in your system's NFS server for
- version 3 of the NFS protocol (RFC 1813).
-
- If unsure, say Y.
-
-config NFSD_V3_ACL
- bool "NFS server support for the NFSv3 ACL protocol extension"
- depends on NFSD_V3
- select NFSD_V2_ACL
- help
- Solaris NFS servers support an auxiliary NFSv3 ACL protocol that
- never became an official part of the NFS version 3 protocol.
- This protocol extension allows applications on NFS clients to
- manipulate POSIX Access Control Lists on files residing on NFS
- servers. NFS servers enforce POSIX ACLs on local files whether
- this protocol is available or not.
-
- This option enables support in your system's NFS server for the
- NFSv3 ACL protocol extension allowing NFS clients to manipulate
- POSIX ACLs on files exported by your system's NFS server. NFS
- clients which support the Solaris NFSv3 ACL protocol can then
- access and modify ACLs on your NFS server.
-
- To store ACLs on your NFS server, you also need to enable ACL-
- related CONFIG options for your local file systems of choice.
-
- If unsure, say N.
-
-config NFSD_V4
- bool "NFS server support for NFS version 4 (EXPERIMENTAL)"
- depends on NFSD && PROC_FS && EXPERIMENTAL
- select NFSD_V3
- select FS_POSIX_ACL
- select SUNRPC_GSS
- select CRYPTO
- help
- This option enables support in your system's NFS server for
- version 4 of the NFS protocol (RFC 3530).
-
- To export files using NFSv4, you need to install additional user
- space programs which can be found in the Linux nfs-utils package,
- available from http://linux-nfs.org/.
-
- If unsure, say N.
-
-config NFSD_FAULT_INJECTION
- bool "NFS server manual fault injection"
- depends on NFSD_V4 && DEBUG_KERNEL
- help
- This option enables support for manually injecting faults
- into the NFS server. This is intended to be used for
- testing error recovery on the NFS client.
-
- If unsure, say N.
diff --git a/ANDROID_3.4.5/fs/nfsd/Makefile b/ANDROID_3.4.5/fs/nfsd/Makefile
deleted file mode 100644
index af32ef06..00000000
--- a/ANDROID_3.4.5/fs/nfsd/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the Linux nfs server
-#
-
-obj-$(CONFIG_NFSD) += nfsd.o
-
-nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
- export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
-nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o
-nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
-nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
-nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
-nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
- nfs4acl.o nfs4callback.o nfs4recover.o
diff --git a/ANDROID_3.4.5/fs/nfsd/acl.h b/ANDROID_3.4.5/fs/nfsd/acl.h
deleted file mode 100644
index 34e5c40a..00000000
--- a/ANDROID_3.4.5/fs/nfsd/acl.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Common NFSv4 ACL handling definitions.
- *
- * Copyright (c) 2002 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Marius Aamodt Eriksen <marius@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef LINUX_NFS4_ACL_H
-#define LINUX_NFS4_ACL_H
-
-#include <linux/posix_acl.h>
-
-/* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to
- * fit in a page: */
-#define NFS4_ACL_MAX 170
-
-struct nfs4_acl *nfs4_acl_new(int);
-int nfs4_acl_get_whotype(char *, u32);
-int nfs4_acl_write_who(int who, char *p);
-int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
- uid_t who, u32 mask);
-
-#define NFS4_ACL_TYPE_DEFAULT 0x01
-#define NFS4_ACL_DIR 0x02
-#define NFS4_ACL_OWNER 0x04
-
-struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *,
- struct posix_acl *, unsigned int flags);
-int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **,
- struct posix_acl **, unsigned int flags);
-
-#endif /* LINUX_NFS4_ACL_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/auth.c b/ANDROID_3.4.5/fs/nfsd/auth.c
deleted file mode 100644
index 79717a40..00000000
--- a/ANDROID_3.4.5/fs/nfsd/auth.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */
-
-#include <linux/sched.h>
-#include "nfsd.h"
-#include "auth.h"
-
-int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
-{
- struct exp_flavor_info *f;
- struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
-
- for (f = exp->ex_flavors; f < end; f++) {
- if (f->pseudoflavor == rqstp->rq_flavor)
- return f->flags;
- }
- return exp->ex_flags;
-
-}
-
-int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
-{
- struct group_info *rqgi;
- struct group_info *gi;
- struct cred *new;
- int i;
- int flags = nfsexp_flags(rqstp, exp);
- int ret;
-
- validate_process_creds();
-
- /* discard any old override before preparing the new set */
- revert_creds(get_cred(current->real_cred));
- new = prepare_creds();
- if (!new)
- return -ENOMEM;
-
- new->fsuid = rqstp->rq_cred.cr_uid;
- new->fsgid = rqstp->rq_cred.cr_gid;
-
- rqgi = rqstp->rq_cred.cr_group_info;
-
- if (flags & NFSEXP_ALLSQUASH) {
- new->fsuid = exp->ex_anon_uid;
- new->fsgid = exp->ex_anon_gid;
- gi = groups_alloc(0);
- if (!gi)
- goto oom;
- } else if (flags & NFSEXP_ROOTSQUASH) {
- if (!new->fsuid)
- new->fsuid = exp->ex_anon_uid;
- if (!new->fsgid)
- new->fsgid = exp->ex_anon_gid;
-
- gi = groups_alloc(rqgi->ngroups);
- if (!gi)
- goto oom;
-
- for (i = 0; i < rqgi->ngroups; i++) {
- if (!GROUP_AT(rqgi, i))
- GROUP_AT(gi, i) = exp->ex_anon_gid;
- else
- GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
- }
- } else {
- gi = get_group_info(rqgi);
- }
-
- if (new->fsuid == (uid_t) -1)
- new->fsuid = exp->ex_anon_uid;
- if (new->fsgid == (gid_t) -1)
- new->fsgid = exp->ex_anon_gid;
-
- ret = set_groups(new, gi);
- put_group_info(gi);
- if (ret < 0)
- goto error;
-
- if (new->fsuid)
- new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
- else
- new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
- new->cap_permitted);
- validate_process_creds();
- put_cred(override_creds(new));
- put_cred(new);
- validate_process_creds();
- return 0;
-
-oom:
- ret = -ENOMEM;
-error:
- abort_creds(new);
- return ret;
-}
-
diff --git a/ANDROID_3.4.5/fs/nfsd/auth.h b/ANDROID_3.4.5/fs/nfsd/auth.h
deleted file mode 100644
index 78b3c0e9..00000000
--- a/ANDROID_3.4.5/fs/nfsd/auth.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * nfsd-specific authentication stuff.
- * uid/gid mapping not yet implemented.
- *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef LINUX_NFSD_AUTH_H
-#define LINUX_NFSD_AUTH_H
-
-#define nfsd_luid(rq, uid) ((u32)(uid))
-#define nfsd_lgid(rq, gid) ((u32)(gid))
-#define nfsd_ruid(rq, uid) ((u32)(uid))
-#define nfsd_rgid(rq, gid) ((u32)(gid))
-
-/*
- * Set the current process's fsuid/fsgid etc to those of the NFS
- * client user
- */
-int nfsd_setuser(struct svc_rqst *, struct svc_export *);
-
-#endif /* LINUX_NFSD_AUTH_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/cache.h b/ANDROID_3.4.5/fs/nfsd/cache.h
deleted file mode 100644
index 93cc9d34..00000000
--- a/ANDROID_3.4.5/fs/nfsd/cache.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Request reply cache. This was heavily inspired by the
- * implementation in 4.3BSD/4.4BSD.
- *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef NFSCACHE_H
-#define NFSCACHE_H
-
-#include <linux/sunrpc/svc.h>
-
-/*
- * Representation of a reply cache entry.
- */
-struct svc_cacherep {
- struct hlist_node c_hash;
- struct list_head c_lru;
-
- unsigned char c_state, /* unused, inprog, done */
- c_type, /* status, buffer */
- c_secure : 1; /* req came from port < 1024 */
- struct sockaddr_in c_addr;
- __be32 c_xid;
- u32 c_prot;
- u32 c_proc;
- u32 c_vers;
- unsigned long c_timestamp;
- union {
- struct kvec u_vec;
- __be32 u_status;
- } c_u;
-};
-
-#define c_replvec c_u.u_vec
-#define c_replstat c_u.u_status
-
-/* cache entry states */
-enum {
- RC_UNUSED,
- RC_INPROG,
- RC_DONE
-};
-
-/* return values */
-enum {
- RC_DROPIT,
- RC_REPLY,
- RC_DOIT,
- RC_INTR
-};
-
-/*
- * Cache types.
- * We may want to add more types one day, e.g. for diropres and
- * attrstat replies. Using cache entries with fixed length instead
- * of buffer pointers may be more efficient.
- */
-enum {
- RC_NOCACHE,
- RC_REPLSTAT,
- RC_REPLBUFF,
-};
-
-/*
- * If requests are retransmitted within this interval, they're dropped.
- */
-#define RC_DELAY (HZ/5)
-
-int nfsd_reply_cache_init(void);
-void nfsd_reply_cache_shutdown(void);
-int nfsd_cache_lookup(struct svc_rqst *);
-void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
-
-#ifdef CONFIG_NFSD_V4
-void nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp);
-#else /* CONFIG_NFSD_V4 */
-static inline void nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp)
-{
-}
-#endif /* CONFIG_NFSD_V4 */
-
-#endif /* NFSCACHE_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/current_stateid.h b/ANDROID_3.4.5/fs/nfsd/current_stateid.h
deleted file mode 100644
index 41235512..00000000
--- a/ANDROID_3.4.5/fs/nfsd/current_stateid.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef _NFSD4_CURRENT_STATE_H
-#define _NFSD4_CURRENT_STATE_H
-
-#include "state.h"
-#include "xdr4.h"
-
-extern void clear_current_stateid(struct nfsd4_compound_state *cstate);
-/*
- * functions to set current state id
- */
-extern void nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *);
-extern void nfsd4_set_openstateid(struct nfsd4_compound_state *, struct nfsd4_open *);
-extern void nfsd4_set_lockstateid(struct nfsd4_compound_state *, struct nfsd4_lock *);
-extern void nfsd4_set_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *);
-
-/*
- * functions to consume current state id
- */
-extern void nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *);
-extern void nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *, struct nfsd4_delegreturn *);
-extern void nfsd4_get_freestateid(struct nfsd4_compound_state *, struct nfsd4_free_stateid *);
-extern void nfsd4_get_setattrstateid(struct nfsd4_compound_state *, struct nfsd4_setattr *);
-extern void nfsd4_get_closestateid(struct nfsd4_compound_state *, struct nfsd4_close *);
-extern void nfsd4_get_lockustateid(struct nfsd4_compound_state *, struct nfsd4_locku *);
-extern void nfsd4_get_readstateid(struct nfsd4_compound_state *, struct nfsd4_read *);
-extern void nfsd4_get_writestateid(struct nfsd4_compound_state *, struct nfsd4_write *);
-
-#endif /* _NFSD4_CURRENT_STATE_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/export.c b/ANDROID_3.4.5/fs/nfsd/export.c
deleted file mode 100644
index 8e9689ab..00000000
--- a/ANDROID_3.4.5/fs/nfsd/export.c
+++ /dev/null
@@ -1,1263 +0,0 @@
-/*
- * NFS exporting and validation.
- *
- * We maintain a list of clients, each of which has a list of
- * exports. To export an fs to a given client, you first have
- * to create the client entry with NFSCTL_ADDCLIENT, which
- * creates a client control block and adds it to the hash
- * table. Then, you call NFSCTL_EXPORT for each fs.
- *
- *
- * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
- */
-
-#include <linux/slab.h>
-#include <linux/namei.h>
-#include <linux/module.h>
-#include <linux/exportfs.h>
-
-#include <net/ipv6.h>
-
-#include "nfsd.h"
-#include "nfsfh.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_EXPORT
-
-typedef struct auth_domain svc_client;
-typedef struct svc_export svc_export;
-
-/*
- * We have two caches.
- * One maps client+vfsmnt+dentry to export options - the export map
- * The other maps client+filehandle-fragment to export options. - the expkey map
- *
- * The export options are actually stored in the first map, and the
- * second map contains a reference to the entry in the first map.
- */
-
-#define EXPKEY_HASHBITS 8
-#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
-#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
-static struct cache_head *expkey_table[EXPKEY_HASHMAX];
-
-static void expkey_put(struct kref *ref)
-{
- struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
-
- if (test_bit(CACHE_VALID, &key->h.flags) &&
- !test_bit(CACHE_NEGATIVE, &key->h.flags))
- path_put(&key->ek_path);
- auth_domain_put(key->ek_client);
- kfree(key);
-}
-
-static void expkey_request(struct cache_detail *cd,
- struct cache_head *h,
- char **bpp, int *blen)
-{
- /* client fsidtype \xfsid */
- struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
- char type[5];
-
- qword_add(bpp, blen, ek->ek_client->name);
- snprintf(type, 5, "%d", ek->ek_fsidtype);
- qword_add(bpp, blen, type);
- qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
- (*bpp)[-1] = '\n';
-}
-
-static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
-{
- return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
-}
-
-static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
-static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
-static struct cache_detail svc_expkey_cache;
-
-static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
-{
- /* client fsidtype fsid [path] */
- char *buf;
- int len;
- struct auth_domain *dom = NULL;
- int err;
- int fsidtype;
- char *ep;
- struct svc_expkey key;
- struct svc_expkey *ek = NULL;
-
- if (mesg[mlen - 1] != '\n')
- return -EINVAL;
- mesg[mlen-1] = 0;
-
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- err = -ENOMEM;
- if (!buf)
- goto out;
-
- err = -EINVAL;
- if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
- goto out;
-
- err = -ENOENT;
- dom = auth_domain_find(buf);
- if (!dom)
- goto out;
- dprintk("found domain %s\n", buf);
-
- err = -EINVAL;
- if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
- goto out;
- fsidtype = simple_strtoul(buf, &ep, 10);
- if (*ep)
- goto out;
- dprintk("found fsidtype %d\n", fsidtype);
- if (key_len(fsidtype)==0) /* invalid type */
- goto out;
- if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
- goto out;
- dprintk("found fsid length %d\n", len);
- if (len != key_len(fsidtype))
- goto out;
-
- /* OK, we seem to have a valid key */
- key.h.flags = 0;
- key.h.expiry_time = get_expiry(&mesg);
- if (key.h.expiry_time == 0)
- goto out;
-
- key.ek_client = dom;
- key.ek_fsidtype = fsidtype;
- memcpy(key.ek_fsid, buf, len);
-
- ek = svc_expkey_lookup(&key);
- err = -ENOMEM;
- if (!ek)
- goto out;
-
- /* now we want a pathname, or empty meaning NEGATIVE */
- err = -EINVAL;
- len = qword_get(&mesg, buf, PAGE_SIZE);
- if (len < 0)
- goto out;
- dprintk("Path seems to be <%s>\n", buf);
- err = 0;
- if (len == 0) {
- set_bit(CACHE_NEGATIVE, &key.h.flags);
- ek = svc_expkey_update(&key, ek);
- if (!ek)
- err = -ENOMEM;
- } else {
- err = kern_path(buf, 0, &key.ek_path);
- if (err)
- goto out;
-
- dprintk("Found the path %s\n", buf);
-
- ek = svc_expkey_update(&key, ek);
- if (!ek)
- err = -ENOMEM;
- path_put(&key.ek_path);
- }
- cache_flush();
- out:
- if (ek)
- cache_put(&ek->h, &svc_expkey_cache);
- if (dom)
- auth_domain_put(dom);
- kfree(buf);
- return err;
-}
-
-static int expkey_show(struct seq_file *m,
- struct cache_detail *cd,
- struct cache_head *h)
-{
- struct svc_expkey *ek ;
- int i;
-
- if (h ==NULL) {
- seq_puts(m, "#domain fsidtype fsid [path]\n");
- return 0;
- }
- ek = container_of(h, struct svc_expkey, h);
- seq_printf(m, "%s %d 0x", ek->ek_client->name,
- ek->ek_fsidtype);
- for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
- seq_printf(m, "%08x", ek->ek_fsid[i]);
- if (test_bit(CACHE_VALID, &h->flags) &&
- !test_bit(CACHE_NEGATIVE, &h->flags)) {
- seq_printf(m, " ");
- seq_path(m, &ek->ek_path, "\\ \t\n");
- }
- seq_printf(m, "\n");
- return 0;
-}
-
-static inline int expkey_match (struct cache_head *a, struct cache_head *b)
-{
- struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
- struct svc_expkey *new = container_of(b, struct svc_expkey, h);
-
- if (orig->ek_fsidtype != new->ek_fsidtype ||
- orig->ek_client != new->ek_client ||
- memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
- return 0;
- return 1;
-}
-
-static inline void expkey_init(struct cache_head *cnew,
- struct cache_head *citem)
-{
- struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
- struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
-
- kref_get(&item->ek_client->ref);
- new->ek_client = item->ek_client;
- new->ek_fsidtype = item->ek_fsidtype;
-
- memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
-}
-
-static inline void expkey_update(struct cache_head *cnew,
- struct cache_head *citem)
-{
- struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
- struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
-
- new->ek_path = item->ek_path;
- path_get(&item->ek_path);
-}
-
-static struct cache_head *expkey_alloc(void)
-{
- struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
- if (i)
- return &i->h;
- else
- return NULL;
-}
-
-static struct cache_detail svc_expkey_cache = {
- .owner = THIS_MODULE,
- .hash_size = EXPKEY_HASHMAX,
- .hash_table = expkey_table,
- .name = "nfsd.fh",
- .cache_put = expkey_put,
- .cache_upcall = expkey_upcall,
- .cache_parse = expkey_parse,
- .cache_show = expkey_show,
- .match = expkey_match,
- .init = expkey_init,
- .update = expkey_update,
- .alloc = expkey_alloc,
-};
-
-static int
-svc_expkey_hash(struct svc_expkey *item)
-{
- int hash = item->ek_fsidtype;
- char * cp = (char*)item->ek_fsid;
- int len = key_len(item->ek_fsidtype);
-
- hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
- hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
- hash &= EXPKEY_HASHMASK;
- return hash;
-}
-
-static struct svc_expkey *
-svc_expkey_lookup(struct svc_expkey *item)
-{
- struct cache_head *ch;
- int hash = svc_expkey_hash(item);
-
- ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h,
- hash);
- if (ch)
- return container_of(ch, struct svc_expkey, h);
- else
- return NULL;
-}
-
-static struct svc_expkey *
-svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
-{
- struct cache_head *ch;
- int hash = svc_expkey_hash(new);
-
- ch = sunrpc_cache_update(&svc_expkey_cache, &new->h,
- &old->h, hash);
- if (ch)
- return container_of(ch, struct svc_expkey, h);
- else
- return NULL;
-}
-
-
-#define EXPORT_HASHBITS 8
-#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
-
-static struct cache_head *export_table[EXPORT_HASHMAX];
-
-static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
-{
- int i;
-
- for (i = 0; i < fsloc->locations_count; i++) {
- kfree(fsloc->locations[i].path);
- kfree(fsloc->locations[i].hosts);
- }
- kfree(fsloc->locations);
-}
-
-static void svc_export_put(struct kref *ref)
-{
- struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
- path_put(&exp->ex_path);
- auth_domain_put(exp->ex_client);
- nfsd4_fslocs_free(&exp->ex_fslocs);
- kfree(exp);
-}
-
-static void svc_export_request(struct cache_detail *cd,
- struct cache_head *h,
- char **bpp, int *blen)
-{
- /* client path */
- struct svc_export *exp = container_of(h, struct svc_export, h);
- char *pth;
-
- qword_add(bpp, blen, exp->ex_client->name);
- pth = d_path(&exp->ex_path, *bpp, *blen);
- if (IS_ERR(pth)) {
- /* is this correct? */
- (*bpp)[0] = '\n';
- return;
- }
- qword_add(bpp, blen, pth);
- (*bpp)[-1] = '\n';
-}
-
-static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
-{
- return sunrpc_cache_pipe_upcall(cd, h, svc_export_request);
-}
-
-static struct svc_export *svc_export_update(struct svc_export *new,
- struct svc_export *old);
-static struct svc_export *svc_export_lookup(struct svc_export *);
-
-static int check_export(struct inode *inode, int *flags, unsigned char *uuid)
-{
-
- /*
- * We currently export only dirs, regular files, and (for v4
- * pseudoroot) symlinks.
- */
- if (!S_ISDIR(inode->i_mode) &&
- !S_ISLNK(inode->i_mode) &&
- !S_ISREG(inode->i_mode))
- return -ENOTDIR;
-
- /*
- * Mountd should never pass down a writeable V4ROOT export, but,
- * just to make sure:
- */
- if (*flags & NFSEXP_V4ROOT)
- *flags |= NFSEXP_READONLY;
-
- /* There are two requirements on a filesystem to be exportable.
- * 1: We must be able to identify the filesystem from a number.
- * either a device number (so FS_REQUIRES_DEV needed)
- * or an FSID number (so NFSEXP_FSID or ->uuid is needed).
- * 2: We must be able to find an inode from a filehandle.
- * This means that s_export_op must be set.
- */
- if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
- !(*flags & NFSEXP_FSID) &&
- uuid == NULL) {
- dprintk("exp_export: export of non-dev fs without fsid\n");
- return -EINVAL;
- }
-
- if (!inode->i_sb->s_export_op ||
- !inode->i_sb->s_export_op->fh_to_dentry) {
- dprintk("exp_export: export of invalid fs type.\n");
- return -EINVAL;
- }
-
- return 0;
-
-}
-
-#ifdef CONFIG_NFSD_V4
-
-static int
-fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
-{
- int len;
- int migrated, i, err;
-
- /* listsize */
- err = get_int(mesg, &fsloc->locations_count);
- if (err)
- return err;
- if (fsloc->locations_count > MAX_FS_LOCATIONS)
- return -EINVAL;
- if (fsloc->locations_count == 0)
- return 0;
-
- fsloc->locations = kzalloc(fsloc->locations_count
- * sizeof(struct nfsd4_fs_location), GFP_KERNEL);
- if (!fsloc->locations)
- return -ENOMEM;
- for (i=0; i < fsloc->locations_count; i++) {
- /* colon separated host list */
- err = -EINVAL;
- len = qword_get(mesg, buf, PAGE_SIZE);
- if (len <= 0)
- goto out_free_all;
- err = -ENOMEM;
- fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
- if (!fsloc->locations[i].hosts)
- goto out_free_all;
- err = -EINVAL;
- /* slash separated path component list */
- len = qword_get(mesg, buf, PAGE_SIZE);
- if (len <= 0)
- goto out_free_all;
- err = -ENOMEM;
- fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
- if (!fsloc->locations[i].path)
- goto out_free_all;
- }
- /* migrated */
- err = get_int(mesg, &migrated);
- if (err)
- goto out_free_all;
- err = -EINVAL;
- if (migrated < 0 || migrated > 1)
- goto out_free_all;
- fsloc->migrated = migrated;
- return 0;
-out_free_all:
- nfsd4_fslocs_free(fsloc);
- return err;
-}
-
-static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
-{
- int listsize, err;
- struct exp_flavor_info *f;
-
- err = get_int(mesg, &listsize);
- if (err)
- return err;
- if (listsize < 0 || listsize > MAX_SECINFO_LIST)
- return -EINVAL;
-
- for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
- err = get_int(mesg, &f->pseudoflavor);
- if (err)
- return err;
- /*
- * XXX: It would be nice to also check whether this
- * pseudoflavor is supported, so we can discover the
- * problem at export time instead of when a client fails
- * to authenticate.
- */
- err = get_int(mesg, &f->flags);
- if (err)
- return err;
- /* Only some flags are allowed to differ between flavors: */
- if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
- return -EINVAL;
- }
- exp->ex_nflavors = listsize;
- return 0;
-}
-
-#else /* CONFIG_NFSD_V4 */
-static inline int
-fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
-static inline int
-secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
-#endif
-
-static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
-{
- /* client path expiry [flags anonuid anongid fsid] */
- char *buf;
- int len;
- int err;
- struct auth_domain *dom = NULL;
- struct svc_export exp = {}, *expp;
- int an_int;
-
- if (mesg[mlen-1] != '\n')
- return -EINVAL;
- mesg[mlen-1] = 0;
-
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- /* client */
- err = -EINVAL;
- len = qword_get(&mesg, buf, PAGE_SIZE);
- if (len <= 0)
- goto out;
-
- err = -ENOENT;
- dom = auth_domain_find(buf);
- if (!dom)
- goto out;
-
- /* path */
- err = -EINVAL;
- if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
- goto out1;
-
- err = kern_path(buf, 0, &exp.ex_path);
- if (err)
- goto out1;
-
- exp.ex_client = dom;
-
- /* expiry */
- err = -EINVAL;
- exp.h.expiry_time = get_expiry(&mesg);
- if (exp.h.expiry_time == 0)
- goto out3;
-
- /* flags */
- err = get_int(&mesg, &an_int);
- if (err == -ENOENT) {
- err = 0;
- set_bit(CACHE_NEGATIVE, &exp.h.flags);
- } else {
- if (err || an_int < 0)
- goto out3;
- exp.ex_flags= an_int;
-
- /* anon uid */
- err = get_int(&mesg, &an_int);
- if (err)
- goto out3;
- exp.ex_anon_uid= an_int;
-
- /* anon gid */
- err = get_int(&mesg, &an_int);
- if (err)
- goto out3;
- exp.ex_anon_gid= an_int;
-
- /* fsid */
- err = get_int(&mesg, &an_int);
- if (err)
- goto out3;
- exp.ex_fsid = an_int;
-
- while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
- if (strcmp(buf, "fsloc") == 0)
- err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
- else if (strcmp(buf, "uuid") == 0) {
- /* expect a 16 byte uuid encoded as \xXXXX... */
- len = qword_get(&mesg, buf, PAGE_SIZE);
- if (len != 16)
- err = -EINVAL;
- else {
- exp.ex_uuid =
- kmemdup(buf, 16, GFP_KERNEL);
- if (exp.ex_uuid == NULL)
- err = -ENOMEM;
- }
- } else if (strcmp(buf, "secinfo") == 0)
- err = secinfo_parse(&mesg, buf, &exp);
- else
- /* quietly ignore unknown words and anything
- * following. Newer user-space can try to set
- * new values, then see what the result was.
- */
- break;
- if (err)
- goto out4;
- }
-
- err = check_export(exp.ex_path.dentry->d_inode, &exp.ex_flags,
- exp.ex_uuid);
- if (err)
- goto out4;
- }
-
- expp = svc_export_lookup(&exp);
- if (expp)
- expp = svc_export_update(&exp, expp);
- else
- err = -ENOMEM;
- cache_flush();
- if (expp == NULL)
- err = -ENOMEM;
- else
- exp_put(expp);
-out4:
- nfsd4_fslocs_free(&exp.ex_fslocs);
- kfree(exp.ex_uuid);
-out3:
- path_put(&exp.ex_path);
-out1:
- auth_domain_put(dom);
-out:
- kfree(buf);
- return err;
-}
-
-static void exp_flags(struct seq_file *m, int flag, int fsid,
- uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
-static void show_secinfo(struct seq_file *m, struct svc_export *exp);
-
-static int svc_export_show(struct seq_file *m,
- struct cache_detail *cd,
- struct cache_head *h)
-{
- struct svc_export *exp ;
-
- if (h ==NULL) {
- seq_puts(m, "#path domain(flags)\n");
- return 0;
- }
- exp = container_of(h, struct svc_export, h);
- seq_path(m, &exp->ex_path, " \t\n\\");
- seq_putc(m, '\t');
- seq_escape(m, exp->ex_client->name, " \t\n\\");
- seq_putc(m, '(');
- if (test_bit(CACHE_VALID, &h->flags) &&
- !test_bit(CACHE_NEGATIVE, &h->flags)) {
- exp_flags(m, exp->ex_flags, exp->ex_fsid,
- exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
- if (exp->ex_uuid) {
- int i;
- seq_puts(m, ",uuid=");
- for (i=0; i<16; i++) {
- if ((i&3) == 0 && i)
- seq_putc(m, ':');
- seq_printf(m, "%02x", exp->ex_uuid[i]);
- }
- }
- show_secinfo(m, exp);
- }
- seq_puts(m, ")\n");
- return 0;
-}
-static int svc_export_match(struct cache_head *a, struct cache_head *b)
-{
- struct svc_export *orig = container_of(a, struct svc_export, h);
- struct svc_export *new = container_of(b, struct svc_export, h);
- return orig->ex_client == new->ex_client &&
- orig->ex_path.dentry == new->ex_path.dentry &&
- orig->ex_path.mnt == new->ex_path.mnt;
-}
-
-static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
-{
- struct svc_export *new = container_of(cnew, struct svc_export, h);
- struct svc_export *item = container_of(citem, struct svc_export, h);
-
- kref_get(&item->ex_client->ref);
- new->ex_client = item->ex_client;
- new->ex_path.dentry = dget(item->ex_path.dentry);
- new->ex_path.mnt = mntget(item->ex_path.mnt);
- new->ex_fslocs.locations = NULL;
- new->ex_fslocs.locations_count = 0;
- new->ex_fslocs.migrated = 0;
-}
-
-static void export_update(struct cache_head *cnew, struct cache_head *citem)
-{
- struct svc_export *new = container_of(cnew, struct svc_export, h);
- struct svc_export *item = container_of(citem, struct svc_export, h);
- int i;
-
- new->ex_flags = item->ex_flags;
- new->ex_anon_uid = item->ex_anon_uid;
- new->ex_anon_gid = item->ex_anon_gid;
- new->ex_fsid = item->ex_fsid;
- new->ex_uuid = item->ex_uuid;
- item->ex_uuid = NULL;
- new->ex_fslocs.locations = item->ex_fslocs.locations;
- item->ex_fslocs.locations = NULL;
- new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
- item->ex_fslocs.locations_count = 0;
- new->ex_fslocs.migrated = item->ex_fslocs.migrated;
- item->ex_fslocs.migrated = 0;
- new->ex_nflavors = item->ex_nflavors;
- for (i = 0; i < MAX_SECINFO_LIST; i++) {
- new->ex_flavors[i] = item->ex_flavors[i];
- }
-}
-
-static struct cache_head *svc_export_alloc(void)
-{
- struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
- if (i)
- return &i->h;
- else
- return NULL;
-}
-
-struct cache_detail svc_export_cache = {
- .owner = THIS_MODULE,
- .hash_size = EXPORT_HASHMAX,
- .hash_table = export_table,
- .name = "nfsd.export",
- .cache_put = svc_export_put,
- .cache_upcall = svc_export_upcall,
- .cache_parse = svc_export_parse,
- .cache_show = svc_export_show,
- .match = svc_export_match,
- .init = svc_export_init,
- .update = export_update,
- .alloc = svc_export_alloc,
-};
-
-static int
-svc_export_hash(struct svc_export *exp)
-{
- int hash;
-
- hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
- hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
- hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
- return hash;
-}
-
-static struct svc_export *
-svc_export_lookup(struct svc_export *exp)
-{
- struct cache_head *ch;
- int hash = svc_export_hash(exp);
-
- ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h,
- hash);
- if (ch)
- return container_of(ch, struct svc_export, h);
- else
- return NULL;
-}
-
-static struct svc_export *
-svc_export_update(struct svc_export *new, struct svc_export *old)
-{
- struct cache_head *ch;
- int hash = svc_export_hash(old);
-
- ch = sunrpc_cache_update(&svc_export_cache, &new->h,
- &old->h,
- hash);
- if (ch)
- return container_of(ch, struct svc_export, h);
- else
- return NULL;
-}
-
-
-static struct svc_expkey *
-exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
-{
- struct svc_expkey key, *ek;
- int err;
-
- if (!clp)
- return ERR_PTR(-ENOENT);
-
- key.ek_client = clp;
- key.ek_fsidtype = fsid_type;
- memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
-
- ek = svc_expkey_lookup(&key);
- if (ek == NULL)
- return ERR_PTR(-ENOMEM);
- err = cache_check(&svc_expkey_cache, &ek->h, reqp);
- if (err)
- return ERR_PTR(err);
- return ek;
-}
-
-
-static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
- struct cache_req *reqp)
-{
- struct svc_export *exp, key;
- int err;
-
- if (!clp)
- return ERR_PTR(-ENOENT);
-
- key.ex_client = clp;
- key.ex_path = *path;
-
- exp = svc_export_lookup(&key);
- if (exp == NULL)
- return ERR_PTR(-ENOMEM);
- err = cache_check(&svc_export_cache, &exp->h, reqp);
- if (err)
- return ERR_PTR(err);
- return exp;
-}
-
-/*
- * Find the export entry for a given dentry.
- */
-static struct svc_export *exp_parent(svc_client *clp, struct path *path)
-{
- struct dentry *saved = dget(path->dentry);
- svc_export *exp = exp_get_by_name(clp, path, NULL);
-
- while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
- struct dentry *parent = dget_parent(path->dentry);
- dput(path->dentry);
- path->dentry = parent;
- exp = exp_get_by_name(clp, path, NULL);
- }
- dput(path->dentry);
- path->dentry = saved;
- return exp;
-}
-
-
-
-/*
- * Obtain the root fh on behalf of a client.
- * This could be done in user space, but I feel that it adds some safety
- * since its harder to fool a kernel module than a user space program.
- */
-int
-exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
-{
- struct svc_export *exp;
- struct path path;
- struct inode *inode;
- struct svc_fh fh;
- int err;
-
- err = -EPERM;
- /* NB: we probably ought to check that it's NUL-terminated */
- if (kern_path(name, 0, &path)) {
- printk("nfsd: exp_rootfh path not found %s", name);
- return err;
- }
- inode = path.dentry->d_inode;
-
- dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
- name, path.dentry, clp->name,
- inode->i_sb->s_id, inode->i_ino);
- exp = exp_parent(clp, &path);
- if (IS_ERR(exp)) {
- err = PTR_ERR(exp);
- goto out;
- }
-
- /*
- * fh must be initialized before calling fh_compose
- */
- fh_init(&fh, maxsize);
- if (fh_compose(&fh, exp, path.dentry, NULL))
- err = -EINVAL;
- else
- err = 0;
- memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
- fh_put(&fh);
- exp_put(exp);
-out:
- path_put(&path);
- return err;
-}
-
-static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
- u32 *fsidv, struct cache_req *reqp)
-{
- struct svc_export *exp;
- struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
- if (IS_ERR(ek))
- return ERR_CAST(ek);
-
- exp = exp_get_by_name(clp, &ek->ek_path, reqp);
- cache_put(&ek->h, &svc_expkey_cache);
-
- if (IS_ERR(exp))
- return ERR_CAST(exp);
- return exp;
-}
-
-__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
-{
- struct exp_flavor_info *f;
- struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
-
- /* legacy gss-only clients are always OK: */
- if (exp->ex_client == rqstp->rq_gssclient)
- return 0;
- /* ip-address based client; check sec= export option: */
- for (f = exp->ex_flavors; f < end; f++) {
- if (f->pseudoflavor == rqstp->rq_flavor)
- return 0;
- }
- /* defaults in absence of sec= options: */
- if (exp->ex_nflavors == 0) {
- if (rqstp->rq_flavor == RPC_AUTH_NULL ||
- rqstp->rq_flavor == RPC_AUTH_UNIX)
- return 0;
- }
- return nfserr_wrongsec;
-}
-
-/*
- * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
- * auth_unix client) if it's available and has secinfo information;
- * otherwise, will try to use rq_gssclient.
- *
- * Called from functions that handle requests; functions that do work on
- * behalf of mountd are passed a single client name to use, and should
- * use exp_get_by_name() or exp_find().
- */
-struct svc_export *
-rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
-{
- struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
-
- if (rqstp->rq_client == NULL)
- goto gss;
-
- /* First try the auth_unix client: */
- exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
- if (PTR_ERR(exp) == -ENOENT)
- goto gss;
- if (IS_ERR(exp))
- return exp;
- /* If it has secinfo, assume there are no gss/... clients */
- if (exp->ex_nflavors > 0)
- return exp;
-gss:
- /* Otherwise, try falling back on gss client */
- if (rqstp->rq_gssclient == NULL)
- return exp;
- gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
- if (PTR_ERR(gssexp) == -ENOENT)
- return exp;
- if (!IS_ERR(exp))
- exp_put(exp);
- return gssexp;
-}
-
-struct svc_export *
-rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
-{
- struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
-
- if (rqstp->rq_client == NULL)
- goto gss;
-
- /* First try the auth_unix client: */
- exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);
- if (PTR_ERR(exp) == -ENOENT)
- goto gss;
- if (IS_ERR(exp))
- return exp;
- /* If it has secinfo, assume there are no gss/... clients */
- if (exp->ex_nflavors > 0)
- return exp;
-gss:
- /* Otherwise, try falling back on gss client */
- if (rqstp->rq_gssclient == NULL)
- return exp;
- gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
- &rqstp->rq_chandle);
- if (PTR_ERR(gssexp) == -ENOENT)
- return exp;
- if (!IS_ERR(exp))
- exp_put(exp);
- return gssexp;
-}
-
-struct svc_export *
-rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
-{
- struct dentry *saved = dget(path->dentry);
- struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
-
- while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
- struct dentry *parent = dget_parent(path->dentry);
- dput(path->dentry);
- path->dentry = parent;
- exp = rqst_exp_get_by_name(rqstp, path);
- }
- dput(path->dentry);
- path->dentry = saved;
- return exp;
-}
-
-struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
-{
- u32 fsidv[2];
-
- mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
-
- return rqst_exp_find(rqstp, FSID_NUM, fsidv);
-}
-
-/*
- * Called when we need the filehandle for the root of the pseudofs,
- * for a given NFSv4 client. The root is defined to be the
- * export point with fsid==0
- */
-__be32
-exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
-{
- struct svc_export *exp;
- __be32 rv;
-
- exp = rqst_find_fsidzero_export(rqstp);
- if (IS_ERR(exp))
- return nfserrno(PTR_ERR(exp));
- rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
- exp_put(exp);
- return rv;
-}
-
-/* Iterator */
-
-static void *e_start(struct seq_file *m, loff_t *pos)
- __acquires(svc_export_cache.hash_lock)
-{
- loff_t n = *pos;
- unsigned hash, export;
- struct cache_head *ch;
-
- read_lock(&svc_export_cache.hash_lock);
- if (!n--)
- return SEQ_START_TOKEN;
- hash = n >> 32;
- export = n & ((1LL<<32) - 1);
-
-
- for (ch=export_table[hash]; ch; ch=ch->next)
- if (!export--)
- return ch;
- n &= ~((1LL<<32) - 1);
- do {
- hash++;
- n += 1LL<<32;
- } while(hash < EXPORT_HASHMAX && export_table[hash]==NULL);
- if (hash >= EXPORT_HASHMAX)
- return NULL;
- *pos = n+1;
- return export_table[hash];
-}
-
-static void *e_next(struct seq_file *m, void *p, loff_t *pos)
-{
- struct cache_head *ch = p;
- int hash = (*pos >> 32);
-
- if (p == SEQ_START_TOKEN)
- hash = 0;
- else if (ch->next == NULL) {
- hash++;
- *pos += 1LL<<32;
- } else {
- ++*pos;
- return ch->next;
- }
- *pos &= ~((1LL<<32) - 1);
- while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) {
- hash++;
- *pos += 1LL<<32;
- }
- if (hash >= EXPORT_HASHMAX)
- return NULL;
- ++*pos;
- return export_table[hash];
-}
-
-static void e_stop(struct seq_file *m, void *p)
- __releases(svc_export_cache.hash_lock)
-{
- read_unlock(&svc_export_cache.hash_lock);
-}
-
-static struct flags {
- int flag;
- char *name[2];
-} expflags[] = {
- { NFSEXP_READONLY, {"ro", "rw"}},
- { NFSEXP_INSECURE_PORT, {"insecure", ""}},
- { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
- { NFSEXP_ALLSQUASH, {"all_squash", ""}},
- { NFSEXP_ASYNC, {"async", "sync"}},
- { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
- { NFSEXP_NOHIDE, {"nohide", ""}},
- { NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
- { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
- { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
- { NFSEXP_V4ROOT, {"v4root", ""}},
- { 0, {"", ""}}
-};
-
-static void show_expflags(struct seq_file *m, int flags, int mask)
-{
- struct flags *flg;
- int state, first = 0;
-
- for (flg = expflags; flg->flag; flg++) {
- if (flg->flag & ~mask)
- continue;
- state = (flg->flag & flags) ? 0 : 1;
- if (*flg->name[state])
- seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
- }
-}
-
-static void show_secinfo_flags(struct seq_file *m, int flags)
-{
- seq_printf(m, ",");
- show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
-}
-
-static bool secinfo_flags_equal(int f, int g)
-{
- f &= NFSEXP_SECINFO_FLAGS;
- g &= NFSEXP_SECINFO_FLAGS;
- return f == g;
-}
-
-static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
-{
- int flags;
-
- flags = (*fp)->flags;
- seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
- (*fp)++;
- while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
- seq_printf(m, ":%d", (*fp)->pseudoflavor);
- (*fp)++;
- }
- return flags;
-}
-
-static void show_secinfo(struct seq_file *m, struct svc_export *exp)
-{
- struct exp_flavor_info *f;
- struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
- int flags;
-
- if (exp->ex_nflavors == 0)
- return;
- f = exp->ex_flavors;
- flags = show_secinfo_run(m, &f, end);
- if (!secinfo_flags_equal(flags, exp->ex_flags))
- show_secinfo_flags(m, flags);
- while (f != end) {
- flags = show_secinfo_run(m, &f, end);
- show_secinfo_flags(m, flags);
- }
-}
-
-static void exp_flags(struct seq_file *m, int flag, int fsid,
- uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
-{
- show_expflags(m, flag, NFSEXP_ALLFLAGS);
- if (flag & NFSEXP_FSID)
- seq_printf(m, ",fsid=%d", fsid);
- if (anonu != (uid_t)-2 && anonu != (0x10000-2))
- seq_printf(m, ",anonuid=%u", anonu);
- if (anong != (gid_t)-2 && anong != (0x10000-2))
- seq_printf(m, ",anongid=%u", anong);
- if (fsloc && fsloc->locations_count > 0) {
- char *loctype = (fsloc->migrated) ? "refer" : "replicas";
- int i;
-
- seq_printf(m, ",%s=", loctype);
- seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
- seq_putc(m, '@');
- seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
- for (i = 1; i < fsloc->locations_count; i++) {
- seq_putc(m, ';');
- seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
- seq_putc(m, '@');
- seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
- }
- }
-}
-
-static int e_show(struct seq_file *m, void *p)
-{
- struct cache_head *cp = p;
- struct svc_export *exp = container_of(cp, struct svc_export, h);
-
- if (p == SEQ_START_TOKEN) {
- seq_puts(m, "# Version 1.1\n");
- seq_puts(m, "# Path Client(Flags) # IPs\n");
- return 0;
- }
-
- cache_get(&exp->h);
- if (cache_check(&svc_export_cache, &exp->h, NULL))
- return 0;
- cache_put(&exp->h, &svc_export_cache);
- return svc_export_show(m, &svc_export_cache, cp);
-}
-
-const struct seq_operations nfs_exports_op = {
- .start = e_start,
- .next = e_next,
- .stop = e_stop,
- .show = e_show,
-};
-
-
-/*
- * Initialize the exports module.
- */
-int
-nfsd_export_init(void)
-{
- int rv;
- dprintk("nfsd: initializing export module.\n");
-
- rv = cache_register_net(&svc_export_cache, &init_net);
- if (rv)
- return rv;
- rv = cache_register_net(&svc_expkey_cache, &init_net);
- if (rv)
- cache_unregister_net(&svc_export_cache, &init_net);
- return rv;
-
-}
-
-/*
- * Flush exports table - called when last nfsd thread is killed
- */
-void
-nfsd_export_flush(void)
-{
- cache_purge(&svc_expkey_cache);
- cache_purge(&svc_export_cache);
-}
-
-/*
- * Shutdown the exports module.
- */
-void
-nfsd_export_shutdown(void)
-{
-
- dprintk("nfsd: shutting down export module.\n");
-
- cache_unregister_net(&svc_expkey_cache, &init_net);
- cache_unregister_net(&svc_export_cache, &init_net);
- svcauth_unix_purge();
-
- dprintk("nfsd: export shutdown complete.\n");
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/fault_inject.c b/ANDROID_3.4.5/fs/nfsd/fault_inject.c
deleted file mode 100644
index 9559ce46..00000000
--- a/ANDROID_3.4.5/fs/nfsd/fault_inject.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
- *
- * Uses debugfs to create fault injection points for client testing
- */
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/debugfs.h>
-#include <linux/module.h>
-
-#include "state.h"
-#include "fault_inject.h"
-
-struct nfsd_fault_inject_op {
- char *file;
- void (*func)(u64);
-};
-
-static struct nfsd_fault_inject_op inject_ops[] = {
- {
- .file = "forget_clients",
- .func = nfsd_forget_clients,
- },
- {
- .file = "forget_locks",
- .func = nfsd_forget_locks,
- },
- {
- .file = "forget_openowners",
- .func = nfsd_forget_openowners,
- },
- {
- .file = "forget_delegations",
- .func = nfsd_forget_delegations,
- },
- {
- .file = "recall_delegations",
- .func = nfsd_recall_delegations,
- },
-};
-
-static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
-static struct dentry *debug_dir;
-
-static int nfsd_inject_set(void *op_ptr, u64 val)
-{
- struct nfsd_fault_inject_op *op = op_ptr;
-
- if (val == 0)
- printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file);
- else
- printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val);
-
- op->func(val);
- return 0;
-}
-
-static int nfsd_inject_get(void *data, u64 *val)
-{
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n");
-
-void nfsd_fault_inject_cleanup(void)
-{
- debugfs_remove_recursive(debug_dir);
-}
-
-int nfsd_fault_inject_init(void)
-{
- unsigned int i;
- struct nfsd_fault_inject_op *op;
- umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
-
- debug_dir = debugfs_create_dir("nfsd", NULL);
- if (!debug_dir)
- goto fail;
-
- for (i = 0; i < NUM_INJECT_OPS; i++) {
- op = &inject_ops[i];
- if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
- goto fail;
- }
- return 0;
-
-fail:
- nfsd_fault_inject_cleanup();
- return -ENOMEM;
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/fault_inject.h b/ANDROID_3.4.5/fs/nfsd/fault_inject.h
deleted file mode 100644
index 90bd0570..00000000
--- a/ANDROID_3.4.5/fs/nfsd/fault_inject.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
- *
- * Function definitions for fault injection
- */
-
-#ifndef LINUX_NFSD_FAULT_INJECT_H
-#define LINUX_NFSD_FAULT_INJECT_H
-
-#ifdef CONFIG_NFSD_FAULT_INJECTION
-int nfsd_fault_inject_init(void);
-void nfsd_fault_inject_cleanup(void);
-void nfsd_forget_clients(u64);
-void nfsd_forget_locks(u64);
-void nfsd_forget_openowners(u64);
-void nfsd_forget_delegations(u64);
-void nfsd_recall_delegations(u64);
-#else /* CONFIG_NFSD_FAULT_INJECTION */
-static inline int nfsd_fault_inject_init(void) { return 0; }
-static inline void nfsd_fault_inject_cleanup(void) {}
-static inline void nfsd_forget_clients(u64 num) {}
-static inline void nfsd_forget_locks(u64 num) {}
-static inline void nfsd_forget_openowners(u64 num) {}
-static inline void nfsd_forget_delegations(u64 num) {}
-static inline void nfsd_recall_delegations(u64 num) {}
-#endif /* CONFIG_NFSD_FAULT_INJECTION */
-
-#endif /* LINUX_NFSD_FAULT_INJECT_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/idmap.h b/ANDROID_3.4.5/fs/nfsd/idmap.h
deleted file mode 100644
index 2f3be132..00000000
--- a/ANDROID_3.4.5/fs/nfsd/idmap.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Mapping of UID to name and vice versa.
- *
- * Copyright (c) 2002, 2003 The Regents of the University of
- * Michigan. All rights reserved.
-> *
- * Marius Aamodt Eriksen <marius@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef LINUX_NFSD_IDMAP_H
-#define LINUX_NFSD_IDMAP_H
-
-#include <linux/in.h>
-#include <linux/sunrpc/svc.h>
-
-/* XXX from linux/nfs_idmap.h */
-#define IDMAP_NAMESZ 128
-
-#ifdef CONFIG_NFSD_V4
-int nfsd_idmap_init(void);
-void nfsd_idmap_shutdown(void);
-#else
-static inline int nfsd_idmap_init(void)
-{
- return 0;
-}
-static inline void nfsd_idmap_shutdown(void)
-{
-}
-#endif
-
-__be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
-__be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
-int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *);
-int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *);
-
-#endif /* LINUX_NFSD_IDMAP_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/lockd.c b/ANDROID_3.4.5/fs/nfsd/lockd.c
deleted file mode 100644
index 77e7a5cc..00000000
--- a/ANDROID_3.4.5/fs/nfsd/lockd.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * This file contains all the stubs needed when communicating with lockd.
- * This level of indirection is necessary so we can run nfsd+lockd without
- * requiring the nfs client to be compiled in/loaded, and vice versa.
- *
- * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/file.h>
-#include <linux/lockd/bind.h>
-#include "nfsd.h"
-#include "vfs.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_LOCKD
-
-#ifdef CONFIG_LOCKD_V4
-#define nlm_stale_fh nlm4_stale_fh
-#define nlm_failed nlm4_failed
-#else
-#define nlm_stale_fh nlm_lck_denied_nolocks
-#define nlm_failed nlm_lck_denied_nolocks
-#endif
-/*
- * Note: we hold the dentry use count while the file is open.
- */
-static __be32
-nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
-{
- __be32 nfserr;
- struct svc_fh fh;
-
- /* must initialize before using! but maxsize doesn't matter */
- fh_init(&fh,0);
- fh.fh_handle.fh_size = f->size;
- memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size);
- fh.fh_export = NULL;
-
- nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp);
- fh_put(&fh);
- /* We return nlm error codes as nlm doesn't know
- * about nfsd, but nfsd does know about nlm..
- */
- switch (nfserr) {
- case nfs_ok:
- return 0;
- case nfserr_dropit:
- return nlm_drop_reply;
- case nfserr_stale:
- return nlm_stale_fh;
- default:
- return nlm_failed;
- }
-}
-
-static void
-nlm_fclose(struct file *filp)
-{
- fput(filp);
-}
-
-static struct nlmsvc_binding nfsd_nlm_ops = {
- .fopen = nlm_fopen, /* open file for locking */
- .fclose = nlm_fclose, /* close file */
-};
-
-void
-nfsd_lockd_init(void)
-{
- dprintk("nfsd: initializing lockd\n");
- nlmsvc_ops = &nfsd_nlm_ops;
-}
-
-void
-nfsd_lockd_shutdown(void)
-{
- nlmsvc_ops = NULL;
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/netns.h b/ANDROID_3.4.5/fs/nfsd/netns.h
deleted file mode 100644
index 12e0cff4..00000000
--- a/ANDROID_3.4.5/fs/nfsd/netns.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * per net namespace data structures for nfsd
- *
- * Copyright (C) 2012, Jeff Layton <jlayton@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef __NFSD_NETNS_H__
-#define __NFSD_NETNS_H__
-
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-
-struct cld_net;
-
-struct nfsd_net {
- struct cld_net *cld_net;
-};
-
-extern int nfsd_net_id;
-#endif /* __NFSD_NETNS_H__ */
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs2acl.c b/ANDROID_3.4.5/fs/nfsd/nfs2acl.c
deleted file mode 100644
index 6aa5590c..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs2acl.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Process version 2 NFSACL requests.
- *
- * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
- */
-
-#include "nfsd.h"
-/* FIXME: nfsacl.h is a broken header */
-#include <linux/nfsacl.h>
-#include <linux/gfp.h>
-#include "cache.h"
-#include "xdr3.h"
-#include "vfs.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_PROC
-#define RETURN_STATUS(st) { resp->status = (st); return (st); }
-
-/*
- * NULL call.
- */
-static __be32
-nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
-{
- return nfs_ok;
-}
-
-/*
- * Get the Access and/or Default ACL of a file.
- */
-static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
- struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
-{
- svc_fh *fh;
- struct posix_acl *acl;
- __be32 nfserr = 0;
-
- dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
-
- fh = fh_copy(&resp->fh, &argp->fh);
- nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
- if (nfserr)
- RETURN_STATUS(nfserr);
-
- if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
- RETURN_STATUS(nfserr_inval);
- resp->mask = argp->mask;
-
- if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
- acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
- if (IS_ERR(acl)) {
- int err = PTR_ERR(acl);
-
- if (err == -ENODATA || err == -EOPNOTSUPP)
- acl = NULL;
- else {
- nfserr = nfserrno(err);
- goto fail;
- }
- }
- if (acl == NULL) {
- /* Solaris returns the inode's minimum ACL. */
-
- struct inode *inode = fh->fh_dentry->d_inode;
- acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
- }
- resp->acl_access = acl;
- }
- if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
- /* Check how Solaris handles requests for the Default ACL
- of a non-directory! */
-
- acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
- if (IS_ERR(acl)) {
- int err = PTR_ERR(acl);
-
- if (err == -ENODATA || err == -EOPNOTSUPP)
- acl = NULL;
- else {
- nfserr = nfserrno(err);
- goto fail;
- }
- }
- resp->acl_default = acl;
- }
-
- /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
- RETURN_STATUS(0);
-
-fail:
- posix_acl_release(resp->acl_access);
- posix_acl_release(resp->acl_default);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Set the Access and/or Default ACL of a file.
- */
-static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
- struct nfsd3_setaclargs *argp,
- struct nfsd_attrstat *resp)
-{
- svc_fh *fh;
- __be32 nfserr = 0;
-
- dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
-
- fh = fh_copy(&resp->fh, &argp->fh);
- nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
-
- if (!nfserr) {
- nfserr = nfserrno( nfsd_set_posix_acl(
- fh, ACL_TYPE_ACCESS, argp->acl_access) );
- }
- if (!nfserr) {
- nfserr = nfserrno( nfsd_set_posix_acl(
- fh, ACL_TYPE_DEFAULT, argp->acl_default) );
- }
-
- /* argp->acl_{access,default} may have been allocated in
- nfssvc_decode_setaclargs. */
- posix_acl_release(argp->acl_access);
- posix_acl_release(argp->acl_default);
- return nfserr;
-}
-
-/*
- * Check file attributes
- */
-static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
- struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
-{
- dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
-
- fh_copy(&resp->fh, &argp->fh);
- return fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
-}
-
-/*
- * Check file access
- */
-static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
- struct nfsd3_accessres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
- SVCFH_fmt(&argp->fh),
- argp->access);
-
- fh_copy(&resp->fh, &argp->fh);
- resp->access = argp->access;
- nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
- return nfserr;
-}
-
-/*
- * XDR decode functions
- */
-static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_getaclargs *argp)
-{
- if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
- return 0;
- argp->mask = ntohl(*p); p++;
-
- return xdr_argsize_check(rqstp, p);
-}
-
-
-static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_setaclargs *argp)
-{
- struct kvec *head = rqstp->rq_arg.head;
- unsigned int base;
- int n;
-
- if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
- return 0;
- argp->mask = ntohl(*p++);
- if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) ||
- !xdr_argsize_check(rqstp, p))
- return 0;
-
- base = (char *)p - (char *)head->iov_base;
- n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
- (argp->mask & NFS_ACL) ?
- &argp->acl_access : NULL);
- if (n > 0)
- n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
- (argp->mask & NFS_DFACL) ?
- &argp->acl_default : NULL);
- return (n > 0);
-}
-
-static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_fhandle *argp)
-{
- if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
- return 0;
- return xdr_argsize_check(rqstp, p);
-}
-
-static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_accessargs *argp)
-{
- if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
- return 0;
- argp->access = ntohl(*p++);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-/*
- * XDR encode functions
- */
-
-/*
- * There must be an encoding function for void results so svc_process
- * will work properly.
- */
-int
-nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
-{
- return xdr_ressize_check(rqstp, p);
-}
-
-/* GETACL */
-static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_getaclres *resp)
-{
- struct dentry *dentry = resp->fh.fh_dentry;
- struct inode *inode;
- struct kvec *head = rqstp->rq_res.head;
- unsigned int base;
- int n;
- int w;
-
- /*
- * Since this is version 2, the check for nfserr in
- * nfsd_dispatch actually ensures the following cannot happen.
- * However, it seems fragile to depend on that.
- */
- if (dentry == NULL || dentry->d_inode == NULL)
- return 0;
- inode = dentry->d_inode;
-
- p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
- *p++ = htonl(resp->mask);
- if (!xdr_ressize_check(rqstp, p))
- return 0;
- base = (char *)p - (char *)head->iov_base;
-
- rqstp->rq_res.page_len = w = nfsacl_size(
- (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
- while (w > 0) {
- if (!rqstp->rq_respages[rqstp->rq_resused++])
- return 0;
- w -= PAGE_SIZE;
- }
-
- n = nfsacl_encode(&rqstp->rq_res, base, inode,
- resp->acl_access,
- resp->mask & NFS_ACL, 0);
- if (n > 0)
- n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
- resp->acl_default,
- resp->mask & NFS_DFACL,
- NFS_ACL_DEFAULT);
- if (n <= 0)
- return 0;
- return 1;
-}
-
-static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_attrstat *resp)
-{
- p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
- return xdr_ressize_check(rqstp, p);
-}
-
-/* ACCESS */
-static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_accessres *resp)
-{
- p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
- *p++ = htonl(resp->access);
- return xdr_ressize_check(rqstp, p);
-}
-
-/*
- * XDR release functions
- */
-static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_getaclres *resp)
-{
- fh_put(&resp->fh);
- posix_acl_release(resp->acl_access);
- posix_acl_release(resp->acl_default);
- return 1;
-}
-
-static int nfsaclsvc_release_attrstat(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_attrstat *resp)
-{
- fh_put(&resp->fh);
- return 1;
-}
-
-static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_accessres *resp)
-{
- fh_put(&resp->fh);
- return 1;
-}
-
-#define nfsaclsvc_decode_voidargs NULL
-#define nfsaclsvc_release_void NULL
-#define nfsd3_fhandleargs nfsd_fhandle
-#define nfsd3_attrstatres nfsd_attrstat
-#define nfsd3_voidres nfsd3_voidargs
-struct nfsd3_voidargs { int dummy; };
-
-#define PROC(name, argt, rest, relt, cache, respsize) \
- { (svc_procfunc) nfsacld_proc_##name, \
- (kxdrproc_t) nfsaclsvc_decode_##argt##args, \
- (kxdrproc_t) nfsaclsvc_encode_##rest##res, \
- (kxdrproc_t) nfsaclsvc_release_##relt, \
- sizeof(struct nfsd3_##argt##args), \
- sizeof(struct nfsd3_##rest##res), \
- 0, \
- cache, \
- respsize, \
- }
-
-#define ST 1 /* status*/
-#define AT 21 /* attributes */
-#define pAT (1+AT) /* post attributes - conditional */
-#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
-
-static struct svc_procedure nfsd_acl_procedures2[] = {
- PROC(null, void, void, void, RC_NOCACHE, ST),
- PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
- PROC(setacl, setacl, attrstat, attrstat, RC_NOCACHE, ST+AT),
- PROC(getattr, fhandle, attrstat, attrstat, RC_NOCACHE, ST+AT),
- PROC(access, access, access, access, RC_NOCACHE, ST+AT+1),
-};
-
-struct svc_version nfsd_acl_version2 = {
- .vs_vers = 2,
- .vs_nproc = 5,
- .vs_proc = nfsd_acl_procedures2,
- .vs_dispatch = nfsd_dispatch,
- .vs_xdrsize = NFS3_SVC_XDRSIZE,
- .vs_hidden = 0,
-};
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs3acl.c b/ANDROID_3.4.5/fs/nfsd/nfs3acl.c
deleted file mode 100644
index a596e9d9..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs3acl.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Process version 3 NFSACL requests.
- *
- * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
- */
-
-#include "nfsd.h"
-/* FIXME: nfsacl.h is a broken header */
-#include <linux/nfsacl.h>
-#include <linux/gfp.h>
-#include "cache.h"
-#include "xdr3.h"
-#include "vfs.h"
-
-#define RETURN_STATUS(st) { resp->status = (st); return (st); }
-
-/*
- * NULL call.
- */
-static __be32
-nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
-{
- return nfs_ok;
-}
-
-/*
- * Get the Access and/or Default ACL of a file.
- */
-static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
- struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
-{
- svc_fh *fh;
- struct posix_acl *acl;
- __be32 nfserr = 0;
-
- fh = fh_copy(&resp->fh, &argp->fh);
- nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
- if (nfserr)
- RETURN_STATUS(nfserr);
-
- if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
- RETURN_STATUS(nfserr_inval);
- resp->mask = argp->mask;
-
- if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
- acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
- if (IS_ERR(acl)) {
- int err = PTR_ERR(acl);
-
- if (err == -ENODATA || err == -EOPNOTSUPP)
- acl = NULL;
- else {
- nfserr = nfserrno(err);
- goto fail;
- }
- }
- if (acl == NULL) {
- /* Solaris returns the inode's minimum ACL. */
-
- struct inode *inode = fh->fh_dentry->d_inode;
- acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
- }
- resp->acl_access = acl;
- }
- if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
- /* Check how Solaris handles requests for the Default ACL
- of a non-directory! */
-
- acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
- if (IS_ERR(acl)) {
- int err = PTR_ERR(acl);
-
- if (err == -ENODATA || err == -EOPNOTSUPP)
- acl = NULL;
- else {
- nfserr = nfserrno(err);
- goto fail;
- }
- }
- resp->acl_default = acl;
- }
-
- /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */
- RETURN_STATUS(0);
-
-fail:
- posix_acl_release(resp->acl_access);
- posix_acl_release(resp->acl_default);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Set the Access and/or Default ACL of a file.
- */
-static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
- struct nfsd3_setaclargs *argp,
- struct nfsd3_attrstat *resp)
-{
- svc_fh *fh;
- __be32 nfserr = 0;
-
- fh = fh_copy(&resp->fh, &argp->fh);
- nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
-
- if (!nfserr) {
- nfserr = nfserrno( nfsd_set_posix_acl(
- fh, ACL_TYPE_ACCESS, argp->acl_access) );
- }
- if (!nfserr) {
- nfserr = nfserrno( nfsd_set_posix_acl(
- fh, ACL_TYPE_DEFAULT, argp->acl_default) );
- }
-
- /* argp->acl_{access,default} may have been allocated in
- nfs3svc_decode_setaclargs. */
- posix_acl_release(argp->acl_access);
- posix_acl_release(argp->acl_default);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * XDR decode functions
- */
-static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_getaclargs *args)
-{
- if (!(p = nfs3svc_decode_fh(p, &args->fh)))
- return 0;
- args->mask = ntohl(*p); p++;
-
- return xdr_argsize_check(rqstp, p);
-}
-
-
-static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_setaclargs *args)
-{
- struct kvec *head = rqstp->rq_arg.head;
- unsigned int base;
- int n;
-
- if (!(p = nfs3svc_decode_fh(p, &args->fh)))
- return 0;
- args->mask = ntohl(*p++);
- if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) ||
- !xdr_argsize_check(rqstp, p))
- return 0;
-
- base = (char *)p - (char *)head->iov_base;
- n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
- (args->mask & NFS_ACL) ?
- &args->acl_access : NULL);
- if (n > 0)
- n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
- (args->mask & NFS_DFACL) ?
- &args->acl_default : NULL);
- return (n > 0);
-}
-
-/*
- * XDR encode functions
- */
-
-/* GETACL */
-static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_getaclres *resp)
-{
- struct dentry *dentry = resp->fh.fh_dentry;
-
- p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
- if (resp->status == 0 && dentry && dentry->d_inode) {
- struct inode *inode = dentry->d_inode;
- struct kvec *head = rqstp->rq_res.head;
- unsigned int base;
- int n;
- int w;
-
- *p++ = htonl(resp->mask);
- if (!xdr_ressize_check(rqstp, p))
- return 0;
- base = (char *)p - (char *)head->iov_base;
-
- rqstp->rq_res.page_len = w = nfsacl_size(
- (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
- while (w > 0) {
- if (!rqstp->rq_respages[rqstp->rq_resused++])
- return 0;
- w -= PAGE_SIZE;
- }
-
- n = nfsacl_encode(&rqstp->rq_res, base, inode,
- resp->acl_access,
- resp->mask & NFS_ACL, 0);
- if (n > 0)
- n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
- resp->acl_default,
- resp->mask & NFS_DFACL,
- NFS_ACL_DEFAULT);
- if (n <= 0)
- return 0;
- } else
- if (!xdr_ressize_check(rqstp, p))
- return 0;
-
- return 1;
-}
-
-/* SETACL */
-static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_attrstat *resp)
-{
- p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
-
- return xdr_ressize_check(rqstp, p);
-}
-
-/*
- * XDR release functions
- */
-static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_getaclres *resp)
-{
- fh_put(&resp->fh);
- posix_acl_release(resp->acl_access);
- posix_acl_release(resp->acl_default);
- return 1;
-}
-
-#define nfs3svc_decode_voidargs NULL
-#define nfs3svc_release_void NULL
-#define nfsd3_setaclres nfsd3_attrstat
-#define nfsd3_voidres nfsd3_voidargs
-struct nfsd3_voidargs { int dummy; };
-
-#define PROC(name, argt, rest, relt, cache, respsize) \
- { (svc_procfunc) nfsd3_proc_##name, \
- (kxdrproc_t) nfs3svc_decode_##argt##args, \
- (kxdrproc_t) nfs3svc_encode_##rest##res, \
- (kxdrproc_t) nfs3svc_release_##relt, \
- sizeof(struct nfsd3_##argt##args), \
- sizeof(struct nfsd3_##rest##res), \
- 0, \
- cache, \
- respsize, \
- }
-
-#define ST 1 /* status*/
-#define AT 21 /* attributes */
-#define pAT (1+AT) /* post attributes - conditional */
-#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
-
-static struct svc_procedure nfsd_acl_procedures3[] = {
- PROC(null, void, void, void, RC_NOCACHE, ST),
- PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
- PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT),
-};
-
-struct svc_version nfsd_acl_version3 = {
- .vs_vers = 3,
- .vs_nproc = 3,
- .vs_proc = nfsd_acl_procedures3,
- .vs_dispatch = nfsd_dispatch,
- .vs_xdrsize = NFS3_SVC_XDRSIZE,
- .vs_hidden = 0,
-};
-
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs3proc.c b/ANDROID_3.4.5/fs/nfsd/nfs3proc.c
deleted file mode 100644
index 9095f3c2..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs3proc.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/*
- * Process version 3 NFS requests.
- *
- * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/magic.h>
-
-#include "cache.h"
-#include "xdr3.h"
-#include "vfs.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_PROC
-
-#define RETURN_STATUS(st) { resp->status = (st); return (st); }
-
-static int nfs3_ftypes[] = {
- 0, /* NF3NON */
- S_IFREG, /* NF3REG */
- S_IFDIR, /* NF3DIR */
- S_IFBLK, /* NF3BLK */
- S_IFCHR, /* NF3CHR */
- S_IFLNK, /* NF3LNK */
- S_IFSOCK, /* NF3SOCK */
- S_IFIFO, /* NF3FIFO */
-};
-
-/*
- * NULL call.
- */
-static __be32
-nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
-{
- return nfs_ok;
-}
-
-/*
- * Get a file's attributes
- */
-static __be32
-nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
- struct nfsd3_attrstat *resp)
-{
- int err;
- __be32 nfserr;
-
- dprintk("nfsd: GETATTR(3) %s\n",
- SVCFH_fmt(&argp->fh));
-
- fh_copy(&resp->fh, &argp->fh);
- nfserr = fh_verify(rqstp, &resp->fh, 0,
- NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
- if (nfserr)
- RETURN_STATUS(nfserr);
-
- err = vfs_getattr(resp->fh.fh_export->ex_path.mnt,
- resp->fh.fh_dentry, &resp->stat);
- nfserr = nfserrno(err);
-
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Set a file's attributes
- */
-static __be32
-nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
- struct nfsd3_attrstat *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: SETATTR(3) %s\n",
- SVCFH_fmt(&argp->fh));
-
- fh_copy(&resp->fh, &argp->fh);
- nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
- argp->check_guard, argp->guardtime);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Look up a path name component
- */
-static __be32
-nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
- struct nfsd3_diropres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: LOOKUP(3) %s %.*s\n",
- SVCFH_fmt(&argp->fh),
- argp->len,
- argp->name);
-
- fh_copy(&resp->dirfh, &argp->fh);
- fh_init(&resp->fh, NFS3_FHSIZE);
-
- nfserr = nfsd_lookup(rqstp, &resp->dirfh,
- argp->name,
- argp->len,
- &resp->fh);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Check file access
- */
-static __be32
-nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
- struct nfsd3_accessres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: ACCESS(3) %s 0x%x\n",
- SVCFH_fmt(&argp->fh),
- argp->access);
-
- fh_copy(&resp->fh, &argp->fh);
- resp->access = argp->access;
- nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Read a symlink.
- */
-static __be32
-nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
- struct nfsd3_readlinkres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
-
- /* Read the symlink. */
- fh_copy(&resp->fh, &argp->fh);
- resp->len = NFS3_MAXPATHLEN;
- nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Read a portion of a file.
- */
-static __be32
-nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
- struct nfsd3_readres *resp)
-{
- __be32 nfserr;
- u32 max_blocksize = svc_max_payload(rqstp);
-
- dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
- SVCFH_fmt(&argp->fh),
- (unsigned long) argp->count,
- (unsigned long long) argp->offset);
-
- /* Obtain buffer pointer for payload.
- * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
- * + 1 (xdr opaque byte count) = 26
- */
-
- resp->count = argp->count;
- if (max_blocksize < resp->count)
- resp->count = max_blocksize;
-
- svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
-
- fh_copy(&resp->fh, &argp->fh);
- nfserr = nfsd_read(rqstp, &resp->fh,
- argp->offset,
- rqstp->rq_vec, argp->vlen,
- &resp->count);
- if (nfserr == 0) {
- struct inode *inode = resp->fh.fh_dentry->d_inode;
-
- resp->eof = (argp->offset + resp->count) >= inode->i_size;
- }
-
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Write data to a file
- */
-static __be32
-nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
- struct nfsd3_writeres *resp)
-{
- __be32 nfserr;
- unsigned long cnt = argp->len;
-
- dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n",
- SVCFH_fmt(&argp->fh),
- argp->len,
- (unsigned long long) argp->offset,
- argp->stable? " stable" : "");
-
- fh_copy(&resp->fh, &argp->fh);
- resp->committed = argp->stable;
- nfserr = nfsd_write(rqstp, &resp->fh, NULL,
- argp->offset,
- rqstp->rq_vec, argp->vlen,
- &cnt,
- &resp->committed);
- resp->count = cnt;
- RETURN_STATUS(nfserr);
-}
-
-/*
- * With NFSv3, CREATE processing is a lot easier than with NFSv2.
- * At least in theory; we'll see how it fares in practice when the
- * first reports about SunOS compatibility problems start to pour in...
- */
-static __be32
-nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
- struct nfsd3_diropres *resp)
-{
- svc_fh *dirfhp, *newfhp = NULL;
- struct iattr *attr;
- __be32 nfserr;
-
- dprintk("nfsd: CREATE(3) %s %.*s\n",
- SVCFH_fmt(&argp->fh),
- argp->len,
- argp->name);
-
- dirfhp = fh_copy(&resp->dirfh, &argp->fh);
- newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
- attr = &argp->attrs;
-
- /* Get the directory inode */
- nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_CREATE);
- if (nfserr)
- RETURN_STATUS(nfserr);
-
- /* Unfudge the mode bits */
- attr->ia_mode &= ~S_IFMT;
- if (!(attr->ia_valid & ATTR_MODE)) {
- attr->ia_valid |= ATTR_MODE;
- attr->ia_mode = S_IFREG;
- } else {
- attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG;
- }
-
- /* Now create the file and set attributes */
- nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
- attr, newfhp,
- argp->createmode, argp->verf, NULL, NULL);
-
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Make directory. This operation is not idempotent.
- */
-static __be32
-nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
- struct nfsd3_diropres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: MKDIR(3) %s %.*s\n",
- SVCFH_fmt(&argp->fh),
- argp->len,
- argp->name);
-
- argp->attrs.ia_valid &= ~ATTR_SIZE;
- fh_copy(&resp->dirfh, &argp->fh);
- fh_init(&resp->fh, NFS3_FHSIZE);
- nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
- &argp->attrs, S_IFDIR, 0, &resp->fh);
- fh_unlock(&resp->dirfh);
- RETURN_STATUS(nfserr);
-}
-
-static __be32
-nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
- struct nfsd3_diropres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
- SVCFH_fmt(&argp->ffh),
- argp->flen, argp->fname,
- argp->tlen, argp->tname);
-
- fh_copy(&resp->dirfh, &argp->ffh);
- fh_init(&resp->fh, NFS3_FHSIZE);
- nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
- argp->tname, argp->tlen,
- &resp->fh, &argp->attrs);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Make socket/fifo/device.
- */
-static __be32
-nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
- struct nfsd3_diropres *resp)
-{
- __be32 nfserr;
- int type;
- dev_t rdev = 0;
-
- dprintk("nfsd: MKNOD(3) %s %.*s\n",
- SVCFH_fmt(&argp->fh),
- argp->len,
- argp->name);
-
- fh_copy(&resp->dirfh, &argp->fh);
- fh_init(&resp->fh, NFS3_FHSIZE);
-
- if (argp->ftype == 0 || argp->ftype >= NF3BAD)
- RETURN_STATUS(nfserr_inval);
- if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
- rdev = MKDEV(argp->major, argp->minor);
- if (MAJOR(rdev) != argp->major ||
- MINOR(rdev) != argp->minor)
- RETURN_STATUS(nfserr_inval);
- } else
- if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
- RETURN_STATUS(nfserr_inval);
-
- type = nfs3_ftypes[argp->ftype];
- nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
- &argp->attrs, type, rdev, &resp->fh);
- fh_unlock(&resp->dirfh);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Remove file/fifo/socket etc.
- */
-static __be32
-nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
- struct nfsd3_attrstat *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: REMOVE(3) %s %.*s\n",
- SVCFH_fmt(&argp->fh),
- argp->len,
- argp->name);
-
- /* Unlink. -S_IFDIR means file must not be a directory */
- fh_copy(&resp->fh, &argp->fh);
- nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
- fh_unlock(&resp->fh);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Remove a directory
- */
-static __be32
-nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
- struct nfsd3_attrstat *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: RMDIR(3) %s %.*s\n",
- SVCFH_fmt(&argp->fh),
- argp->len,
- argp->name);
-
- fh_copy(&resp->fh, &argp->fh);
- nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
- fh_unlock(&resp->fh);
- RETURN_STATUS(nfserr);
-}
-
-static __be32
-nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
- struct nfsd3_renameres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: RENAME(3) %s %.*s ->\n",
- SVCFH_fmt(&argp->ffh),
- argp->flen,
- argp->fname);
- dprintk("nfsd: -> %s %.*s\n",
- SVCFH_fmt(&argp->tfh),
- argp->tlen,
- argp->tname);
-
- fh_copy(&resp->ffh, &argp->ffh);
- fh_copy(&resp->tfh, &argp->tfh);
- nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
- &resp->tfh, argp->tname, argp->tlen);
- RETURN_STATUS(nfserr);
-}
-
-static __be32
-nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
- struct nfsd3_linkres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: LINK(3) %s ->\n",
- SVCFH_fmt(&argp->ffh));
- dprintk("nfsd: -> %s %.*s\n",
- SVCFH_fmt(&argp->tfh),
- argp->tlen,
- argp->tname);
-
- fh_copy(&resp->fh, &argp->ffh);
- fh_copy(&resp->tfh, &argp->tfh);
- nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
- &resp->fh);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Read a portion of a directory.
- */
-static __be32
-nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
- struct nfsd3_readdirres *resp)
-{
- __be32 nfserr;
- int count;
-
- dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
- SVCFH_fmt(&argp->fh),
- argp->count, (u32) argp->cookie);
-
- /* Make sure we've room for the NULL ptr & eof flag, and shrink to
- * client read size */
- count = (argp->count >> 2) - 2;
-
- /* Read directory and encode entries on the fly */
- fh_copy(&resp->fh, &argp->fh);
-
- resp->buflen = count;
- resp->common.err = nfs_ok;
- resp->buffer = argp->buffer;
- resp->rqstp = rqstp;
- nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
- &resp->common, nfs3svc_encode_entry);
- memcpy(resp->verf, argp->verf, 8);
- resp->count = resp->buffer - argp->buffer;
- if (resp->offset)
- xdr_encode_hyper(resp->offset, argp->cookie);
-
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Read a portion of a directory, including file handles and attrs.
- * For now, we choose to ignore the dircount parameter.
- */
-static __be32
-nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
- struct nfsd3_readdirres *resp)
-{
- __be32 nfserr;
- int count = 0;
- loff_t offset;
- int i;
- caddr_t page_addr = NULL;
-
- dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
- SVCFH_fmt(&argp->fh),
- argp->count, (u32) argp->cookie);
-
- /* Convert byte count to number of words (i.e. >> 2),
- * and reserve room for the NULL ptr & eof flag (-2 words) */
- resp->count = (argp->count >> 2) - 2;
-
- /* Read directory and encode entries on the fly */
- fh_copy(&resp->fh, &argp->fh);
-
- resp->common.err = nfs_ok;
- resp->buffer = argp->buffer;
- resp->buflen = resp->count;
- resp->rqstp = rqstp;
- offset = argp->cookie;
- nfserr = nfsd_readdir(rqstp, &resp->fh,
- &offset,
- &resp->common,
- nfs3svc_encode_entry_plus);
- memcpy(resp->verf, argp->verf, 8);
- for (i=1; i<rqstp->rq_resused ; i++) {
- page_addr = page_address(rqstp->rq_respages[i]);
-
- if (((caddr_t)resp->buffer >= page_addr) &&
- ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
- count += (caddr_t)resp->buffer - page_addr;
- break;
- }
- count += PAGE_SIZE;
- }
- resp->count = count >> 2;
- if (resp->offset) {
- if (unlikely(resp->offset1)) {
- /* we ended up with offset on a page boundary */
- *resp->offset = htonl(offset >> 32);
- *resp->offset1 = htonl(offset & 0xffffffff);
- resp->offset1 = NULL;
- } else {
- xdr_encode_hyper(resp->offset, offset);
- }
- }
-
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Get file system stats
- */
-static __be32
-nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
- struct nfsd3_fsstatres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: FSSTAT(3) %s\n",
- SVCFH_fmt(&argp->fh));
-
- nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
- fh_put(&argp->fh);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Get file system info
- */
-static __be32
-nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
- struct nfsd3_fsinfores *resp)
-{
- __be32 nfserr;
- u32 max_blocksize = svc_max_payload(rqstp);
-
- dprintk("nfsd: FSINFO(3) %s\n",
- SVCFH_fmt(&argp->fh));
-
- resp->f_rtmax = max_blocksize;
- resp->f_rtpref = max_blocksize;
- resp->f_rtmult = PAGE_SIZE;
- resp->f_wtmax = max_blocksize;
- resp->f_wtpref = max_blocksize;
- resp->f_wtmult = PAGE_SIZE;
- resp->f_dtpref = PAGE_SIZE;
- resp->f_maxfilesize = ~(u32) 0;
- resp->f_properties = NFS3_FSF_DEFAULT;
-
- nfserr = fh_verify(rqstp, &argp->fh, 0,
- NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
-
- /* Check special features of the file system. May request
- * different read/write sizes for file systems known to have
- * problems with large blocks */
- if (nfserr == 0) {
- struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
-
- /* Note that we don't care for remote fs's here */
- if (sb->s_magic == MSDOS_SUPER_MAGIC) {
- resp->f_properties = NFS3_FSF_BILLYBOY;
- }
- resp->f_maxfilesize = sb->s_maxbytes;
- }
-
- fh_put(&argp->fh);
- RETURN_STATUS(nfserr);
-}
-
-/*
- * Get pathconf info for the specified file
- */
-static __be32
-nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
- struct nfsd3_pathconfres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: PATHCONF(3) %s\n",
- SVCFH_fmt(&argp->fh));
-
- /* Set default pathconf */
- resp->p_link_max = 255; /* at least */
- resp->p_name_max = 255; /* at least */
- resp->p_no_trunc = 0;
- resp->p_chown_restricted = 1;
- resp->p_case_insensitive = 0;
- resp->p_case_preserving = 1;
-
- nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
-
- if (nfserr == 0) {
- struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
-
- /* Note that we don't care for remote fs's here */
- switch (sb->s_magic) {
- case EXT2_SUPER_MAGIC:
- resp->p_link_max = EXT2_LINK_MAX;
- resp->p_name_max = EXT2_NAME_LEN;
- break;
- case MSDOS_SUPER_MAGIC:
- resp->p_case_insensitive = 1;
- resp->p_case_preserving = 0;
- break;
- }
- }
-
- fh_put(&argp->fh);
- RETURN_STATUS(nfserr);
-}
-
-
-/*
- * Commit a file (range) to stable storage.
- */
-static __be32
-nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
- struct nfsd3_commitres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
- SVCFH_fmt(&argp->fh),
- argp->count,
- (unsigned long long) argp->offset);
-
- if (argp->offset > NFS_OFFSET_MAX)
- RETURN_STATUS(nfserr_inval);
-
- fh_copy(&resp->fh, &argp->fh);
- nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
-
- RETURN_STATUS(nfserr);
-}
-
-
-/*
- * NFSv3 Server procedures.
- * Only the results of non-idempotent operations are cached.
- */
-#define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle
-#define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat
-#define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat
-#define nfsd3_mkdirargs nfsd3_createargs
-#define nfsd3_readdirplusargs nfsd3_readdirargs
-#define nfsd3_fhandleargs nfsd_fhandle
-#define nfsd3_fhandleres nfsd3_attrstat
-#define nfsd3_attrstatres nfsd3_attrstat
-#define nfsd3_wccstatres nfsd3_attrstat
-#define nfsd3_createres nfsd3_diropres
-#define nfsd3_voidres nfsd3_voidargs
-struct nfsd3_voidargs { int dummy; };
-
-#define PROC(name, argt, rest, relt, cache, respsize) \
- { (svc_procfunc) nfsd3_proc_##name, \
- (kxdrproc_t) nfs3svc_decode_##argt##args, \
- (kxdrproc_t) nfs3svc_encode_##rest##res, \
- (kxdrproc_t) nfs3svc_release_##relt, \
- sizeof(struct nfsd3_##argt##args), \
- sizeof(struct nfsd3_##rest##res), \
- 0, \
- cache, \
- respsize, \
- }
-
-#define ST 1 /* status*/
-#define FH 17 /* filehandle with length */
-#define AT 21 /* attributes */
-#define pAT (1+AT) /* post attributes - conditional */
-#define WC (7+pAT) /* WCC attributes */
-
-static struct svc_procedure nfsd_procedures3[22] = {
- [NFS3PROC_NULL] = {
- .pc_func = (svc_procfunc) nfsd3_proc_null,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres,
- .pc_argsize = sizeof(struct nfsd3_voidargs),
- .pc_ressize = sizeof(struct nfsd3_voidres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST,
- },
- [NFS3PROC_GETATTR] = {
- .pc_func = (svc_procfunc) nfsd3_proc_getattr,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_fhandleargs),
- .pc_ressize = sizeof(struct nfsd3_attrstatres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+AT,
- },
- [NFS3PROC_SETATTR] = {
- .pc_func = (svc_procfunc) nfsd3_proc_setattr,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_sattrargs),
- .pc_ressize = sizeof(struct nfsd3_wccstatres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+WC,
- },
- [NFS3PROC_LOOKUP] = {
- .pc_func = (svc_procfunc) nfsd3_proc_lookup,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_diropargs),
- .pc_ressize = sizeof(struct nfsd3_diropres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+FH+pAT+pAT,
- },
- [NFS3PROC_ACCESS] = {
- .pc_func = (svc_procfunc) nfsd3_proc_access,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_accessargs),
- .pc_ressize = sizeof(struct nfsd3_accessres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+1,
- },
- [NFS3PROC_READLINK] = {
- .pc_func = (svc_procfunc) nfsd3_proc_readlink,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_readlinkargs),
- .pc_ressize = sizeof(struct nfsd3_readlinkres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
- },
- [NFS3PROC_READ] = {
- .pc_func = (svc_procfunc) nfsd3_proc_read,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_readres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_readargs),
- .pc_ressize = sizeof(struct nfsd3_readres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
- },
- [NFS3PROC_WRITE] = {
- .pc_func = (svc_procfunc) nfsd3_proc_write,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_writeargs),
- .pc_ressize = sizeof(struct nfsd3_writeres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+WC+4,
- },
- [NFS3PROC_CREATE] = {
- .pc_func = (svc_procfunc) nfsd3_proc_create,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_createargs),
- .pc_ressize = sizeof(struct nfsd3_createres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+(1+FH+pAT)+WC,
- },
- [NFS3PROC_MKDIR] = {
- .pc_func = (svc_procfunc) nfsd3_proc_mkdir,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_mkdirargs),
- .pc_ressize = sizeof(struct nfsd3_createres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+(1+FH+pAT)+WC,
- },
- [NFS3PROC_SYMLINK] = {
- .pc_func = (svc_procfunc) nfsd3_proc_symlink,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_symlinkargs),
- .pc_ressize = sizeof(struct nfsd3_createres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+(1+FH+pAT)+WC,
- },
- [NFS3PROC_MKNOD] = {
- .pc_func = (svc_procfunc) nfsd3_proc_mknod,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_mknodargs),
- .pc_ressize = sizeof(struct nfsd3_createres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+(1+FH+pAT)+WC,
- },
- [NFS3PROC_REMOVE] = {
- .pc_func = (svc_procfunc) nfsd3_proc_remove,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_diropargs),
- .pc_ressize = sizeof(struct nfsd3_wccstatres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+WC,
- },
- [NFS3PROC_RMDIR] = {
- .pc_func = (svc_procfunc) nfsd3_proc_rmdir,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_diropargs),
- .pc_ressize = sizeof(struct nfsd3_wccstatres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+WC,
- },
- [NFS3PROC_RENAME] = {
- .pc_func = (svc_procfunc) nfsd3_proc_rename,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_renameargs),
- .pc_ressize = sizeof(struct nfsd3_renameres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+WC+WC,
- },
- [NFS3PROC_LINK] = {
- .pc_func = (svc_procfunc) nfsd3_proc_link,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_linkargs),
- .pc_ressize = sizeof(struct nfsd3_linkres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+pAT+WC,
- },
- [NFS3PROC_READDIR] = {
- .pc_func = (svc_procfunc) nfsd3_proc_readdir,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_readdirargs),
- .pc_ressize = sizeof(struct nfsd3_readdirres),
- .pc_cachetype = RC_NOCACHE,
- },
- [NFS3PROC_READDIRPLUS] = {
- .pc_func = (svc_procfunc) nfsd3_proc_readdirplus,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
- .pc_ressize = sizeof(struct nfsd3_readdirres),
- .pc_cachetype = RC_NOCACHE,
- },
- [NFS3PROC_FSSTAT] = {
- .pc_func = (svc_procfunc) nfsd3_proc_fsstat,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres,
- .pc_argsize = sizeof(struct nfsd3_fhandleargs),
- .pc_ressize = sizeof(struct nfsd3_fsstatres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+2*6+1,
- },
- [NFS3PROC_FSINFO] = {
- .pc_func = (svc_procfunc) nfsd3_proc_fsinfo,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores,
- .pc_argsize = sizeof(struct nfsd3_fhandleargs),
- .pc_ressize = sizeof(struct nfsd3_fsinfores),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+12,
- },
- [NFS3PROC_PATHCONF] = {
- .pc_func = (svc_procfunc) nfsd3_proc_pathconf,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres,
- .pc_argsize = sizeof(struct nfsd3_fhandleargs),
- .pc_ressize = sizeof(struct nfsd3_pathconfres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+6,
- },
- [NFS3PROC_COMMIT] = {
- .pc_func = (svc_procfunc) nfsd3_proc_commit,
- .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs,
- .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres,
- .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_commitargs),
- .pc_ressize = sizeof(struct nfsd3_commitres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+WC+2,
- },
-};
-
-struct svc_version nfsd_version3 = {
- .vs_vers = 3,
- .vs_nproc = 22,
- .vs_proc = nfsd_procedures3,
- .vs_dispatch = nfsd_dispatch,
- .vs_xdrsize = NFS3_SVC_XDRSIZE,
-};
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs3xdr.c b/ANDROID_3.4.5/fs/nfsd/nfs3xdr.c
deleted file mode 100644
index 43f46cd9..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs3xdr.c
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * XDR support for nfsd/protocol version 3.
- *
- * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
- *
- * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
- */
-
-#include <linux/namei.h>
-#include "xdr3.h"
-#include "auth.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_XDR
-
-
-/*
- * Mapping of S_IF* types to NFS file types
- */
-static u32 nfs3_ftypes[] = {
- NF3NON, NF3FIFO, NF3CHR, NF3BAD,
- NF3DIR, NF3BAD, NF3BLK, NF3BAD,
- NF3REG, NF3BAD, NF3LNK, NF3BAD,
- NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
-};
-
-/*
- * XDR functions for basic NFS types
- */
-static __be32 *
-encode_time3(__be32 *p, struct timespec *time)
-{
- *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
- return p;
-}
-
-static __be32 *
-decode_time3(__be32 *p, struct timespec *time)
-{
- time->tv_sec = ntohl(*p++);
- time->tv_nsec = ntohl(*p++);
- return p;
-}
-
-static __be32 *
-decode_fh(__be32 *p, struct svc_fh *fhp)
-{
- unsigned int size;
- fh_init(fhp, NFS3_FHSIZE);
- size = ntohl(*p++);
- if (size > NFS3_FHSIZE)
- return NULL;
-
- memcpy(&fhp->fh_handle.fh_base, p, size);
- fhp->fh_handle.fh_size = size;
- return p + XDR_QUADLEN(size);
-}
-
-/* Helper function for NFSv3 ACL code */
-__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp)
-{
- return decode_fh(p, fhp);
-}
-
-static __be32 *
-encode_fh(__be32 *p, struct svc_fh *fhp)
-{
- unsigned int size = fhp->fh_handle.fh_size;
- *p++ = htonl(size);
- if (size) p[XDR_QUADLEN(size)-1]=0;
- memcpy(p, &fhp->fh_handle.fh_base, size);
- return p + XDR_QUADLEN(size);
-}
-
-/*
- * Decode a file name and make sure that the path contains
- * no slashes or null bytes.
- */
-static __be32 *
-decode_filename(__be32 *p, char **namp, unsigned int *lenp)
-{
- char *name;
- unsigned int i;
-
- if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
- for (i = 0, name = *namp; i < *lenp; i++, name++) {
- if (*name == '\0' || *name == '/')
- return NULL;
- }
- }
-
- return p;
-}
-
-static __be32 *
-decode_sattr3(__be32 *p, struct iattr *iap)
-{
- u32 tmp;
-
- iap->ia_valid = 0;
-
- if (*p++) {
- iap->ia_valid |= ATTR_MODE;
- iap->ia_mode = ntohl(*p++);
- }
- if (*p++) {
- iap->ia_valid |= ATTR_UID;
- iap->ia_uid = ntohl(*p++);
- }
- if (*p++) {
- iap->ia_valid |= ATTR_GID;
- iap->ia_gid = ntohl(*p++);
- }
- if (*p++) {
- u64 newsize;
-
- iap->ia_valid |= ATTR_SIZE;
- p = xdr_decode_hyper(p, &newsize);
- if (newsize <= NFS_OFFSET_MAX)
- iap->ia_size = newsize;
- else
- iap->ia_size = NFS_OFFSET_MAX;
- }
- if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
- iap->ia_valid |= ATTR_ATIME;
- } else if (tmp == 2) { /* set to client time */
- iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
- iap->ia_atime.tv_sec = ntohl(*p++);
- iap->ia_atime.tv_nsec = ntohl(*p++);
- }
- if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
- iap->ia_valid |= ATTR_MTIME;
- } else if (tmp == 2) { /* set to client time */
- iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
- iap->ia_mtime.tv_sec = ntohl(*p++);
- iap->ia_mtime.tv_nsec = ntohl(*p++);
- }
- return p;
-}
-
-static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
-{
- u64 f;
- switch(fsid_source(fhp)) {
- default:
- case FSIDSOURCE_DEV:
- p = xdr_encode_hyper(p, (u64)huge_encode_dev
- (fhp->fh_dentry->d_inode->i_sb->s_dev));
- break;
- case FSIDSOURCE_FSID:
- p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
- break;
- case FSIDSOURCE_UUID:
- f = ((u64*)fhp->fh_export->ex_uuid)[0];
- f ^= ((u64*)fhp->fh_export->ex_uuid)[1];
- p = xdr_encode_hyper(p, f);
- break;
- }
- return p;
-}
-
-static __be32 *
-encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
- struct kstat *stat)
-{
- *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
- *p++ = htonl((u32) stat->mode);
- *p++ = htonl((u32) stat->nlink);
- *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
- *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
- if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
- p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
- } else {
- p = xdr_encode_hyper(p, (u64) stat->size);
- }
- p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
- *p++ = htonl((u32) MAJOR(stat->rdev));
- *p++ = htonl((u32) MINOR(stat->rdev));
- p = encode_fsid(p, fhp);
- p = xdr_encode_hyper(p, stat->ino);
- p = encode_time3(p, &stat->atime);
- p = encode_time3(p, &stat->mtime);
- p = encode_time3(p, &stat->ctime);
-
- return p;
-}
-
-static __be32 *
-encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
- /* Attributes to follow */
- *p++ = xdr_one;
- return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
-}
-
-/*
- * Encode post-operation attributes.
- * The inode may be NULL if the call failed because of a stale file
- * handle. In this case, no attributes are returned.
- */
-static __be32 *
-encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
- struct dentry *dentry = fhp->fh_dentry;
- if (dentry && dentry->d_inode) {
- int err;
- struct kstat stat;
-
- err = vfs_getattr(fhp->fh_export->ex_path.mnt, dentry, &stat);
- if (!err) {
- *p++ = xdr_one; /* attributes follow */
- lease_get_mtime(dentry->d_inode, &stat.mtime);
- return encode_fattr3(rqstp, p, fhp, &stat);
- }
- }
- *p++ = xdr_zero;
- return p;
-}
-
-/* Helper for NFSv3 ACLs */
-__be32 *
-nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
- return encode_post_op_attr(rqstp, p, fhp);
-}
-
-/*
- * Enocde weak cache consistency data
- */
-static __be32 *
-encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
- struct dentry *dentry = fhp->fh_dentry;
-
- if (dentry && dentry->d_inode && fhp->fh_post_saved) {
- if (fhp->fh_pre_saved) {
- *p++ = xdr_one;
- p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
- p = encode_time3(p, &fhp->fh_pre_mtime);
- p = encode_time3(p, &fhp->fh_pre_ctime);
- } else {
- *p++ = xdr_zero;
- }
- return encode_saved_post_attr(rqstp, p, fhp);
- }
- /* no pre- or post-attrs */
- *p++ = xdr_zero;
- return encode_post_op_attr(rqstp, p, fhp);
-}
-
-/*
- * Fill in the post_op attr for the wcc data
- */
-void fill_post_wcc(struct svc_fh *fhp)
-{
- int err;
-
- if (fhp->fh_post_saved)
- printk("nfsd: inode locked twice during operation.\n");
-
- err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry,
- &fhp->fh_post_attr);
- fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version;
- if (err) {
- fhp->fh_post_saved = 0;
- /* Grab the ctime anyway - set_change_info might use it */
- fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime;
- } else
- fhp->fh_post_saved = 1;
-}
-
-/*
- * XDR decode functions
- */
-int
-nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_sattrargs *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- p = decode_sattr3(p, &args->attrs);
-
- if ((args->check_guard = ntohl(*p++)) != 0) {
- struct timespec time;
- p = decode_time3(p, &time);
- args->guardtime = time.tv_sec;
- }
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_diropargs *args)
-{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len)))
- return 0;
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_accessargs *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- args->access = ntohl(*p++);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_readargs *args)
-{
- unsigned int len;
- int v,pn;
- u32 max_blocksize = svc_max_payload(rqstp);
-
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- p = xdr_decode_hyper(p, &args->offset);
-
- len = args->count = ntohl(*p++);
-
- if (len > max_blocksize)
- len = max_blocksize;
-
- /* set up the kvec */
- v=0;
- while (len > 0) {
- pn = rqstp->rq_resused++;
- rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
- rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
- len -= rqstp->rq_vec[v].iov_len;
- v++;
- }
- args->vlen = v;
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_writeargs *args)
-{
- unsigned int len, v, hdr, dlen;
- u32 max_blocksize = svc_max_payload(rqstp);
-
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- p = xdr_decode_hyper(p, &args->offset);
-
- args->count = ntohl(*p++);
- args->stable = ntohl(*p++);
- len = args->len = ntohl(*p++);
- /*
- * The count must equal the amount of data passed.
- */
- if (args->count != args->len)
- return 0;
-
- /*
- * Check to make sure that we got the right number of
- * bytes.
- */
- hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
- dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
- - hdr;
- /*
- * Round the length of the data which was specified up to
- * the next multiple of XDR units and then compare that
- * against the length which was actually received.
- * Note that when RPCSEC/GSS (for example) is used, the
- * data buffer can be padded so dlen might be larger
- * than required. It must never be smaller.
- */
- if (dlen < XDR_QUADLEN(len)*4)
- return 0;
-
- if (args->count > max_blocksize) {
- args->count = max_blocksize;
- len = args->len = max_blocksize;
- }
- rqstp->rq_vec[0].iov_base = (void*)p;
- rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
- v = 0;
- while (len > rqstp->rq_vec[v].iov_len) {
- len -= rqstp->rq_vec[v].iov_len;
- v++;
- rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
- rqstp->rq_vec[v].iov_len = PAGE_SIZE;
- }
- rqstp->rq_vec[v].iov_len = len;
- args->vlen = v + 1;
- return 1;
-}
-
-int
-nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_createargs *args)
-{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len)))
- return 0;
-
- switch (args->createmode = ntohl(*p++)) {
- case NFS3_CREATE_UNCHECKED:
- case NFS3_CREATE_GUARDED:
- p = decode_sattr3(p, &args->attrs);
- break;
- case NFS3_CREATE_EXCLUSIVE:
- args->verf = p;
- p += 2;
- break;
- default:
- return 0;
- }
-
- return xdr_argsize_check(rqstp, p);
-}
-int
-nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_createargs *args)
-{
- if (!(p = decode_fh(p, &args->fh)) ||
- !(p = decode_filename(p, &args->name, &args->len)))
- return 0;
- p = decode_sattr3(p, &args->attrs);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_symlinkargs *args)
-{
- unsigned int len, avail;
- char *old, *new;
- struct kvec *vec;
-
- if (!(p = decode_fh(p, &args->ffh)) ||
- !(p = decode_filename(p, &args->fname, &args->flen))
- )
- return 0;
- p = decode_sattr3(p, &args->attrs);
-
- /* now decode the pathname, which might be larger than the first page.
- * As we have to check for nul's anyway, we copy it into a new page
- * This page appears in the rq_res.pages list, but as pages_len is always
- * 0, it won't get in the way
- */
- len = ntohl(*p++);
- if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
- return 0;
- args->tname = new =
- page_address(rqstp->rq_respages[rqstp->rq_resused++]);
- args->tlen = len;
- /* first copy and check from the first page */
- old = (char*)p;
- vec = &rqstp->rq_arg.head[0];
- avail = vec->iov_len - (old - (char*)vec->iov_base);
- while (len && avail && *old) {
- *new++ = *old++;
- len--;
- avail--;
- }
- /* now copy next page if there is one */
- if (len && !avail && rqstp->rq_arg.page_len) {
- avail = rqstp->rq_arg.page_len;
- if (avail > PAGE_SIZE)
- avail = PAGE_SIZE;
- old = page_address(rqstp->rq_arg.pages[0]);
- }
- while (len && avail && *old) {
- *new++ = *old++;
- len--;
- avail--;
- }
- *new = '\0';
- if (len)
- return 0;
-
- return 1;
-}
-
-int
-nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_mknodargs *args)
-{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len)))
- return 0;
-
- args->ftype = ntohl(*p++);
-
- if (args->ftype == NF3BLK || args->ftype == NF3CHR
- || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
- p = decode_sattr3(p, &args->attrs);
-
- if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
- args->major = ntohl(*p++);
- args->minor = ntohl(*p++);
- }
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_renameargs *args)
-{
- if (!(p = decode_fh(p, &args->ffh))
- || !(p = decode_filename(p, &args->fname, &args->flen))
- || !(p = decode_fh(p, &args->tfh))
- || !(p = decode_filename(p, &args->tname, &args->tlen)))
- return 0;
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_readlinkargs *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- args->buffer =
- page_address(rqstp->rq_respages[rqstp->rq_resused++]);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_linkargs *args)
-{
- if (!(p = decode_fh(p, &args->ffh))
- || !(p = decode_fh(p, &args->tfh))
- || !(p = decode_filename(p, &args->tname, &args->tlen)))
- return 0;
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_readdirargs *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- p = xdr_decode_hyper(p, &args->cookie);
- args->verf = p; p += 2;
- args->dircount = ~0;
- args->count = ntohl(*p++);
-
- if (args->count > PAGE_SIZE)
- args->count = PAGE_SIZE;
-
- args->buffer =
- page_address(rqstp->rq_respages[rqstp->rq_resused++]);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_readdirargs *args)
-{
- int len, pn;
- u32 max_blocksize = svc_max_payload(rqstp);
-
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- p = xdr_decode_hyper(p, &args->cookie);
- args->verf = p; p += 2;
- args->dircount = ntohl(*p++);
- args->count = ntohl(*p++);
-
- len = (args->count > max_blocksize) ? max_blocksize :
- args->count;
- args->count = len;
-
- while (len > 0) {
- pn = rqstp->rq_resused++;
- if (!args->buffer)
- args->buffer = page_address(rqstp->rq_respages[pn]);
- len -= PAGE_SIZE;
- }
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_commitargs *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- p = xdr_decode_hyper(p, &args->offset);
- args->count = ntohl(*p++);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-/*
- * XDR encode functions
- */
-/*
- * There must be an encoding function for void results so svc_process
- * will work properly.
- */
-int
-nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
-{
- return xdr_ressize_check(rqstp, p);
-}
-
-/* GETATTR */
-int
-nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_attrstat *resp)
-{
- if (resp->status == 0) {
- lease_get_mtime(resp->fh.fh_dentry->d_inode,
- &resp->stat.mtime);
- p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
- }
- return xdr_ressize_check(rqstp, p);
-}
-
-/* SETATTR, REMOVE, RMDIR */
-int
-nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_attrstat *resp)
-{
- p = encode_wcc_data(rqstp, p, &resp->fh);
- return xdr_ressize_check(rqstp, p);
-}
-
-/* LOOKUP */
-int
-nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_diropres *resp)
-{
- if (resp->status == 0) {
- p = encode_fh(p, &resp->fh);
- p = encode_post_op_attr(rqstp, p, &resp->fh);
- }
- p = encode_post_op_attr(rqstp, p, &resp->dirfh);
- return xdr_ressize_check(rqstp, p);
-}
-
-/* ACCESS */
-int
-nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_accessres *resp)
-{
- p = encode_post_op_attr(rqstp, p, &resp->fh);
- if (resp->status == 0)
- *p++ = htonl(resp->access);
- return xdr_ressize_check(rqstp, p);
-}
-
-/* READLINK */
-int
-nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_readlinkres *resp)
-{
- p = encode_post_op_attr(rqstp, p, &resp->fh);
- if (resp->status == 0) {
- *p++ = htonl(resp->len);
- xdr_ressize_check(rqstp, p);
- rqstp->rq_res.page_len = resp->len;
- if (resp->len & 3) {
- /* need to pad the tail */
- rqstp->rq_res.tail[0].iov_base = p;
- *p = 0;
- rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
- }
- return 1;
- } else
- return xdr_ressize_check(rqstp, p);
-}
-
-/* READ */
-int
-nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_readres *resp)
-{
- p = encode_post_op_attr(rqstp, p, &resp->fh);
- if (resp->status == 0) {
- *p++ = htonl(resp->count);
- *p++ = htonl(resp->eof);
- *p++ = htonl(resp->count); /* xdr opaque count */
- xdr_ressize_check(rqstp, p);
- /* now update rqstp->rq_res to reflect data as well */
- rqstp->rq_res.page_len = resp->count;
- if (resp->count & 3) {
- /* need to pad the tail */
- rqstp->rq_res.tail[0].iov_base = p;
- *p = 0;
- rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
- }
- return 1;
- } else
- return xdr_ressize_check(rqstp, p);
-}
-
-/* WRITE */
-int
-nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_writeres *resp)
-{
- p = encode_wcc_data(rqstp, p, &resp->fh);
- if (resp->status == 0) {
- *p++ = htonl(resp->count);
- *p++ = htonl(resp->committed);
- *p++ = htonl(nfssvc_boot.tv_sec);
- *p++ = htonl(nfssvc_boot.tv_usec);
- }
- return xdr_ressize_check(rqstp, p);
-}
-
-/* CREATE, MKDIR, SYMLINK, MKNOD */
-int
-nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_diropres *resp)
-{
- if (resp->status == 0) {
- *p++ = xdr_one;
- p = encode_fh(p, &resp->fh);
- p = encode_post_op_attr(rqstp, p, &resp->fh);
- }
- p = encode_wcc_data(rqstp, p, &resp->dirfh);
- return xdr_ressize_check(rqstp, p);
-}
-
-/* RENAME */
-int
-nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_renameres *resp)
-{
- p = encode_wcc_data(rqstp, p, &resp->ffh);
- p = encode_wcc_data(rqstp, p, &resp->tfh);
- return xdr_ressize_check(rqstp, p);
-}
-
-/* LINK */
-int
-nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_linkres *resp)
-{
- p = encode_post_op_attr(rqstp, p, &resp->fh);
- p = encode_wcc_data(rqstp, p, &resp->tfh);
- return xdr_ressize_check(rqstp, p);
-}
-
-/* READDIR */
-int
-nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_readdirres *resp)
-{
- p = encode_post_op_attr(rqstp, p, &resp->fh);
-
- if (resp->status == 0) {
- /* stupid readdir cookie */
- memcpy(p, resp->verf, 8); p += 2;
- xdr_ressize_check(rqstp, p);
- if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE)
- return 1; /*No room for trailer */
- rqstp->rq_res.page_len = (resp->count) << 2;
-
- /* add the 'tail' to the end of the 'head' page - page 0. */
- rqstp->rq_res.tail[0].iov_base = p;
- *p++ = 0; /* no more entries */
- *p++ = htonl(resp->common.err == nfserr_eof);
- rqstp->rq_res.tail[0].iov_len = 2<<2;
- return 1;
- } else
- return xdr_ressize_check(rqstp, p);
-}
-
-static __be32 *
-encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
- int namlen, u64 ino)
-{
- *p++ = xdr_one; /* mark entry present */
- p = xdr_encode_hyper(p, ino); /* file id */
- p = xdr_encode_array(p, name, namlen);/* name length & name */
-
- cd->offset = p; /* remember pointer */
- p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */
-
- return p;
-}
-
-static __be32
-compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
- const char *name, int namlen)
-{
- struct svc_export *exp;
- struct dentry *dparent, *dchild;
- __be32 rv = nfserr_noent;
-
- dparent = cd->fh.fh_dentry;
- exp = cd->fh.fh_export;
-
- if (isdotent(name, namlen)) {
- if (namlen == 2) {
- dchild = dget_parent(dparent);
- /* filesystem root - cannot return filehandle for ".." */
- if (dchild == dparent)
- goto out;
- } else
- dchild = dget(dparent);
- } else
- dchild = lookup_one_len(name, dparent, namlen);
- if (IS_ERR(dchild))
- return rv;
- if (d_mountpoint(dchild))
- goto out;
- if (!dchild->d_inode)
- goto out;
- rv = fh_compose(fhp, exp, dchild, &cd->fh);
-out:
- dput(dchild);
- return rv;
-}
-
-static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
-{
- struct svc_fh fh;
- __be32 err;
-
- fh_init(&fh, NFS3_FHSIZE);
- err = compose_entry_fh(cd, &fh, name, namlen);
- if (err) {
- *p++ = 0;
- *p++ = 0;
- goto out;
- }
- p = encode_post_op_attr(cd->rqstp, p, &fh);
- *p++ = xdr_one; /* yes, a file handle follows */
- p = encode_fh(p, &fh);
-out:
- fh_put(&fh);
- return p;
-}
-
-/*
- * Encode a directory entry. This one works for both normal readdir
- * and readdirplus.
- * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
- * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
- *
- * The readdirplus baggage is 1+21 words for post_op_attr, plus the
- * file handle.
- */
-
-#define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
-#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
-static int
-encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type, int plus)
-{
- struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
- common);
- __be32 *p = cd->buffer;
- caddr_t curr_page_addr = NULL;
- int pn; /* current page number */
- int slen; /* string (name) length */
- int elen; /* estimated entry length in words */
- int num_entry_words = 0; /* actual number of words */
-
- if (cd->offset) {
- u64 offset64 = offset;
-
- if (unlikely(cd->offset1)) {
- /* we ended up with offset on a page boundary */
- *cd->offset = htonl(offset64 >> 32);
- *cd->offset1 = htonl(offset64 & 0xffffffff);
- cd->offset1 = NULL;
- } else {
- xdr_encode_hyper(cd->offset, offset64);
- }
- }
-
- /*
- dprintk("encode_entry(%.*s @%ld%s)\n",
- namlen, name, (long) offset, plus? " plus" : "");
- */
-
- /* truncate filename if too long */
- if (namlen > NFS3_MAXNAMLEN)
- namlen = NFS3_MAXNAMLEN;
-
- slen = XDR_QUADLEN(namlen);
- elen = slen + NFS3_ENTRY_BAGGAGE
- + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
-
- if (cd->buflen < elen) {
- cd->common.err = nfserr_toosmall;
- return -EINVAL;
- }
-
- /* determine which page in rq_respages[] we are currently filling */
- for (pn=1; pn < cd->rqstp->rq_resused; pn++) {
- curr_page_addr = page_address(cd->rqstp->rq_respages[pn]);
-
- if (((caddr_t)cd->buffer >= curr_page_addr) &&
- ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE))
- break;
- }
-
- if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) {
- /* encode entry in current page */
-
- p = encode_entry_baggage(cd, p, name, namlen, ino);
-
- if (plus)
- p = encode_entryplus_baggage(cd, p, name, namlen);
- num_entry_words = p - cd->buffer;
- } else if (cd->rqstp->rq_respages[pn+1] != NULL) {
- /* temporarily encode entry into next page, then move back to
- * current and next page in rq_respages[] */
- __be32 *p1, *tmp;
- int len1, len2;
-
- /* grab next page for temporary storage of entry */
- p1 = tmp = page_address(cd->rqstp->rq_respages[pn+1]);
-
- p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
-
- if (plus)
- p1 = encode_entryplus_baggage(cd, p1, name, namlen);
-
- /* determine entry word length and lengths to go in pages */
- num_entry_words = p1 - tmp;
- len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
- if ((num_entry_words << 2) < len1) {
- /* the actual number of words in the entry is less
- * than elen and can still fit in the current page
- */
- memmove(p, tmp, num_entry_words << 2);
- p += num_entry_words;
-
- /* update offset */
- cd->offset = cd->buffer + (cd->offset - tmp);
- } else {
- unsigned int offset_r = (cd->offset - tmp) << 2;
-
- /* update pointer to offset location.
- * This is a 64bit quantity, so we need to
- * deal with 3 cases:
- * - entirely in first page
- * - entirely in second page
- * - 4 bytes in each page
- */
- if (offset_r + 8 <= len1) {
- cd->offset = p + (cd->offset - tmp);
- } else if (offset_r >= len1) {
- cd->offset -= len1 >> 2;
- } else {
- /* sitting on the fence */
- BUG_ON(offset_r != len1 - 4);
- cd->offset = p + (cd->offset - tmp);
- cd->offset1 = tmp;
- }
-
- len2 = (num_entry_words << 2) - len1;
-
- /* move from temp page to current and next pages */
- memmove(p, tmp, len1);
- memmove(tmp, (caddr_t)tmp+len1, len2);
-
- p = tmp + (len2 >> 2);
- }
- }
- else {
- cd->common.err = nfserr_toosmall;
- return -EINVAL;
- }
-
- cd->buflen -= num_entry_words;
- cd->buffer = p;
- cd->common.err = nfs_ok;
- return 0;
-
-}
-
-int
-nfs3svc_encode_entry(void *cd, const char *name,
- int namlen, loff_t offset, u64 ino, unsigned int d_type)
-{
- return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
-}
-
-int
-nfs3svc_encode_entry_plus(void *cd, const char *name,
- int namlen, loff_t offset, u64 ino,
- unsigned int d_type)
-{
- return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
-}
-
-/* FSSTAT */
-int
-nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_fsstatres *resp)
-{
- struct kstatfs *s = &resp->stats;
- u64 bs = s->f_bsize;
-
- *p++ = xdr_zero; /* no post_op_attr */
-
- if (resp->status == 0) {
- p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
- p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
- p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
- p = xdr_encode_hyper(p, s->f_files); /* total inodes */
- p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
- p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
- *p++ = htonl(resp->invarsec); /* mean unchanged time */
- }
- return xdr_ressize_check(rqstp, p);
-}
-
-/* FSINFO */
-int
-nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_fsinfores *resp)
-{
- *p++ = xdr_zero; /* no post_op_attr */
-
- if (resp->status == 0) {
- *p++ = htonl(resp->f_rtmax);
- *p++ = htonl(resp->f_rtpref);
- *p++ = htonl(resp->f_rtmult);
- *p++ = htonl(resp->f_wtmax);
- *p++ = htonl(resp->f_wtpref);
- *p++ = htonl(resp->f_wtmult);
- *p++ = htonl(resp->f_dtpref);
- p = xdr_encode_hyper(p, resp->f_maxfilesize);
- *p++ = xdr_one;
- *p++ = xdr_zero;
- *p++ = htonl(resp->f_properties);
- }
-
- return xdr_ressize_check(rqstp, p);
-}
-
-/* PATHCONF */
-int
-nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_pathconfres *resp)
-{
- *p++ = xdr_zero; /* no post_op_attr */
-
- if (resp->status == 0) {
- *p++ = htonl(resp->p_link_max);
- *p++ = htonl(resp->p_name_max);
- *p++ = htonl(resp->p_no_trunc);
- *p++ = htonl(resp->p_chown_restricted);
- *p++ = htonl(resp->p_case_insensitive);
- *p++ = htonl(resp->p_case_preserving);
- }
-
- return xdr_ressize_check(rqstp, p);
-}
-
-/* COMMIT */
-int
-nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_commitres *resp)
-{
- p = encode_wcc_data(rqstp, p, &resp->fh);
- /* Write verifier */
- if (resp->status == 0) {
- *p++ = htonl(nfssvc_boot.tv_sec);
- *p++ = htonl(nfssvc_boot.tv_usec);
- }
- return xdr_ressize_check(rqstp, p);
-}
-
-/*
- * XDR release functions
- */
-int
-nfs3svc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_attrstat *resp)
-{
- fh_put(&resp->fh);
- return 1;
-}
-
-int
-nfs3svc_release_fhandle2(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd3_fhandle_pair *resp)
-{
- fh_put(&resp->fh1);
- fh_put(&resp->fh2);
- return 1;
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs4acl.c b/ANDROID_3.4.5/fs/nfsd/nfs4acl.c
deleted file mode 100644
index 9c51aff0..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs4acl.c
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
- * Common NFSv4 ACL handling code.
- *
- * Copyright (c) 2002, 2003 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Marius Aamodt Eriksen <marius@umich.edu>
- * Jeff Sedlak <jsedlak@umich.edu>
- * J. Bruce Fields <bfields@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-#include <linux/nfs_fs.h>
-#include <linux/export.h>
-#include "acl.h"
-
-
-/* mode bit translations: */
-#define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
-#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA)
-#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
-#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
-#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
-
-/* We don't support these bits; insist they be neither allowed nor denied */
-#define NFS4_MASK_UNSUPP (NFS4_ACE_DELETE | NFS4_ACE_WRITE_OWNER \
- | NFS4_ACE_READ_NAMED_ATTRS | NFS4_ACE_WRITE_NAMED_ATTRS)
-
-/* flags used to simulate posix default ACLs */
-#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
- | NFS4_ACE_DIRECTORY_INHERIT_ACE)
-
-#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \
- | NFS4_ACE_INHERIT_ONLY_ACE \
- | NFS4_ACE_IDENTIFIER_GROUP)
-
-#define MASK_EQUAL(mask1, mask2) \
- ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
-
-static u32
-mask_from_posix(unsigned short perm, unsigned int flags)
-{
- int mask = NFS4_ANYONE_MODE;
-
- if (flags & NFS4_ACL_OWNER)
- mask |= NFS4_OWNER_MODE;
- if (perm & ACL_READ)
- mask |= NFS4_READ_MODE;
- if (perm & ACL_WRITE)
- mask |= NFS4_WRITE_MODE;
- if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
- mask |= NFS4_ACE_DELETE_CHILD;
- if (perm & ACL_EXECUTE)
- mask |= NFS4_EXECUTE_MODE;
- return mask;
-}
-
-static u32
-deny_mask_from_posix(unsigned short perm, u32 flags)
-{
- u32 mask = 0;
-
- if (perm & ACL_READ)
- mask |= NFS4_READ_MODE;
- if (perm & ACL_WRITE)
- mask |= NFS4_WRITE_MODE;
- if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
- mask |= NFS4_ACE_DELETE_CHILD;
- if (perm & ACL_EXECUTE)
- mask |= NFS4_EXECUTE_MODE;
- return mask;
-}
-
-/* XXX: modify functions to return NFS errors; they're only ever
- * used by nfs code, after all.... */
-
-/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
- * side of being more restrictive, so the mode bit mapping below is
- * pessimistic. An optimistic version would be needed to handle DENY's,
- * but we espect to coalesce all ALLOWs and DENYs before mapping to mode
- * bits. */
-
-static void
-low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
-{
- u32 write_mode = NFS4_WRITE_MODE;
-
- if (flags & NFS4_ACL_DIR)
- write_mode |= NFS4_ACE_DELETE_CHILD;
- *mode = 0;
- if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
- *mode |= ACL_READ;
- if ((perm & write_mode) == write_mode)
- *mode |= ACL_WRITE;
- if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
- *mode |= ACL_EXECUTE;
-}
-
-struct ace_container {
- struct nfs4_ace *ace;
- struct list_head ace_l;
-};
-
-static short ace2type(struct nfs4_ace *);
-static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
- unsigned int);
-
-struct nfs4_acl *
-nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
- unsigned int flags)
-{
- struct nfs4_acl *acl;
- int size = 0;
-
- if (pacl) {
- if (posix_acl_valid(pacl) < 0)
- return ERR_PTR(-EINVAL);
- size += 2*pacl->a_count;
- }
- if (dpacl) {
- if (posix_acl_valid(dpacl) < 0)
- return ERR_PTR(-EINVAL);
- size += 2*dpacl->a_count;
- }
-
- /* Allocate for worst case: one (deny, allow) pair each: */
- acl = nfs4_acl_new(size);
- if (acl == NULL)
- return ERR_PTR(-ENOMEM);
-
- if (pacl)
- _posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
-
- if (dpacl)
- _posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT);
-
- return acl;
-}
-
-struct posix_acl_summary {
- unsigned short owner;
- unsigned short users;
- unsigned short group;
- unsigned short groups;
- unsigned short other;
- unsigned short mask;
-};
-
-static void
-summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas)
-{
- struct posix_acl_entry *pa, *pe;
-
- /*
- * Only pas.users and pas.groups need initialization; previous
- * posix_acl_valid() calls ensure that the other fields will be
- * initialized in the following loop. But, just to placate gcc:
- */
- memset(pas, 0, sizeof(*pas));
- pas->mask = 07;
-
- pe = acl->a_entries + acl->a_count;
-
- FOREACH_ACL_ENTRY(pa, acl, pe) {
- switch (pa->e_tag) {
- case ACL_USER_OBJ:
- pas->owner = pa->e_perm;
- break;
- case ACL_GROUP_OBJ:
- pas->group = pa->e_perm;
- break;
- case ACL_USER:
- pas->users |= pa->e_perm;
- break;
- case ACL_GROUP:
- pas->groups |= pa->e_perm;
- break;
- case ACL_OTHER:
- pas->other = pa->e_perm;
- break;
- case ACL_MASK:
- pas->mask = pa->e_perm;
- break;
- }
- }
- /* We'll only care about effective permissions: */
- pas->users &= pas->mask;
- pas->group &= pas->mask;
- pas->groups &= pas->mask;
-}
-
-/* We assume the acl has been verified with posix_acl_valid. */
-static void
-_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
- unsigned int flags)
-{
- struct posix_acl_entry *pa, *group_owner_entry;
- struct nfs4_ace *ace;
- struct posix_acl_summary pas;
- unsigned short deny;
- int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?
- NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0);
-
- BUG_ON(pacl->a_count < 3);
- summarize_posix_acl(pacl, &pas);
-
- pa = pacl->a_entries;
- ace = acl->aces + acl->naces;
-
- /* We could deny everything not granted by the owner: */
- deny = ~pas.owner;
- /*
- * but it is equivalent (and simpler) to deny only what is not
- * granted by later entries:
- */
- deny &= pas.users | pas.group | pas.groups | pas.other;
- if (deny) {
- ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = deny_mask_from_posix(deny, flags);
- ace->whotype = NFS4_ACL_WHO_OWNER;
- ace++;
- acl->naces++;
- }
-
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);
- ace->whotype = NFS4_ACL_WHO_OWNER;
- ace++;
- acl->naces++;
- pa++;
-
- while (pa->e_tag == ACL_USER) {
- deny = ~(pa->e_perm & pas.mask);
- deny &= pas.groups | pas.group | pas.other;
- if (deny) {
- ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = deny_mask_from_posix(deny, flags);
- ace->whotype = NFS4_ACL_WHO_NAMED;
- ace->who = pa->e_id;
- ace++;
- acl->naces++;
- }
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
- flags);
- ace->whotype = NFS4_ACL_WHO_NAMED;
- ace->who = pa->e_id;
- ace++;
- acl->naces++;
- pa++;
- }
-
- /* In the case of groups, we apply allow ACEs first, then deny ACEs,
- * since a user can be in more than one group. */
-
- /* allow ACEs */
-
- group_owner_entry = pa;
-
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = mask_from_posix(pas.group, flags);
- ace->whotype = NFS4_ACL_WHO_GROUP;
- ace++;
- acl->naces++;
- pa++;
-
- while (pa->e_tag == ACL_GROUP) {
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
- ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
- flags);
- ace->whotype = NFS4_ACL_WHO_NAMED;
- ace->who = pa->e_id;
- ace++;
- acl->naces++;
- pa++;
- }
-
- /* deny ACEs */
-
- pa = group_owner_entry;
-
- deny = ~pas.group & pas.other;
- if (deny) {
- ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = deny_mask_from_posix(deny, flags);
- ace->whotype = NFS4_ACL_WHO_GROUP;
- ace++;
- acl->naces++;
- }
- pa++;
-
- while (pa->e_tag == ACL_GROUP) {
- deny = ~(pa->e_perm & pas.mask);
- deny &= pas.other;
- if (deny) {
- ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
- ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
- ace->access_mask = deny_mask_from_posix(deny, flags);
- ace->whotype = NFS4_ACL_WHO_NAMED;
- ace->who = pa->e_id;
- ace++;
- acl->naces++;
- }
- pa++;
- }
-
- if (pa->e_tag == ACL_MASK)
- pa++;
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = mask_from_posix(pa->e_perm, flags);
- ace->whotype = NFS4_ACL_WHO_EVERYONE;
- acl->naces++;
-}
-
-static void
-sort_pacl_range(struct posix_acl *pacl, int start, int end) {
- int sorted = 0, i;
- struct posix_acl_entry tmp;
-
- /* We just do a bubble sort; easy to do in place, and we're not
- * expecting acl's to be long enough to justify anything more. */
- while (!sorted) {
- sorted = 1;
- for (i = start; i < end; i++) {
- if (pacl->a_entries[i].e_id
- > pacl->a_entries[i+1].e_id) {
- sorted = 0;
- tmp = pacl->a_entries[i];
- pacl->a_entries[i] = pacl->a_entries[i+1];
- pacl->a_entries[i+1] = tmp;
- }
- }
- }
-}
-
-static void
-sort_pacl(struct posix_acl *pacl)
-{
- /* posix_acl_valid requires that users and groups be in order
- * by uid/gid. */
- int i, j;
-
- if (pacl->a_count <= 4)
- return; /* no users or groups */
- i = 1;
- while (pacl->a_entries[i].e_tag == ACL_USER)
- i++;
- sort_pacl_range(pacl, 1, i-1);
-
- BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
- j = ++i;
- while (pacl->a_entries[j].e_tag == ACL_GROUP)
- j++;
- sort_pacl_range(pacl, i, j-1);
- return;
-}
-
-/*
- * While processing the NFSv4 ACE, this maintains bitmasks representing
- * which permission bits have been allowed and which denied to a given
- * entity: */
-struct posix_ace_state {
- u32 allow;
- u32 deny;
-};
-
-struct posix_user_ace_state {
- uid_t uid;
- struct posix_ace_state perms;
-};
-
-struct posix_ace_state_array {
- int n;
- struct posix_user_ace_state aces[];
-};
-
-/*
- * While processing the NFSv4 ACE, this maintains the partial permissions
- * calculated so far: */
-
-struct posix_acl_state {
- int empty;
- struct posix_ace_state owner;
- struct posix_ace_state group;
- struct posix_ace_state other;
- struct posix_ace_state everyone;
- struct posix_ace_state mask; /* Deny unused in this case */
- struct posix_ace_state_array *users;
- struct posix_ace_state_array *groups;
-};
-
-static int
-init_state(struct posix_acl_state *state, int cnt)
-{
- int alloc;
-
- memset(state, 0, sizeof(struct posix_acl_state));
- state->empty = 1;
- /*
- * In the worst case, each individual acl could be for a distinct
- * named user or group, but we don't no which, so we allocate
- * enough space for either:
- */
- alloc = sizeof(struct posix_ace_state_array)
- + cnt*sizeof(struct posix_user_ace_state);
- state->users = kzalloc(alloc, GFP_KERNEL);
- if (!state->users)
- return -ENOMEM;
- state->groups = kzalloc(alloc, GFP_KERNEL);
- if (!state->groups) {
- kfree(state->users);
- return -ENOMEM;
- }
- return 0;
-}
-
-static void
-free_state(struct posix_acl_state *state) {
- kfree(state->users);
- kfree(state->groups);
-}
-
-static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
-{
- state->mask.allow |= astate->allow;
-}
-
-/*
- * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS,
- * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate
- * to traditional read/write/execute permissions.
- *
- * It's problematic to reject acls that use certain mode bits, because it
- * places the burden on users to learn the rules about which bits one
- * particular server sets, without giving the user a lot of help--we return an
- * error that could mean any number of different things. To make matters
- * worse, the problematic bits might be introduced by some application that's
- * automatically mapping from some other acl model.
- *
- * So wherever possible we accept anything, possibly erring on the side of
- * denying more permissions than necessary.
- *
- * However we do reject *explicit* DENY's of a few bits representing
- * permissions we could never deny:
- */
-
-static inline int check_deny(u32 mask, int isowner)
-{
- if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL))
- return -EINVAL;
- if (!isowner)
- return 0;
- if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL))
- return -EINVAL;
- return 0;
-}
-
-static struct posix_acl *
-posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
-{
- struct posix_acl_entry *pace;
- struct posix_acl *pacl;
- int nace;
- int i, error = 0;
-
- /*
- * ACLs with no ACEs are treated differently in the inheritable
- * and effective cases: when there are no inheritable ACEs, we
- * set a zero-length default posix acl:
- */
- if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) {
- pacl = posix_acl_alloc(0, GFP_KERNEL);
- return pacl ? pacl : ERR_PTR(-ENOMEM);
- }
- /*
- * When there are no effective ACEs, the following will end
- * up setting a 3-element effective posix ACL with all
- * permissions zero.
- */
- nace = 4 + state->users->n + state->groups->n;
- pacl = posix_acl_alloc(nace, GFP_KERNEL);
- if (!pacl)
- return ERR_PTR(-ENOMEM);
-
- pace = pacl->a_entries;
- pace->e_tag = ACL_USER_OBJ;
- error = check_deny(state->owner.deny, 1);
- if (error)
- goto out_err;
- low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags);
- pace->e_id = ACL_UNDEFINED_ID;
-
- for (i=0; i < state->users->n; i++) {
- pace++;
- pace->e_tag = ACL_USER;
- error = check_deny(state->users->aces[i].perms.deny, 0);
- if (error)
- goto out_err;
- low_mode_from_nfs4(state->users->aces[i].perms.allow,
- &pace->e_perm, flags);
- pace->e_id = state->users->aces[i].uid;
- add_to_mask(state, &state->users->aces[i].perms);
- }
-
- pace++;
- pace->e_tag = ACL_GROUP_OBJ;
- error = check_deny(state->group.deny, 0);
- if (error)
- goto out_err;
- low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags);
- pace->e_id = ACL_UNDEFINED_ID;
- add_to_mask(state, &state->group);
-
- for (i=0; i < state->groups->n; i++) {
- pace++;
- pace->e_tag = ACL_GROUP;
- error = check_deny(state->groups->aces[i].perms.deny, 0);
- if (error)
- goto out_err;
- low_mode_from_nfs4(state->groups->aces[i].perms.allow,
- &pace->e_perm, flags);
- pace->e_id = state->groups->aces[i].uid;
- add_to_mask(state, &state->groups->aces[i].perms);
- }
-
- pace++;
- pace->e_tag = ACL_MASK;
- low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
- pace->e_id = ACL_UNDEFINED_ID;
-
- pace++;
- pace->e_tag = ACL_OTHER;
- error = check_deny(state->other.deny, 0);
- if (error)
- goto out_err;
- low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags);
- pace->e_id = ACL_UNDEFINED_ID;
-
- return pacl;
-out_err:
- posix_acl_release(pacl);
- return ERR_PTR(error);
-}
-
-static inline void allow_bits(struct posix_ace_state *astate, u32 mask)
-{
- /* Allow all bits in the mask not already denied: */
- astate->allow |= mask & ~astate->deny;
-}
-
-static inline void deny_bits(struct posix_ace_state *astate, u32 mask)
-{
- /* Deny all bits in the mask not already allowed: */
- astate->deny |= mask & ~astate->allow;
-}
-
-static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid)
-{
- int i;
-
- for (i = 0; i < a->n; i++)
- if (a->aces[i].uid == uid)
- return i;
- /* Not found: */
- a->n++;
- a->aces[i].uid = uid;
- a->aces[i].perms.allow = state->everyone.allow;
- a->aces[i].perms.deny = state->everyone.deny;
-
- return i;
-}
-
-static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
-{
- int i;
-
- for (i=0; i < a->n; i++)
- deny_bits(&a->aces[i].perms, mask);
-}
-
-static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
-{
- int i;
-
- for (i=0; i < a->n; i++)
- allow_bits(&a->aces[i].perms, mask);
-}
-
-static void process_one_v4_ace(struct posix_acl_state *state,
- struct nfs4_ace *ace)
-{
- u32 mask = ace->access_mask;
- int i;
-
- state->empty = 0;
-
- switch (ace2type(ace)) {
- case ACL_USER_OBJ:
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
- allow_bits(&state->owner, mask);
- } else {
- deny_bits(&state->owner, mask);
- }
- break;
- case ACL_USER:
- i = find_uid(state, state->users, ace->who);
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
- allow_bits(&state->users->aces[i].perms, mask);
- } else {
- deny_bits(&state->users->aces[i].perms, mask);
- mask = state->users->aces[i].perms.deny;
- deny_bits(&state->owner, mask);
- }
- break;
- case ACL_GROUP_OBJ:
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
- allow_bits(&state->group, mask);
- } else {
- deny_bits(&state->group, mask);
- mask = state->group.deny;
- deny_bits(&state->owner, mask);
- deny_bits(&state->everyone, mask);
- deny_bits_array(state->users, mask);
- deny_bits_array(state->groups, mask);
- }
- break;
- case ACL_GROUP:
- i = find_uid(state, state->groups, ace->who);
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
- allow_bits(&state->groups->aces[i].perms, mask);
- } else {
- deny_bits(&state->groups->aces[i].perms, mask);
- mask = state->groups->aces[i].perms.deny;
- deny_bits(&state->owner, mask);
- deny_bits(&state->group, mask);
- deny_bits(&state->everyone, mask);
- deny_bits_array(state->users, mask);
- deny_bits_array(state->groups, mask);
- }
- break;
- case ACL_OTHER:
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
- allow_bits(&state->owner, mask);
- allow_bits(&state->group, mask);
- allow_bits(&state->other, mask);
- allow_bits(&state->everyone, mask);
- allow_bits_array(state->users, mask);
- allow_bits_array(state->groups, mask);
- } else {
- deny_bits(&state->owner, mask);
- deny_bits(&state->group, mask);
- deny_bits(&state->other, mask);
- deny_bits(&state->everyone, mask);
- deny_bits_array(state->users, mask);
- deny_bits_array(state->groups, mask);
- }
- }
-}
-
-int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
- struct posix_acl **dpacl, unsigned int flags)
-{
- struct posix_acl_state effective_acl_state, default_acl_state;
- struct nfs4_ace *ace;
- int ret;
-
- ret = init_state(&effective_acl_state, acl->naces);
- if (ret)
- return ret;
- ret = init_state(&default_acl_state, acl->naces);
- if (ret)
- goto out_estate;
- ret = -EINVAL;
- for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
- ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
- goto out_dstate;
- if (ace->flag & ~NFS4_SUPPORTED_FLAGS)
- goto out_dstate;
- if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) {
- process_one_v4_ace(&effective_acl_state, ace);
- continue;
- }
- if (!(flags & NFS4_ACL_DIR))
- goto out_dstate;
- /*
- * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT
- * is set, we're effectively turning on the other. That's OK,
- * according to rfc 3530.
- */
- process_one_v4_ace(&default_acl_state, ace);
-
- if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE))
- process_one_v4_ace(&effective_acl_state, ace);
- }
- *pacl = posix_state_to_acl(&effective_acl_state, flags);
- if (IS_ERR(*pacl)) {
- ret = PTR_ERR(*pacl);
- *pacl = NULL;
- goto out_dstate;
- }
- *dpacl = posix_state_to_acl(&default_acl_state,
- flags | NFS4_ACL_TYPE_DEFAULT);
- if (IS_ERR(*dpacl)) {
- ret = PTR_ERR(*dpacl);
- *dpacl = NULL;
- posix_acl_release(*pacl);
- *pacl = NULL;
- goto out_dstate;
- }
- sort_pacl(*pacl);
- sort_pacl(*dpacl);
- ret = 0;
-out_dstate:
- free_state(&default_acl_state);
-out_estate:
- free_state(&effective_acl_state);
- return ret;
-}
-
-static short
-ace2type(struct nfs4_ace *ace)
-{
- switch (ace->whotype) {
- case NFS4_ACL_WHO_NAMED:
- return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ?
- ACL_GROUP : ACL_USER);
- case NFS4_ACL_WHO_OWNER:
- return ACL_USER_OBJ;
- case NFS4_ACL_WHO_GROUP:
- return ACL_GROUP_OBJ;
- case NFS4_ACL_WHO_EVERYONE:
- return ACL_OTHER;
- }
- BUG();
- return -1;
-}
-
-EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4);
-EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix);
-
-struct nfs4_acl *
-nfs4_acl_new(int n)
-{
- struct nfs4_acl *acl;
-
- acl = kmalloc(sizeof(*acl) + n*sizeof(struct nfs4_ace), GFP_KERNEL);
- if (acl == NULL)
- return NULL;
- acl->naces = 0;
- return acl;
-}
-
-static struct {
- char *string;
- int stringlen;
- int type;
-} s2t_map[] = {
- {
- .string = "OWNER@",
- .stringlen = sizeof("OWNER@") - 1,
- .type = NFS4_ACL_WHO_OWNER,
- },
- {
- .string = "GROUP@",
- .stringlen = sizeof("GROUP@") - 1,
- .type = NFS4_ACL_WHO_GROUP,
- },
- {
- .string = "EVERYONE@",
- .stringlen = sizeof("EVERYONE@") - 1,
- .type = NFS4_ACL_WHO_EVERYONE,
- },
-};
-
-int
-nfs4_acl_get_whotype(char *p, u32 len)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
- if (s2t_map[i].stringlen == len &&
- 0 == memcmp(s2t_map[i].string, p, len))
- return s2t_map[i].type;
- }
- return NFS4_ACL_WHO_NAMED;
-}
-
-int
-nfs4_acl_write_who(int who, char *p)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
- if (s2t_map[i].type == who) {
- memcpy(p, s2t_map[i].string, s2t_map[i].stringlen);
- return s2t_map[i].stringlen;
- }
- }
- BUG();
- return -1;
-}
-
-EXPORT_SYMBOL(nfs4_acl_new);
-EXPORT_SYMBOL(nfs4_acl_get_whotype);
-EXPORT_SYMBOL(nfs4_acl_write_who);
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs4callback.c b/ANDROID_3.4.5/fs/nfsd/nfs4callback.c
deleted file mode 100644
index c8e9f637..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs4callback.c
+++ /dev/null
@@ -1,1037 +0,0 @@
-/*
- * Copyright (c) 2001 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Kendrick Smith <kmsmith@umich.edu>
- * Andy Adamson <andros@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/svc_xprt.h>
-#include <linux/slab.h>
-#include "nfsd.h"
-#include "state.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_PROC
-
-static void nfsd4_mark_cb_fault(struct nfs4_client *, int reason);
-
-#define NFSPROC4_CB_NULL 0
-#define NFSPROC4_CB_COMPOUND 1
-
-/* Index of predefined Linux callback client operations */
-
-enum {
- NFSPROC4_CLNT_CB_NULL = 0,
- NFSPROC4_CLNT_CB_RECALL,
- NFSPROC4_CLNT_CB_SEQUENCE,
-};
-
-#define NFS4_MAXTAGLEN 20
-
-#define NFS4_enc_cb_null_sz 0
-#define NFS4_dec_cb_null_sz 0
-#define cb_compound_enc_hdr_sz 4
-#define cb_compound_dec_hdr_sz (3 + (NFS4_MAXTAGLEN >> 2))
-#define sessionid_sz (NFS4_MAX_SESSIONID_LEN >> 2)
-#define cb_sequence_enc_sz (sessionid_sz + 4 + \
- 1 /* no referring calls list yet */)
-#define cb_sequence_dec_sz (op_dec_sz + sessionid_sz + 4)
-
-#define op_enc_sz 1
-#define op_dec_sz 2
-#define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2))
-#define enc_stateid_sz (NFS4_STATEID_SIZE >> 2)
-#define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \
- cb_sequence_enc_sz + \
- 1 + enc_stateid_sz + \
- enc_nfs4_fh_sz)
-
-#define NFS4_dec_cb_recall_sz (cb_compound_dec_hdr_sz + \
- cb_sequence_dec_sz + \
- op_dec_sz)
-
-struct nfs4_cb_compound_hdr {
- /* args */
- u32 ident; /* minorversion 0 only */
- u32 nops;
- __be32 *nops_p;
- u32 minorversion;
- /* res */
- int status;
-};
-
-/*
- * Handle decode buffer overflows out-of-line.
- */
-static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
-{
- dprintk("NFS: %s prematurely hit the end of our receive buffer. "
- "Remaining buffer length is %tu words.\n",
- func, xdr->end - xdr->p);
-}
-
-static __be32 *xdr_encode_empty_array(__be32 *p)
-{
- *p++ = xdr_zero;
- return p;
-}
-
-/*
- * Encode/decode NFSv4 CB basic data types
- *
- * Basic NFSv4 callback data types are defined in section 15 of RFC
- * 3530: "Network File System (NFS) version 4 Protocol" and section
- * 20 of RFC 5661: "Network File System (NFS) Version 4 Minor Version
- * 1 Protocol"
- */
-
-/*
- * nfs_cb_opnum4
- *
- * enum nfs_cb_opnum4 {
- * OP_CB_GETATTR = 3,
- * ...
- * };
- */
-enum nfs_cb_opnum4 {
- OP_CB_GETATTR = 3,
- OP_CB_RECALL = 4,
- OP_CB_LAYOUTRECALL = 5,
- OP_CB_NOTIFY = 6,
- OP_CB_PUSH_DELEG = 7,
- OP_CB_RECALL_ANY = 8,
- OP_CB_RECALLABLE_OBJ_AVAIL = 9,
- OP_CB_RECALL_SLOT = 10,
- OP_CB_SEQUENCE = 11,
- OP_CB_WANTS_CANCELLED = 12,
- OP_CB_NOTIFY_LOCK = 13,
- OP_CB_NOTIFY_DEVICEID = 14,
- OP_CB_ILLEGAL = 10044
-};
-
-static void encode_nfs_cb_opnum4(struct xdr_stream *xdr, enum nfs_cb_opnum4 op)
-{
- __be32 *p;
-
- p = xdr_reserve_space(xdr, 4);
- *p = cpu_to_be32(op);
-}
-
-/*
- * nfs_fh4
- *
- * typedef opaque nfs_fh4<NFS4_FHSIZE>;
- */
-static void encode_nfs_fh4(struct xdr_stream *xdr, const struct knfsd_fh *fh)
-{
- u32 length = fh->fh_size;
- __be32 *p;
-
- BUG_ON(length > NFS4_FHSIZE);
- p = xdr_reserve_space(xdr, 4 + length);
- xdr_encode_opaque(p, &fh->fh_base, length);
-}
-
-/*
- * stateid4
- *
- * struct stateid4 {
- * uint32_t seqid;
- * opaque other[12];
- * };
- */
-static void encode_stateid4(struct xdr_stream *xdr, const stateid_t *sid)
-{
- __be32 *p;
-
- p = xdr_reserve_space(xdr, NFS4_STATEID_SIZE);
- *p++ = cpu_to_be32(sid->si_generation);
- xdr_encode_opaque_fixed(p, &sid->si_opaque, NFS4_STATEID_OTHER_SIZE);
-}
-
-/*
- * sessionid4
- *
- * typedef opaque sessionid4[NFS4_SESSIONID_SIZE];
- */
-static void encode_sessionid4(struct xdr_stream *xdr,
- const struct nfsd4_session *session)
-{
- __be32 *p;
-
- p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN);
- xdr_encode_opaque_fixed(p, session->se_sessionid.data,
- NFS4_MAX_SESSIONID_LEN);
-}
-
-/*
- * nfsstat4
- */
-static const struct {
- int stat;
- int errno;
-} nfs_cb_errtbl[] = {
- { NFS4_OK, 0 },
- { NFS4ERR_PERM, -EPERM },
- { NFS4ERR_NOENT, -ENOENT },
- { NFS4ERR_IO, -EIO },
- { NFS4ERR_NXIO, -ENXIO },
- { NFS4ERR_ACCESS, -EACCES },
- { NFS4ERR_EXIST, -EEXIST },
- { NFS4ERR_XDEV, -EXDEV },
- { NFS4ERR_NOTDIR, -ENOTDIR },
- { NFS4ERR_ISDIR, -EISDIR },
- { NFS4ERR_INVAL, -EINVAL },
- { NFS4ERR_FBIG, -EFBIG },
- { NFS4ERR_NOSPC, -ENOSPC },
- { NFS4ERR_ROFS, -EROFS },
- { NFS4ERR_MLINK, -EMLINK },
- { NFS4ERR_NAMETOOLONG, -ENAMETOOLONG },
- { NFS4ERR_NOTEMPTY, -ENOTEMPTY },
- { NFS4ERR_DQUOT, -EDQUOT },
- { NFS4ERR_STALE, -ESTALE },
- { NFS4ERR_BADHANDLE, -EBADHANDLE },
- { NFS4ERR_BAD_COOKIE, -EBADCOOKIE },
- { NFS4ERR_NOTSUPP, -ENOTSUPP },
- { NFS4ERR_TOOSMALL, -ETOOSMALL },
- { NFS4ERR_SERVERFAULT, -ESERVERFAULT },
- { NFS4ERR_BADTYPE, -EBADTYPE },
- { NFS4ERR_LOCKED, -EAGAIN },
- { NFS4ERR_RESOURCE, -EREMOTEIO },
- { NFS4ERR_SYMLINK, -ELOOP },
- { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP },
- { NFS4ERR_DEADLOCK, -EDEADLK },
- { -1, -EIO }
-};
-
-/*
- * If we cannot translate the error, the recovery routines should
- * handle it.
- *
- * Note: remaining NFSv4 error codes have values > 10000, so should
- * not conflict with native Linux error codes.
- */
-static int nfs_cb_stat_to_errno(int status)
-{
- int i;
-
- for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) {
- if (nfs_cb_errtbl[i].stat == status)
- return nfs_cb_errtbl[i].errno;
- }
-
- dprintk("NFSD: Unrecognized NFS CB status value: %u\n", status);
- return -status;
-}
-
-static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
- enum nfsstat4 *status)
-{
- __be32 *p;
- u32 op;
-
- p = xdr_inline_decode(xdr, 4 + 4);
- if (unlikely(p == NULL))
- goto out_overflow;
- op = be32_to_cpup(p++);
- if (unlikely(op != expected))
- goto out_unexpected;
- *status = be32_to_cpup(p);
- return 0;
-out_overflow:
- print_overflow_msg(__func__, xdr);
- return -EIO;
-out_unexpected:
- dprintk("NFSD: Callback server returned operation %d but "
- "we issued a request for %d\n", op, expected);
- return -EIO;
-}
-
-/*
- * CB_COMPOUND4args
- *
- * struct CB_COMPOUND4args {
- * utf8str_cs tag;
- * uint32_t minorversion;
- * uint32_t callback_ident;
- * nfs_cb_argop4 argarray<>;
- * };
-*/
-static void encode_cb_compound4args(struct xdr_stream *xdr,
- struct nfs4_cb_compound_hdr *hdr)
-{
- __be32 * p;
-
- p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
- p = xdr_encode_empty_array(p); /* empty tag */
- *p++ = cpu_to_be32(hdr->minorversion);
- *p++ = cpu_to_be32(hdr->ident);
-
- hdr->nops_p = p;
- *p = cpu_to_be32(hdr->nops); /* argarray element count */
-}
-
-/*
- * Update argarray element count
- */
-static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr)
-{
- BUG_ON(hdr->nops > NFS4_MAX_BACK_CHANNEL_OPS);
- *hdr->nops_p = cpu_to_be32(hdr->nops);
-}
-
-/*
- * CB_COMPOUND4res
- *
- * struct CB_COMPOUND4res {
- * nfsstat4 status;
- * utf8str_cs tag;
- * nfs_cb_resop4 resarray<>;
- * };
- */
-static int decode_cb_compound4res(struct xdr_stream *xdr,
- struct nfs4_cb_compound_hdr *hdr)
-{
- u32 length;
- __be32 *p;
-
- p = xdr_inline_decode(xdr, 4 + 4);
- if (unlikely(p == NULL))
- goto out_overflow;
- hdr->status = be32_to_cpup(p++);
- /* Ignore the tag */
- length = be32_to_cpup(p++);
- p = xdr_inline_decode(xdr, length + 4);
- if (unlikely(p == NULL))
- goto out_overflow;
- hdr->nops = be32_to_cpup(p);
- return 0;
-out_overflow:
- print_overflow_msg(__func__, xdr);
- return -EIO;
-}
-
-/*
- * CB_RECALL4args
- *
- * struct CB_RECALL4args {
- * stateid4 stateid;
- * bool truncate;
- * nfs_fh4 fh;
- * };
- */
-static void encode_cb_recall4args(struct xdr_stream *xdr,
- const struct nfs4_delegation *dp,
- struct nfs4_cb_compound_hdr *hdr)
-{
- __be32 *p;
-
- encode_nfs_cb_opnum4(xdr, OP_CB_RECALL);
- encode_stateid4(xdr, &dp->dl_stid.sc_stateid);
-
- p = xdr_reserve_space(xdr, 4);
- *p++ = xdr_zero; /* truncate */
-
- encode_nfs_fh4(xdr, &dp->dl_fh);
-
- hdr->nops++;
-}
-
-/*
- * CB_SEQUENCE4args
- *
- * struct CB_SEQUENCE4args {
- * sessionid4 csa_sessionid;
- * sequenceid4 csa_sequenceid;
- * slotid4 csa_slotid;
- * slotid4 csa_highest_slotid;
- * bool csa_cachethis;
- * referring_call_list4 csa_referring_call_lists<>;
- * };
- */
-static void encode_cb_sequence4args(struct xdr_stream *xdr,
- const struct nfsd4_callback *cb,
- struct nfs4_cb_compound_hdr *hdr)
-{
- struct nfsd4_session *session = cb->cb_clp->cl_cb_session;
- __be32 *p;
-
- if (hdr->minorversion == 0)
- return;
-
- encode_nfs_cb_opnum4(xdr, OP_CB_SEQUENCE);
- encode_sessionid4(xdr, session);
-
- p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4 + 4);
- *p++ = cpu_to_be32(session->se_cb_seq_nr); /* csa_sequenceid */
- *p++ = xdr_zero; /* csa_slotid */
- *p++ = xdr_zero; /* csa_highest_slotid */
- *p++ = xdr_zero; /* csa_cachethis */
- xdr_encode_empty_array(p); /* csa_referring_call_lists */
-
- hdr->nops++;
-}
-
-/*
- * CB_SEQUENCE4resok
- *
- * struct CB_SEQUENCE4resok {
- * sessionid4 csr_sessionid;
- * sequenceid4 csr_sequenceid;
- * slotid4 csr_slotid;
- * slotid4 csr_highest_slotid;
- * slotid4 csr_target_highest_slotid;
- * };
- *
- * union CB_SEQUENCE4res switch (nfsstat4 csr_status) {
- * case NFS4_OK:
- * CB_SEQUENCE4resok csr_resok4;
- * default:
- * void;
- * };
- *
- * Our current back channel implmentation supports a single backchannel
- * with a single slot.
- */
-static int decode_cb_sequence4resok(struct xdr_stream *xdr,
- struct nfsd4_callback *cb)
-{
- struct nfsd4_session *session = cb->cb_clp->cl_cb_session;
- struct nfs4_sessionid id;
- int status;
- __be32 *p;
- u32 dummy;
-
- status = -ESERVERFAULT;
-
- /*
- * If the server returns different values for sessionID, slotID or
- * sequence number, the server is looney tunes.
- */
- p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN + 4 + 4 + 4 + 4);
- if (unlikely(p == NULL))
- goto out_overflow;
- memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN);
- if (memcmp(id.data, session->se_sessionid.data,
- NFS4_MAX_SESSIONID_LEN) != 0) {
- dprintk("NFS: %s Invalid session id\n", __func__);
- goto out;
- }
- p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN);
-
- dummy = be32_to_cpup(p++);
- if (dummy != session->se_cb_seq_nr) {
- dprintk("NFS: %s Invalid sequence number\n", __func__);
- goto out;
- }
-
- dummy = be32_to_cpup(p++);
- if (dummy != 0) {
- dprintk("NFS: %s Invalid slotid\n", __func__);
- goto out;
- }
-
- /*
- * FIXME: process highest slotid and target highest slotid
- */
- status = 0;
-out:
- if (status)
- nfsd4_mark_cb_fault(cb->cb_clp, status);
- return status;
-out_overflow:
- print_overflow_msg(__func__, xdr);
- return -EIO;
-}
-
-static int decode_cb_sequence4res(struct xdr_stream *xdr,
- struct nfsd4_callback *cb)
-{
- enum nfsstat4 nfserr;
- int status;
-
- if (cb->cb_minorversion == 0)
- return 0;
-
- status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr);
- if (unlikely(status))
- goto out;
- if (unlikely(nfserr != NFS4_OK))
- goto out_default;
- status = decode_cb_sequence4resok(xdr, cb);
-out:
- return status;
-out_default:
- return nfs_cb_stat_to_errno(nfserr);
-}
-
-/*
- * NFSv4.0 and NFSv4.1 XDR encode functions
- *
- * NFSv4.0 callback argument types are defined in section 15 of RFC
- * 3530: "Network File System (NFS) version 4 Protocol" and section 20
- * of RFC 5661: "Network File System (NFS) Version 4 Minor Version 1
- * Protocol".
- */
-
-/*
- * NB: Without this zero space reservation, callbacks over krb5p fail
- */
-static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
- void *__unused)
-{
- xdr_reserve_space(xdr, 0);
-}
-
-/*
- * 20.2. Operation 4: CB_RECALL - Recall a Delegation
- */
-static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr,
- const struct nfsd4_callback *cb)
-{
- const struct nfs4_delegation *args = cb->cb_op;
- struct nfs4_cb_compound_hdr hdr = {
- .ident = cb->cb_clp->cl_cb_ident,
- .minorversion = cb->cb_minorversion,
- };
-
- encode_cb_compound4args(xdr, &hdr);
- encode_cb_sequence4args(xdr, cb, &hdr);
- encode_cb_recall4args(xdr, args, &hdr);
- encode_cb_nops(&hdr);
-}
-
-
-/*
- * NFSv4.0 and NFSv4.1 XDR decode functions
- *
- * NFSv4.0 callback result types are defined in section 15 of RFC
- * 3530: "Network File System (NFS) version 4 Protocol" and section 20
- * of RFC 5661: "Network File System (NFS) Version 4 Minor Version 1
- * Protocol".
- */
-
-static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr,
- void *__unused)
-{
- return 0;
-}
-
-/*
- * 20.2. Operation 4: CB_RECALL - Recall a Delegation
- */
-static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
- struct xdr_stream *xdr,
- struct nfsd4_callback *cb)
-{
- struct nfs4_cb_compound_hdr hdr;
- enum nfsstat4 nfserr;
- int status;
-
- status = decode_cb_compound4res(xdr, &hdr);
- if (unlikely(status))
- goto out;
-
- if (cb != NULL) {
- status = decode_cb_sequence4res(xdr, cb);
- if (unlikely(status))
- goto out;
- }
-
- status = decode_cb_op_status(xdr, OP_CB_RECALL, &nfserr);
- if (unlikely(status))
- goto out;
- if (unlikely(nfserr != NFS4_OK))
- status = nfs_cb_stat_to_errno(nfserr);
-out:
- return status;
-}
-
-/*
- * RPC procedure tables
- */
-#define PROC(proc, call, argtype, restype) \
-[NFSPROC4_CLNT_##proc] = { \
- .p_proc = NFSPROC4_CB_##call, \
- .p_encode = (kxdreproc_t)nfs4_xdr_enc_##argtype, \
- .p_decode = (kxdrdproc_t)nfs4_xdr_dec_##restype, \
- .p_arglen = NFS4_enc_##argtype##_sz, \
- .p_replen = NFS4_dec_##restype##_sz, \
- .p_statidx = NFSPROC4_CB_##call, \
- .p_name = #proc, \
-}
-
-static struct rpc_procinfo nfs4_cb_procedures[] = {
- PROC(CB_NULL, NULL, cb_null, cb_null),
- PROC(CB_RECALL, COMPOUND, cb_recall, cb_recall),
-};
-
-static struct rpc_version nfs_cb_version4 = {
-/*
- * Note on the callback rpc program version number: despite language in rfc
- * 5661 section 18.36.3 requiring servers to use 4 in this field, the
- * official xdr descriptions for both 4.0 and 4.1 specify version 1, and
- * in practice that appears to be what implementations use. The section
- * 18.36.3 language is expected to be fixed in an erratum.
- */
- .number = 1,
- .nrprocs = ARRAY_SIZE(nfs4_cb_procedures),
- .procs = nfs4_cb_procedures
-};
-
-static const struct rpc_version *nfs_cb_version[] = {
- &nfs_cb_version4,
-};
-
-static const struct rpc_program cb_program;
-
-static struct rpc_stat cb_stats = {
- .program = &cb_program
-};
-
-#define NFS4_CALLBACK 0x40000000
-static const struct rpc_program cb_program = {
- .name = "nfs4_cb",
- .number = NFS4_CALLBACK,
- .nrvers = ARRAY_SIZE(nfs_cb_version),
- .version = nfs_cb_version,
- .stats = &cb_stats,
- .pipe_dir_name = "nfsd4_cb",
-};
-
-static int max_cb_time(void)
-{
- return max(nfsd4_lease/10, (time_t)1) * HZ;
-}
-
-
-static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
-{
- struct rpc_timeout timeparms = {
- .to_initval = max_cb_time(),
- .to_retries = 0,
- };
- struct rpc_create_args args = {
- .net = &init_net,
- .address = (struct sockaddr *) &conn->cb_addr,
- .addrsize = conn->cb_addrlen,
- .saddress = (struct sockaddr *) &conn->cb_saddr,
- .timeout = &timeparms,
- .program = &cb_program,
- .version = 0,
- .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
- };
- struct rpc_clnt *client;
-
- if (clp->cl_minorversion == 0) {
- if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
- return -EINVAL;
- args.client_name = clp->cl_principal;
- args.prognumber = conn->cb_prog,
- args.protocol = XPRT_TRANSPORT_TCP;
- args.authflavor = clp->cl_flavor;
- clp->cl_cb_ident = conn->cb_ident;
- } else {
- if (!conn->cb_xprt)
- return -EINVAL;
- clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
- clp->cl_cb_session = ses;
- args.bc_xprt = conn->cb_xprt;
- args.prognumber = clp->cl_cb_session->se_cb_prog;
- args.protocol = XPRT_TRANSPORT_BC_TCP;
- args.authflavor = RPC_AUTH_UNIX;
- }
- /* Create RPC client */
- client = rpc_create(&args);
- if (IS_ERR(client)) {
- dprintk("NFSD: couldn't create callback client: %ld\n",
- PTR_ERR(client));
- return PTR_ERR(client);
- }
- clp->cl_cb_client = client;
- return 0;
-
-}
-
-static void warn_no_callback_path(struct nfs4_client *clp, int reason)
-{
- dprintk("NFSD: warning: no callback path to client %.*s: error %d\n",
- (int)clp->cl_name.len, clp->cl_name.data, reason);
-}
-
-static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
-{
- clp->cl_cb_state = NFSD4_CB_DOWN;
- warn_no_callback_path(clp, reason);
-}
-
-static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason)
-{
- clp->cl_cb_state = NFSD4_CB_FAULT;
- warn_no_callback_path(clp, reason);
-}
-
-static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
-{
- struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
-
- if (task->tk_status)
- nfsd4_mark_cb_down(clp, task->tk_status);
- else
- clp->cl_cb_state = NFSD4_CB_UP;
-}
-
-static const struct rpc_call_ops nfsd4_cb_probe_ops = {
- /* XXX: release method to ensure we set the cb channel down if
- * necessary on early failure? */
- .rpc_call_done = nfsd4_cb_probe_done,
-};
-
-static struct rpc_cred *callback_cred;
-
-int set_callback_cred(void)
-{
- if (callback_cred)
- return 0;
- callback_cred = rpc_lookup_machine_cred("nfs");
- if (!callback_cred)
- return -ENOMEM;
- return 0;
-}
-
-static struct workqueue_struct *callback_wq;
-
-static void run_nfsd4_cb(struct nfsd4_callback *cb)
-{
- queue_work(callback_wq, &cb->cb_work);
-}
-
-static void do_probe_callback(struct nfs4_client *clp)
-{
- struct nfsd4_callback *cb = &clp->cl_cb_null;
-
- cb->cb_op = NULL;
- cb->cb_clp = clp;
-
- cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL];
- cb->cb_msg.rpc_argp = NULL;
- cb->cb_msg.rpc_resp = NULL;
- cb->cb_msg.rpc_cred = callback_cred;
-
- cb->cb_ops = &nfsd4_cb_probe_ops;
-
- run_nfsd4_cb(cb);
-}
-
-/*
- * Poke the callback thread to process any updates to the callback
- * parameters, and send a null probe.
- */
-void nfsd4_probe_callback(struct nfs4_client *clp)
-{
- /* XXX: atomicity? Also, should we be using cl_flags? */
- clp->cl_cb_state = NFSD4_CB_UNKNOWN;
- set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags);
- do_probe_callback(clp);
-}
-
-void nfsd4_probe_callback_sync(struct nfs4_client *clp)
-{
- nfsd4_probe_callback(clp);
- flush_workqueue(callback_wq);
-}
-
-void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
-{
- clp->cl_cb_state = NFSD4_CB_UNKNOWN;
- spin_lock(&clp->cl_lock);
- memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
- spin_unlock(&clp->cl_lock);
-}
-
-/*
- * There's currently a single callback channel slot.
- * If the slot is available, then mark it busy. Otherwise, set the
- * thread for sleeping on the callback RPC wait queue.
- */
-static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
-{
- if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
- rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
- dprintk("%s slot is busy\n", __func__);
- return false;
- }
- return true;
-}
-
-/*
- * TODO: cb_sequence should support referring call lists, cachethis, multiple
- * slots, and mark callback channel down on communication errors.
- */
-static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
-{
- struct nfsd4_callback *cb = calldata;
- struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_stid.sc_client;
- u32 minorversion = clp->cl_minorversion;
-
- cb->cb_minorversion = minorversion;
- if (minorversion) {
- if (!nfsd41_cb_get_slot(clp, task))
- return;
- }
- spin_lock(&clp->cl_lock);
- if (list_empty(&cb->cb_per_client)) {
- /* This is the first call, not a restart */
- cb->cb_done = false;
- list_add(&cb->cb_per_client, &clp->cl_callbacks);
- }
- spin_unlock(&clp->cl_lock);
- rpc_call_start(task);
-}
-
-static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
-{
- struct nfsd4_callback *cb = calldata;
- struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_stid.sc_client;
-
- dprintk("%s: minorversion=%d\n", __func__,
- clp->cl_minorversion);
-
- if (clp->cl_minorversion) {
- /* No need for lock, access serialized in nfsd4_cb_prepare */
- ++clp->cl_cb_session->se_cb_seq_nr;
- clear_bit(0, &clp->cl_cb_slot_busy);
- rpc_wake_up_next(&clp->cl_cb_waitq);
- dprintk("%s: freed slot, new seqid=%d\n", __func__,
- clp->cl_cb_session->se_cb_seq_nr);
-
- /* We're done looking into the sequence information */
- task->tk_msg.rpc_resp = NULL;
- }
-}
-
-
-static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
-{
- struct nfsd4_callback *cb = calldata;
- struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- struct nfs4_client *clp = dp->dl_stid.sc_client;
- struct rpc_clnt *current_rpc_client = clp->cl_cb_client;
-
- nfsd4_cb_done(task, calldata);
-
- if (current_rpc_client != task->tk_client) {
- /* We're shutting down or changing cl_cb_client; leave
- * it to nfsd4_process_cb_update to restart the call if
- * necessary. */
- return;
- }
-
- if (cb->cb_done)
- return;
- switch (task->tk_status) {
- case 0:
- cb->cb_done = true;
- return;
- case -EBADHANDLE:
- case -NFS4ERR_BAD_STATEID:
- /* Race: client probably got cb_recall
- * before open reply granting delegation */
- break;
- default:
- /* Network partition? */
- nfsd4_mark_cb_down(clp, task->tk_status);
- }
- if (dp->dl_retries--) {
- rpc_delay(task, 2*HZ);
- task->tk_status = 0;
- rpc_restart_call_prepare(task);
- return;
- }
- nfsd4_mark_cb_down(clp, task->tk_status);
- cb->cb_done = true;
-}
-
-static void nfsd4_cb_recall_release(void *calldata)
-{
- struct nfsd4_callback *cb = calldata;
- struct nfs4_client *clp = cb->cb_clp;
- struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
-
- if (cb->cb_done) {
- spin_lock(&clp->cl_lock);
- list_del(&cb->cb_per_client);
- spin_unlock(&clp->cl_lock);
- nfs4_put_delegation(dp);
- }
-}
-
-static const struct rpc_call_ops nfsd4_cb_recall_ops = {
- .rpc_call_prepare = nfsd4_cb_prepare,
- .rpc_call_done = nfsd4_cb_recall_done,
- .rpc_release = nfsd4_cb_recall_release,
-};
-
-int nfsd4_create_callback_queue(void)
-{
- callback_wq = create_singlethread_workqueue("nfsd4_callbacks");
- if (!callback_wq)
- return -ENOMEM;
- return 0;
-}
-
-void nfsd4_destroy_callback_queue(void)
-{
- destroy_workqueue(callback_wq);
-}
-
-/* must be called under the state lock */
-void nfsd4_shutdown_callback(struct nfs4_client *clp)
-{
- set_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags);
- /*
- * Note this won't actually result in a null callback;
- * instead, nfsd4_do_callback_rpc() will detect the killed
- * client, destroy the rpc client, and stop:
- */
- do_probe_callback(clp);
- flush_workqueue(callback_wq);
-}
-
-static void nfsd4_release_cb(struct nfsd4_callback *cb)
-{
- if (cb->cb_ops->rpc_release)
- cb->cb_ops->rpc_release(cb);
-}
-
-/* requires cl_lock: */
-static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
-{
- struct nfsd4_session *s;
- struct nfsd4_conn *c;
-
- list_for_each_entry(s, &clp->cl_sessions, se_perclnt) {
- list_for_each_entry(c, &s->se_conns, cn_persession) {
- if (c->cn_flags & NFS4_CDFC4_BACK)
- return c;
- }
- }
- return NULL;
-}
-
-static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
-{
- struct nfs4_cb_conn conn;
- struct nfs4_client *clp = cb->cb_clp;
- struct nfsd4_session *ses = NULL;
- struct nfsd4_conn *c;
- int err;
-
- /*
- * This is either an update, or the client dying; in either case,
- * kill the old client:
- */
- if (clp->cl_cb_client) {
- rpc_shutdown_client(clp->cl_cb_client);
- clp->cl_cb_client = NULL;
- }
- if (clp->cl_cb_conn.cb_xprt) {
- svc_xprt_put(clp->cl_cb_conn.cb_xprt);
- clp->cl_cb_conn.cb_xprt = NULL;
- }
- if (test_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags))
- return;
- spin_lock(&clp->cl_lock);
- /*
- * Only serialized callback code is allowed to clear these
- * flags; main nfsd code can only set them:
- */
- BUG_ON(!(clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK));
- clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags);
- memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
- c = __nfsd4_find_backchannel(clp);
- if (c) {
- svc_xprt_get(c->cn_xprt);
- conn.cb_xprt = c->cn_xprt;
- ses = c->cn_session;
- }
- spin_unlock(&clp->cl_lock);
-
- err = setup_callback_client(clp, &conn, ses);
- if (err) {
- nfsd4_mark_cb_down(clp, err);
- return;
- }
- /* Yay, the callback channel's back! Restart any callbacks: */
- list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
- run_nfsd4_cb(cb);
-}
-
-void nfsd4_do_callback_rpc(struct work_struct *w)
-{
- struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
- struct nfs4_client *clp = cb->cb_clp;
- struct rpc_clnt *clnt;
-
- if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK)
- nfsd4_process_cb_update(cb);
-
- clnt = clp->cl_cb_client;
- if (!clnt) {
- /* Callback channel broken, or client killed; give up: */
- nfsd4_release_cb(cb);
- return;
- }
- rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
- cb->cb_ops, cb);
-}
-
-void nfsd4_cb_recall(struct nfs4_delegation *dp)
-{
- struct nfsd4_callback *cb = &dp->dl_recall;
- struct nfs4_client *clp = dp->dl_stid.sc_client;
-
- dp->dl_retries = 1;
- cb->cb_op = dp;
- cb->cb_clp = clp;
- cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
- cb->cb_msg.rpc_argp = cb;
- cb->cb_msg.rpc_resp = cb;
- cb->cb_msg.rpc_cred = callback_cred;
-
- cb->cb_ops = &nfsd4_cb_recall_ops;
- dp->dl_retries = 1;
-
- INIT_LIST_HEAD(&cb->cb_per_client);
- cb->cb_done = true;
-
- run_nfsd4_cb(&dp->dl_recall);
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs4idmap.c b/ANDROID_3.4.5/fs/nfsd/nfs4idmap.c
deleted file mode 100644
index 322d11ce..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs4idmap.c
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
- * Mapping of UID/GIDs to name and vice versa.
- *
- * Copyright (c) 2002, 2003 The Regents of the University of
- * Michigan. All rights reserved.
- *
- * Marius Aamodt Eriksen <marius@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/module.h>
-#include <linux/seq_file.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <net/net_namespace.h>
-#include "idmap.h"
-#include "nfsd.h"
-
-/*
- * Turn off idmapping when using AUTH_SYS.
- */
-static bool nfs4_disable_idmapping = true;
-module_param(nfs4_disable_idmapping, bool, 0644);
-MODULE_PARM_DESC(nfs4_disable_idmapping,
- "Turn off server's NFSv4 idmapping when using 'sec=sys'");
-
-/*
- * Cache entry
- */
-
-/*
- * XXX we know that IDMAP_NAMESZ < PAGE_SIZE, but it's ugly to rely on
- * that.
- */
-
-#define IDMAP_TYPE_USER 0
-#define IDMAP_TYPE_GROUP 1
-
-struct ent {
- struct cache_head h;
- int type; /* User / Group */
- uid_t id;
- char name[IDMAP_NAMESZ];
- char authname[IDMAP_NAMESZ];
-};
-
-/* Common entry handling */
-
-#define ENT_HASHBITS 8
-#define ENT_HASHMAX (1 << ENT_HASHBITS)
-
-static void
-ent_init(struct cache_head *cnew, struct cache_head *citm)
-{
- struct ent *new = container_of(cnew, struct ent, h);
- struct ent *itm = container_of(citm, struct ent, h);
-
- new->id = itm->id;
- new->type = itm->type;
-
- strlcpy(new->name, itm->name, sizeof(new->name));
- strlcpy(new->authname, itm->authname, sizeof(new->name));
-}
-
-static void
-ent_put(struct kref *ref)
-{
- struct ent *map = container_of(ref, struct ent, h.ref);
- kfree(map);
-}
-
-static struct cache_head *
-ent_alloc(void)
-{
- struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL);
- if (e)
- return &e->h;
- else
- return NULL;
-}
-
-/*
- * ID -> Name cache
- */
-
-static struct cache_head *idtoname_table[ENT_HASHMAX];
-
-static uint32_t
-idtoname_hash(struct ent *ent)
-{
- uint32_t hash;
-
- hash = hash_str(ent->authname, ENT_HASHBITS);
- hash = hash_long(hash ^ ent->id, ENT_HASHBITS);
-
- /* Flip LSB for user/group */
- if (ent->type == IDMAP_TYPE_GROUP)
- hash ^= 1;
-
- return hash;
-}
-
-static void
-idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
- int *blen)
-{
- struct ent *ent = container_of(ch, struct ent, h);
- char idstr[11];
-
- qword_add(bpp, blen, ent->authname);
- snprintf(idstr, sizeof(idstr), "%u", ent->id);
- qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user");
- qword_add(bpp, blen, idstr);
-
- (*bpp)[-1] = '\n';
-}
-
-static int
-idtoname_upcall(struct cache_detail *cd, struct cache_head *ch)
-{
- return sunrpc_cache_pipe_upcall(cd, ch, idtoname_request);
-}
-
-static int
-idtoname_match(struct cache_head *ca, struct cache_head *cb)
-{
- struct ent *a = container_of(ca, struct ent, h);
- struct ent *b = container_of(cb, struct ent, h);
-
- return (a->id == b->id && a->type == b->type &&
- strcmp(a->authname, b->authname) == 0);
-}
-
-static int
-idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
-{
- struct ent *ent;
-
- if (h == NULL) {
- seq_puts(m, "#domain type id [name]\n");
- return 0;
- }
- ent = container_of(h, struct ent, h);
- seq_printf(m, "%s %s %u", ent->authname,
- ent->type == IDMAP_TYPE_GROUP ? "group" : "user",
- ent->id);
- if (test_bit(CACHE_VALID, &h->flags))
- seq_printf(m, " %s", ent->name);
- seq_printf(m, "\n");
- return 0;
-}
-
-static void
-warn_no_idmapd(struct cache_detail *detail, int has_died)
-{
- printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n",
- has_died ? "died" : "not been started");
-}
-
-
-static int idtoname_parse(struct cache_detail *, char *, int);
-static struct ent *idtoname_lookup(struct ent *);
-static struct ent *idtoname_update(struct ent *, struct ent *);
-
-static struct cache_detail idtoname_cache = {
- .owner = THIS_MODULE,
- .hash_size = ENT_HASHMAX,
- .hash_table = idtoname_table,
- .name = "nfs4.idtoname",
- .cache_put = ent_put,
- .cache_upcall = idtoname_upcall,
- .cache_parse = idtoname_parse,
- .cache_show = idtoname_show,
- .warn_no_listener = warn_no_idmapd,
- .match = idtoname_match,
- .init = ent_init,
- .update = ent_init,
- .alloc = ent_alloc,
-};
-
-static int
-idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
-{
- struct ent ent, *res;
- char *buf1, *bp;
- int len;
- int error = -EINVAL;
-
- if (buf[buflen - 1] != '\n')
- return (-EINVAL);
- buf[buflen - 1]= '\0';
-
- buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (buf1 == NULL)
- return (-ENOMEM);
-
- memset(&ent, 0, sizeof(ent));
-
- /* Authentication name */
- if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
- goto out;
- memcpy(ent.authname, buf1, sizeof(ent.authname));
-
- /* Type */
- if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
- goto out;
- ent.type = strcmp(buf1, "user") == 0 ?
- IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
-
- /* ID */
- if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
- goto out;
- ent.id = simple_strtoul(buf1, &bp, 10);
- if (bp == buf1)
- goto out;
-
- /* expiry */
- ent.h.expiry_time = get_expiry(&buf);
- if (ent.h.expiry_time == 0)
- goto out;
-
- error = -ENOMEM;
- res = idtoname_lookup(&ent);
- if (!res)
- goto out;
-
- /* Name */
- error = -EINVAL;
- len = qword_get(&buf, buf1, PAGE_SIZE);
- if (len < 0)
- goto out;
- if (len == 0)
- set_bit(CACHE_NEGATIVE, &ent.h.flags);
- else if (len >= IDMAP_NAMESZ)
- goto out;
- else
- memcpy(ent.name, buf1, sizeof(ent.name));
- error = -ENOMEM;
- res = idtoname_update(&ent, res);
- if (res == NULL)
- goto out;
-
- cache_put(&res->h, &idtoname_cache);
-
- error = 0;
-out:
- kfree(buf1);
-
- return error;
-}
-
-
-static struct ent *
-idtoname_lookup(struct ent *item)
-{
- struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache,
- &item->h,
- idtoname_hash(item));
- if (ch)
- return container_of(ch, struct ent, h);
- else
- return NULL;
-}
-
-static struct ent *
-idtoname_update(struct ent *new, struct ent *old)
-{
- struct cache_head *ch = sunrpc_cache_update(&idtoname_cache,
- &new->h, &old->h,
- idtoname_hash(new));
- if (ch)
- return container_of(ch, struct ent, h);
- else
- return NULL;
-}
-
-
-/*
- * Name -> ID cache
- */
-
-static struct cache_head *nametoid_table[ENT_HASHMAX];
-
-static inline int
-nametoid_hash(struct ent *ent)
-{
- return hash_str(ent->name, ENT_HASHBITS);
-}
-
-static void
-nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
- int *blen)
-{
- struct ent *ent = container_of(ch, struct ent, h);
-
- qword_add(bpp, blen, ent->authname);
- qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user");
- qword_add(bpp, blen, ent->name);
-
- (*bpp)[-1] = '\n';
-}
-
-static int
-nametoid_upcall(struct cache_detail *cd, struct cache_head *ch)
-{
- return sunrpc_cache_pipe_upcall(cd, ch, nametoid_request);
-}
-
-static int
-nametoid_match(struct cache_head *ca, struct cache_head *cb)
-{
- struct ent *a = container_of(ca, struct ent, h);
- struct ent *b = container_of(cb, struct ent, h);
-
- return (a->type == b->type && strcmp(a->name, b->name) == 0 &&
- strcmp(a->authname, b->authname) == 0);
-}
-
-static int
-nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
-{
- struct ent *ent;
-
- if (h == NULL) {
- seq_puts(m, "#domain type name [id]\n");
- return 0;
- }
- ent = container_of(h, struct ent, h);
- seq_printf(m, "%s %s %s", ent->authname,
- ent->type == IDMAP_TYPE_GROUP ? "group" : "user",
- ent->name);
- if (test_bit(CACHE_VALID, &h->flags))
- seq_printf(m, " %u", ent->id);
- seq_printf(m, "\n");
- return 0;
-}
-
-static struct ent *nametoid_lookup(struct ent *);
-static struct ent *nametoid_update(struct ent *, struct ent *);
-static int nametoid_parse(struct cache_detail *, char *, int);
-
-static struct cache_detail nametoid_cache = {
- .owner = THIS_MODULE,
- .hash_size = ENT_HASHMAX,
- .hash_table = nametoid_table,
- .name = "nfs4.nametoid",
- .cache_put = ent_put,
- .cache_upcall = nametoid_upcall,
- .cache_parse = nametoid_parse,
- .cache_show = nametoid_show,
- .warn_no_listener = warn_no_idmapd,
- .match = nametoid_match,
- .init = ent_init,
- .update = ent_init,
- .alloc = ent_alloc,
-};
-
-static int
-nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
-{
- struct ent ent, *res;
- char *buf1;
- int error = -EINVAL;
-
- if (buf[buflen - 1] != '\n')
- return (-EINVAL);
- buf[buflen - 1]= '\0';
-
- buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (buf1 == NULL)
- return (-ENOMEM);
-
- memset(&ent, 0, sizeof(ent));
-
- /* Authentication name */
- if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
- goto out;
- memcpy(ent.authname, buf1, sizeof(ent.authname));
-
- /* Type */
- if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
- goto out;
- ent.type = strcmp(buf1, "user") == 0 ?
- IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
-
- /* Name */
- error = qword_get(&buf, buf1, PAGE_SIZE);
- if (error <= 0 || error >= IDMAP_NAMESZ)
- goto out;
- memcpy(ent.name, buf1, sizeof(ent.name));
-
- /* expiry */
- ent.h.expiry_time = get_expiry(&buf);
- if (ent.h.expiry_time == 0)
- goto out;
-
- /* ID */
- error = get_int(&buf, &ent.id);
- if (error == -EINVAL)
- goto out;
- if (error == -ENOENT)
- set_bit(CACHE_NEGATIVE, &ent.h.flags);
-
- error = -ENOMEM;
- res = nametoid_lookup(&ent);
- if (res == NULL)
- goto out;
- res = nametoid_update(&ent, res);
- if (res == NULL)
- goto out;
-
- cache_put(&res->h, &nametoid_cache);
- error = 0;
-out:
- kfree(buf1);
-
- return (error);
-}
-
-
-static struct ent *
-nametoid_lookup(struct ent *item)
-{
- struct cache_head *ch = sunrpc_cache_lookup(&nametoid_cache,
- &item->h,
- nametoid_hash(item));
- if (ch)
- return container_of(ch, struct ent, h);
- else
- return NULL;
-}
-
-static struct ent *
-nametoid_update(struct ent *new, struct ent *old)
-{
- struct cache_head *ch = sunrpc_cache_update(&nametoid_cache,
- &new->h, &old->h,
- nametoid_hash(new));
- if (ch)
- return container_of(ch, struct ent, h);
- else
- return NULL;
-}
-
-/*
- * Exported API
- */
-
-int
-nfsd_idmap_init(void)
-{
- int rv;
-
- rv = cache_register_net(&idtoname_cache, &init_net);
- if (rv)
- return rv;
- rv = cache_register_net(&nametoid_cache, &init_net);
- if (rv)
- cache_unregister_net(&idtoname_cache, &init_net);
- return rv;
-}
-
-void
-nfsd_idmap_shutdown(void)
-{
- cache_unregister_net(&idtoname_cache, &init_net);
- cache_unregister_net(&nametoid_cache, &init_net);
-}
-
-static int
-idmap_lookup(struct svc_rqst *rqstp,
- struct ent *(*lookup_fn)(struct ent *), struct ent *key,
- struct cache_detail *detail, struct ent **item)
-{
- int ret;
-
- *item = lookup_fn(key);
- if (!*item)
- return -ENOMEM;
- retry:
- ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle);
-
- if (ret == -ETIMEDOUT) {
- struct ent *prev_item = *item;
- *item = lookup_fn(key);
- if (*item != prev_item)
- goto retry;
- cache_put(&(*item)->h, detail);
- }
- return ret;
-}
-
-static char *
-rqst_authname(struct svc_rqst *rqstp)
-{
- struct auth_domain *clp;
-
- clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client;
- return clp->name;
-}
-
-static __be32
-idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
- uid_t *id)
-{
- struct ent *item, key = {
- .type = type,
- };
- int ret;
-
- if (namelen + 1 > sizeof(key.name))
- return nfserr_badowner;
- memcpy(key.name, name, namelen);
- key.name[namelen] = '\0';
- strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
- ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
- if (ret == -ENOENT)
- return nfserr_badowner;
- if (ret)
- return nfserrno(ret);
- *id = item->id;
- cache_put(&item->h, &nametoid_cache);
- return 0;
-}
-
-static int
-idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
-{
- struct ent *item, key = {
- .id = id,
- .type = type,
- };
- int ret;
-
- strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
- ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
- if (ret == -ENOENT)
- return sprintf(name, "%u", id);
- if (ret)
- return ret;
- ret = strlen(item->name);
- BUG_ON(ret > IDMAP_NAMESZ);
- memcpy(name, item->name, ret);
- cache_put(&item->h, &idtoname_cache);
- return ret;
-}
-
-static bool
-numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id)
-{
- int ret;
- char buf[11];
-
- if (namelen + 1 > sizeof(buf))
- /* too long to represent a 32-bit id: */
- return false;
- /* Just to make sure it's null-terminated: */
- memcpy(buf, name, namelen);
- buf[namelen] = '\0';
- ret = kstrtouint(name, 10, id);
- return ret == 0;
-}
-
-static __be32
-do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id)
-{
- if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS)
- if (numeric_name_to_id(rqstp, type, name, namelen, id))
- return 0;
- /*
- * otherwise, fall through and try idmapping, for
- * backwards compatibility with clients sending names:
- */
- return idmap_name_to_id(rqstp, type, name, namelen, id);
-}
-
-static int
-do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
-{
- if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS)
- return sprintf(name, "%u", id);
- return idmap_id_to_name(rqstp, type, id, name);
-}
-
-__be32
-nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
- __u32 *id)
-{
- return do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
-}
-
-__be32
-nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
- __u32 *id)
-{
- return do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id);
-}
-
-int
-nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
-{
- return do_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);
-}
-
-int
-nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
-{
- return do_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs4proc.c b/ANDROID_3.4.5/fs/nfsd/nfs4proc.c
deleted file mode 100644
index 987e719f..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs4proc.c
+++ /dev/null
@@ -1,1769 +0,0 @@
-/*
- * Server-side procedures for NFSv4.
- *
- * Copyright (c) 2002 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Kendrick Smith <kmsmith@umich.edu>
- * Andy Adamson <andros@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include <linux/file.h>
-#include <linux/slab.h>
-
-#include "idmap.h"
-#include "cache.h"
-#include "xdr4.h"
-#include "vfs.h"
-#include "current_stateid.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_PROC
-
-static u32 nfsd_attrmask[] = {
- NFSD_WRITEABLE_ATTRS_WORD0,
- NFSD_WRITEABLE_ATTRS_WORD1,
- NFSD_WRITEABLE_ATTRS_WORD2
-};
-
-static u32 nfsd41_ex_attrmask[] = {
- NFSD_SUPPATTR_EXCLCREAT_WORD0,
- NFSD_SUPPATTR_EXCLCREAT_WORD1,
- NFSD_SUPPATTR_EXCLCREAT_WORD2
-};
-
-static __be32
-check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- u32 *bmval, u32 *writable)
-{
- struct dentry *dentry = cstate->current_fh.fh_dentry;
-
- /*
- * Check about attributes are supported by the NFSv4 server or not.
- * According to spec, unsupported attributes return ERR_ATTRNOTSUPP.
- */
- if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) ||
- (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) ||
- (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion)))
- return nfserr_attrnotsupp;
-
- /*
- * Check FATTR4_WORD0_ACL can be supported
- * in current environment or not.
- */
- if (bmval[0] & FATTR4_WORD0_ACL) {
- if (!IS_POSIXACL(dentry->d_inode))
- return nfserr_attrnotsupp;
- }
-
- /*
- * According to spec, read-only attributes return ERR_INVAL.
- */
- if (writable) {
- if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
- (bmval[2] & ~writable[2]))
- return nfserr_inval;
- }
-
- return nfs_ok;
-}
-
-static __be32
-nfsd4_check_open_attributes(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
-{
- __be32 status = nfs_ok;
-
- if (open->op_create == NFS4_OPEN_CREATE) {
- if (open->op_createmode == NFS4_CREATE_UNCHECKED
- || open->op_createmode == NFS4_CREATE_GUARDED)
- status = check_attr_support(rqstp, cstate,
- open->op_bmval, nfsd_attrmask);
- else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1)
- status = check_attr_support(rqstp, cstate,
- open->op_bmval, nfsd41_ex_attrmask);
- }
-
- return status;
-}
-
-static int
-is_create_with_attrs(struct nfsd4_open *open)
-{
- return open->op_create == NFS4_OPEN_CREATE
- && (open->op_createmode == NFS4_CREATE_UNCHECKED
- || open->op_createmode == NFS4_CREATE_GUARDED
- || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
-}
-
-/*
- * if error occurs when setting the acl, just clear the acl bit
- * in the returned attr bitmap.
- */
-static void
-do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct nfs4_acl *acl, u32 *bmval)
-{
- __be32 status;
-
- status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
- if (status)
- /*
- * We should probably fail the whole open at this point,
- * but we've already created the file, so it's too late;
- * So this seems the least of evils:
- */
- bmval[0] &= ~FATTR4_WORD0_ACL;
-}
-
-static inline void
-fh_dup2(struct svc_fh *dst, struct svc_fh *src)
-{
- fh_put(dst);
- dget(src->fh_dentry);
- if (src->fh_export)
- cache_get(&src->fh_export->h);
- *dst = *src;
-}
-
-static __be32
-do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
-{
- __be32 status;
-
- if (open->op_truncate &&
- !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
- return nfserr_inval;
-
- accmode |= NFSD_MAY_READ_IF_EXEC;
-
- if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
- accmode |= NFSD_MAY_READ;
- if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
- accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC);
- if (open->op_share_deny & NFS4_SHARE_DENY_READ)
- accmode |= NFSD_MAY_WRITE;
-
- status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
-
- return status;
-}
-
-static __be32 nfsd_check_obj_isreg(struct svc_fh *fh)
-{
- umode_t mode = fh->fh_dentry->d_inode->i_mode;
-
- if (S_ISREG(mode))
- return nfs_ok;
- if (S_ISDIR(mode))
- return nfserr_isdir;
- /*
- * Using err_symlink as our catch-all case may look odd; but
- * there's no other obvious error for this case in 4.0, and we
- * happen to know that it will cause the linux v4 client to do
- * the right thing on attempts to open something other than a
- * regular file.
- */
- return nfserr_symlink;
-}
-
-static __be32
-do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
-{
- struct svc_fh *resfh;
- __be32 status;
-
- resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
- if (!resfh)
- return nfserr_jukebox;
- fh_init(resfh, NFS4_FHSIZE);
- open->op_truncate = 0;
-
- if (open->op_create) {
- /* FIXME: check session persistence and pnfs flags.
- * The nfsv4.1 spec requires the following semantics:
- *
- * Persistent | pNFS | Server REQUIRED | Client Allowed
- * Reply Cache | server | |
- * -------------+--------+-----------------+--------------------
- * no | no | EXCLUSIVE4_1 | EXCLUSIVE4_1
- * | | | (SHOULD)
- * | | and EXCLUSIVE4 | or EXCLUSIVE4
- * | | | (SHOULD NOT)
- * no | yes | EXCLUSIVE4_1 | EXCLUSIVE4_1
- * yes | no | GUARDED4 | GUARDED4
- * yes | yes | GUARDED4 | GUARDED4
- */
-
- /*
- * Note: create modes (UNCHECKED,GUARDED...) are the same
- * in NFSv4 as in v3 except EXCLUSIVE4_1.
- */
- status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
- open->op_fname.len, &open->op_iattr,
- resfh, open->op_createmode,
- (u32 *)open->op_verf.data,
- &open->op_truncate, &open->op_created);
-
- /*
- * Following rfc 3530 14.2.16, use the returned bitmask
- * to indicate which attributes we used to store the
- * verifier:
- */
- if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
- open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS |
- FATTR4_WORD1_TIME_MODIFY);
- } else {
- status = nfsd_lookup(rqstp, current_fh,
- open->op_fname.data, open->op_fname.len, resfh);
- fh_unlock(current_fh);
- }
- if (status)
- goto out;
- status = nfsd_check_obj_isreg(resfh);
- if (status)
- goto out;
-
- if (is_create_with_attrs(open) && open->op_acl != NULL)
- do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval);
-
- /* set reply cache */
- fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
- &resfh->fh_handle);
- if (!open->op_created)
- status = do_open_permission(rqstp, resfh, open,
- NFSD_MAY_NOP);
- set_change_info(&open->op_cinfo, current_fh);
- fh_dup2(current_fh, resfh);
-out:
- fh_put(resfh);
- kfree(resfh);
- return status;
-}
-
-static __be32
-do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
-{
- __be32 status;
-
- /* We don't know the target directory, and therefore can not
- * set the change info
- */
-
- memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
-
- /* set replay cache */
- fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
- &current_fh->fh_handle);
-
- open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
- (open->op_iattr.ia_size == 0);
-
- status = do_open_permission(rqstp, current_fh, open,
- NFSD_MAY_OWNER_OVERRIDE);
-
- return status;
-}
-
-static void
-copy_clientid(clientid_t *clid, struct nfsd4_session *session)
-{
- struct nfsd4_sessionid *sid =
- (struct nfsd4_sessionid *)session->se_sessionid.data;
-
- clid->cl_boot = sid->clientid.cl_boot;
- clid->cl_id = sid->clientid.cl_id;
-}
-
-static __be32
-nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_open *open)
-{
- __be32 status;
- struct nfsd4_compoundres *resp;
-
- dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n",
- (int)open->op_fname.len, open->op_fname.data,
- open->op_openowner);
-
- /* This check required by spec. */
- if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
- return nfserr_inval;
-
- open->op_created = 0;
- /*
- * RFC5661 18.51.3
- * Before RECLAIM_COMPLETE done, server should deny new lock
- */
- if (nfsd4_has_session(cstate) &&
- !test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
- &cstate->session->se_client->cl_flags) &&
- open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_grace;
-
- if (nfsd4_has_session(cstate))
- copy_clientid(&open->op_clientid, cstate->session);
-
- nfs4_lock_state();
-
- /* check seqid for replay. set nfs4_owner */
- resp = rqstp->rq_resp;
- status = nfsd4_process_open1(&resp->cstate, open);
- if (status == nfserr_replay_me) {
- struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay;
- fh_put(&cstate->current_fh);
- fh_copy_shallow(&cstate->current_fh.fh_handle,
- &rp->rp_openfh);
- status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
- if (status)
- dprintk("nfsd4_open: replay failed"
- " restoring previous filehandle\n");
- else
- status = nfserr_replay_me;
- }
- if (status)
- goto out;
-
- status = nfsd4_check_open_attributes(rqstp, cstate, open);
- if (status)
- goto out;
-
- /* Openowner is now set, so sequence id will get bumped. Now we need
- * these checks before we do any creates: */
- status = nfserr_grace;
- if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
- goto out;
- status = nfserr_no_grace;
- if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- goto out;
-
- switch (open->op_claim_type) {
- case NFS4_OPEN_CLAIM_DELEGATE_CUR:
- case NFS4_OPEN_CLAIM_NULL:
- status = do_open_lookup(rqstp, &cstate->current_fh,
- open);
- if (status)
- goto out;
- break;
- case NFS4_OPEN_CLAIM_PREVIOUS:
- open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
- status = nfs4_check_open_reclaim(&open->op_clientid);
- if (status)
- goto out;
- case NFS4_OPEN_CLAIM_FH:
- case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
- status = do_open_fhandle(rqstp, &cstate->current_fh,
- open);
- if (status)
- goto out;
- break;
- case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
- case NFS4_OPEN_CLAIM_DELEGATE_PREV:
- open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
- dprintk("NFSD: unsupported OPEN claim type %d\n",
- open->op_claim_type);
- status = nfserr_notsupp;
- goto out;
- default:
- dprintk("NFSD: Invalid OPEN claim type %d\n",
- open->op_claim_type);
- status = nfserr_inval;
- goto out;
- }
- /*
- * nfsd4_process_open2() does the actual opening of the file. If
- * successful, it (1) truncates the file if open->op_truncate was
- * set, (2) sets open->op_stateid, (3) sets open->op_delegation.
- */
- status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
- WARN_ON(status && open->op_created);
-out:
- nfsd4_cleanup_open_state(open, status);
- if (open->op_openowner)
- cstate->replay_owner = &open->op_openowner->oo_owner;
- else
- nfs4_unlock_state();
- return status;
-}
-
-/*
- * filehandle-manipulating ops.
- */
-static __be32
-nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct svc_fh **getfh)
-{
- if (!cstate->current_fh.fh_dentry)
- return nfserr_nofilehandle;
-
- *getfh = &cstate->current_fh;
- return nfs_ok;
-}
-
-static __be32
-nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_putfh *putfh)
-{
- fh_put(&cstate->current_fh);
- cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
- memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
- putfh->pf_fhlen);
- return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
-}
-
-static __be32
-nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- void *arg)
-{
- __be32 status;
-
- fh_put(&cstate->current_fh);
- status = exp_pseudoroot(rqstp, &cstate->current_fh);
- return status;
-}
-
-static __be32
-nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- void *arg)
-{
- if (!cstate->save_fh.fh_dentry)
- return nfserr_restorefh;
-
- fh_dup2(&cstate->current_fh, &cstate->save_fh);
- if (HAS_STATE_ID(cstate, SAVED_STATE_ID_FLAG)) {
- memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t));
- SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
- }
- return nfs_ok;
-}
-
-static __be32
-nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- void *arg)
-{
- if (!cstate->current_fh.fh_dentry)
- return nfserr_nofilehandle;
-
- fh_dup2(&cstate->save_fh, &cstate->current_fh);
- if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) {
- memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t));
- SET_STATE_ID(cstate, SAVED_STATE_ID_FLAG);
- }
- return nfs_ok;
-}
-
-/*
- * misc nfsv4 ops
- */
-static __be32
-nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_access *access)
-{
- if (access->ac_req_access & ~NFS3_ACCESS_FULL)
- return nfserr_inval;
-
- access->ac_resp_access = access->ac_req_access;
- return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
- &access->ac_supported);
-}
-
-static void gen_boot_verifier(nfs4_verifier *verifier)
-{
- __be32 verf[2];
-
- verf[0] = (__be32)nfssvc_boot.tv_sec;
- verf[1] = (__be32)nfssvc_boot.tv_usec;
- memcpy(verifier->data, verf, sizeof(verifier->data));
-}
-
-static __be32
-nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_commit *commit)
-{
- gen_boot_verifier(&commit->co_verf);
- return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
- commit->co_count);
-}
-
-static __be32
-nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_create *create)
-{
- struct svc_fh resfh;
- __be32 status;
- dev_t rdev;
-
- fh_init(&resfh, NFS4_FHSIZE);
-
- status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
- NFSD_MAY_CREATE);
- if (status)
- return status;
-
- status = check_attr_support(rqstp, cstate, create->cr_bmval,
- nfsd_attrmask);
- if (status)
- return status;
-
- switch (create->cr_type) {
- case NF4LNK:
- /* ugh! we have to null-terminate the linktext, or
- * vfs_symlink() will choke. it is always safe to
- * null-terminate by brute force, since at worst we
- * will overwrite the first byte of the create namelen
- * in the XDR buffer, which has already been extracted
- * during XDR decode.
- */
- create->cr_linkname[create->cr_linklen] = 0;
-
- status = nfsd_symlink(rqstp, &cstate->current_fh,
- create->cr_name, create->cr_namelen,
- create->cr_linkname, create->cr_linklen,
- &resfh, &create->cr_iattr);
- break;
-
- case NF4BLK:
- rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
- if (MAJOR(rdev) != create->cr_specdata1 ||
- MINOR(rdev) != create->cr_specdata2)
- return nfserr_inval;
- status = nfsd_create(rqstp, &cstate->current_fh,
- create->cr_name, create->cr_namelen,
- &create->cr_iattr, S_IFBLK, rdev, &resfh);
- break;
-
- case NF4CHR:
- rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
- if (MAJOR(rdev) != create->cr_specdata1 ||
- MINOR(rdev) != create->cr_specdata2)
- return nfserr_inval;
- status = nfsd_create(rqstp, &cstate->current_fh,
- create->cr_name, create->cr_namelen,
- &create->cr_iattr,S_IFCHR, rdev, &resfh);
- break;
-
- case NF4SOCK:
- status = nfsd_create(rqstp, &cstate->current_fh,
- create->cr_name, create->cr_namelen,
- &create->cr_iattr, S_IFSOCK, 0, &resfh);
- break;
-
- case NF4FIFO:
- status = nfsd_create(rqstp, &cstate->current_fh,
- create->cr_name, create->cr_namelen,
- &create->cr_iattr, S_IFIFO, 0, &resfh);
- break;
-
- case NF4DIR:
- create->cr_iattr.ia_valid &= ~ATTR_SIZE;
- status = nfsd_create(rqstp, &cstate->current_fh,
- create->cr_name, create->cr_namelen,
- &create->cr_iattr, S_IFDIR, 0, &resfh);
- break;
-
- default:
- status = nfserr_badtype;
- }
-
- if (status)
- goto out;
-
- if (create->cr_acl != NULL)
- do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
- create->cr_bmval);
-
- fh_unlock(&cstate->current_fh);
- set_change_info(&create->cr_cinfo, &cstate->current_fh);
- fh_dup2(&cstate->current_fh, &resfh);
-out:
- fh_put(&resfh);
- return status;
-}
-
-static __be32
-nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_getattr *getattr)
-{
- __be32 status;
-
- status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
- if (status)
- return status;
-
- if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
- return nfserr_inval;
-
- getattr->ga_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
- getattr->ga_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
- getattr->ga_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
-
- getattr->ga_fhp = &cstate->current_fh;
- return nfs_ok;
-}
-
-static __be32
-nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_link *link)
-{
- __be32 status = nfserr_nofilehandle;
-
- if (!cstate->save_fh.fh_dentry)
- return status;
- status = nfsd_link(rqstp, &cstate->current_fh,
- link->li_name, link->li_namelen, &cstate->save_fh);
- if (!status)
- set_change_info(&link->li_cinfo, &cstate->current_fh);
- return status;
-}
-
-static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
-{
- struct svc_fh tmp_fh;
- __be32 ret;
-
- fh_init(&tmp_fh, NFS4_FHSIZE);
- ret = exp_pseudoroot(rqstp, &tmp_fh);
- if (ret)
- return ret;
- if (tmp_fh.fh_dentry == fh->fh_dentry) {
- fh_put(&tmp_fh);
- return nfserr_noent;
- }
- fh_put(&tmp_fh);
- return nfsd_lookup(rqstp, fh, "..", 2, fh);
-}
-
-static __be32
-nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- void *arg)
-{
- return nfsd4_do_lookupp(rqstp, &cstate->current_fh);
-}
-
-static __be32
-nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_lookup *lookup)
-{
- return nfsd_lookup(rqstp, &cstate->current_fh,
- lookup->lo_name, lookup->lo_len,
- &cstate->current_fh);
-}
-
-static __be32
-nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_read *read)
-{
- __be32 status;
-
- /* no need to check permission - this will be done in nfsd_read() */
-
- read->rd_filp = NULL;
- if (read->rd_offset >= OFFSET_MAX)
- return nfserr_inval;
-
- nfs4_lock_state();
- /* check stateid */
- if ((status = nfs4_preprocess_stateid_op(cstate, &read->rd_stateid,
- RD_STATE, &read->rd_filp))) {
- dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
- goto out;
- }
- if (read->rd_filp)
- get_file(read->rd_filp);
- status = nfs_ok;
-out:
- nfs4_unlock_state();
- read->rd_rqstp = rqstp;
- read->rd_fhp = &cstate->current_fh;
- return status;
-}
-
-static __be32
-nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_readdir *readdir)
-{
- u64 cookie = readdir->rd_cookie;
- static const nfs4_verifier zeroverf;
-
- /* no need to check permission - this will be done in nfsd_readdir() */
-
- if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
- return nfserr_inval;
-
- readdir->rd_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
- readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
- readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
-
- if ((cookie == 1) || (cookie == 2) ||
- (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
- return nfserr_bad_cookie;
-
- readdir->rd_rqstp = rqstp;
- readdir->rd_fhp = &cstate->current_fh;
- return nfs_ok;
-}
-
-static __be32
-nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_readlink *readlink)
-{
- readlink->rl_rqstp = rqstp;
- readlink->rl_fhp = &cstate->current_fh;
- return nfs_ok;
-}
-
-static __be32
-nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_remove *remove)
-{
- __be32 status;
-
- if (locks_in_grace())
- return nfserr_grace;
- status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
- remove->rm_name, remove->rm_namelen);
- if (!status) {
- fh_unlock(&cstate->current_fh);
- set_change_info(&remove->rm_cinfo, &cstate->current_fh);
- }
- return status;
-}
-
-static __be32
-nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_rename *rename)
-{
- __be32 status = nfserr_nofilehandle;
-
- if (!cstate->save_fh.fh_dentry)
- return status;
- if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
- & NFSEXP_NOSUBTREECHECK))
- return nfserr_grace;
- status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
- rename->rn_snamelen, &cstate->current_fh,
- rename->rn_tname, rename->rn_tnamelen);
-
- /* the underlying filesystem returns different error's than required
- * by NFSv4. both save_fh and current_fh have been verified.. */
- if (status == nfserr_isdir)
- status = nfserr_exist;
- else if ((status == nfserr_notdir) &&
- (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) &&
- S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode)))
- status = nfserr_exist;
-
- if (!status) {
- set_change_info(&rename->rn_sinfo, &cstate->current_fh);
- set_change_info(&rename->rn_tinfo, &cstate->save_fh);
- }
- return status;
-}
-
-static __be32
-nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_secinfo *secinfo)
-{
- struct svc_fh resfh;
- struct svc_export *exp;
- struct dentry *dentry;
- __be32 err;
-
- fh_init(&resfh, NFS4_FHSIZE);
- err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC);
- if (err)
- return err;
- err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
- secinfo->si_name, secinfo->si_namelen,
- &exp, &dentry);
- if (err)
- return err;
- if (dentry->d_inode == NULL) {
- exp_put(exp);
- err = nfserr_noent;
- } else
- secinfo->si_exp = exp;
- dput(dentry);
- if (cstate->minorversion)
- /* See rfc 5661 section 2.6.3.1.1.8 */
- fh_put(&cstate->current_fh);
- return err;
-}
-
-static __be32
-nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_secinfo_no_name *sin)
-{
- __be32 err;
-
- switch (sin->sin_style) {
- case NFS4_SECINFO_STYLE4_CURRENT_FH:
- break;
- case NFS4_SECINFO_STYLE4_PARENT:
- err = nfsd4_do_lookupp(rqstp, &cstate->current_fh);
- if (err)
- return err;
- break;
- default:
- return nfserr_inval;
- }
- exp_get(cstate->current_fh.fh_export);
- sin->sin_exp = cstate->current_fh.fh_export;
- fh_put(&cstate->current_fh);
- return nfs_ok;
-}
-
-static __be32
-nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_setattr *setattr)
-{
- __be32 status = nfs_ok;
- int err;
-
- if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
- nfs4_lock_state();
- status = nfs4_preprocess_stateid_op(cstate,
- &setattr->sa_stateid, WR_STATE, NULL);
- nfs4_unlock_state();
- if (status) {
- dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
- return status;
- }
- }
- err = fh_want_write(&cstate->current_fh);
- if (err)
- return nfserrno(err);
- status = nfs_ok;
-
- status = check_attr_support(rqstp, cstate, setattr->sa_bmval,
- nfsd_attrmask);
- if (status)
- goto out;
-
- if (setattr->sa_acl != NULL)
- status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
- setattr->sa_acl);
- if (status)
- goto out;
- status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
- 0, (time_t)0);
-out:
- fh_drop_write(&cstate->current_fh);
- return status;
-}
-
-static __be32
-nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_write *write)
-{
- stateid_t *stateid = &write->wr_stateid;
- struct file *filp = NULL;
- __be32 status = nfs_ok;
- unsigned long cnt;
-
- /* no need to check permission - this will be done in nfsd_write() */
-
- if (write->wr_offset >= OFFSET_MAX)
- return nfserr_inval;
-
- nfs4_lock_state();
- status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp);
- if (filp)
- get_file(filp);
- nfs4_unlock_state();
-
- if (status) {
- dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
- return status;
- }
-
- cnt = write->wr_buflen;
- write->wr_how_written = write->wr_stable_how;
- gen_boot_verifier(&write->wr_verifier);
-
- status = nfsd_write(rqstp, &cstate->current_fh, filp,
- write->wr_offset, rqstp->rq_vec, write->wr_vlen,
- &cnt, &write->wr_how_written);
- if (filp)
- fput(filp);
-
- write->wr_bytes_written = cnt;
-
- return status;
-}
-
-/* This routine never returns NFS_OK! If there are no other errors, it
- * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the
- * attributes matched. VERIFY is implemented by mapping NFSERR_SAME
- * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
- */
-static __be32
-_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_verify *verify)
-{
- __be32 *buf, *p;
- int count;
- __be32 status;
-
- status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
- if (status)
- return status;
-
- status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL);
- if (status)
- return status;
-
- if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
- || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
- return nfserr_inval;
- if (verify->ve_attrlen & 3)
- return nfserr_inval;
-
- /* count in words:
- * bitmap_len(1) + bitmap(2) + attr_len(1) = 4
- */
- count = 4 + (verify->ve_attrlen >> 2);
- buf = kmalloc(count << 2, GFP_KERNEL);
- if (!buf)
- return nfserr_jukebox;
-
- status = nfsd4_encode_fattr(&cstate->current_fh,
- cstate->current_fh.fh_export,
- cstate->current_fh.fh_dentry, buf,
- &count, verify->ve_bmval,
- rqstp, 0);
-
- /* this means that nfsd4_encode_fattr() ran out of space */
- if (status == nfserr_resource && count == 0)
- status = nfserr_not_same;
- if (status)
- goto out_kfree;
-
- /* skip bitmap */
- p = buf + 1 + ntohl(buf[0]);
- status = nfserr_not_same;
- if (ntohl(*p++) != verify->ve_attrlen)
- goto out_kfree;
- if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen))
- status = nfserr_same;
-
-out_kfree:
- kfree(buf);
- return status;
-}
-
-static __be32
-nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_verify *verify)
-{
- __be32 status;
-
- status = _nfsd4_verify(rqstp, cstate, verify);
- return status == nfserr_not_same ? nfs_ok : status;
-}
-
-static __be32
-nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_verify *verify)
-{
- __be32 status;
-
- status = _nfsd4_verify(rqstp, cstate, verify);
- return status == nfserr_same ? nfs_ok : status;
-}
-
-/*
- * NULL call.
- */
-static __be32
-nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
-{
- return nfs_ok;
-}
-
-static inline void nfsd4_increment_op_stats(u32 opnum)
-{
- if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
- nfsdstats.nfs4_opcount[opnum]++;
-}
-
-typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
- void *);
-typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op);
-typedef void(*stateid_setter)(struct nfsd4_compound_state *, void *);
-typedef void(*stateid_getter)(struct nfsd4_compound_state *, void *);
-
-enum nfsd4_op_flags {
- ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */
- ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */
- ALLOWED_AS_FIRST_OP = 1 << 2, /* ops reqired first in compound */
- /* For rfc 5661 section 2.6.3.1.1: */
- OP_HANDLES_WRONGSEC = 1 << 3,
- OP_IS_PUTFH_LIKE = 1 << 4,
- /*
- * These are the ops whose result size we estimate before
- * encoding, to avoid performing an op then not being able to
- * respond or cache a response. This includes writes and setattrs
- * as well as the operations usually called "nonidempotent":
- */
- OP_MODIFIES_SOMETHING = 1 << 5,
- /*
- * Cache compounds containing these ops in the xid-based drc:
- * We use the DRC for compounds containing non-idempotent
- * operations, *except* those that are 4.1-specific (since
- * sessions provide their own EOS), and except for stateful
- * operations other than setclientid and setclientid_confirm
- * (since sequence numbers provide EOS for open, lock, etc in
- * the v4.0 case).
- */
- OP_CACHEME = 1 << 6,
- /*
- * These are ops which clear current state id.
- */
- OP_CLEAR_STATEID = 1 << 7,
-};
-
-struct nfsd4_operation {
- nfsd4op_func op_func;
- u32 op_flags;
- char *op_name;
- /* Try to get response size before operation */
- nfsd4op_rsize op_rsize_bop;
- stateid_setter op_get_currentstateid;
- stateid_getter op_set_currentstateid;
-};
-
-static struct nfsd4_operation nfsd4_ops[];
-
-#ifdef NFSD_DEBUG
-static const char *nfsd4_op_name(unsigned opnum);
-#endif
-
-/*
- * Enforce NFSv4.1 COMPOUND ordering rules:
- *
- * Also note, enforced elsewhere:
- * - SEQUENCE other than as first op results in
- * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().)
- * - BIND_CONN_TO_SESSION must be the only op in its compound.
- * (Enforced in nfsd4_bind_conn_to_session().)
- * - DESTROY_SESSION must be the final operation in a compound, if
- * sessionid's in SEQUENCE and DESTROY_SESSION are the same.
- * (Enforced in nfsd4_destroy_session().)
- */
-static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args)
-{
- struct nfsd4_op *op = &args->ops[0];
-
- /* These ordering requirements don't apply to NFSv4.0: */
- if (args->minorversion == 0)
- return nfs_ok;
- /* This is weird, but OK, not our problem: */
- if (args->opcnt == 0)
- return nfs_ok;
- if (op->status == nfserr_op_illegal)
- return nfs_ok;
- if (!(nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP))
- return nfserr_op_not_in_session;
- if (op->opnum == OP_SEQUENCE)
- return nfs_ok;
- if (args->opcnt != 1)
- return nfserr_not_only_op;
- return nfs_ok;
-}
-
-static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
-{
- return &nfsd4_ops[op->opnum];
-}
-
-bool nfsd4_cache_this_op(struct nfsd4_op *op)
-{
- return OPDESC(op)->op_flags & OP_CACHEME;
-}
-
-static bool need_wrongsec_check(struct svc_rqst *rqstp)
-{
- struct nfsd4_compoundres *resp = rqstp->rq_resp;
- struct nfsd4_compoundargs *argp = rqstp->rq_argp;
- struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
- struct nfsd4_op *next = &argp->ops[resp->opcnt];
- struct nfsd4_operation *thisd;
- struct nfsd4_operation *nextd;
-
- thisd = OPDESC(this);
- /*
- * Most ops check wronsec on our own; only the putfh-like ops
- * have special rules.
- */
- if (!(thisd->op_flags & OP_IS_PUTFH_LIKE))
- return false;
- /*
- * rfc 5661 2.6.3.1.1.6: don't bother erroring out a
- * put-filehandle operation if we're not going to use the
- * result:
- */
- if (argp->opcnt == resp->opcnt)
- return false;
-
- nextd = OPDESC(next);
- /*
- * Rest of 2.6.3.1.1: certain operations will return WRONGSEC
- * errors themselves as necessary; others should check for them
- * now:
- */
- return !(nextd->op_flags & OP_HANDLES_WRONGSEC);
-}
-
-/*
- * COMPOUND call.
- */
-static __be32
-nfsd4_proc_compound(struct svc_rqst *rqstp,
- struct nfsd4_compoundargs *args,
- struct nfsd4_compoundres *resp)
-{
- struct nfsd4_op *op;
- struct nfsd4_operation *opdesc;
- struct nfsd4_compound_state *cstate = &resp->cstate;
- int slack_bytes;
- u32 plen = 0;
- __be32 status;
-
- resp->xbuf = &rqstp->rq_res;
- resp->p = rqstp->rq_res.head[0].iov_base +
- rqstp->rq_res.head[0].iov_len;
- resp->tagp = resp->p;
- /* reserve space for: taglen, tag, and opcnt */
- resp->p += 2 + XDR_QUADLEN(args->taglen);
- resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE;
- resp->taglen = args->taglen;
- resp->tag = args->tag;
- resp->opcnt = 0;
- resp->rqstp = rqstp;
- resp->cstate.minorversion = args->minorversion;
- resp->cstate.replay_owner = NULL;
- resp->cstate.session = NULL;
- fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
- fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
- /*
- * Don't use the deferral mechanism for NFSv4; compounds make it
- * too hard to avoid non-idempotency problems.
- */
- rqstp->rq_usedeferral = 0;
-
- /*
- * According to RFC3010, this takes precedence over all other errors.
- */
- status = nfserr_minor_vers_mismatch;
- if (args->minorversion > nfsd_supported_minorversion)
- goto out;
-
- status = nfs41_check_op_ordering(args);
- if (status) {
- op = &args->ops[0];
- op->status = status;
- goto encode_op;
- }
-
- while (!status && resp->opcnt < args->opcnt) {
- op = &args->ops[resp->opcnt++];
-
- dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
- resp->opcnt, args->opcnt, op->opnum,
- nfsd4_op_name(op->opnum));
- /*
- * The XDR decode routines may have pre-set op->status;
- * for example, if there is a miscellaneous XDR error
- * it will be set to nfserr_bad_xdr.
- */
- if (op->status)
- goto encode_op;
-
- /* We must be able to encode a successful response to
- * this operation, with enough room left over to encode a
- * failed response to the next operation. If we don't
- * have enough room, fail with ERR_RESOURCE.
- */
- slack_bytes = (char *)resp->end - (char *)resp->p;
- if (slack_bytes < COMPOUND_SLACK_SPACE
- + COMPOUND_ERR_SLACK_SPACE) {
- BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE);
- op->status = nfserr_resource;
- goto encode_op;
- }
-
- opdesc = OPDESC(op);
-
- if (!cstate->current_fh.fh_dentry) {
- if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
- op->status = nfserr_nofilehandle;
- goto encode_op;
- }
- } else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
- !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
- op->status = nfserr_moved;
- goto encode_op;
- }
-
- /* If op is non-idempotent */
- if (opdesc->op_flags & OP_MODIFIES_SOMETHING) {
- plen = opdesc->op_rsize_bop(rqstp, op);
- op->status = nfsd4_check_resp_size(resp, plen);
- }
-
- if (op->status)
- goto encode_op;
-
- if (opdesc->op_func) {
- if (opdesc->op_get_currentstateid)
- opdesc->op_get_currentstateid(cstate, &op->u);
- op->status = opdesc->op_func(rqstp, cstate, &op->u);
- } else
- BUG_ON(op->status == nfs_ok);
-
- if (!op->status) {
- if (opdesc->op_set_currentstateid)
- opdesc->op_set_currentstateid(cstate, &op->u);
-
- if (opdesc->op_flags & OP_CLEAR_STATEID)
- clear_current_stateid(cstate);
-
- if (need_wrongsec_check(rqstp))
- op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
- }
-
-encode_op:
- /* Only from SEQUENCE */
- if (resp->cstate.status == nfserr_replay_cache) {
- dprintk("%s NFS4.1 replay from cache\n", __func__);
- status = op->status;
- goto out;
- }
- if (op->status == nfserr_replay_me) {
- op->replay = &cstate->replay_owner->so_replay;
- nfsd4_encode_replay(resp, op);
- status = op->status = op->replay->rp_status;
- } else {
- nfsd4_encode_operation(resp, op);
- status = op->status;
- }
-
- dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n",
- args->ops, args->opcnt, resp->opcnt, op->opnum,
- be32_to_cpu(status));
-
- if (cstate->replay_owner) {
- nfs4_unlock_state();
- cstate->replay_owner = NULL;
- }
- /* XXX Ugh, we need to get rid of this kind of special case: */
- if (op->opnum == OP_READ && op->u.read.rd_filp)
- fput(op->u.read.rd_filp);
-
- nfsd4_increment_op_stats(op->opnum);
- }
-
- resp->cstate.status = status;
- fh_put(&resp->cstate.current_fh);
- fh_put(&resp->cstate.save_fh);
- BUG_ON(resp->cstate.replay_owner);
-out:
- /* Reset deferral mechanism for RPC deferrals */
- rqstp->rq_usedeferral = 1;
- dprintk("nfsv4 compound returned %d\n", ntohl(status));
- return status;
-}
-
-#define op_encode_hdr_size (2)
-#define op_encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE))
-#define op_encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE))
-#define op_encode_change_info_maxsz (5)
-#define nfs4_fattr_bitmap_maxsz (4)
-
-#define op_encode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
-#define op_encode_lock_denied_maxsz (8 + op_encode_lockowner_maxsz)
-
-#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
-
-#define op_encode_ace_maxsz (3 + nfs4_owner_maxsz)
-#define op_encode_delegation_maxsz (1 + op_encode_stateid_maxsz + 1 + \
- op_encode_ace_maxsz)
-
-#define op_encode_channel_attrs_maxsz (6 + 1 + 1)
-
-static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32);
-}
-
-static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_change_info_maxsz
- + nfs4_fattr_bitmap_maxsz) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_change_info_maxsz)
- * sizeof(__be32);
-}
-
-static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_lock_denied_maxsz)
- * sizeof(__be32);
-}
-
-static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_stateid_maxsz
- + op_encode_change_info_maxsz + 1
- + nfs4_fattr_bitmap_maxsz
- + op_encode_delegation_maxsz) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- u32 maxcount = 0, rlen = 0;
-
- maxcount = svc_max_payload(rqstp);
- rlen = op->u.read.rd_length;
-
- if (rlen > maxcount)
- rlen = maxcount;
-
- return (op_encode_hdr_size + 2) * sizeof(__be32) + rlen;
-}
-
-static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- u32 rlen = op->u.readdir.rd_maxcount;
-
- if (rlen > PAGE_SIZE)
- rlen = PAGE_SIZE;
-
- return (op_encode_hdr_size + op_encode_verifier_maxsz)
- * sizeof(__be32) + rlen;
-}
-
-static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_change_info_maxsz)
- * sizeof(__be32);
-}
-
-static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_change_info_maxsz
- + op_encode_change_info_maxsz) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\
- 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\
- 2 + /*eir_server_owner.so_minor_id */\
- /* eir_server_owner.so_major_id<> */\
- XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
- /* eir_server_scope<> */\
- XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
- 1 + /* eir_server_impl_id array length */\
- 0 /* ignored eir_server_impl_id contents */) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + \
- XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\
- 2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32);
-}
-
-static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
-{
- return (op_encode_hdr_size + \
- XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\
- 2 + /* csr_sequence, csr_flags */\
- op_encode_channel_attrs_maxsz + \
- op_encode_channel_attrs_maxsz) * sizeof(__be32);
-}
-
-static struct nfsd4_operation nfsd4_ops[] = {
- [OP_ACCESS] = {
- .op_func = (nfsd4op_func)nfsd4_access,
- .op_name = "OP_ACCESS",
- },
- [OP_CLOSE] = {
- .op_func = (nfsd4op_func)nfsd4_close,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_CLOSE",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
- .op_get_currentstateid = (stateid_getter)nfsd4_get_closestateid,
- .op_set_currentstateid = (stateid_setter)nfsd4_set_closestateid,
- },
- [OP_COMMIT] = {
- .op_func = (nfsd4op_func)nfsd4_commit,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_COMMIT",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_commit_rsize,
- },
- [OP_CREATE] = {
- .op_func = (nfsd4op_func)nfsd4_create,
- .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID,
- .op_name = "OP_CREATE",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize,
- },
- [OP_DELEGRETURN] = {
- .op_func = (nfsd4op_func)nfsd4_delegreturn,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_DELEGRETURN",
- .op_rsize_bop = nfsd4_only_status_rsize,
- .op_get_currentstateid = (stateid_getter)nfsd4_get_delegreturnstateid,
- },
- [OP_GETATTR] = {
- .op_func = (nfsd4op_func)nfsd4_getattr,
- .op_flags = ALLOWED_ON_ABSENT_FS,
- .op_name = "OP_GETATTR",
- },
- [OP_GETFH] = {
- .op_func = (nfsd4op_func)nfsd4_getfh,
- .op_name = "OP_GETFH",
- },
- [OP_LINK] = {
- .op_func = (nfsd4op_func)nfsd4_link,
- .op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING
- | OP_CACHEME,
- .op_name = "OP_LINK",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_link_rsize,
- },
- [OP_LOCK] = {
- .op_func = (nfsd4op_func)nfsd4_lock,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_LOCK",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize,
- .op_set_currentstateid = (stateid_setter)nfsd4_set_lockstateid,
- },
- [OP_LOCKT] = {
- .op_func = (nfsd4op_func)nfsd4_lockt,
- .op_name = "OP_LOCKT",
- },
- [OP_LOCKU] = {
- .op_func = (nfsd4op_func)nfsd4_locku,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_LOCKU",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
- .op_get_currentstateid = (stateid_getter)nfsd4_get_lockustateid,
- },
- [OP_LOOKUP] = {
- .op_func = (nfsd4op_func)nfsd4_lookup,
- .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
- .op_name = "OP_LOOKUP",
- },
- [OP_LOOKUPP] = {
- .op_func = (nfsd4op_func)nfsd4_lookupp,
- .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
- .op_name = "OP_LOOKUPP",
- },
- [OP_NVERIFY] = {
- .op_func = (nfsd4op_func)nfsd4_nverify,
- .op_name = "OP_NVERIFY",
- },
- [OP_OPEN] = {
- .op_func = (nfsd4op_func)nfsd4_open,
- .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
- .op_name = "OP_OPEN",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize,
- .op_set_currentstateid = (stateid_setter)nfsd4_set_openstateid,
- },
- [OP_OPEN_CONFIRM] = {
- .op_func = (nfsd4op_func)nfsd4_open_confirm,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_OPEN_CONFIRM",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
- },
- [OP_OPEN_DOWNGRADE] = {
- .op_func = (nfsd4op_func)nfsd4_open_downgrade,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_OPEN_DOWNGRADE",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize,
- .op_get_currentstateid = (stateid_getter)nfsd4_get_opendowngradestateid,
- .op_set_currentstateid = (stateid_setter)nfsd4_set_opendowngradestateid,
- },
- [OP_PUTFH] = {
- .op_func = (nfsd4op_func)nfsd4_putfh,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
- | OP_CLEAR_STATEID,
- .op_name = "OP_PUTFH",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_PUTPUBFH] = {
- .op_func = (nfsd4op_func)nfsd4_putrootfh,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
- | OP_CLEAR_STATEID,
- .op_name = "OP_PUTPUBFH",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_PUTROOTFH] = {
- .op_func = (nfsd4op_func)nfsd4_putrootfh,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING
- | OP_CLEAR_STATEID,
- .op_name = "OP_PUTROOTFH",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_READ] = {
- .op_func = (nfsd4op_func)nfsd4_read,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_READ",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize,
- .op_get_currentstateid = (stateid_getter)nfsd4_get_readstateid,
- },
- [OP_READDIR] = {
- .op_func = (nfsd4op_func)nfsd4_readdir,
- .op_flags = OP_MODIFIES_SOMETHING,
- .op_name = "OP_READDIR",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_readdir_rsize,
- },
- [OP_READLINK] = {
- .op_func = (nfsd4op_func)nfsd4_readlink,
- .op_name = "OP_READLINK",
- },
- [OP_REMOVE] = {
- .op_func = (nfsd4op_func)nfsd4_remove,
- .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
- .op_name = "OP_REMOVE",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_remove_rsize,
- },
- [OP_RENAME] = {
- .op_func = (nfsd4op_func)nfsd4_rename,
- .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
- .op_name = "OP_RENAME",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_rename_rsize,
- },
- [OP_RENEW] = {
- .op_func = (nfsd4op_func)nfsd4_renew,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_MODIFIES_SOMETHING,
- .op_name = "OP_RENEW",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
-
- },
- [OP_RESTOREFH] = {
- .op_func = (nfsd4op_func)nfsd4_restorefh,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
- .op_name = "OP_RESTOREFH",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_SAVEFH] = {
- .op_func = (nfsd4op_func)nfsd4_savefh,
- .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
- .op_name = "OP_SAVEFH",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_SECINFO] = {
- .op_func = (nfsd4op_func)nfsd4_secinfo,
- .op_flags = OP_HANDLES_WRONGSEC,
- .op_name = "OP_SECINFO",
- },
- [OP_SETATTR] = {
- .op_func = (nfsd4op_func)nfsd4_setattr,
- .op_name = "OP_SETATTR",
- .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize,
- .op_get_currentstateid = (stateid_getter)nfsd4_get_setattrstateid,
- },
- [OP_SETCLIENTID] = {
- .op_func = (nfsd4op_func)nfsd4_setclientid,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_MODIFIES_SOMETHING | OP_CACHEME,
- .op_name = "OP_SETCLIENTID",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_setclientid_rsize,
- },
- [OP_SETCLIENTID_CONFIRM] = {
- .op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_MODIFIES_SOMETHING | OP_CACHEME,
- .op_name = "OP_SETCLIENTID_CONFIRM",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_VERIFY] = {
- .op_func = (nfsd4op_func)nfsd4_verify,
- .op_name = "OP_VERIFY",
- },
- [OP_WRITE] = {
- .op_func = (nfsd4op_func)nfsd4_write,
- .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
- .op_name = "OP_WRITE",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize,
- .op_get_currentstateid = (stateid_getter)nfsd4_get_writestateid,
- },
- [OP_RELEASE_LOCKOWNER] = {
- .op_func = (nfsd4op_func)nfsd4_release_lockowner,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
- | OP_MODIFIES_SOMETHING,
- .op_name = "OP_RELEASE_LOCKOWNER",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
-
- /* NFSv4.1 operations */
- [OP_EXCHANGE_ID] = {
- .op_func = (nfsd4op_func)nfsd4_exchange_id,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
- | OP_MODIFIES_SOMETHING,
- .op_name = "OP_EXCHANGE_ID",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize,
- },
- [OP_BIND_CONN_TO_SESSION] = {
- .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
- | OP_MODIFIES_SOMETHING,
- .op_name = "OP_BIND_CONN_TO_SESSION",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_bind_conn_to_session_rsize,
- },
- [OP_CREATE_SESSION] = {
- .op_func = (nfsd4op_func)nfsd4_create_session,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
- | OP_MODIFIES_SOMETHING,
- .op_name = "OP_CREATE_SESSION",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_session_rsize,
- },
- [OP_DESTROY_SESSION] = {
- .op_func = (nfsd4op_func)nfsd4_destroy_session,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
- | OP_MODIFIES_SOMETHING,
- .op_name = "OP_DESTROY_SESSION",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_SEQUENCE] = {
- .op_func = (nfsd4op_func)nfsd4_sequence,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
- .op_name = "OP_SEQUENCE",
- },
- [OP_DESTROY_CLIENTID] = {
- .op_func = (nfsd4op_func)nfsd4_destroy_clientid,
- .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
- | OP_MODIFIES_SOMETHING,
- .op_name = "OP_DESTROY_CLIENTID",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_RECLAIM_COMPLETE] = {
- .op_func = (nfsd4op_func)nfsd4_reclaim_complete,
- .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
- .op_name = "OP_RECLAIM_COMPLETE",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
- [OP_SECINFO_NO_NAME] = {
- .op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
- .op_flags = OP_HANDLES_WRONGSEC,
- .op_name = "OP_SECINFO_NO_NAME",
- },
- [OP_TEST_STATEID] = {
- .op_func = (nfsd4op_func)nfsd4_test_stateid,
- .op_flags = ALLOWED_WITHOUT_FH,
- .op_name = "OP_TEST_STATEID",
- },
- [OP_FREE_STATEID] = {
- .op_func = (nfsd4op_func)nfsd4_free_stateid,
- .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
- .op_name = "OP_FREE_STATEID",
- .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
- },
-};
-
-#ifdef NFSD_DEBUG
-static const char *nfsd4_op_name(unsigned opnum)
-{
- if (opnum < ARRAY_SIZE(nfsd4_ops))
- return nfsd4_ops[opnum].op_name;
- return "unknown_operation";
-}
-#endif
-
-#define nfsd4_voidres nfsd4_voidargs
-struct nfsd4_voidargs { int dummy; };
-
-static struct svc_procedure nfsd_procedures4[2] = {
- [NFSPROC4_NULL] = {
- .pc_func = (svc_procfunc) nfsd4_proc_null,
- .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres,
- .pc_argsize = sizeof(struct nfsd4_voidargs),
- .pc_ressize = sizeof(struct nfsd4_voidres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = 1,
- },
- [NFSPROC4_COMPOUND] = {
- .pc_func = (svc_procfunc) nfsd4_proc_compound,
- .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs,
- .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres,
- .pc_argsize = sizeof(struct nfsd4_compoundargs),
- .pc_ressize = sizeof(struct nfsd4_compoundres),
- .pc_release = nfsd4_release_compoundargs,
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = NFSD_BUFSIZE/4,
- },
-};
-
-struct svc_version nfsd_version4 = {
- .vs_vers = 4,
- .vs_nproc = 2,
- .vs_proc = nfsd_procedures4,
- .vs_dispatch = nfsd_dispatch,
- .vs_xdrsize = NFS4_SVC_XDRSIZE,
-};
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs4recover.c b/ANDROID_3.4.5/fs/nfsd/nfs4recover.c
deleted file mode 100644
index ed3f9206..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs4recover.c
+++ /dev/null
@@ -1,1046 +0,0 @@
-/*
-* Copyright (c) 2004 The Regents of the University of Michigan.
-* Copyright (c) 2012 Jeff Layton <jlayton@redhat.com>
-* All rights reserved.
-*
-* Andy Adamson <andros@citi.umich.edu>
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions
-* are met:
-*
-* 1. Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* 2. Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-* 3. Neither the name of the University nor the names of its
-* contributors may be used to endorse or promote products derived
-* from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*
-*/
-
-#include <linux/file.h>
-#include <linux/slab.h>
-#include <linux/namei.h>
-#include <linux/crypto.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <net/net_namespace.h>
-#include <linux/sunrpc/rpc_pipe_fs.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/nfsd/cld.h>
-
-#include "nfsd.h"
-#include "state.h"
-#include "vfs.h"
-#include "netns.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_PROC
-
-/* Declarations */
-struct nfsd4_client_tracking_ops {
- int (*init)(struct net *);
- void (*exit)(struct net *);
- void (*create)(struct nfs4_client *);
- void (*remove)(struct nfs4_client *);
- int (*check)(struct nfs4_client *);
- void (*grace_done)(struct net *, time_t);
-};
-
-/* Globals */
-static struct file *rec_file;
-static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
-static struct nfsd4_client_tracking_ops *client_tracking_ops;
-
-static int
-nfs4_save_creds(const struct cred **original_creds)
-{
- struct cred *new;
-
- new = prepare_creds();
- if (!new)
- return -ENOMEM;
-
- new->fsuid = 0;
- new->fsgid = 0;
- *original_creds = override_creds(new);
- put_cred(new);
- return 0;
-}
-
-static void
-nfs4_reset_creds(const struct cred *original)
-{
- revert_creds(original);
-}
-
-static void
-md5_to_hex(char *out, char *md5)
-{
- int i;
-
- for (i=0; i<16; i++) {
- unsigned char c = md5[i];
-
- *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
- *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
- }
- *out = '\0';
-}
-
-__be32
-nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
-{
- struct xdr_netobj cksum;
- struct hash_desc desc;
- struct scatterlist sg;
- __be32 status = nfserr_jukebox;
-
- dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
- clname->len, clname->data);
- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(desc.tfm))
- goto out_no_tfm;
- cksum.len = crypto_hash_digestsize(desc.tfm);
- cksum.data = kmalloc(cksum.len, GFP_KERNEL);
- if (cksum.data == NULL)
- goto out;
-
- sg_init_one(&sg, clname->data, clname->len);
-
- if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data))
- goto out;
-
- md5_to_hex(dname, cksum.data);
-
- status = nfs_ok;
-out:
- kfree(cksum.data);
- crypto_free_hash(desc.tfm);
-out_no_tfm:
- return status;
-}
-
-static void
-nfsd4_create_clid_dir(struct nfs4_client *clp)
-{
- const struct cred *original_cred;
- char *dname = clp->cl_recdir;
- struct dentry *dir, *dentry;
- int status;
-
- dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
-
- if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
- return;
- if (!rec_file)
- return;
- status = nfs4_save_creds(&original_cred);
- if (status < 0)
- return;
-
- dir = rec_file->f_path.dentry;
- /* lock the parent */
- mutex_lock(&dir->d_inode->i_mutex);
-
- dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1);
- if (IS_ERR(dentry)) {
- status = PTR_ERR(dentry);
- goto out_unlock;
- }
- if (dentry->d_inode)
- /*
- * In the 4.1 case, where we're called from
- * reclaim_complete(), records from the previous reboot
- * may still be left, so this is OK.
- *
- * In the 4.0 case, we should never get here; but we may
- * as well be forgiving and just succeed silently.
- */
- goto out_put;
- status = mnt_want_write_file(rec_file);
- if (status)
- goto out_put;
- status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU);
- mnt_drop_write_file(rec_file);
-out_put:
- dput(dentry);
-out_unlock:
- mutex_unlock(&dir->d_inode->i_mutex);
- if (status == 0)
- vfs_fsync(rec_file, 0);
- else
- printk(KERN_ERR "NFSD: failed to write recovery record"
- " (err %d); please check that %s exists"
- " and is writeable", status,
- user_recovery_dirname);
- nfs4_reset_creds(original_cred);
-}
-
-typedef int (recdir_func)(struct dentry *, struct dentry *);
-
-struct name_list {
- char name[HEXDIR_LEN];
- struct list_head list;
-};
-
-static int
-nfsd4_build_namelist(void *arg, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type)
-{
- struct list_head *names = arg;
- struct name_list *entry;
-
- if (namlen != HEXDIR_LEN - 1)
- return 0;
- entry = kmalloc(sizeof(struct name_list), GFP_KERNEL);
- if (entry == NULL)
- return -ENOMEM;
- memcpy(entry->name, name, HEXDIR_LEN - 1);
- entry->name[HEXDIR_LEN - 1] = '\0';
- list_add(&entry->list, names);
- return 0;
-}
-
-static int
-nfsd4_list_rec_dir(recdir_func *f)
-{
- const struct cred *original_cred;
- struct dentry *dir = rec_file->f_path.dentry;
- LIST_HEAD(names);
- int status;
-
- status = nfs4_save_creds(&original_cred);
- if (status < 0)
- return status;
-
- status = vfs_llseek(rec_file, 0, SEEK_SET);
- if (status < 0) {
- nfs4_reset_creds(original_cred);
- return status;
- }
-
- status = vfs_readdir(rec_file, nfsd4_build_namelist, &names);
- mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
- while (!list_empty(&names)) {
- struct name_list *entry;
- entry = list_entry(names.next, struct name_list, list);
- if (!status) {
- struct dentry *dentry;
- dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
- if (IS_ERR(dentry)) {
- status = PTR_ERR(dentry);
- break;
- }
- status = f(dir, dentry);
- dput(dentry);
- }
- list_del(&entry->list);
- kfree(entry);
- }
- mutex_unlock(&dir->d_inode->i_mutex);
- nfs4_reset_creds(original_cred);
- return status;
-}
-
-static int
-nfsd4_unlink_clid_dir(char *name, int namlen)
-{
- struct dentry *dir, *dentry;
- int status;
-
- dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
-
- dir = rec_file->f_path.dentry;
- mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
- dentry = lookup_one_len(name, dir, namlen);
- if (IS_ERR(dentry)) {
- status = PTR_ERR(dentry);
- goto out_unlock;
- }
- status = -ENOENT;
- if (!dentry->d_inode)
- goto out;
- status = vfs_rmdir(dir->d_inode, dentry);
-out:
- dput(dentry);
-out_unlock:
- mutex_unlock(&dir->d_inode->i_mutex);
- return status;
-}
-
-static void
-nfsd4_remove_clid_dir(struct nfs4_client *clp)
-{
- const struct cred *original_cred;
- int status;
-
- if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
- return;
-
- status = mnt_want_write_file(rec_file);
- if (status)
- goto out;
- clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
-
- status = nfs4_save_creds(&original_cred);
- if (status < 0)
- goto out;
-
- status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
- nfs4_reset_creds(original_cred);
- if (status == 0)
- vfs_fsync(rec_file, 0);
- mnt_drop_write_file(rec_file);
-out:
- if (status)
- printk("NFSD: Failed to remove expired client state directory"
- " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
-}
-
-static int
-purge_old(struct dentry *parent, struct dentry *child)
-{
- int status;
-
- if (nfs4_has_reclaimed_state(child->d_name.name, false))
- return 0;
-
- status = vfs_rmdir(parent->d_inode, child);
- if (status)
- printk("failed to remove client recovery directory %s\n",
- child->d_name.name);
- /* Keep trying, success or failure: */
- return 0;
-}
-
-static void
-nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
-{
- int status;
-
- if (!rec_file)
- return;
- status = mnt_want_write_file(rec_file);
- if (status)
- goto out;
- status = nfsd4_list_rec_dir(purge_old);
- if (status == 0)
- vfs_fsync(rec_file, 0);
- mnt_drop_write_file(rec_file);
-out:
- if (status)
- printk("nfsd4: failed to purge old clients from recovery"
- " directory %s\n", rec_file->f_path.dentry->d_name.name);
-}
-
-static int
-load_recdir(struct dentry *parent, struct dentry *child)
-{
- if (child->d_name.len != HEXDIR_LEN - 1) {
- printk("nfsd4: illegal name %s in recovery directory\n",
- child->d_name.name);
- /* Keep trying; maybe the others are OK: */
- return 0;
- }
- nfs4_client_to_reclaim(child->d_name.name);
- return 0;
-}
-
-static int
-nfsd4_recdir_load(void) {
- int status;
-
- if (!rec_file)
- return 0;
-
- status = nfsd4_list_rec_dir(load_recdir);
- if (status)
- printk("nfsd4: failed loading clients from recovery"
- " directory %s\n", rec_file->f_path.dentry->d_name.name);
- return status;
-}
-
-/*
- * Hold reference to the recovery directory.
- */
-
-static int
-nfsd4_init_recdir(void)
-{
- const struct cred *original_cred;
- int status;
-
- printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
- user_recovery_dirname);
-
- BUG_ON(rec_file);
-
- status = nfs4_save_creds(&original_cred);
- if (status < 0) {
- printk("NFSD: Unable to change credentials to find recovery"
- " directory: error %d\n",
- status);
- return status;
- }
-
- rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
- if (IS_ERR(rec_file)) {
- printk("NFSD: unable to find recovery directory %s\n",
- user_recovery_dirname);
- status = PTR_ERR(rec_file);
- rec_file = NULL;
- }
-
- nfs4_reset_creds(original_cred);
- return status;
-}
-
-static int
-nfsd4_load_reboot_recovery_data(struct net *net)
-{
- int status;
-
- /* XXX: The legacy code won't work in a container */
- if (net != &init_net) {
- WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client "
- "tracking in a container!\n");
- return -EINVAL;
- }
-
- nfs4_lock_state();
- status = nfsd4_init_recdir();
- if (!status)
- status = nfsd4_recdir_load();
- nfs4_unlock_state();
- if (status)
- printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n");
- return status;
-}
-
-static void
-nfsd4_shutdown_recdir(void)
-{
- if (!rec_file)
- return;
- fput(rec_file);
- rec_file = NULL;
-}
-
-static void
-nfsd4_legacy_tracking_exit(struct net *net)
-{
- nfs4_release_reclaim();
- nfsd4_shutdown_recdir();
-}
-
-/*
- * Change the NFSv4 recovery directory to recdir.
- */
-int
-nfs4_reset_recoverydir(char *recdir)
-{
- int status;
- struct path path;
-
- status = kern_path(recdir, LOOKUP_FOLLOW, &path);
- if (status)
- return status;
- status = -ENOTDIR;
- if (S_ISDIR(path.dentry->d_inode->i_mode)) {
- strcpy(user_recovery_dirname, recdir);
- status = 0;
- }
- path_put(&path);
- return status;
-}
-
-char *
-nfs4_recoverydir(void)
-{
- return user_recovery_dirname;
-}
-
-static int
-nfsd4_check_legacy_client(struct nfs4_client *clp)
-{
- /* did we already find that this client is stable? */
- if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
- return 0;
-
- /* look for it in the reclaim hashtable otherwise */
- if (nfsd4_find_reclaim_client(clp)) {
- set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
- return 0;
- }
-
- return -ENOENT;
-}
-
-static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
- .init = nfsd4_load_reboot_recovery_data,
- .exit = nfsd4_legacy_tracking_exit,
- .create = nfsd4_create_clid_dir,
- .remove = nfsd4_remove_clid_dir,
- .check = nfsd4_check_legacy_client,
- .grace_done = nfsd4_recdir_purge_old,
-};
-
-/* Globals */
-#define NFSD_PIPE_DIR "nfsd"
-#define NFSD_CLD_PIPE "cld"
-
-/* per-net-ns structure for holding cld upcall info */
-struct cld_net {
- struct rpc_pipe *cn_pipe;
- spinlock_t cn_lock;
- struct list_head cn_list;
- unsigned int cn_xid;
-};
-
-struct cld_upcall {
- struct list_head cu_list;
- struct cld_net *cu_net;
- struct task_struct *cu_task;
- struct cld_msg cu_msg;
-};
-
-static int
-__cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
-{
- int ret;
- struct rpc_pipe_msg msg;
-
- memset(&msg, 0, sizeof(msg));
- msg.data = cmsg;
- msg.len = sizeof(*cmsg);
-
- /*
- * Set task state before we queue the upcall. That prevents
- * wake_up_process in the downcall from racing with schedule.
- */
- set_current_state(TASK_UNINTERRUPTIBLE);
- ret = rpc_queue_upcall(pipe, &msg);
- if (ret < 0) {
- set_current_state(TASK_RUNNING);
- goto out;
- }
-
- schedule();
- set_current_state(TASK_RUNNING);
-
- if (msg.errno < 0)
- ret = msg.errno;
-out:
- return ret;
-}
-
-static int
-cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
-{
- int ret;
-
- /*
- * -EAGAIN occurs when pipe is closed and reopened while there are
- * upcalls queued.
- */
- do {
- ret = __cld_pipe_upcall(pipe, cmsg);
- } while (ret == -EAGAIN);
-
- return ret;
-}
-
-static ssize_t
-cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
-{
- struct cld_upcall *tmp, *cup;
- struct cld_msg *cmsg = (struct cld_msg *)src;
- uint32_t xid;
- struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
- nfsd_net_id);
- struct cld_net *cn = nn->cld_net;
-
- if (mlen != sizeof(*cmsg)) {
- dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen,
- sizeof(*cmsg));
- return -EINVAL;
- }
-
- /* copy just the xid so we can try to find that */
- if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) {
- dprintk("%s: error when copying xid from userspace", __func__);
- return -EFAULT;
- }
-
- /* walk the list and find corresponding xid */
- cup = NULL;
- spin_lock(&cn->cn_lock);
- list_for_each_entry(tmp, &cn->cn_list, cu_list) {
- if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) {
- cup = tmp;
- list_del_init(&cup->cu_list);
- break;
- }
- }
- spin_unlock(&cn->cn_lock);
-
- /* couldn't find upcall? */
- if (!cup) {
- dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid);
- return -EINVAL;
- }
-
- if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
- return -EFAULT;
-
- wake_up_process(cup->cu_task);
- return mlen;
-}
-
-static void
-cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
-{
- struct cld_msg *cmsg = msg->data;
- struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
- cu_msg);
-
- /* errno >= 0 means we got a downcall */
- if (msg->errno >= 0)
- return;
-
- wake_up_process(cup->cu_task);
-}
-
-static const struct rpc_pipe_ops cld_upcall_ops = {
- .upcall = rpc_pipe_generic_upcall,
- .downcall = cld_pipe_downcall,
- .destroy_msg = cld_pipe_destroy_msg,
-};
-
-static struct dentry *
-nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
-{
- struct dentry *dir, *dentry;
-
- dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR);
- if (dir == NULL)
- return ERR_PTR(-ENOENT);
- dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
- dput(dir);
- return dentry;
-}
-
-static void
-nfsd4_cld_unregister_sb(struct rpc_pipe *pipe)
-{
- if (pipe->dentry)
- rpc_unlink(pipe->dentry);
-}
-
-static struct dentry *
-nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
-{
- struct super_block *sb;
- struct dentry *dentry;
-
- sb = rpc_get_sb_net(net);
- if (!sb)
- return NULL;
- dentry = nfsd4_cld_register_sb(sb, pipe);
- rpc_put_sb_net(net);
- return dentry;
-}
-
-static void
-nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
-{
- struct super_block *sb;
-
- sb = rpc_get_sb_net(net);
- if (sb) {
- nfsd4_cld_unregister_sb(pipe);
- rpc_put_sb_net(net);
- }
-}
-
-/* Initialize rpc_pipefs pipe for communication with client tracking daemon */
-static int
-nfsd4_init_cld_pipe(struct net *net)
-{
- int ret;
- struct dentry *dentry;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- struct cld_net *cn;
-
- if (nn->cld_net)
- return 0;
-
- cn = kzalloc(sizeof(*cn), GFP_KERNEL);
- if (!cn) {
- ret = -ENOMEM;
- goto err;
- }
-
- cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
- if (IS_ERR(cn->cn_pipe)) {
- ret = PTR_ERR(cn->cn_pipe);
- goto err;
- }
- spin_lock_init(&cn->cn_lock);
- INIT_LIST_HEAD(&cn->cn_list);
-
- dentry = nfsd4_cld_register_net(net, cn->cn_pipe);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto err_destroy_data;
- }
-
- cn->cn_pipe->dentry = dentry;
- nn->cld_net = cn;
- return 0;
-
-err_destroy_data:
- rpc_destroy_pipe_data(cn->cn_pipe);
-err:
- kfree(cn);
- printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n",
- ret);
- return ret;
-}
-
-static void
-nfsd4_remove_cld_pipe(struct net *net)
-{
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- struct cld_net *cn = nn->cld_net;
-
- nfsd4_cld_unregister_net(net, cn->cn_pipe);
- rpc_destroy_pipe_data(cn->cn_pipe);
- kfree(nn->cld_net);
- nn->cld_net = NULL;
-}
-
-static struct cld_upcall *
-alloc_cld_upcall(struct cld_net *cn)
-{
- struct cld_upcall *new, *tmp;
-
- new = kzalloc(sizeof(*new), GFP_KERNEL);
- if (!new)
- return new;
-
- /* FIXME: hard cap on number in flight? */
-restart_search:
- spin_lock(&cn->cn_lock);
- list_for_each_entry(tmp, &cn->cn_list, cu_list) {
- if (tmp->cu_msg.cm_xid == cn->cn_xid) {
- cn->cn_xid++;
- spin_unlock(&cn->cn_lock);
- goto restart_search;
- }
- }
- new->cu_task = current;
- new->cu_msg.cm_vers = CLD_UPCALL_VERSION;
- put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid);
- new->cu_net = cn;
- list_add(&new->cu_list, &cn->cn_list);
- spin_unlock(&cn->cn_lock);
-
- dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid);
-
- return new;
-}
-
-static void
-free_cld_upcall(struct cld_upcall *victim)
-{
- struct cld_net *cn = victim->cu_net;
-
- spin_lock(&cn->cn_lock);
- list_del(&victim->cu_list);
- spin_unlock(&cn->cn_lock);
- kfree(victim);
-}
-
-/* Ask daemon to create a new record */
-static void
-nfsd4_cld_create(struct nfs4_client *clp)
-{
- int ret;
- struct cld_upcall *cup;
- /* FIXME: determine net from clp */
- struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
- struct cld_net *cn = nn->cld_net;
-
- /* Don't upcall if it's already stored */
- if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
- return;
-
- cup = alloc_cld_upcall(cn);
- if (!cup) {
- ret = -ENOMEM;
- goto out_err;
- }
-
- cup->cu_msg.cm_cmd = Cld_Create;
- cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
- memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
- clp->cl_name.len);
-
- ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
- if (!ret) {
- ret = cup->cu_msg.cm_status;
- set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
- }
-
- free_cld_upcall(cup);
-out_err:
- if (ret)
- printk(KERN_ERR "NFSD: Unable to create client "
- "record on stable storage: %d\n", ret);
-}
-
-/* Ask daemon to create a new record */
-static void
-nfsd4_cld_remove(struct nfs4_client *clp)
-{
- int ret;
- struct cld_upcall *cup;
- /* FIXME: determine net from clp */
- struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
- struct cld_net *cn = nn->cld_net;
-
- /* Don't upcall if it's already removed */
- if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
- return;
-
- cup = alloc_cld_upcall(cn);
- if (!cup) {
- ret = -ENOMEM;
- goto out_err;
- }
-
- cup->cu_msg.cm_cmd = Cld_Remove;
- cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
- memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
- clp->cl_name.len);
-
- ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
- if (!ret) {
- ret = cup->cu_msg.cm_status;
- clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
- }
-
- free_cld_upcall(cup);
-out_err:
- if (ret)
- printk(KERN_ERR "NFSD: Unable to remove client "
- "record from stable storage: %d\n", ret);
-}
-
-/* Check for presence of a record, and update its timestamp */
-static int
-nfsd4_cld_check(struct nfs4_client *clp)
-{
- int ret;
- struct cld_upcall *cup;
- /* FIXME: determine net from clp */
- struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
- struct cld_net *cn = nn->cld_net;
-
- /* Don't upcall if one was already stored during this grace pd */
- if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
- return 0;
-
- cup = alloc_cld_upcall(cn);
- if (!cup) {
- printk(KERN_ERR "NFSD: Unable to check client record on "
- "stable storage: %d\n", -ENOMEM);
- return -ENOMEM;
- }
-
- cup->cu_msg.cm_cmd = Cld_Check;
- cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
- memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
- clp->cl_name.len);
-
- ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
- if (!ret) {
- ret = cup->cu_msg.cm_status;
- set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
- }
-
- free_cld_upcall(cup);
- return ret;
-}
-
-static void
-nfsd4_cld_grace_done(struct net *net, time_t boot_time)
-{
- int ret;
- struct cld_upcall *cup;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- struct cld_net *cn = nn->cld_net;
-
- cup = alloc_cld_upcall(cn);
- if (!cup) {
- ret = -ENOMEM;
- goto out_err;
- }
-
- cup->cu_msg.cm_cmd = Cld_GraceDone;
- cup->cu_msg.cm_u.cm_gracetime = (int64_t)boot_time;
- ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
- if (!ret)
- ret = cup->cu_msg.cm_status;
-
- free_cld_upcall(cup);
-out_err:
- if (ret)
- printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
-}
-
-static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
- .init = nfsd4_init_cld_pipe,
- .exit = nfsd4_remove_cld_pipe,
- .create = nfsd4_cld_create,
- .remove = nfsd4_cld_remove,
- .check = nfsd4_cld_check,
- .grace_done = nfsd4_cld_grace_done,
-};
-
-int
-nfsd4_client_tracking_init(struct net *net)
-{
- int status;
- struct path path;
-
- if (!client_tracking_ops) {
- client_tracking_ops = &nfsd4_cld_tracking_ops;
- status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
- if (!status) {
- if (S_ISDIR(path.dentry->d_inode->i_mode))
- client_tracking_ops =
- &nfsd4_legacy_tracking_ops;
- path_put(&path);
- }
- }
-
- status = client_tracking_ops->init(net);
- if (status) {
- printk(KERN_WARNING "NFSD: Unable to initialize client "
- "recovery tracking! (%d)\n", status);
- client_tracking_ops = NULL;
- }
- return status;
-}
-
-void
-nfsd4_client_tracking_exit(struct net *net)
-{
- if (client_tracking_ops) {
- client_tracking_ops->exit(net);
- client_tracking_ops = NULL;
- }
-}
-
-void
-nfsd4_client_record_create(struct nfs4_client *clp)
-{
- if (client_tracking_ops)
- client_tracking_ops->create(clp);
-}
-
-void
-nfsd4_client_record_remove(struct nfs4_client *clp)
-{
- if (client_tracking_ops)
- client_tracking_ops->remove(clp);
-}
-
-int
-nfsd4_client_record_check(struct nfs4_client *clp)
-{
- if (client_tracking_ops)
- return client_tracking_ops->check(clp);
-
- return -EOPNOTSUPP;
-}
-
-void
-nfsd4_record_grace_done(struct net *net, time_t boot_time)
-{
- if (client_tracking_ops)
- client_tracking_ops->grace_done(net, boot_time);
-}
-
-static int
-rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
-{
- struct super_block *sb = ptr;
- struct net *net = sb->s_fs_info;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- struct cld_net *cn = nn->cld_net;
- struct dentry *dentry;
- int ret = 0;
-
- if (!try_module_get(THIS_MODULE))
- return 0;
-
- if (!cn) {
- module_put(THIS_MODULE);
- return 0;
- }
-
- switch (event) {
- case RPC_PIPEFS_MOUNT:
- dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- break;
- }
- cn->cn_pipe->dentry = dentry;
- break;
- case RPC_PIPEFS_UMOUNT:
- if (cn->cn_pipe->dentry)
- nfsd4_cld_unregister_sb(cn->cn_pipe);
- break;
- default:
- ret = -ENOTSUPP;
- break;
- }
- module_put(THIS_MODULE);
- return ret;
-}
-
-struct notifier_block nfsd4_cld_block = {
- .notifier_call = rpc_pipefs_event,
-};
-
-int
-register_cld_notifier(void)
-{
- return rpc_pipefs_notifier_register(&nfsd4_cld_block);
-}
-
-void
-unregister_cld_notifier(void)
-{
- rpc_pipefs_notifier_unregister(&nfsd4_cld_block);
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs4state.c b/ANDROID_3.4.5/fs/nfsd/nfs4state.c
deleted file mode 100644
index e79c24e2..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs4state.c
+++ /dev/null
@@ -1,4889 +0,0 @@
-/*
-* Copyright (c) 2001 The Regents of the University of Michigan.
-* All rights reserved.
-*
-* Kendrick Smith <kmsmith@umich.edu>
-* Andy Adamson <kandros@umich.edu>
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions
-* are met:
-*
-* 1. Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* 2. Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-* 3. Neither the name of the University nor the names of its
-* contributors may be used to endorse or promote products derived
-* from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*
-*/
-
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/namei.h>
-#include <linux/swap.h>
-#include <linux/pagemap.h>
-#include <linux/sunrpc/svcauth_gss.h>
-#include <linux/sunrpc/clnt.h>
-#include "xdr4.h"
-#include "vfs.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_PROC
-
-/* Globals */
-time_t nfsd4_lease = 90; /* default lease time */
-time_t nfsd4_grace = 90;
-static time_t boot_time;
-
-#define all_ones {{~0,~0},~0}
-static const stateid_t one_stateid = {
- .si_generation = ~0,
- .si_opaque = all_ones,
-};
-static const stateid_t zero_stateid = {
- /* all fields zero */
-};
-static const stateid_t currentstateid = {
- .si_generation = 1,
-};
-
-static u64 current_sessionid = 1;
-
-#define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
-#define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
-#define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
-
-/* forward declarations */
-static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
-
-/* Locking: */
-
-/* Currently used for almost all code touching nfsv4 state: */
-static DEFINE_MUTEX(client_mutex);
-
-/*
- * Currently used for the del_recall_lru and file hash table. In an
- * effort to decrease the scope of the client_mutex, this spinlock may
- * eventually cover more:
- */
-static DEFINE_SPINLOCK(recall_lock);
-
-static struct kmem_cache *openowner_slab = NULL;
-static struct kmem_cache *lockowner_slab = NULL;
-static struct kmem_cache *file_slab = NULL;
-static struct kmem_cache *stateid_slab = NULL;
-static struct kmem_cache *deleg_slab = NULL;
-
-void
-nfs4_lock_state(void)
-{
- mutex_lock(&client_mutex);
-}
-
-static void free_session(struct kref *);
-
-/* Must be called under the client_lock */
-static void nfsd4_put_session_locked(struct nfsd4_session *ses)
-{
- kref_put(&ses->se_ref, free_session);
-}
-
-static void nfsd4_get_session(struct nfsd4_session *ses)
-{
- kref_get(&ses->se_ref);
-}
-
-void
-nfs4_unlock_state(void)
-{
- mutex_unlock(&client_mutex);
-}
-
-static inline u32
-opaque_hashval(const void *ptr, int nbytes)
-{
- unsigned char *cptr = (unsigned char *) ptr;
-
- u32 x = 0;
- while (nbytes--) {
- x *= 37;
- x += *cptr++;
- }
- return x;
-}
-
-static struct list_head del_recall_lru;
-
-static void nfsd4_free_file(struct nfs4_file *f)
-{
- kmem_cache_free(file_slab, f);
-}
-
-static inline void
-put_nfs4_file(struct nfs4_file *fi)
-{
- if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) {
- list_del(&fi->fi_hash);
- spin_unlock(&recall_lock);
- iput(fi->fi_inode);
- nfsd4_free_file(fi);
- }
-}
-
-static inline void
-get_nfs4_file(struct nfs4_file *fi)
-{
- atomic_inc(&fi->fi_ref);
-}
-
-static int num_delegations;
-unsigned int max_delegations;
-
-/*
- * Open owner state (share locks)
- */
-
-/* hash tables for lock and open owners */
-#define OWNER_HASH_BITS 8
-#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
-#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
-
-static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
-{
- unsigned int ret;
-
- ret = opaque_hashval(ownername->data, ownername->len);
- ret += clientid;
- return ret & OWNER_HASH_MASK;
-}
-
-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)
-
-static unsigned int file_hashval(struct inode *ino)
-{
- /* XXX: why are we hashing on inode pointer, anyway? */
- return hash_ptr(ino, FILE_HASH_BITS);
-}
-
-static struct list_head file_hashtbl[FILE_HASH_SIZE];
-
-static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
-{
- BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
- atomic_inc(&fp->fi_access[oflag]);
-}
-
-static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
-{
- if (oflag == O_RDWR) {
- __nfs4_file_get_access(fp, O_RDONLY);
- __nfs4_file_get_access(fp, O_WRONLY);
- } else
- __nfs4_file_get_access(fp, oflag);
-}
-
-static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
-{
- if (fp->fi_fds[oflag]) {
- fput(fp->fi_fds[oflag]);
- fp->fi_fds[oflag] = NULL;
- }
-}
-
-static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
-{
- if (atomic_dec_and_test(&fp->fi_access[oflag])) {
- nfs4_file_put_fd(fp, oflag);
- /*
- * It's also safe to get rid of the RDWR open *if*
- * we no longer have need of the other kind of access
- * or if we already have the other kind of open:
- */
- if (fp->fi_fds[1-oflag]
- || atomic_read(&fp->fi_access[1 - oflag]) == 0)
- nfs4_file_put_fd(fp, O_RDWR);
- }
-}
-
-static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
-{
- if (oflag == O_RDWR) {
- __nfs4_file_put_access(fp, O_RDONLY);
- __nfs4_file_put_access(fp, O_WRONLY);
- } else
- __nfs4_file_put_access(fp, oflag);
-}
-
-static inline int get_new_stid(struct nfs4_stid *stid)
-{
- static int min_stateid = 0;
- struct idr *stateids = &stid->sc_client->cl_stateids;
- int new_stid;
- int error;
-
- error = idr_get_new_above(stateids, stid, min_stateid, &new_stid);
- /*
- * Note: the necessary preallocation was done in
- * nfs4_alloc_stateid(). The idr code caps the number of
- * preallocations that can exist at a time, but the state lock
- * prevents anyone from using ours before we get here:
- */
- BUG_ON(error);
- /*
- * It shouldn't be a problem to reuse an opaque stateid value.
- * I don't think it is for 4.1. But with 4.0 I worry that, for
- * example, a stray write retransmission could be accepted by
- * the server when it should have been rejected. Therefore,
- * adopt a trick from the sctp code to attempt to maximize the
- * amount of time until an id is reused, by ensuring they always
- * "increase" (mod INT_MAX):
- */
-
- min_stateid = new_stid+1;
- if (min_stateid == INT_MAX)
- min_stateid = 0;
- return new_stid;
-}
-
-static void init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type)
-{
- stateid_t *s = &stid->sc_stateid;
- int new_id;
-
- stid->sc_type = type;
- stid->sc_client = cl;
- s->si_opaque.so_clid = cl->cl_clientid;
- new_id = get_new_stid(stid);
- s->si_opaque.so_id = (u32)new_id;
- /* Will be incremented before return to client: */
- s->si_generation = 0;
-}
-
-static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab)
-{
- struct idr *stateids = &cl->cl_stateids;
-
- if (!idr_pre_get(stateids, GFP_KERNEL))
- return NULL;
- /*
- * Note: if we fail here (or any time between now and the time
- * we actually get the new idr), we won't need to undo the idr
- * preallocation, since the idr code caps the number of
- * preallocated entries.
- */
- return kmem_cache_alloc(slab, GFP_KERNEL);
-}
-
-static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
-{
- return openlockstateid(nfs4_alloc_stid(clp, stateid_slab));
-}
-
-static struct nfs4_delegation *
-alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
-{
- struct nfs4_delegation *dp;
- struct nfs4_file *fp = stp->st_file;
-
- dprintk("NFSD alloc_init_deleg\n");
- /*
- * Major work on the lease subsystem (for example, to support
- * calbacks on stat) will be required before we can support
- * write delegations properly.
- */
- if (type != NFS4_OPEN_DELEGATE_READ)
- return NULL;
- if (fp->fi_had_conflict)
- return NULL;
- if (num_delegations > max_delegations)
- return NULL;
- dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
- if (dp == NULL)
- return dp;
- init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID);
- /*
- * delegation seqid's are never incremented. The 4.1 special
- * meaning of seqid 0 isn't meaningful, really, but let's avoid
- * 0 anyway just for consistency and use 1:
- */
- dp->dl_stid.sc_stateid.si_generation = 1;
- num_delegations++;
- INIT_LIST_HEAD(&dp->dl_perfile);
- INIT_LIST_HEAD(&dp->dl_perclnt);
- INIT_LIST_HEAD(&dp->dl_recall_lru);
- get_nfs4_file(fp);
- dp->dl_file = fp;
- dp->dl_type = type;
- fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
- dp->dl_time = 0;
- atomic_set(&dp->dl_count, 1);
- INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
- return dp;
-}
-
-void
-nfs4_put_delegation(struct nfs4_delegation *dp)
-{
- if (atomic_dec_and_test(&dp->dl_count)) {
- dprintk("NFSD: freeing dp %p\n",dp);
- put_nfs4_file(dp->dl_file);
- kmem_cache_free(deleg_slab, dp);
- num_delegations--;
- }
-}
-
-static void nfs4_put_deleg_lease(struct nfs4_file *fp)
-{
- if (atomic_dec_and_test(&fp->fi_delegees)) {
- vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
- fp->fi_lease = NULL;
- fput(fp->fi_deleg_file);
- fp->fi_deleg_file = NULL;
- }
-}
-
-static void unhash_stid(struct nfs4_stid *s)
-{
- struct idr *stateids = &s->sc_client->cl_stateids;
-
- idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
-}
-
-/* Called under the state lock. */
-static void
-unhash_delegation(struct nfs4_delegation *dp)
-{
- unhash_stid(&dp->dl_stid);
- list_del_init(&dp->dl_perclnt);
- spin_lock(&recall_lock);
- list_del_init(&dp->dl_perfile);
- list_del_init(&dp->dl_recall_lru);
- spin_unlock(&recall_lock);
- nfs4_put_deleg_lease(dp->dl_file);
- nfs4_put_delegation(dp);
-}
-
-/*
- * SETCLIENTID state
- */
-
-/* client_lock protects the client lru list and session hash table */
-static DEFINE_SPINLOCK(client_lock);
-
-/* Hash tables for nfs4_clientid state */
-#define CLIENT_HASH_BITS 4
-#define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS)
-#define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1)
-
-static unsigned int clientid_hashval(u32 id)
-{
- return id & CLIENT_HASH_MASK;
-}
-
-static unsigned int clientstr_hashval(const char *name)
-{
- return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
-}
-
-/*
- * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
- * used in reboot/reset lease grace period processing
- *
- * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed
- * setclientid_confirmed info.
- *
- * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed
- * setclientid info.
- *
- * client_lru holds client queue ordered by nfs4_client.cl_time
- * for lease renewal.
- *
- * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
- * for last close replay.
- */
-static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE];
-static int reclaim_str_hashtbl_size = 0;
-static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head client_lru;
-static struct list_head close_lru;
-
-/*
- * We store the NONE, READ, WRITE, and BOTH bits separately in the
- * st_{access,deny}_bmap field of the stateid, in order to track not
- * only what share bits are currently in force, but also what
- * combinations of share bits previous opens have used. This allows us
- * to enforce the recommendation of rfc 3530 14.2.19 that the server
- * return an error if the client attempt to downgrade to a combination
- * of share bits not explicable by closing some of its previous opens.
- *
- * XXX: This enforcement is actually incomplete, since we don't keep
- * track of access/deny bit combinations; so, e.g., we allow:
- *
- * OPEN allow read, deny write
- * OPEN allow both, deny none
- * DOWNGRADE allow read, deny none
- *
- * which we should reject.
- */
-static void
-set_access(unsigned int *access, unsigned long bmap) {
- int i;
-
- *access = 0;
- for (i = 1; i < 4; i++) {
- if (test_bit(i, &bmap))
- *access |= i;
- }
-}
-
-static void
-set_deny(unsigned int *deny, unsigned long bmap) {
- int i;
-
- *deny = 0;
- for (i = 0; i < 4; i++) {
- if (test_bit(i, &bmap))
- *deny |= i ;
- }
-}
-
-static int
-test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) {
- unsigned int access, deny;
-
- set_access(&access, stp->st_access_bmap);
- set_deny(&deny, stp->st_deny_bmap);
- if ((access & open->op_share_deny) || (deny & open->op_share_access))
- return 0;
- return 1;
-}
-
-static int nfs4_access_to_omode(u32 access)
-{
- switch (access & NFS4_SHARE_ACCESS_BOTH) {
- case NFS4_SHARE_ACCESS_READ:
- return O_RDONLY;
- case NFS4_SHARE_ACCESS_WRITE:
- return O_WRONLY;
- case NFS4_SHARE_ACCESS_BOTH:
- return O_RDWR;
- }
- BUG();
-}
-
-static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
-{
- list_del(&stp->st_perfile);
- list_del(&stp->st_perstateowner);
-}
-
-static void close_generic_stateid(struct nfs4_ol_stateid *stp)
-{
- int i;
-
- if (stp->st_access_bmap) {
- for (i = 1; i < 4; i++) {
- if (test_bit(i, &stp->st_access_bmap))
- nfs4_file_put_access(stp->st_file,
- nfs4_access_to_omode(i));
- __clear_bit(i, &stp->st_access_bmap);
- }
- }
- put_nfs4_file(stp->st_file);
- stp->st_file = NULL;
-}
-
-static void free_generic_stateid(struct nfs4_ol_stateid *stp)
-{
- kmem_cache_free(stateid_slab, stp);
-}
-
-static void release_lock_stateid(struct nfs4_ol_stateid *stp)
-{
- struct file *file;
-
- unhash_generic_stateid(stp);
- unhash_stid(&stp->st_stid);
- file = find_any_file(stp->st_file);
- if (file)
- locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
- close_generic_stateid(stp);
- free_generic_stateid(stp);
-}
-
-static void unhash_lockowner(struct nfs4_lockowner *lo)
-{
- struct nfs4_ol_stateid *stp;
-
- list_del(&lo->lo_owner.so_strhash);
- list_del(&lo->lo_perstateid);
- list_del(&lo->lo_owner_ino_hash);
- while (!list_empty(&lo->lo_owner.so_stateids)) {
- stp = list_first_entry(&lo->lo_owner.so_stateids,
- struct nfs4_ol_stateid, st_perstateowner);
- release_lock_stateid(stp);
- }
-}
-
-static void release_lockowner(struct nfs4_lockowner *lo)
-{
- unhash_lockowner(lo);
- nfs4_free_lockowner(lo);
-}
-
-static void
-release_stateid_lockowners(struct nfs4_ol_stateid *open_stp)
-{
- struct nfs4_lockowner *lo;
-
- while (!list_empty(&open_stp->st_lockowners)) {
- lo = list_entry(open_stp->st_lockowners.next,
- struct nfs4_lockowner, lo_perstateid);
- release_lockowner(lo);
- }
-}
-
-static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
-{
- unhash_generic_stateid(stp);
- release_stateid_lockowners(stp);
- close_generic_stateid(stp);
-}
-
-static void release_open_stateid(struct nfs4_ol_stateid *stp)
-{
- unhash_open_stateid(stp);
- unhash_stid(&stp->st_stid);
- free_generic_stateid(stp);
-}
-
-static void unhash_openowner(struct nfs4_openowner *oo)
-{
- struct nfs4_ol_stateid *stp;
-
- list_del(&oo->oo_owner.so_strhash);
- list_del(&oo->oo_perclient);
- while (!list_empty(&oo->oo_owner.so_stateids)) {
- stp = list_first_entry(&oo->oo_owner.so_stateids,
- struct nfs4_ol_stateid, st_perstateowner);
- release_open_stateid(stp);
- }
-}
-
-static void release_last_closed_stateid(struct nfs4_openowner *oo)
-{
- struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
-
- if (s) {
- unhash_stid(&s->st_stid);
- free_generic_stateid(s);
- oo->oo_last_closed_stid = NULL;
- }
-}
-
-static void release_openowner(struct nfs4_openowner *oo)
-{
- unhash_openowner(oo);
- list_del(&oo->oo_close_lru);
- release_last_closed_stateid(oo);
- nfs4_free_openowner(oo);
-}
-
-#define SESSION_HASH_SIZE 512
-static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE];
-
-static inline int
-hash_sessionid(struct nfs4_sessionid *sessionid)
-{
- struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;
-
- return sid->sequence % SESSION_HASH_SIZE;
-}
-
-#ifdef NFSD_DEBUG
-static inline void
-dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
-{
- u32 *ptr = (u32 *)(&sessionid->data[0]);
- dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
-}
-#else
-static inline void
-dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
-{
-}
-#endif
-
-
-static void
-gen_sessionid(struct nfsd4_session *ses)
-{
- struct nfs4_client *clp = ses->se_client;
- struct nfsd4_sessionid *sid;
-
- sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
- sid->clientid = clp->cl_clientid;
- sid->sequence = current_sessionid++;
- sid->reserved = 0;
-}
-
-/*
- * The protocol defines ca_maxresponssize_cached to include the size of
- * the rpc header, but all we need to cache is the data starting after
- * the end of the initial SEQUENCE operation--the rest we regenerate
- * each time. Therefore we can advertise a ca_maxresponssize_cached
- * value that is the number of bytes in our cache plus a few additional
- * bytes. In order to stay on the safe side, and not promise more than
- * we can cache, those additional bytes must be the minimum possible: 24
- * bytes of rpc header (xid through accept state, with AUTH_NULL
- * verifier), 12 for the compound header (with zero-length tag), and 44
- * for the SEQUENCE op response:
- */
-#define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44)
-
-static void
-free_session_slots(struct nfsd4_session *ses)
-{
- int i;
-
- for (i = 0; i < ses->se_fchannel.maxreqs; i++)
- kfree(ses->se_slots[i]);
-}
-
-/*
- * We don't actually need to cache the rpc and session headers, so we
- * can allocate a little less for each slot:
- */
-static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
-{
- return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
-}
-
-static int nfsd4_sanitize_slot_size(u32 size)
-{
- size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */
- size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE);
-
- return size;
-}
-
-/*
- * XXX: If we run out of reserved DRC memory we could (up to a point)
- * re-negotiate active sessions and reduce their slot usage to make
- * room for new connections. For now we just fail the create session.
- */
-static int nfsd4_get_drc_mem(int slotsize, u32 num)
-{
- int avail;
-
- num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
-
- spin_lock(&nfsd_drc_lock);
- avail = min_t(int, NFSD_MAX_MEM_PER_SESSION,
- nfsd_drc_max_mem - nfsd_drc_mem_used);
- num = min_t(int, num, avail / slotsize);
- nfsd_drc_mem_used += num * slotsize;
- spin_unlock(&nfsd_drc_lock);
-
- return num;
-}
-
-static void nfsd4_put_drc_mem(int slotsize, int num)
-{
- spin_lock(&nfsd_drc_lock);
- nfsd_drc_mem_used -= slotsize * num;
- spin_unlock(&nfsd_drc_lock);
-}
-
-static struct nfsd4_session *alloc_session(int slotsize, int numslots)
-{
- struct nfsd4_session *new;
- int mem, i;
-
- BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
- + sizeof(struct nfsd4_session) > PAGE_SIZE);
- mem = numslots * sizeof(struct nfsd4_slot *);
-
- new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
- if (!new)
- return NULL;
- /* allocate each struct nfsd4_slot and data cache in one piece */
- for (i = 0; i < numslots; i++) {
- mem = sizeof(struct nfsd4_slot) + slotsize;
- new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
- if (!new->se_slots[i])
- goto out_free;
- }
- return new;
-out_free:
- while (i--)
- kfree(new->se_slots[i]);
- kfree(new);
- return NULL;
-}
-
-static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize)
-{
- u32 maxrpc = nfsd_serv->sv_max_mesg;
-
- new->maxreqs = numslots;
- new->maxresp_cached = min_t(u32, req->maxresp_cached,
- slotsize + NFSD_MIN_HDR_SEQ_SZ);
- new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
- new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
- new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
-}
-
-static void free_conn(struct nfsd4_conn *c)
-{
- svc_xprt_put(c->cn_xprt);
- kfree(c);
-}
-
-static void nfsd4_conn_lost(struct svc_xpt_user *u)
-{
- struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
- struct nfs4_client *clp = c->cn_session->se_client;
-
- spin_lock(&clp->cl_lock);
- if (!list_empty(&c->cn_persession)) {
- list_del(&c->cn_persession);
- free_conn(c);
- }
- spin_unlock(&clp->cl_lock);
- nfsd4_probe_callback(clp);
-}
-
-static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
-{
- struct nfsd4_conn *conn;
-
- conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
- if (!conn)
- return NULL;
- svc_xprt_get(rqstp->rq_xprt);
- conn->cn_xprt = rqstp->rq_xprt;
- conn->cn_flags = flags;
- INIT_LIST_HEAD(&conn->cn_xpt_user.list);
- return conn;
-}
-
-static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
-{
- conn->cn_session = ses;
- list_add(&conn->cn_persession, &ses->se_conns);
-}
-
-static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
-{
- struct nfs4_client *clp = ses->se_client;
-
- spin_lock(&clp->cl_lock);
- __nfsd4_hash_conn(conn, ses);
- spin_unlock(&clp->cl_lock);
-}
-
-static int nfsd4_register_conn(struct nfsd4_conn *conn)
-{
- conn->cn_xpt_user.callback = nfsd4_conn_lost;
- return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
-}
-
-static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
-{
- struct nfsd4_conn *conn;
- int ret;
-
- conn = alloc_conn(rqstp, dir);
- if (!conn)
- return nfserr_jukebox;
- nfsd4_hash_conn(conn, ses);
- ret = nfsd4_register_conn(conn);
- if (ret)
- /* oops; xprt is already down: */
- nfsd4_conn_lost(&conn->cn_xpt_user);
- return nfs_ok;
-}
-
-static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
-{
- u32 dir = NFS4_CDFC4_FORE;
-
- if (ses->se_flags & SESSION4_BACK_CHAN)
- dir |= NFS4_CDFC4_BACK;
-
- return nfsd4_new_conn(rqstp, ses, dir);
-}
-
-/* must be called under client_lock */
-static void nfsd4_del_conns(struct nfsd4_session *s)
-{
- struct nfs4_client *clp = s->se_client;
- struct nfsd4_conn *c;
-
- spin_lock(&clp->cl_lock);
- while (!list_empty(&s->se_conns)) {
- c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
- list_del_init(&c->cn_persession);
- spin_unlock(&clp->cl_lock);
-
- unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
- free_conn(c);
-
- spin_lock(&clp->cl_lock);
- }
- spin_unlock(&clp->cl_lock);
-}
-
-static void free_session(struct kref *kref)
-{
- struct nfsd4_session *ses;
- int mem;
-
- lockdep_assert_held(&client_lock);
- ses = container_of(kref, struct nfsd4_session, se_ref);
- nfsd4_del_conns(ses);
- spin_lock(&nfsd_drc_lock);
- mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
- nfsd_drc_mem_used -= mem;
- spin_unlock(&nfsd_drc_lock);
- free_session_slots(ses);
- kfree(ses);
-}
-
-void nfsd4_put_session(struct nfsd4_session *ses)
-{
- spin_lock(&client_lock);
- nfsd4_put_session_locked(ses);
- spin_unlock(&client_lock);
-}
-
-static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
-{
- struct nfsd4_session *new;
- struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
- int numslots, slotsize;
- int status;
- int idx;
-
- /*
- * Note decreasing slot size below client's request may
- * make it difficult for client to function correctly, whereas
- * decreasing the number of slots will (just?) affect
- * performance. When short on memory we therefore prefer to
- * decrease number of slots instead of their size.
- */
- slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
- numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
- if (numslots < 1)
- return NULL;
-
- new = alloc_session(slotsize, numslots);
- if (!new) {
- nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
- return NULL;
- }
- init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
-
- new->se_client = clp;
- gen_sessionid(new);
-
- INIT_LIST_HEAD(&new->se_conns);
-
- new->se_cb_seq_nr = 1;
- new->se_flags = cses->flags;
- new->se_cb_prog = cses->callback_prog;
- kref_init(&new->se_ref);
- idx = hash_sessionid(&new->se_sessionid);
- spin_lock(&client_lock);
- list_add(&new->se_hash, &sessionid_hashtbl[idx]);
- spin_lock(&clp->cl_lock);
- list_add(&new->se_perclnt, &clp->cl_sessions);
- spin_unlock(&clp->cl_lock);
- spin_unlock(&client_lock);
-
- status = nfsd4_new_conn_from_crses(rqstp, new);
- /* whoops: benny points out, status is ignored! (err, or bogus) */
- if (status) {
- spin_lock(&client_lock);
- free_session(&new->se_ref);
- spin_unlock(&client_lock);
- return NULL;
- }
- if (cses->flags & SESSION4_BACK_CHAN) {
- struct sockaddr *sa = svc_addr(rqstp);
- /*
- * This is a little silly; with sessions there's no real
- * use for the callback address. Use the peer address
- * as a reasonable default for now, but consider fixing
- * the rpc client not to require an address in the
- * future:
- */
- rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
- clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
- }
- nfsd4_probe_callback(clp);
- return new;
-}
-
-/* caller must hold client_lock */
-static struct nfsd4_session *
-find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid)
-{
- struct nfsd4_session *elem;
- int idx;
-
- dump_sessionid(__func__, sessionid);
- idx = hash_sessionid(sessionid);
- /* Search in the appropriate list */
- list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) {
- if (!memcmp(elem->se_sessionid.data, sessionid->data,
- NFS4_MAX_SESSIONID_LEN)) {
- return elem;
- }
- }
-
- dprintk("%s: session not found\n", __func__);
- return NULL;
-}
-
-/* caller must hold client_lock */
-static void
-unhash_session(struct nfsd4_session *ses)
-{
- list_del(&ses->se_hash);
- spin_lock(&ses->se_client->cl_lock);
- list_del(&ses->se_perclnt);
- spin_unlock(&ses->se_client->cl_lock);
-}
-
-/* must be called under the client_lock */
-static inline void
-renew_client_locked(struct nfs4_client *clp)
-{
- if (is_client_expired(clp)) {
- dprintk("%s: client (clientid %08x/%08x) already expired\n",
- __func__,
- clp->cl_clientid.cl_boot,
- clp->cl_clientid.cl_id);
- return;
- }
-
- dprintk("renewing client (clientid %08x/%08x)\n",
- clp->cl_clientid.cl_boot,
- clp->cl_clientid.cl_id);
- list_move_tail(&clp->cl_lru, &client_lru);
- clp->cl_time = get_seconds();
-}
-
-static inline void
-renew_client(struct nfs4_client *clp)
-{
- spin_lock(&client_lock);
- renew_client_locked(clp);
- spin_unlock(&client_lock);
-}
-
-/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
-static int
-STALE_CLIENTID(clientid_t *clid)
-{
- if (clid->cl_boot == boot_time)
- return 0;
- dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
- clid->cl_boot, clid->cl_id, boot_time);
- return 1;
-}
-
-/*
- * XXX Should we use a slab cache ?
- * This type of memory management is somewhat inefficient, but we use it
- * anyway since SETCLIENTID is not a common operation.
- */
-static struct nfs4_client *alloc_client(struct xdr_netobj name)
-{
- struct nfs4_client *clp;
-
- clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
- if (clp == NULL)
- return NULL;
- clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
- if (clp->cl_name.data == NULL) {
- kfree(clp);
- return NULL;
- }
- clp->cl_name.len = name.len;
- return clp;
-}
-
-static inline void
-free_client(struct nfs4_client *clp)
-{
- lockdep_assert_held(&client_lock);
- while (!list_empty(&clp->cl_sessions)) {
- struct nfsd4_session *ses;
- ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
- se_perclnt);
- list_del(&ses->se_perclnt);
- nfsd4_put_session_locked(ses);
- }
- if (clp->cl_cred.cr_group_info)
- put_group_info(clp->cl_cred.cr_group_info);
- kfree(clp->cl_principal);
- kfree(clp->cl_name.data);
- kfree(clp);
-}
-
-void
-release_session_client(struct nfsd4_session *session)
-{
- struct nfs4_client *clp = session->se_client;
-
- if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock))
- return;
- if (is_client_expired(clp)) {
- free_client(clp);
- session->se_client = NULL;
- } else
- renew_client_locked(clp);
- spin_unlock(&client_lock);
-}
-
-/* must be called under the client_lock */
-static inline void
-unhash_client_locked(struct nfs4_client *clp)
-{
- struct nfsd4_session *ses;
-
- mark_client_expired(clp);
- list_del(&clp->cl_lru);
- spin_lock(&clp->cl_lock);
- list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
- list_del_init(&ses->se_hash);
- spin_unlock(&clp->cl_lock);
-}
-
-static void
-expire_client(struct nfs4_client *clp)
-{
- struct nfs4_openowner *oo;
- struct nfs4_delegation *dp;
- struct list_head reaplist;
-
- INIT_LIST_HEAD(&reaplist);
- spin_lock(&recall_lock);
- while (!list_empty(&clp->cl_delegations)) {
- dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
- list_del_init(&dp->dl_perclnt);
- list_move(&dp->dl_recall_lru, &reaplist);
- }
- spin_unlock(&recall_lock);
- while (!list_empty(&reaplist)) {
- dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
- }
- while (!list_empty(&clp->cl_openowners)) {
- oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
- release_openowner(oo);
- }
- nfsd4_shutdown_callback(clp);
- if (clp->cl_cb_conn.cb_xprt)
- svc_xprt_put(clp->cl_cb_conn.cb_xprt);
- list_del(&clp->cl_idhash);
- list_del(&clp->cl_strhash);
- spin_lock(&client_lock);
- unhash_client_locked(clp);
- if (atomic_read(&clp->cl_refcount) == 0)
- free_client(clp);
- spin_unlock(&client_lock);
-}
-
-static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
-{
- memcpy(target->cl_verifier.data, source->data,
- sizeof(target->cl_verifier.data));
-}
-
-static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
-{
- target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
- target->cl_clientid.cl_id = source->cl_clientid.cl_id;
-}
-
-static void copy_cred(struct svc_cred *target, struct svc_cred *source)
-{
- target->cr_uid = source->cr_uid;
- target->cr_gid = source->cr_gid;
- target->cr_group_info = source->cr_group_info;
- get_group_info(target->cr_group_info);
-}
-
-static int same_name(const char *n1, const char *n2)
-{
- return 0 == memcmp(n1, n2, HEXDIR_LEN);
-}
-
-static int
-same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
-{
- return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
-}
-
-static int
-same_clid(clientid_t *cl1, clientid_t *cl2)
-{
- return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
-}
-
-/* XXX what about NGROUP */
-static int
-same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
-{
- return cr1->cr_uid == cr2->cr_uid;
-}
-
-static void gen_clid(struct nfs4_client *clp)
-{
- static u32 current_clientid = 1;
-
- clp->cl_clientid.cl_boot = boot_time;
- clp->cl_clientid.cl_id = current_clientid++;
-}
-
-static void gen_confirm(struct nfs4_client *clp)
-{
- __be32 verf[2];
- static u32 i;
-
- verf[0] = (__be32)get_seconds();
- verf[1] = (__be32)i++;
- memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
-}
-
-static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
-{
- return idr_find(&cl->cl_stateids, t->si_opaque.so_id);
-}
-
-static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
-{
- struct nfs4_stid *s;
-
- s = find_stateid(cl, t);
- if (!s)
- return NULL;
- if (typemask & s->sc_type)
- return s;
- return NULL;
-}
-
-static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
- struct svc_rqst *rqstp, nfs4_verifier *verf)
-{
- struct nfs4_client *clp;
- struct sockaddr *sa = svc_addr(rqstp);
- char *princ;
-
- clp = alloc_client(name);
- if (clp == NULL)
- return NULL;
-
- INIT_LIST_HEAD(&clp->cl_sessions);
-
- princ = svc_gss_principal(rqstp);
- if (princ) {
- clp->cl_principal = kstrdup(princ, GFP_KERNEL);
- if (clp->cl_principal == NULL) {
- spin_lock(&client_lock);
- free_client(clp);
- spin_unlock(&client_lock);
- return NULL;
- }
- }
-
- idr_init(&clp->cl_stateids);
- memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
- atomic_set(&clp->cl_refcount, 0);
- clp->cl_cb_state = NFSD4_CB_UNKNOWN;
- INIT_LIST_HEAD(&clp->cl_idhash);
- INIT_LIST_HEAD(&clp->cl_strhash);
- INIT_LIST_HEAD(&clp->cl_openowners);
- INIT_LIST_HEAD(&clp->cl_delegations);
- INIT_LIST_HEAD(&clp->cl_lru);
- INIT_LIST_HEAD(&clp->cl_callbacks);
- spin_lock_init(&clp->cl_lock);
- INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
- clp->cl_time = get_seconds();
- clear_bit(0, &clp->cl_cb_slot_busy);
- rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
- copy_verf(clp, verf);
- rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
- clp->cl_flavor = rqstp->rq_flavor;
- copy_cred(&clp->cl_cred, &rqstp->rq_cred);
- gen_confirm(clp);
- clp->cl_cb_session = NULL;
- return clp;
-}
-
-static void
-add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
-{
- unsigned int idhashval;
-
- list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]);
- idhashval = clientid_hashval(clp->cl_clientid.cl_id);
- list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]);
- renew_client(clp);
-}
-
-static void
-move_to_confirmed(struct nfs4_client *clp)
-{
- unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
- unsigned int strhashval;
-
- dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
- list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
- strhashval = clientstr_hashval(clp->cl_recdir);
- list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
- renew_client(clp);
-}
-
-static struct nfs4_client *
-find_confirmed_client(clientid_t *clid)
-{
- struct nfs4_client *clp;
- unsigned int idhashval = clientid_hashval(clid->cl_id);
-
- list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
- if (same_clid(&clp->cl_clientid, clid)) {
- renew_client(clp);
- return clp;
- }
- }
- return NULL;
-}
-
-static struct nfs4_client *
-find_unconfirmed_client(clientid_t *clid)
-{
- struct nfs4_client *clp;
- unsigned int idhashval = clientid_hashval(clid->cl_id);
-
- list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
- if (same_clid(&clp->cl_clientid, clid))
- return clp;
- }
- return NULL;
-}
-
-static bool clp_used_exchangeid(struct nfs4_client *clp)
-{
- return clp->cl_exchange_flags != 0;
-}
-
-static struct nfs4_client *
-find_confirmed_client_by_str(const char *dname, unsigned int hashval)
-{
- struct nfs4_client *clp;
-
- list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
- if (same_name(clp->cl_recdir, dname))
- return clp;
- }
- return NULL;
-}
-
-static struct nfs4_client *
-find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
-{
- struct nfs4_client *clp;
-
- list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
- if (same_name(clp->cl_recdir, dname))
- return clp;
- }
- return NULL;
-}
-
-static void
-gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
-{
- struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
- struct sockaddr *sa = svc_addr(rqstp);
- u32 scopeid = rpc_get_scope_id(sa);
- unsigned short expected_family;
-
- /* Currently, we only support tcp and tcp6 for the callback channel */
- if (se->se_callback_netid_len == 3 &&
- !memcmp(se->se_callback_netid_val, "tcp", 3))
- expected_family = AF_INET;
- else if (se->se_callback_netid_len == 4 &&
- !memcmp(se->se_callback_netid_val, "tcp6", 4))
- expected_family = AF_INET6;
- else
- goto out_err;
-
- conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val,
- se->se_callback_addr_len,
- (struct sockaddr *)&conn->cb_addr,
- sizeof(conn->cb_addr));
-
- if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
- goto out_err;
-
- if (conn->cb_addr.ss_family == AF_INET6)
- ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
-
- conn->cb_prog = se->se_callback_prog;
- conn->cb_ident = se->se_callback_ident;
- memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen);
- return;
-out_err:
- conn->cb_addr.ss_family = AF_UNSPEC;
- conn->cb_addrlen = 0;
- dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
- "will not receive delegations\n",
- clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
-
- return;
-}
-
-/*
- * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size.
- */
-void
-nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
-{
- struct nfsd4_slot *slot = resp->cstate.slot;
- unsigned int base;
-
- dprintk("--> %s slot %p\n", __func__, slot);
-
- slot->sl_opcnt = resp->opcnt;
- slot->sl_status = resp->cstate.status;
-
- slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
- if (nfsd4_not_cached(resp)) {
- slot->sl_datalen = 0;
- return;
- }
- slot->sl_datalen = (char *)resp->p - (char *)resp->cstate.datap;
- base = (char *)resp->cstate.datap -
- (char *)resp->xbuf->head[0].iov_base;
- if (read_bytes_from_xdr_buf(resp->xbuf, base, slot->sl_data,
- slot->sl_datalen))
- WARN("%s: sessions DRC could not cache compound\n", __func__);
- return;
-}
-
-/*
- * Encode the replay sequence operation from the slot values.
- * If cachethis is FALSE encode the uncached rep error on the next
- * operation which sets resp->p and increments resp->opcnt for
- * nfs4svc_encode_compoundres.
- *
- */
-static __be32
-nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
- struct nfsd4_compoundres *resp)
-{
- struct nfsd4_op *op;
- struct nfsd4_slot *slot = resp->cstate.slot;
-
- /* Encode the replayed sequence operation */
- op = &args->ops[resp->opcnt - 1];
- nfsd4_encode_operation(resp, op);
-
- /* Return nfserr_retry_uncached_rep in next operation. */
- if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
- op = &args->ops[resp->opcnt++];
- op->status = nfserr_retry_uncached_rep;
- nfsd4_encode_operation(resp, op);
- }
- return op->status;
-}
-
-/*
- * The sequence operation is not cached because we can use the slot and
- * session values.
- */
-__be32
-nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
- struct nfsd4_sequence *seq)
-{
- struct nfsd4_slot *slot = resp->cstate.slot;
- __be32 status;
-
- dprintk("--> %s slot %p\n", __func__, slot);
-
- /* Either returns 0 or nfserr_retry_uncached */
- status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
- if (status == nfserr_retry_uncached_rep)
- return status;
-
- /* The sequence operation has been encoded, cstate->datap set. */
- memcpy(resp->cstate.datap, slot->sl_data, slot->sl_datalen);
-
- resp->opcnt = slot->sl_opcnt;
- resp->p = resp->cstate.datap + XDR_QUADLEN(slot->sl_datalen);
- status = slot->sl_status;
-
- return status;
-}
-
-/*
- * Set the exchange_id flags returned by the server.
- */
-static void
-nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
-{
- /* pNFS is not supported */
- new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
-
- /* Referrals are supported, Migration is not. */
- new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
-
- /* set the wire flags to return to client. */
- clid->flags = new->cl_exchange_flags;
-}
-
-__be32
-nfsd4_exchange_id(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate,
- struct nfsd4_exchange_id *exid)
-{
- struct nfs4_client *unconf, *conf, *new;
- int status;
- unsigned int strhashval;
- char dname[HEXDIR_LEN];
- char addr_str[INET6_ADDRSTRLEN];
- nfs4_verifier verf = exid->verifier;
- struct sockaddr *sa = svc_addr(rqstp);
-
- rpc_ntop(sa, addr_str, sizeof(addr_str));
- dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
- "ip_addr=%s flags %x, spa_how %d\n",
- __func__, rqstp, exid, exid->clname.len, exid->clname.data,
- addr_str, exid->flags, exid->spa_how);
-
- if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
- return nfserr_inval;
-
- /* Currently only support SP4_NONE */
- switch (exid->spa_how) {
- case SP4_NONE:
- break;
- case SP4_SSV:
- return nfserr_serverfault;
- default:
- BUG(); /* checked by xdr code */
- case SP4_MACH_CRED:
- return nfserr_serverfault; /* no excuse :-/ */
- }
-
- status = nfs4_make_rec_clidname(dname, &exid->clname);
-
- if (status)
- goto error;
-
- strhashval = clientstr_hashval(dname);
-
- nfs4_lock_state();
- status = nfs_ok;
-
- conf = find_confirmed_client_by_str(dname, strhashval);
- if (conf) {
- if (!clp_used_exchangeid(conf)) {
- status = nfserr_clid_inuse; /* XXX: ? */
- goto out;
- }
- if (!same_verf(&verf, &conf->cl_verifier)) {
- /* 18.35.4 case 8 */
- if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
- status = nfserr_not_same;
- goto out;
- }
- /* Client reboot: destroy old state */
- expire_client(conf);
- goto out_new;
- }
- if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
- /* 18.35.4 case 9 */
- if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
- status = nfserr_perm;
- goto out;
- }
- expire_client(conf);
- goto out_new;
- }
- /*
- * Set bit when the owner id and verifier map to an already
- * confirmed client id (18.35.3).
- */
- exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
-
- /*
- * Falling into 18.35.4 case 2, possible router replay.
- * Leave confirmed record intact and return same result.
- */
- copy_verf(conf, &verf);
- new = conf;
- goto out_copy;
- }
-
- /* 18.35.4 case 7 */
- if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
- status = nfserr_noent;
- goto out;
- }
-
- unconf = find_unconfirmed_client_by_str(dname, strhashval);
- if (unconf) {
- /*
- * Possible retry or client restart. Per 18.35.4 case 4,
- * a new unconfirmed record should be generated regardless
- * of whether any properties have changed.
- */
- expire_client(unconf);
- }
-
-out_new:
- /* Normal case */
- new = create_client(exid->clname, dname, rqstp, &verf);
- if (new == NULL) {
- status = nfserr_jukebox;
- goto out;
- }
-
- gen_clid(new);
- add_to_unconfirmed(new, strhashval);
-out_copy:
- exid->clientid.cl_boot = new->cl_clientid.cl_boot;
- exid->clientid.cl_id = new->cl_clientid.cl_id;
-
- exid->seqid = 1;
- nfsd4_set_ex_flags(new, exid);
-
- dprintk("nfsd4_exchange_id seqid %d flags %x\n",
- new->cl_cs_slot.sl_seqid, new->cl_exchange_flags);
- status = nfs_ok;
-
-out:
- nfs4_unlock_state();
-error:
- dprintk("nfsd4_exchange_id returns %d\n", ntohl(status));
- return status;
-}
-
-static int
-check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
-{
- dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
- slot_seqid);
-
- /* The slot is in use, and no response has been sent. */
- if (slot_inuse) {
- if (seqid == slot_seqid)
- return nfserr_jukebox;
- else
- return nfserr_seq_misordered;
- }
- /* Note unsigned 32-bit arithmetic handles wraparound: */
- if (likely(seqid == slot_seqid + 1))
- return nfs_ok;
- if (seqid == slot_seqid)
- return nfserr_replay_cache;
- return nfserr_seq_misordered;
-}
-
-/*
- * Cache the create session result into the create session single DRC
- * slot cache by saving the xdr structure. sl_seqid has been set.
- * Do this for solo or embedded create session operations.
- */
-static void
-nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
- struct nfsd4_clid_slot *slot, int nfserr)
-{
- slot->sl_status = nfserr;
- memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
-}
-
-static __be32
-nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
- struct nfsd4_clid_slot *slot)
-{
- memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
- return slot->sl_status;
-}
-
-#define NFSD_MIN_REQ_HDR_SEQ_SZ ((\
- 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
- 1 + /* MIN tag is length with zero, only length */ \
- 3 + /* version, opcount, opcode */ \
- XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
- /* seqid, slotID, slotID, cache */ \
- 4 ) * sizeof(__be32))
-
-#define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
- 2 + /* verifier: AUTH_NULL, length 0 */\
- 1 + /* status */ \
- 1 + /* MIN tag is length with zero, only length */ \
- 3 + /* opcount, opcode, opstatus*/ \
- XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
- /* seqid, slotID, slotID, slotID, status */ \
- 5 ) * sizeof(__be32))
-
-static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel)
-{
- return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ
- || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ;
-}
-
-__be32
-nfsd4_create_session(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate,
- struct nfsd4_create_session *cr_ses)
-{
- struct sockaddr *sa = svc_addr(rqstp);
- struct nfs4_client *conf, *unconf;
- struct nfsd4_session *new;
- struct nfsd4_clid_slot *cs_slot = NULL;
- bool confirm_me = false;
- int status = 0;
-
- if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
- return nfserr_inval;
-
- nfs4_lock_state();
- unconf = find_unconfirmed_client(&cr_ses->clientid);
- conf = find_confirmed_client(&cr_ses->clientid);
-
- if (conf) {
- cs_slot = &conf->cl_cs_slot;
- status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
- if (status == nfserr_replay_cache) {
- dprintk("Got a create_session replay! seqid= %d\n",
- cs_slot->sl_seqid);
- /* Return the cached reply status */
- status = nfsd4_replay_create_session(cr_ses, cs_slot);
- goto out;
- } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
- status = nfserr_seq_misordered;
- dprintk("Sequence misordered!\n");
- dprintk("Expected seqid= %d but got seqid= %d\n",
- cs_slot->sl_seqid, cr_ses->seqid);
- goto out;
- }
- } else if (unconf) {
- if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
- !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
- status = nfserr_clid_inuse;
- goto out;
- }
-
- cs_slot = &unconf->cl_cs_slot;
- status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
- if (status) {
- /* an unconfirmed replay returns misordered */
- status = nfserr_seq_misordered;
- goto out;
- }
-
- confirm_me = true;
- conf = unconf;
- } else {
- status = nfserr_stale_clientid;
- goto out;
- }
-
- /*
- * XXX: we should probably set this at creation time, and check
- * for consistent minorversion use throughout:
- */
- conf->cl_minorversion = 1;
- /*
- * We do not support RDMA or persistent sessions
- */
- cr_ses->flags &= ~SESSION4_PERSIST;
- cr_ses->flags &= ~SESSION4_RDMA;
-
- status = nfserr_toosmall;
- if (check_forechannel_attrs(cr_ses->fore_channel))
- goto out;
-
- status = nfserr_jukebox;
- new = alloc_init_session(rqstp, conf, cr_ses);
- if (!new)
- goto out;
- status = nfs_ok;
- memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
- NFS4_MAX_SESSIONID_LEN);
- memcpy(&cr_ses->fore_channel, &new->se_fchannel,
- sizeof(struct nfsd4_channel_attrs));
- cs_slot->sl_seqid++;
- cr_ses->seqid = cs_slot->sl_seqid;
-
- /* cache solo and embedded create sessions under the state lock */
- nfsd4_cache_create_session(cr_ses, cs_slot, status);
- if (confirm_me)
- move_to_confirmed(conf);
-out:
- nfs4_unlock_state();
- dprintk("%s returns %d\n", __func__, ntohl(status));
- return status;
-}
-
-static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
-{
- struct nfsd4_compoundres *resp = rqstp->rq_resp;
- struct nfsd4_compoundargs *argp = rqstp->rq_argp;
-
- return argp->opcnt == resp->opcnt;
-}
-
-static __be32 nfsd4_map_bcts_dir(u32 *dir)
-{
- switch (*dir) {
- case NFS4_CDFC4_FORE:
- case NFS4_CDFC4_BACK:
- return nfs_ok;
- case NFS4_CDFC4_FORE_OR_BOTH:
- case NFS4_CDFC4_BACK_OR_BOTH:
- *dir = NFS4_CDFC4_BOTH;
- return nfs_ok;
- };
- return nfserr_inval;
-}
-
-__be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate,
- struct nfsd4_bind_conn_to_session *bcts)
-{
- __be32 status;
-
- if (!nfsd4_last_compound_op(rqstp))
- return nfserr_not_only_op;
- spin_lock(&client_lock);
- cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
- /* Sorta weird: we only need the refcnt'ing because new_conn acquires
- * client_lock iself: */
- if (cstate->session) {
- nfsd4_get_session(cstate->session);
- atomic_inc(&cstate->session->se_client->cl_refcount);
- }
- spin_unlock(&client_lock);
- if (!cstate->session)
- return nfserr_badsession;
-
- status = nfsd4_map_bcts_dir(&bcts->dir);
- if (!status)
- nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
- return status;
-}
-
-static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
-{
- if (!session)
- return 0;
- return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
-}
-
-__be32
-nfsd4_destroy_session(struct svc_rqst *r,
- struct nfsd4_compound_state *cstate,
- struct nfsd4_destroy_session *sessionid)
-{
- struct nfsd4_session *ses;
- u32 status = nfserr_badsession;
-
- /* Notes:
- * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid
- * - Should we return nfserr_back_chan_busy if waiting for
- * callbacks on to-be-destroyed session?
- * - Do we need to clear any callback info from previous session?
- */
-
- if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
- if (!nfsd4_last_compound_op(r))
- return nfserr_not_only_op;
- }
- dump_sessionid(__func__, &sessionid->sessionid);
- spin_lock(&client_lock);
- ses = find_in_sessionid_hashtbl(&sessionid->sessionid);
- if (!ses) {
- spin_unlock(&client_lock);
- goto out;
- }
-
- unhash_session(ses);
- spin_unlock(&client_lock);
-
- nfs4_lock_state();
- nfsd4_probe_callback_sync(ses->se_client);
- nfs4_unlock_state();
-
- spin_lock(&client_lock);
- nfsd4_del_conns(ses);
- nfsd4_put_session_locked(ses);
- spin_unlock(&client_lock);
- status = nfs_ok;
-out:
- dprintk("%s returns %d\n", __func__, ntohl(status));
- return status;
-}
-
-static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
-{
- struct nfsd4_conn *c;
-
- list_for_each_entry(c, &s->se_conns, cn_persession) {
- if (c->cn_xprt == xpt) {
- return c;
- }
- }
- return NULL;
-}
-
-static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
-{
- struct nfs4_client *clp = ses->se_client;
- struct nfsd4_conn *c;
- int ret;
-
- spin_lock(&clp->cl_lock);
- c = __nfsd4_find_conn(new->cn_xprt, ses);
- if (c) {
- spin_unlock(&clp->cl_lock);
- free_conn(new);
- return;
- }
- __nfsd4_hash_conn(new, ses);
- spin_unlock(&clp->cl_lock);
- ret = nfsd4_register_conn(new);
- if (ret)
- /* oops; xprt is already down: */
- nfsd4_conn_lost(&new->cn_xpt_user);
- return;
-}
-
-static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
-{
- struct nfsd4_compoundargs *args = rqstp->rq_argp;
-
- return args->opcnt > session->se_fchannel.maxops;
-}
-
-static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
- struct nfsd4_session *session)
-{
- struct xdr_buf *xb = &rqstp->rq_arg;
-
- return xb->len > session->se_fchannel.maxreq_sz;
-}
-
-__be32
-nfsd4_sequence(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate,
- struct nfsd4_sequence *seq)
-{
- struct nfsd4_compoundres *resp = rqstp->rq_resp;
- struct nfsd4_session *session;
- struct nfsd4_slot *slot;
- struct nfsd4_conn *conn;
- int status;
-
- if (resp->opcnt != 1)
- return nfserr_sequence_pos;
-
- /*
- * Will be either used or freed by nfsd4_sequence_check_conn
- * below.
- */
- conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
- if (!conn)
- return nfserr_jukebox;
-
- spin_lock(&client_lock);
- status = nfserr_badsession;
- session = find_in_sessionid_hashtbl(&seq->sessionid);
- if (!session)
- goto out;
-
- status = nfserr_too_many_ops;
- if (nfsd4_session_too_many_ops(rqstp, session))
- goto out;
-
- status = nfserr_req_too_big;
- if (nfsd4_request_too_big(rqstp, session))
- goto out;
-
- status = nfserr_badslot;
- if (seq->slotid >= session->se_fchannel.maxreqs)
- goto out;
-
- slot = session->se_slots[seq->slotid];
- dprintk("%s: slotid %d\n", __func__, seq->slotid);
-
- /* We do not negotiate the number of slots yet, so set the
- * maxslots to the session maxreqs which is used to encode
- * sr_highest_slotid and the sr_target_slot id to maxslots */
- seq->maxslots = session->se_fchannel.maxreqs;
-
- status = check_slot_seqid(seq->seqid, slot->sl_seqid,
- slot->sl_flags & NFSD4_SLOT_INUSE);
- if (status == nfserr_replay_cache) {
- status = nfserr_seq_misordered;
- if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
- goto out;
- cstate->slot = slot;
- cstate->session = session;
- /* Return the cached reply status and set cstate->status
- * for nfsd4_proc_compound processing */
- status = nfsd4_replay_cache_entry(resp, seq);
- cstate->status = nfserr_replay_cache;
- goto out;
- }
- if (status)
- goto out;
-
- nfsd4_sequence_check_conn(conn, session);
- conn = NULL;
-
- /* Success! bump slot seqid */
- slot->sl_seqid = seq->seqid;
- slot->sl_flags |= NFSD4_SLOT_INUSE;
- if (seq->cachethis)
- slot->sl_flags |= NFSD4_SLOT_CACHETHIS;
- else
- slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS;
-
- cstate->slot = slot;
- cstate->session = session;
-
-out:
- /* Hold a session reference until done processing the compound. */
- if (cstate->session) {
- struct nfs4_client *clp = session->se_client;
-
- nfsd4_get_session(cstate->session);
- atomic_inc(&clp->cl_refcount);
- switch (clp->cl_cb_state) {
- case NFSD4_CB_DOWN:
- seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
- break;
- case NFSD4_CB_FAULT:
- seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
- break;
- default:
- seq->status_flags = 0;
- }
- }
- kfree(conn);
- spin_unlock(&client_lock);
- dprintk("%s: return %d\n", __func__, ntohl(status));
- return status;
-}
-
-static inline bool has_resources(struct nfs4_client *clp)
-{
- return !list_empty(&clp->cl_openowners)
- || !list_empty(&clp->cl_delegations)
- || !list_empty(&clp->cl_sessions);
-}
-
-__be32
-nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
-{
- struct nfs4_client *conf, *unconf, *clp;
- int status = 0;
-
- nfs4_lock_state();
- unconf = find_unconfirmed_client(&dc->clientid);
- conf = find_confirmed_client(&dc->clientid);
-
- if (conf) {
- clp = conf;
-
- if (!is_client_expired(conf) && has_resources(conf)) {
- status = nfserr_clientid_busy;
- goto out;
- }
-
- /* rfc5661 18.50.3 */
- if (cstate->session && conf == cstate->session->se_client) {
- status = nfserr_clientid_busy;
- goto out;
- }
- } else if (unconf)
- clp = unconf;
- else {
- status = nfserr_stale_clientid;
- goto out;
- }
-
- expire_client(clp);
-out:
- nfs4_unlock_state();
- dprintk("%s return %d\n", __func__, ntohl(status));
- return status;
-}
-
-__be32
-nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
-{
- int status = 0;
-
- if (rc->rca_one_fs) {
- if (!cstate->current_fh.fh_dentry)
- return nfserr_nofilehandle;
- /*
- * We don't take advantage of the rca_one_fs case.
- * That's OK, it's optional, we can safely ignore it.
- */
- return nfs_ok;
- }
-
- nfs4_lock_state();
- status = nfserr_complete_already;
- if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
- &cstate->session->se_client->cl_flags))
- goto out;
-
- status = nfserr_stale_clientid;
- if (is_client_expired(cstate->session->se_client))
- /*
- * The following error isn't really legal.
- * But we only get here if the client just explicitly
- * destroyed the client. Surely it no longer cares what
- * error it gets back on an operation for the dead
- * client.
- */
- goto out;
-
- status = nfs_ok;
- nfsd4_client_record_create(cstate->session->se_client);
-out:
- nfs4_unlock_state();
- return status;
-}
-
-__be32
-nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_setclientid *setclid)
-{
- struct xdr_netobj clname = setclid->se_name;
- nfs4_verifier clverifier = setclid->se_verf;
- unsigned int strhashval;
- struct nfs4_client *conf, *unconf, *new;
- __be32 status;
- char dname[HEXDIR_LEN];
-
- status = nfs4_make_rec_clidname(dname, &clname);
- if (status)
- return status;
-
- /*
- * XXX The Duplicate Request Cache (DRC) has been checked (??)
- * We get here on a DRC miss.
- */
-
- strhashval = clientstr_hashval(dname);
-
- nfs4_lock_state();
- conf = find_confirmed_client_by_str(dname, strhashval);
- if (conf) {
- /* RFC 3530 14.2.33 CASE 0: */
- status = nfserr_clid_inuse;
- if (clp_used_exchangeid(conf))
- goto out;
- if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
- char addr_str[INET6_ADDRSTRLEN];
- rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
- sizeof(addr_str));
- dprintk("NFSD: setclientid: string in use by client "
- "at %s\n", addr_str);
- goto out;
- }
- }
- /*
- * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION")
- * has a description of SETCLIENTID request processing consisting
- * of 5 bullet points, labeled as CASE0 - CASE4 below.
- */
- unconf = find_unconfirmed_client_by_str(dname, strhashval);
- status = nfserr_jukebox;
- if (!conf) {
- /*
- * RFC 3530 14.2.33 CASE 4:
- * placed first, because it is the normal case
- */
- if (unconf)
- expire_client(unconf);
- new = create_client(clname, dname, rqstp, &clverifier);
- if (new == NULL)
- goto out;
- gen_clid(new);
- } else if (same_verf(&conf->cl_verifier, &clverifier)) {
- /*
- * RFC 3530 14.2.33 CASE 1:
- * probable callback update
- */
- if (unconf) {
- /* Note this is removing unconfirmed {*x***},
- * which is stronger than RFC recommended {vxc**}.
- * This has the advantage that there is at most
- * one {*x***} in either list at any time.
- */
- expire_client(unconf);
- }
- new = create_client(clname, dname, rqstp, &clverifier);
- if (new == NULL)
- goto out;
- copy_clid(new, conf);
- } else if (!unconf) {
- /*
- * RFC 3530 14.2.33 CASE 2:
- * probable client reboot; state will be removed if
- * confirmed.
- */
- new = create_client(clname, dname, rqstp, &clverifier);
- if (new == NULL)
- goto out;
- gen_clid(new);
- } else {
- /*
- * RFC 3530 14.2.33 CASE 3:
- * probable client reboot; state will be removed if
- * confirmed.
- */
- expire_client(unconf);
- new = create_client(clname, dname, rqstp, &clverifier);
- if (new == NULL)
- goto out;
- gen_clid(new);
- }
- /*
- * XXX: we should probably set this at creation time, and check
- * for consistent minorversion use throughout:
- */
- new->cl_minorversion = 0;
- gen_callback(new, setclid, rqstp);
- add_to_unconfirmed(new, strhashval);
- setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
- setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
- memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
- status = nfs_ok;
-out:
- nfs4_unlock_state();
- return status;
-}
-
-
-/*
- * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has
- * a description of SETCLIENTID_CONFIRM request processing consisting of 4
- * bullets, labeled as CASE1 - CASE4 below.
- */
-__be32
-nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate,
- struct nfsd4_setclientid_confirm *setclientid_confirm)
-{
- struct sockaddr *sa = svc_addr(rqstp);
- struct nfs4_client *conf, *unconf;
- nfs4_verifier confirm = setclientid_confirm->sc_confirm;
- clientid_t * clid = &setclientid_confirm->sc_clientid;
- __be32 status;
-
- if (STALE_CLIENTID(clid))
- return nfserr_stale_clientid;
- /*
- * XXX The Duplicate Request Cache (DRC) has been checked (??)
- * We get here on a DRC miss.
- */
-
- nfs4_lock_state();
-
- conf = find_confirmed_client(clid);
- unconf = find_unconfirmed_client(clid);
-
- status = nfserr_clid_inuse;
- if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa))
- goto out;
- if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa))
- goto out;
-
- /*
- * section 14.2.34 of RFC 3530 has a description of
- * SETCLIENTID_CONFIRM request processing consisting
- * of 4 bullet points, labeled as CASE1 - CASE4 below.
- */
- if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) {
- /*
- * RFC 3530 14.2.34 CASE 1:
- * callback update
- */
- if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
- status = nfserr_clid_inuse;
- else {
- nfsd4_change_callback(conf, &unconf->cl_cb_conn);
- nfsd4_probe_callback(conf);
- expire_client(unconf);
- status = nfs_ok;
-
- }
- } else if (conf && !unconf) {
- /*
- * RFC 3530 14.2.34 CASE 2:
- * probable retransmitted request; play it safe and
- * do nothing.
- */
- if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
- status = nfserr_clid_inuse;
- else
- status = nfs_ok;
- } else if (!conf && unconf
- && same_verf(&unconf->cl_confirm, &confirm)) {
- /*
- * RFC 3530 14.2.34 CASE 3:
- * Normal case; new or rebooted client:
- */
- if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
- status = nfserr_clid_inuse;
- } else {
- unsigned int hash =
- clientstr_hashval(unconf->cl_recdir);
- conf = find_confirmed_client_by_str(unconf->cl_recdir,
- hash);
- if (conf) {
- nfsd4_client_record_remove(conf);
- expire_client(conf);
- }
- move_to_confirmed(unconf);
- conf = unconf;
- nfsd4_probe_callback(conf);
- status = nfs_ok;
- }
- } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
- && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
- &confirm)))) {
- /*
- * RFC 3530 14.2.34 CASE 4:
- * Client probably hasn't noticed that we rebooted yet.
- */
- status = nfserr_stale_clientid;
- } else {
- /* check that we have hit one of the cases...*/
- status = nfserr_clid_inuse;
- }
-out:
- nfs4_unlock_state();
- return status;
-}
-
-static struct nfs4_file *nfsd4_alloc_file(void)
-{
- return kmem_cache_alloc(file_slab, GFP_KERNEL);
-}
-
-/* OPEN Share state helper functions */
-static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
-{
- unsigned int hashval = file_hashval(ino);
-
- atomic_set(&fp->fi_ref, 1);
- INIT_LIST_HEAD(&fp->fi_hash);
- INIT_LIST_HEAD(&fp->fi_stateids);
- INIT_LIST_HEAD(&fp->fi_delegations);
- fp->fi_inode = igrab(ino);
- fp->fi_had_conflict = false;
- fp->fi_lease = NULL;
- memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
- memset(fp->fi_access, 0, sizeof(fp->fi_access));
- spin_lock(&recall_lock);
- list_add(&fp->fi_hash, &file_hashtbl[hashval]);
- spin_unlock(&recall_lock);
-}
-
-static void
-nfsd4_free_slab(struct kmem_cache **slab)
-{
- if (*slab == NULL)
- return;
- kmem_cache_destroy(*slab);
- *slab = NULL;
-}
-
-void
-nfsd4_free_slabs(void)
-{
- nfsd4_free_slab(&openowner_slab);
- nfsd4_free_slab(&lockowner_slab);
- nfsd4_free_slab(&file_slab);
- nfsd4_free_slab(&stateid_slab);
- nfsd4_free_slab(&deleg_slab);
-}
-
-int
-nfsd4_init_slabs(void)
-{
- openowner_slab = kmem_cache_create("nfsd4_openowners",
- sizeof(struct nfs4_openowner), 0, 0, NULL);
- if (openowner_slab == NULL)
- goto out_nomem;
- lockowner_slab = kmem_cache_create("nfsd4_lockowners",
- sizeof(struct nfs4_openowner), 0, 0, NULL);
- if (lockowner_slab == NULL)
- goto out_nomem;
- file_slab = kmem_cache_create("nfsd4_files",
- sizeof(struct nfs4_file), 0, 0, NULL);
- if (file_slab == NULL)
- goto out_nomem;
- stateid_slab = kmem_cache_create("nfsd4_stateids",
- sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
- if (stateid_slab == NULL)
- goto out_nomem;
- deleg_slab = kmem_cache_create("nfsd4_delegations",
- sizeof(struct nfs4_delegation), 0, 0, NULL);
- if (deleg_slab == NULL)
- goto out_nomem;
- return 0;
-out_nomem:
- nfsd4_free_slabs();
- dprintk("nfsd4: out of memory while initializing nfsv4\n");
- return -ENOMEM;
-}
-
-void nfs4_free_openowner(struct nfs4_openowner *oo)
-{
- kfree(oo->oo_owner.so_owner.data);
- kmem_cache_free(openowner_slab, oo);
-}
-
-void nfs4_free_lockowner(struct nfs4_lockowner *lo)
-{
- kfree(lo->lo_owner.so_owner.data);
- kmem_cache_free(lockowner_slab, lo);
-}
-
-static void init_nfs4_replay(struct nfs4_replay *rp)
-{
- rp->rp_status = nfserr_serverfault;
- rp->rp_buflen = 0;
- rp->rp_buf = rp->rp_ibuf;
-}
-
-static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
-{
- struct nfs4_stateowner *sop;
-
- sop = kmem_cache_alloc(slab, GFP_KERNEL);
- if (!sop)
- return NULL;
-
- sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
- if (!sop->so_owner.data) {
- kmem_cache_free(slab, sop);
- return NULL;
- }
- sop->so_owner.len = owner->len;
-
- INIT_LIST_HEAD(&sop->so_stateids);
- sop->so_client = clp;
- init_nfs4_replay(&sop->so_replay);
- return sop;
-}
-
-static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
-{
- list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
- list_add(&oo->oo_perclient, &clp->cl_openowners);
-}
-
-static struct nfs4_openowner *
-alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
- struct nfs4_openowner *oo;
-
- oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
- if (!oo)
- return NULL;
- oo->oo_owner.so_is_open_owner = 1;
- oo->oo_owner.so_seqid = open->op_seqid;
- oo->oo_flags = NFS4_OO_NEW;
- oo->oo_time = 0;
- oo->oo_last_closed_stid = NULL;
- INIT_LIST_HEAD(&oo->oo_close_lru);
- hash_openowner(oo, clp, strhashval);
- return oo;
-}
-
-static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
- struct nfs4_openowner *oo = open->op_openowner;
- struct nfs4_client *clp = oo->oo_owner.so_client;
-
- init_stid(&stp->st_stid, clp, NFS4_OPEN_STID);
- INIT_LIST_HEAD(&stp->st_lockowners);
- list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
- list_add(&stp->st_perfile, &fp->fi_stateids);
- stp->st_stateowner = &oo->oo_owner;
- get_nfs4_file(fp);
- stp->st_file = fp;
- stp->st_access_bmap = 0;
- stp->st_deny_bmap = 0;
- __set_bit(open->op_share_access, &stp->st_access_bmap);
- __set_bit(open->op_share_deny, &stp->st_deny_bmap);
- stp->st_openstp = NULL;
-}
-
-static void
-move_to_close_lru(struct nfs4_openowner *oo)
-{
- dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
-
- list_move_tail(&oo->oo_close_lru, &close_lru);
- oo->oo_time = get_seconds();
-}
-
-static int
-same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
- clientid_t *clid)
-{
- return (sop->so_owner.len == owner->len) &&
- 0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
- (sop->so_client->cl_clientid.cl_id == clid->cl_id);
-}
-
-static struct nfs4_openowner *
-find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
-{
- struct nfs4_stateowner *so;
- struct nfs4_openowner *oo;
-
- list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
- if (!so->so_is_open_owner)
- continue;
- if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
- oo = openowner(so);
- renew_client(oo->oo_owner.so_client);
- return oo;
- }
- }
- return NULL;
-}
-
-/* search file_hashtbl[] for file */
-static struct nfs4_file *
-find_file(struct inode *ino)
-{
- unsigned int hashval = file_hashval(ino);
- struct nfs4_file *fp;
-
- spin_lock(&recall_lock);
- list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
- if (fp->fi_inode == ino) {
- get_nfs4_file(fp);
- spin_unlock(&recall_lock);
- return fp;
- }
- }
- spin_unlock(&recall_lock);
- return NULL;
-}
-
-/*
- * Called to check deny when READ with all zero stateid or
- * WRITE with all zero or all one stateid
- */
-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_ol_stateid *stp;
- __be32 ret;
-
- dprintk("NFSD: nfs4_share_conflict\n");
-
- fp = find_file(ino);
- if (!fp)
- return nfs_ok;
- ret = nfserr_locked;
- /* Search for conflicting share reservations */
- list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
- if (test_bit(deny_type, &stp->st_deny_bmap) ||
- test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
- goto out;
- }
- ret = nfs_ok;
-out:
- put_nfs4_file(fp);
- return ret;
-}
-
-static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
-{
- /* We're assuming the state code never drops its reference
- * without first removing the lease. Since we're in this lease
- * callback (and since the lease code is serialized by the kernel
- * lock) we know the server hasn't removed the lease yet, we know
- * it's safe to take a reference: */
- atomic_inc(&dp->dl_count);
-
- list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
-
- /* only place dl_time is set. protected by lock_flocks*/
- 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'll remove it ourself if a delegation isn't returned
- * in time:
- */
- fl->fl_break_time = 0;
-
- spin_lock(&recall_lock);
- 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
-int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
-{
- if (arg & F_UNLCK)
- return lease_modify(onlist, arg);
- else
- return -EAGAIN;
-}
-
-static const struct lock_manager_operations nfsd_lease_mng_ops = {
- .lm_break = nfsd_break_deleg_cb,
- .lm_change = nfsd_change_deleg_cb,
-};
-
-static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
-{
- if (nfsd4_has_session(cstate))
- return nfs_ok;
- if (seqid == so->so_seqid - 1)
- return nfserr_replay_me;
- if (seqid == so->so_seqid)
- return nfs_ok;
- return nfserr_bad_seqid;
-}
-
-__be32
-nfsd4_process_open1(struct nfsd4_compound_state *cstate,
- struct nfsd4_open *open)
-{
- clientid_t *clientid = &open->op_clientid;
- struct nfs4_client *clp = NULL;
- unsigned int strhashval;
- struct nfs4_openowner *oo = NULL;
- __be32 status;
-
- if (STALE_CLIENTID(&open->op_clientid))
- return nfserr_stale_clientid;
- /*
- * In case we need it later, after we've already created the
- * file and don't want to risk a further failure:
- */
- open->op_file = nfsd4_alloc_file();
- if (open->op_file == NULL)
- return nfserr_jukebox;
-
- strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
- oo = find_openstateowner_str(strhashval, open);
- open->op_openowner = oo;
- if (!oo) {
- clp = find_confirmed_client(clientid);
- if (clp == NULL)
- return nfserr_expired;
- goto new_owner;
- }
- if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
- /* Replace unconfirmed owners without checking for replay. */
- clp = oo->oo_owner.so_client;
- release_openowner(oo);
- open->op_openowner = NULL;
- goto new_owner;
- }
- status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
- if (status)
- return status;
- clp = oo->oo_owner.so_client;
- goto alloc_stateid;
-new_owner:
- oo = alloc_init_open_stateowner(strhashval, clp, open);
- if (oo == NULL)
- return nfserr_jukebox;
- open->op_openowner = oo;
-alloc_stateid:
- open->op_stp = nfs4_alloc_stateid(clp);
- if (!open->op_stp)
- return nfserr_jukebox;
- return nfs_ok;
-}
-
-static inline __be32
-nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
-{
- if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
- return nfserr_openmode;
- else
- return nfs_ok;
-}
-
-static int share_access_to_flags(u32 share_access)
-{
- return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
-}
-
-static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
-{
- struct nfs4_stid *ret;
-
- ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
- if (!ret)
- return NULL;
- return delegstateid(ret);
-}
-
-static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
-{
- return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
- open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH;
-}
-
-static __be32
-nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open *open,
- struct nfs4_delegation **dp)
-{
- int flags;
- __be32 status = nfserr_bad_stateid;
-
- *dp = find_deleg_stateid(cl, &open->op_delegate_stateid);
- if (*dp == NULL)
- goto out;
- flags = share_access_to_flags(open->op_share_access);
- status = nfs4_check_delegmode(*dp, flags);
- if (status)
- *dp = NULL;
-out:
- if (!nfsd4_is_deleg_cur(open))
- return nfs_ok;
- if (status)
- return status;
- open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
- return nfs_ok;
-}
-
-static __be32
-nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp)
-{
- struct nfs4_ol_stateid *local;
- struct nfs4_openowner *oo = open->op_openowner;
-
- list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
- /* ignore lock owners */
- if (local->st_stateowner->so_is_open_owner == 0)
- continue;
- /* remember if we have seen this open owner */
- if (local->st_stateowner == &oo->oo_owner)
- *stpp = local;
- /* check for conflicting share reservations */
- if (!test_share(local, open))
- return nfserr_share_denied;
- }
- return nfs_ok;
-}
-
-static void nfs4_free_stateid(struct nfs4_ol_stateid *s)
-{
- kmem_cache_free(stateid_slab, s);
-}
-
-static inline int nfs4_access_to_access(u32 nfs4_access)
-{
- int flags = 0;
-
- if (nfs4_access & NFS4_SHARE_ACCESS_READ)
- flags |= NFSD_MAY_READ;
- if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
- flags |= NFSD_MAY_WRITE;
- return flags;
-}
-
-static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
- struct svc_fh *cur_fh, struct nfsd4_open *open)
-{
- __be32 status;
- int oflag = nfs4_access_to_omode(open->op_share_access);
- int access = nfs4_access_to_access(open->op_share_access);
-
- if (!fp->fi_fds[oflag]) {
- status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
- &fp->fi_fds[oflag]);
- if (status)
- return status;
- }
- nfs4_file_get_access(fp, oflag);
-
- return nfs_ok;
-}
-
-static inline __be32
-nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
- struct nfsd4_open *open)
-{
- struct iattr iattr = {
- .ia_valid = ATTR_SIZE,
- .ia_size = 0,
- };
- if (!open->op_truncate)
- return 0;
- if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
- return nfserr_inval;
- return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
-}
-
-static __be32
-nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
-{
- u32 op_share_access = open->op_share_access;
- bool new_access;
- __be32 status;
-
- new_access = !test_bit(op_share_access, &stp->st_access_bmap);
- if (new_access) {
- status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
- if (status)
- return status;
- }
- status = nfsd4_truncate(rqstp, cur_fh, open);
- if (status) {
- if (new_access) {
- int oflag = nfs4_access_to_omode(op_share_access);
- nfs4_file_put_access(fp, oflag);
- }
- return status;
- }
- /* remember the open */
- __set_bit(op_share_access, &stp->st_access_bmap);
- __set_bit(open->op_share_deny, &stp->st_deny_bmap);
-
- return nfs_ok;
-}
-
-
-static void
-nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session)
-{
- open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
-}
-
-/* Should we give out recallable state?: */
-static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
-{
- if (clp->cl_cb_state == NFSD4_CB_UP)
- return true;
- /*
- * In the sessions case, since we don't have to establish a
- * separate connection for callbacks, we assume it's OK
- * until we hear otherwise:
- */
- 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_stid.sc_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_stid.sc_client->cl_delegations);
- return 0;
-}
-
-static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
-{
- open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
- if (status == -EAGAIN)
- open->op_why_no_deleg = WND4_CONTENTION;
- else {
- open->op_why_no_deleg = WND4_RESOURCE;
- switch (open->op_deleg_want) {
- case NFS4_SHARE_WANT_READ_DELEG:
- case NFS4_SHARE_WANT_WRITE_DELEG:
- case NFS4_SHARE_WANT_ANY_DELEG:
- break;
- case NFS4_SHARE_WANT_CANCEL:
- open->op_why_no_deleg = WND4_CANCELLED;
- break;
- case NFS4_SHARE_WANT_NO_DELEG:
- BUG(); /* not supposed to get here */
- }
- }
-}
-
-/*
- * Attempt to hand out a delegation.
- */
-static void
-nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
-{
- struct nfs4_delegation *dp;
- struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
- int cb_up;
- int status = 0, flag = 0;
-
- cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
- flag = NFS4_OPEN_DELEGATE_NONE;
- open->op_recall = 0;
- switch (open->op_claim_type) {
- case NFS4_OPEN_CLAIM_PREVIOUS:
- if (!cb_up)
- open->op_recall = 1;
- flag = open->op_delegate_type;
- if (flag == NFS4_OPEN_DELEGATE_NONE)
- goto out;
- break;
- case NFS4_OPEN_CLAIM_NULL:
- /* Let's not give out any delegations till everyone's
- * had the chance to reclaim theirs.... */
- if (locks_in_grace())
- goto out;
- if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
- goto out;
- if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
- flag = NFS4_OPEN_DELEGATE_WRITE;
- else
- flag = NFS4_OPEN_DELEGATE_READ;
- break;
- default:
- goto out;
- }
-
- dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag);
- if (dp == NULL)
- goto out_no_deleg;
- status = nfs4_set_delegation(dp, flag);
- if (status)
- goto out_free;
-
- memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
-
- dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
- STATEID_VAL(&dp->dl_stid.sc_stateid));
-out:
- open->op_delegate_type = flag;
- if (flag == NFS4_OPEN_DELEGATE_NONE) {
- if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
- open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
- dprintk("NFSD: WARNING: refusing delegation reclaim\n");
-
- /* 4.1 client asking for a delegation? */
- if (open->op_deleg_want)
- nfsd4_open_deleg_none_ext(open, status);
- }
- return;
-out_free:
- nfs4_put_delegation(dp);
-out_no_deleg:
- flag = NFS4_OPEN_DELEGATE_NONE;
- goto out;
-}
-
-static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
- struct nfs4_delegation *dp)
-{
- if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG &&
- dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
- open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
- open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE;
- } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG &&
- dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) {
- open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
- open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE;
- }
- /* Otherwise the client must be confused wanting a delegation
- * it already has, therefore we don't return
- * NFS4_OPEN_DELEGATE_NONE_EXT and reason.
- */
-}
-
-/*
- * called with nfs4_lock_state() held.
- */
-__be32
-nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
-{
- struct nfsd4_compoundres *resp = rqstp->rq_resp;
- struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
- struct nfs4_file *fp = NULL;
- struct inode *ino = current_fh->fh_dentry->d_inode;
- struct nfs4_ol_stateid *stp = NULL;
- struct nfs4_delegation *dp = NULL;
- __be32 status;
-
- /*
- * Lookup file; if found, lookup stateid and check open request,
- * and check for delegations in the process of being recalled.
- * If not found, create the nfs4_file struct
- */
- fp = find_file(ino);
- if (fp) {
- if ((status = nfs4_check_open(fp, open, &stp)))
- goto out;
- status = nfs4_check_deleg(cl, fp, open, &dp);
- if (status)
- goto out;
- } else {
- status = nfserr_bad_stateid;
- if (nfsd4_is_deleg_cur(open))
- goto out;
- status = nfserr_jukebox;
- fp = open->op_file;
- open->op_file = NULL;
- nfsd4_init_file(fp, ino);
- }
-
- /*
- * OPEN the file, or upgrade an existing OPEN.
- * If truncate fails, the OPEN fails.
- */
- if (stp) {
- /* Stateid was found, this is an OPEN upgrade */
- status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
- if (status)
- goto out;
- } else {
- status = nfs4_get_vfs_file(rqstp, fp, current_fh, open);
- if (status)
- goto out;
- stp = open->op_stp;
- open->op_stp = NULL;
- init_open_stateid(stp, fp, open);
- status = nfsd4_truncate(rqstp, current_fh, open);
- if (status) {
- release_open_stateid(stp);
- goto out;
- }
- }
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
-
- if (nfsd4_has_session(&resp->cstate)) {
- open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
-
- if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
- open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
- open->op_why_no_deleg = WND4_NOT_WANTED;
- goto nodeleg;
- }
- }
-
- /*
- * Attempt to hand out a delegation. No error return, because the
- * OPEN succeeds even if we fail.
- */
- nfs4_open_delegation(current_fh, open, stp);
-nodeleg:
- status = nfs_ok;
-
- dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
- STATEID_VAL(&stp->st_stid.sc_stateid));
-out:
- /* 4.1 client trying to upgrade/downgrade delegation? */
- if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
- open->op_deleg_want)
- nfsd4_deleg_xgrade_none_ext(open, dp);
-
- if (fp)
- put_nfs4_file(fp);
- if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate));
- /*
- * To finish the open response, we just need to set the rflags.
- */
- open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
- if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
- !nfsd4_has_session(&resp->cstate))
- open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
-
- return status;
-}
-
-void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
-{
- if (open->op_openowner) {
- struct nfs4_openowner *oo = open->op_openowner;
-
- if (!list_empty(&oo->oo_owner.so_stateids))
- list_del_init(&oo->oo_close_lru);
- if (oo->oo_flags & NFS4_OO_NEW) {
- if (status) {
- release_openowner(oo);
- open->op_openowner = NULL;
- } else
- oo->oo_flags &= ~NFS4_OO_NEW;
- }
- }
- if (open->op_file)
- nfsd4_free_file(open->op_file);
- if (open->op_stp)
- nfs4_free_stateid(open->op_stp);
-}
-
-__be32
-nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- clientid_t *clid)
-{
- struct nfs4_client *clp;
- __be32 status;
-
- nfs4_lock_state();
- dprintk("process_renew(%08x/%08x): starting\n",
- clid->cl_boot, clid->cl_id);
- status = nfserr_stale_clientid;
- if (STALE_CLIENTID(clid))
- goto out;
- clp = find_confirmed_client(clid);
- status = nfserr_expired;
- if (clp == NULL) {
- /* We assume the client took too long to RENEW. */
- dprintk("nfsd4_renew: clientid not found!\n");
- goto out;
- }
- status = nfserr_cb_path_down;
- if (!list_empty(&clp->cl_delegations)
- && clp->cl_cb_state != NFSD4_CB_UP)
- goto out;
- status = nfs_ok;
-out:
- nfs4_unlock_state();
- return status;
-}
-
-static struct lock_manager nfsd4_manager = {
-};
-
-static void
-nfsd4_end_grace(void)
-{
- dprintk("NFSD: end of grace period\n");
- nfsd4_record_grace_done(&init_net, boot_time);
- locks_end_grace(&nfsd4_manager);
- /*
- * Now that every NFSv4 client has had the chance to recover and
- * to see the (possibly new, possibly shorter) lease time, we
- * can safely set the next grace time to the current lease time:
- */
- nfsd4_grace = nfsd4_lease;
-}
-
-static time_t
-nfs4_laundromat(void)
-{
- struct nfs4_client *clp;
- struct nfs4_openowner *oo;
- struct nfs4_delegation *dp;
- struct list_head *pos, *next, reaplist;
- time_t cutoff = get_seconds() - nfsd4_lease;
- time_t t, clientid_val = nfsd4_lease;
- time_t u, test_val = nfsd4_lease;
-
- nfs4_lock_state();
-
- dprintk("NFSD: laundromat service - starting\n");
- if (locks_in_grace())
- nfsd4_end_grace();
- INIT_LIST_HEAD(&reaplist);
- spin_lock(&client_lock);
- list_for_each_safe(pos, next, &client_lru) {
- clp = list_entry(pos, struct nfs4_client, cl_lru);
- if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
- t = clp->cl_time - cutoff;
- if (clientid_val > t)
- clientid_val = t;
- break;
- }
- if (atomic_read(&clp->cl_refcount)) {
- dprintk("NFSD: client in use (clientid %08x)\n",
- clp->cl_clientid.cl_id);
- continue;
- }
- unhash_client_locked(clp);
- list_add(&clp->cl_lru, &reaplist);
- }
- spin_unlock(&client_lock);
- list_for_each_safe(pos, next, &reaplist) {
- clp = list_entry(pos, struct nfs4_client, cl_lru);
- dprintk("NFSD: purging unused client (clientid %08x)\n",
- clp->cl_clientid.cl_id);
- nfsd4_client_record_remove(clp);
- expire_client(clp);
- }
- spin_lock(&recall_lock);
- list_for_each_safe(pos, next, &del_recall_lru) {
- dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
- if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
- u = dp->dl_time - cutoff;
- if (test_val > u)
- test_val = u;
- break;
- }
- list_move(&dp->dl_recall_lru, &reaplist);
- }
- spin_unlock(&recall_lock);
- list_for_each_safe(pos, next, &reaplist) {
- dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
- }
- test_val = nfsd4_lease;
- list_for_each_safe(pos, next, &close_lru) {
- oo = container_of(pos, struct nfs4_openowner, oo_close_lru);
- if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) {
- u = oo->oo_time - cutoff;
- if (test_val > u)
- test_val = u;
- break;
- }
- release_openowner(oo);
- }
- if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
- clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
- nfs4_unlock_state();
- return clientid_val;
-}
-
-static struct workqueue_struct *laundry_wq;
-static void laundromat_main(struct work_struct *);
-static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
-
-static void
-laundromat_main(struct work_struct *not_used)
-{
- time_t t;
-
- t = nfs4_laundromat();
- dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
- queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
-}
-
-static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
-{
- if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode)
- return nfserr_bad_stateid;
- return nfs_ok;
-}
-
-static int
-STALE_STATEID(stateid_t *stateid)
-{
- if (stateid->si_opaque.so_clid.cl_boot == boot_time)
- return 0;
- dprintk("NFSD: stale stateid " STATEID_FMT "!\n",
- STATEID_VAL(stateid));
- return 1;
-}
-
-static inline int
-access_permit_read(unsigned long access_bmap)
-{
- return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) ||
- test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) ||
- test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap);
-}
-
-static inline int
-access_permit_write(unsigned long access_bmap)
-{
- return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) ||
- test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
-}
-
-static
-__be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
-{
- __be32 status = nfserr_openmode;
-
- /* For lock stateid's, we test the parent open, not the lock: */
- if (stp->st_openstp)
- stp = stp->st_openstp;
- if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
- goto out;
- if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap)))
- goto out;
- status = nfs_ok;
-out:
- return status;
-}
-
-static inline __be32
-check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
-{
- if (ONE_STATEID(stateid) && (flags & RD_STATE))
- return nfs_ok;
- else if (locks_in_grace()) {
- /* Answer in remaining cases depends on existence of
- * conflicting state; so we must wait out the grace period. */
- return nfserr_grace;
- } else if (flags & WR_STATE)
- return nfs4_share_conflict(current_fh,
- NFS4_SHARE_DENY_WRITE);
- else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
- return nfs4_share_conflict(current_fh,
- NFS4_SHARE_DENY_READ);
-}
-
-/*
- * Allow READ/WRITE during grace period on recovered state only for files
- * that are not able to provide mandatory locking.
- */
-static inline int
-grace_disallows_io(struct inode *inode)
-{
- return locks_in_grace() && mandatory_lock(inode);
-}
-
-/* Returns true iff a is later than b: */
-static bool stateid_generation_after(stateid_t *a, stateid_t *b)
-{
- return (s32)a->si_generation - (s32)b->si_generation > 0;
-}
-
-static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
-{
- /*
- * When sessions are used the stateid generation number is ignored
- * when it is zero.
- */
- if (has_session && in->si_generation == 0)
- return nfs_ok;
-
- if (in->si_generation == ref->si_generation)
- return nfs_ok;
-
- /* If the client sends us a stateid from the future, it's buggy: */
- if (stateid_generation_after(in, ref))
- return nfserr_bad_stateid;
- /*
- * However, we could see a stateid from the past, even from a
- * non-buggy client. For example, if the client sends a lock
- * while some IO is outstanding, the lock may bump si_generation
- * while the IO is still in flight. The client could avoid that
- * situation by waiting for responses on all the IO requests,
- * but better performance may result in retrying IO that
- * receives an old_stateid error if requests are rarely
- * reordered in flight:
- */
- return nfserr_old_stateid;
-}
-
-__be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
-{
- struct nfs4_stid *s;
- struct nfs4_ol_stateid *ols;
- __be32 status;
-
- if (STALE_STATEID(stateid))
- return nfserr_stale_stateid;
-
- s = find_stateid(cl, stateid);
- if (!s)
- return nfserr_stale_stateid;
- status = check_stateid_generation(stateid, &s->sc_stateid, 1);
- if (status)
- return status;
- if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID)))
- return nfs_ok;
- ols = openlockstateid(s);
- if (ols->st_stateowner->so_is_open_owner
- && !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
- return nfserr_bad_stateid;
- return nfs_ok;
-}
-
-static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s)
-{
- struct nfs4_client *cl;
-
- if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
- return nfserr_bad_stateid;
- if (STALE_STATEID(stateid))
- return nfserr_stale_stateid;
- cl = find_confirmed_client(&stateid->si_opaque.so_clid);
- if (!cl)
- return nfserr_expired;
- *s = find_stateid_by_type(cl, stateid, typemask);
- if (!*s)
- return nfserr_bad_stateid;
- return nfs_ok;
-
-}
-
-/*
-* Checks for stateid operations
-*/
-__be32
-nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
- stateid_t *stateid, int flags, struct file **filpp)
-{
- struct nfs4_stid *s;
- struct nfs4_ol_stateid *stp = NULL;
- struct nfs4_delegation *dp = NULL;
- struct svc_fh *current_fh = &cstate->current_fh;
- struct inode *ino = current_fh->fh_dentry->d_inode;
- __be32 status;
-
- if (filpp)
- *filpp = NULL;
-
- if (grace_disallows_io(ino))
- return nfserr_grace;
-
- if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
- return check_special_stateids(current_fh, stateid, flags);
-
- status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s);
- if (status)
- return status;
- status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
- if (status)
- goto out;
- switch (s->sc_type) {
- case NFS4_DELEG_STID:
- dp = delegstateid(s);
- status = nfs4_check_delegmode(dp, flags);
- if (status)
- goto out;
- if (filpp) {
- *filpp = dp->dl_file->fi_deleg_file;
- BUG_ON(!*filpp);
- }
- break;
- case NFS4_OPEN_STID:
- case NFS4_LOCK_STID:
- stp = openlockstateid(s);
- status = nfs4_check_fh(current_fh, stp);
- if (status)
- goto out;
- if (stp->st_stateowner->so_is_open_owner
- && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED))
- goto out;
- status = nfs4_check_openmode(stp, flags);
- if (status)
- goto out;
- if (filpp) {
- if (flags & RD_STATE)
- *filpp = find_readable_file(stp->st_file);
- else
- *filpp = find_writeable_file(stp->st_file);
- }
- break;
- default:
- return nfserr_bad_stateid;
- }
- status = nfs_ok;
-out:
- return status;
-}
-
-static __be32
-nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
-{
- if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
- return nfserr_locks_held;
- release_lock_stateid(stp);
- return nfs_ok;
-}
-
-/*
- * Test if the stateid is valid
- */
-__be32
-nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_test_stateid *test_stateid)
-{
- struct nfsd4_test_stateid_id *stateid;
- struct nfs4_client *cl = cstate->session->se_client;
-
- nfs4_lock_state();
- list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
- stateid->ts_id_status = nfs4_validate_stateid(cl, &stateid->ts_id_stateid);
- nfs4_unlock_state();
-
- return nfs_ok;
-}
-
-__be32
-nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_free_stateid *free_stateid)
-{
- stateid_t *stateid = &free_stateid->fr_stateid;
- struct nfs4_stid *s;
- struct nfs4_client *cl = cstate->session->se_client;
- __be32 ret = nfserr_bad_stateid;
-
- nfs4_lock_state();
- s = find_stateid(cl, stateid);
- if (!s)
- goto out;
- switch (s->sc_type) {
- case NFS4_DELEG_STID:
- ret = nfserr_locks_held;
- goto out;
- case NFS4_OPEN_STID:
- case NFS4_LOCK_STID:
- ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
- if (ret)
- goto out;
- if (s->sc_type == NFS4_LOCK_STID)
- ret = nfsd4_free_lock_stateid(openlockstateid(s));
- else
- ret = nfserr_locks_held;
- break;
- default:
- ret = nfserr_bad_stateid;
- }
-out:
- nfs4_unlock_state();
- return ret;
-}
-
-static inline int
-setlkflg (int type)
-{
- return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
- RD_STATE : WR_STATE;
-}
-
-static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
-{
- struct svc_fh *current_fh = &cstate->current_fh;
- struct nfs4_stateowner *sop = stp->st_stateowner;
- __be32 status;
-
- status = nfsd4_check_seqid(cstate, sop, seqid);
- if (status)
- return status;
- if (stp->st_stid.sc_type == NFS4_CLOSED_STID)
- /*
- * "Closed" stateid's exist *only* to return
- * nfserr_replay_me from the previous step.
- */
- return nfserr_bad_stateid;
- status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
- if (status)
- return status;
- return nfs4_check_fh(current_fh, stp);
-}
-
-/*
- * Checks for sequence id mutating operations.
- */
-static __be32
-nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
- stateid_t *stateid, char typemask,
- struct nfs4_ol_stateid **stpp)
-{
- __be32 status;
- struct nfs4_stid *s;
-
- dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
- seqid, STATEID_VAL(stateid));
-
- *stpp = NULL;
- status = nfsd4_lookup_stateid(stateid, typemask, &s);
- if (status)
- return status;
- *stpp = openlockstateid(s);
- cstate->replay_owner = (*stpp)->st_stateowner;
-
- return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
-}
-
-static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp)
-{
- __be32 status;
- struct nfs4_openowner *oo;
-
- status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
- NFS4_OPEN_STID, stpp);
- if (status)
- return status;
- oo = openowner((*stpp)->st_stateowner);
- if (!(oo->oo_flags & NFS4_OO_CONFIRMED))
- return nfserr_bad_stateid;
- return nfs_ok;
-}
-
-__be32
-nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_open_confirm *oc)
-{
- __be32 status;
- struct nfs4_openowner *oo;
- struct nfs4_ol_stateid *stp;
-
- dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
- (int)cstate->current_fh.fh_dentry->d_name.len,
- cstate->current_fh.fh_dentry->d_name.name);
-
- status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
- if (status)
- return status;
-
- nfs4_lock_state();
-
- status = nfs4_preprocess_seqid_op(cstate,
- oc->oc_seqid, &oc->oc_req_stateid,
- NFS4_OPEN_STID, &stp);
- if (status)
- goto out;
- oo = openowner(stp->st_stateowner);
- status = nfserr_bad_stateid;
- if (oo->oo_flags & NFS4_OO_CONFIRMED)
- goto out;
- oo->oo_flags |= NFS4_OO_CONFIRMED;
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
- dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
- __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
-
- nfsd4_client_record_create(oo->oo_owner.so_client);
- status = nfs_ok;
-out:
- if (!cstate->replay_owner)
- nfs4_unlock_state();
- return status;
-}
-
-static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access)
-{
- if (!test_bit(access, &stp->st_access_bmap))
- return;
- nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access));
- __clear_bit(access, &stp->st_access_bmap);
-}
-
-static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access)
-{
- switch (to_access) {
- case NFS4_SHARE_ACCESS_READ:
- nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE);
- nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
- break;
- case NFS4_SHARE_ACCESS_WRITE:
- nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ);
- nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH);
- break;
- case NFS4_SHARE_ACCESS_BOTH:
- break;
- default:
- BUG();
- }
-}
-
-static void
-reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
-{
- int i;
- for (i = 0; i < 4; i++) {
- if ((i & deny) != i)
- __clear_bit(i, bmap);
- }
-}
-
-__be32
-nfsd4_open_downgrade(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate,
- struct nfsd4_open_downgrade *od)
-{
- __be32 status;
- struct nfs4_ol_stateid *stp;
-
- dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
- (int)cstate->current_fh.fh_dentry->d_name.len,
- cstate->current_fh.fh_dentry->d_name.name);
-
- /* We don't yet support WANT bits: */
- if (od->od_deleg_want)
- dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
- od->od_deleg_want);
-
- nfs4_lock_state();
- status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
- &od->od_stateid, &stp);
- if (status)
- goto out;
- status = nfserr_inval;
- if (!test_bit(od->od_share_access, &stp->st_access_bmap)) {
- dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n",
- stp->st_access_bmap, od->od_share_access);
- goto out;
- }
- if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) {
- dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n",
- stp->st_deny_bmap, od->od_share_deny);
- goto out;
- }
- nfs4_stateid_downgrade(stp, od->od_share_access);
-
- reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
-
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
- status = nfs_ok;
-out:
- if (!cstate->replay_owner)
- nfs4_unlock_state();
- return status;
-}
-
-void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so)
-{
- struct nfs4_openowner *oo;
- struct nfs4_ol_stateid *s;
-
- if (!so->so_is_open_owner)
- return;
- oo = openowner(so);
- s = oo->oo_last_closed_stid;
- if (!s)
- return;
- if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) {
- /* Release the last_closed_stid on the next seqid bump: */
- oo->oo_flags |= NFS4_OO_PURGE_CLOSE;
- return;
- }
- oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE;
- release_last_closed_stateid(oo);
-}
-
-static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
-{
- unhash_open_stateid(s);
- s->st_stid.sc_type = NFS4_CLOSED_STID;
-}
-
-/*
- * nfs4_unlock_state() called after encode
- */
-__be32
-nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_close *close)
-{
- __be32 status;
- struct nfs4_openowner *oo;
- struct nfs4_ol_stateid *stp;
-
- dprintk("NFSD: nfsd4_close on file %.*s\n",
- (int)cstate->current_fh.fh_dentry->d_name.len,
- cstate->current_fh.fh_dentry->d_name.name);
-
- nfs4_lock_state();
- status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
- &close->cl_stateid,
- NFS4_OPEN_STID|NFS4_CLOSED_STID,
- &stp);
- if (status)
- goto out;
- oo = openowner(stp->st_stateowner);
- status = nfs_ok;
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
-
- nfsd4_close_open_stateid(stp);
- oo->oo_last_closed_stid = stp;
-
- /* place unused nfs4_stateowners on so_close_lru list to be
- * released by the laundromat service after the lease period
- * to enable us to handle CLOSE replay
- */
- if (list_empty(&oo->oo_owner.so_stateids))
- move_to_close_lru(oo);
-out:
- if (!cstate->replay_owner)
- nfs4_unlock_state();
- return status;
-}
-
-__be32
-nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_delegreturn *dr)
-{
- struct nfs4_delegation *dp;
- stateid_t *stateid = &dr->dr_stateid;
- struct nfs4_stid *s;
- struct inode *inode;
- __be32 status;
-
- if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
- return status;
- inode = cstate->current_fh.fh_dentry->d_inode;
-
- nfs4_lock_state();
- status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s);
- if (status)
- goto out;
- dp = delegstateid(s);
- status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
- if (status)
- goto out;
-
- unhash_delegation(dp);
-out:
- nfs4_unlock_state();
-
- return status;
-}
-
-
-#define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start))
-
-#define LOCKOWNER_INO_HASH_BITS 8
-#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS)
-#define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1)
-
-static inline u64
-end_offset(u64 start, u64 len)
-{
- u64 end;
-
- end = start + len;
- return end >= start ? end: NFS4_MAX_UINT64;
-}
-
-/* last octet in a range */
-static inline u64
-last_byte_offset(u64 start, u64 len)
-{
- u64 end;
-
- BUG_ON(!len);
- end = start + len;
- return end > start ? end - 1: NFS4_MAX_UINT64;
-}
-
-static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername)
-{
- return (file_hashval(inode) + cl_id
- + opaque_hashval(ownername->data, ownername->len))
- & LOCKOWNER_INO_HASH_MASK;
-}
-
-static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE];
-
-/*
- * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
- * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
- * byte, because of sign extension problems. Since NFSv4 calls for 64-bit
- * locking, this prevents us from being completely protocol-compliant. The
- * real solution to this problem is to start using unsigned file offsets in
- * the VFS, but this is a very deep change!
- */
-static inline void
-nfs4_transform_lock_offset(struct file_lock *lock)
-{
- if (lock->fl_start < 0)
- lock->fl_start = OFFSET_MAX;
- if (lock->fl_end < 0)
- lock->fl_end = OFFSET_MAX;
-}
-
-/* Hack!: For now, we're defining this just so we can use a pointer to it
- * as a unique cookie to identify our (NFSv4's) posix locks. */
-static const struct lock_manager_operations nfsd_posix_mng_ops = {
-};
-
-static inline void
-nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
-{
- struct nfs4_lockowner *lo;
-
- if (fl->fl_lmops == &nfsd_posix_mng_ops) {
- lo = (struct nfs4_lockowner *) fl->fl_owner;
- deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
- lo->lo_owner.so_owner.len, GFP_KERNEL);
- if (!deny->ld_owner.data)
- /* We just don't care that much */
- goto nevermind;
- deny->ld_owner.len = lo->lo_owner.so_owner.len;
- deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
- } else {
-nevermind:
- deny->ld_owner.len = 0;
- deny->ld_owner.data = NULL;
- deny->ld_clientid.cl_boot = 0;
- deny->ld_clientid.cl_id = 0;
- }
- deny->ld_start = fl->fl_start;
- deny->ld_length = NFS4_MAX_UINT64;
- if (fl->fl_end != NFS4_MAX_UINT64)
- deny->ld_length = fl->fl_end - fl->fl_start + 1;
- deny->ld_type = NFS4_READ_LT;
- if (fl->fl_type != F_RDLCK)
- deny->ld_type = NFS4_WRITE_LT;
-}
-
-static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner)
-{
- struct nfs4_ol_stateid *lst;
-
- if (!same_owner_str(&lo->lo_owner, owner, clid))
- return false;
- lst = list_first_entry(&lo->lo_owner.so_stateids,
- struct nfs4_ol_stateid, st_perstateowner);
- return lst->st_file->fi_inode == inode;
-}
-
-static struct nfs4_lockowner *
-find_lockowner_str(struct inode *inode, clientid_t *clid,
- struct xdr_netobj *owner)
-{
- unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner);
- struct nfs4_lockowner *lo;
-
- list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
- if (same_lockowner_ino(lo, inode, clid, owner))
- return lo;
- }
- return NULL;
-}
-
-static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
-{
- struct inode *inode = open_stp->st_file->fi_inode;
- unsigned int inohash = lockowner_ino_hashval(inode,
- clp->cl_clientid.cl_id, &lo->lo_owner.so_owner);
-
- list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
- list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]);
- list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
-}
-
-/*
- * Alloc a lock owner structure.
- * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
- * occurred.
- *
- * strhashval = ownerstr_hashval
- */
-
-static struct nfs4_lockowner *
-alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) {
- struct nfs4_lockowner *lo;
-
- lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
- if (!lo)
- return NULL;
- INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
- lo->lo_owner.so_is_open_owner = 0;
- /* It is the openowner seqid that will be incremented in encode in the
- * case of new lockowners; so increment the lock seqid manually: */
- lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1;
- hash_lockowner(lo, strhashval, clp, open_stp);
- return lo;
-}
-
-static struct nfs4_ol_stateid *
-alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
-{
- struct nfs4_ol_stateid *stp;
- struct nfs4_client *clp = lo->lo_owner.so_client;
-
- stp = nfs4_alloc_stateid(clp);
- if (stp == NULL)
- return NULL;
- init_stid(&stp->st_stid, clp, NFS4_LOCK_STID);
- list_add(&stp->st_perfile, &fp->fi_stateids);
- list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
- stp->st_stateowner = &lo->lo_owner;
- get_nfs4_file(fp);
- stp->st_file = fp;
- stp->st_access_bmap = 0;
- stp->st_deny_bmap = open_stp->st_deny_bmap;
- stp->st_openstp = open_stp;
- return stp;
-}
-
-static int
-check_lock_length(u64 offset, u64 length)
-{
- return ((length == 0) || ((length != NFS4_MAX_UINT64) &&
- LOFF_OVERFLOW(offset, length)));
-}
-
-static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
-{
- struct nfs4_file *fp = lock_stp->st_file;
- int oflag = nfs4_access_to_omode(access);
-
- if (test_bit(access, &lock_stp->st_access_bmap))
- return;
- nfs4_file_get_access(fp, oflag);
- __set_bit(access, &lock_stp->st_access_bmap);
-}
-
-__be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new)
-{
- struct nfs4_file *fi = ost->st_file;
- struct nfs4_openowner *oo = openowner(ost->st_stateowner);
- struct nfs4_client *cl = oo->oo_owner.so_client;
- struct nfs4_lockowner *lo;
- unsigned int strhashval;
-
- lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner);
- if (lo) {
- if (!cstate->minorversion)
- return nfserr_bad_seqid;
- /* XXX: a lockowner always has exactly one stateid: */
- *lst = list_first_entry(&lo->lo_owner.so_stateids,
- struct nfs4_ol_stateid, st_perstateowner);
- return nfs_ok;
- }
- strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
- &lock->v.new.owner);
- lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
- if (lo == NULL)
- return nfserr_jukebox;
- *lst = alloc_init_lock_stateid(lo, fi, ost);
- if (*lst == NULL) {
- release_lockowner(lo);
- return nfserr_jukebox;
- }
- *new = true;
- return nfs_ok;
-}
-
-/*
- * LOCK operation
- */
-__be32
-nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_lock *lock)
-{
- struct nfs4_openowner *open_sop = NULL;
- struct nfs4_lockowner *lock_sop = NULL;
- struct nfs4_ol_stateid *lock_stp;
- struct nfs4_file *fp;
- struct file *filp = NULL;
- struct file_lock file_lock;
- struct file_lock conflock;
- __be32 status = 0;
- bool new_state = false;
- int lkflg;
- int err;
-
- dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
- (long long) lock->lk_offset,
- (long long) lock->lk_length);
-
- if (check_lock_length(lock->lk_offset, lock->lk_length))
- return nfserr_inval;
-
- if ((status = fh_verify(rqstp, &cstate->current_fh,
- S_IFREG, NFSD_MAY_LOCK))) {
- dprintk("NFSD: nfsd4_lock: permission denied!\n");
- return status;
- }
-
- nfs4_lock_state();
-
- if (lock->lk_is_new) {
- /*
- * Client indicates that this is a new lockowner.
- * Use open owner and open stateid to create lock owner and
- * lock stateid.
- */
- struct nfs4_ol_stateid *open_stp = NULL;
-
- if (nfsd4_has_session(cstate))
- /* See rfc 5661 18.10.3: given clientid is ignored: */
- memcpy(&lock->v.new.clientid,
- &cstate->session->se_client->cl_clientid,
- sizeof(clientid_t));
-
- status = nfserr_stale_clientid;
- if (STALE_CLIENTID(&lock->lk_new_clientid))
- goto out;
-
- /* validate and update open stateid and open seqid */
- status = nfs4_preprocess_confirmed_seqid_op(cstate,
- lock->lk_new_open_seqid,
- &lock->lk_new_open_stateid,
- &open_stp);
- if (status)
- goto out;
- open_sop = openowner(open_stp->st_stateowner);
- status = nfserr_bad_stateid;
- if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
- &lock->v.new.clientid))
- goto out;
- status = lookup_or_create_lock_state(cstate, open_stp, lock,
- &lock_stp, &new_state);
- if (status)
- goto out;
- } else {
- /* lock (lock owner + lock stateid) already exists */
- status = nfs4_preprocess_seqid_op(cstate,
- lock->lk_old_lock_seqid,
- &lock->lk_old_lock_stateid,
- NFS4_LOCK_STID, &lock_stp);
- if (status)
- goto out;
- }
- lock_sop = lockowner(lock_stp->st_stateowner);
- fp = lock_stp->st_file;
-
- lkflg = setlkflg(lock->lk_type);
- status = nfs4_check_openmode(lock_stp, lkflg);
- if (status)
- goto out;
-
- status = nfserr_grace;
- if (locks_in_grace() && !lock->lk_reclaim)
- goto out;
- status = nfserr_no_grace;
- if (!locks_in_grace() && lock->lk_reclaim)
- goto out;
-
- locks_init_lock(&file_lock);
- switch (lock->lk_type) {
- case NFS4_READ_LT:
- case NFS4_READW_LT:
- filp = find_readable_file(lock_stp->st_file);
- if (filp)
- get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
- file_lock.fl_type = F_RDLCK;
- break;
- case NFS4_WRITE_LT:
- case NFS4_WRITEW_LT:
- filp = find_writeable_file(lock_stp->st_file);
- if (filp)
- get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
- file_lock.fl_type = F_WRLCK;
- break;
- default:
- status = nfserr_inval;
- goto out;
- }
- if (!filp) {
- status = nfserr_openmode;
- goto out;
- }
- file_lock.fl_owner = (fl_owner_t)lock_sop;
- file_lock.fl_pid = current->tgid;
- file_lock.fl_file = filp;
- file_lock.fl_flags = FL_POSIX;
- file_lock.fl_lmops = &nfsd_posix_mng_ops;
-
- file_lock.fl_start = lock->lk_offset;
- file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
- nfs4_transform_lock_offset(&file_lock);
-
- /*
- * Try to lock the file in the VFS.
- * Note: locks.c uses the BKL to protect the inode's lock list.
- */
-
- err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
- switch (-err) {
- case 0: /* success! */
- update_stateid(&lock_stp->st_stid.sc_stateid);
- memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid,
- sizeof(stateid_t));
- status = 0;
- break;
- case (EAGAIN): /* conflock holds conflicting lock */
- status = nfserr_denied;
- dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
- nfs4_set_lock_denied(&conflock, &lock->lk_denied);
- break;
- case (EDEADLK):
- status = nfserr_deadlock;
- break;
- default:
- dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
- status = nfserrno(err);
- break;
- }
-out:
- if (status && new_state)
- release_lockowner(lock_sop);
- if (!cstate->replay_owner)
- nfs4_unlock_state();
- return status;
-}
-
-/*
- * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
- * so we do a temporary open here just to get an open file to pass to
- * vfs_test_lock. (Arguably perhaps test_lock should be done with an
- * inode operation.)
- */
-static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
-{
- struct file *file;
- __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
- if (!err) {
- err = nfserrno(vfs_test_lock(file, lock));
- nfsd_close(file);
- }
- return err;
-}
-
-/*
- * LOCKT operation
- */
-__be32
-nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_lockt *lockt)
-{
- struct inode *inode;
- struct file_lock file_lock;
- struct nfs4_lockowner *lo;
- __be32 status;
-
- if (locks_in_grace())
- return nfserr_grace;
-
- if (check_lock_length(lockt->lt_offset, lockt->lt_length))
- return nfserr_inval;
-
- nfs4_lock_state();
-
- status = nfserr_stale_clientid;
- if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid))
- goto out;
-
- if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
- goto out;
-
- inode = cstate->current_fh.fh_dentry->d_inode;
- locks_init_lock(&file_lock);
- switch (lockt->lt_type) {
- case NFS4_READ_LT:
- case NFS4_READW_LT:
- file_lock.fl_type = F_RDLCK;
- break;
- case NFS4_WRITE_LT:
- case NFS4_WRITEW_LT:
- file_lock.fl_type = F_WRLCK;
- break;
- default:
- dprintk("NFSD: nfs4_lockt: bad lock type!\n");
- status = nfserr_inval;
- goto out;
- }
-
- lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);
- if (lo)
- file_lock.fl_owner = (fl_owner_t)lo;
- file_lock.fl_pid = current->tgid;
- file_lock.fl_flags = FL_POSIX;
-
- file_lock.fl_start = lockt->lt_offset;
- file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
-
- nfs4_transform_lock_offset(&file_lock);
-
- status = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock);
- if (status)
- goto out;
-
- if (file_lock.fl_type != F_UNLCK) {
- status = nfserr_denied;
- nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
- }
-out:
- nfs4_unlock_state();
- return status;
-}
-
-__be32
-nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_locku *locku)
-{
- struct nfs4_ol_stateid *stp;
- struct file *filp = NULL;
- struct file_lock file_lock;
- __be32 status;
- int err;
-
- dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
- (long long) locku->lu_offset,
- (long long) locku->lu_length);
-
- if (check_lock_length(locku->lu_offset, locku->lu_length))
- return nfserr_inval;
-
- nfs4_lock_state();
-
- status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
- &locku->lu_stateid, NFS4_LOCK_STID, &stp);
- if (status)
- goto out;
- filp = find_any_file(stp->st_file);
- if (!filp) {
- status = nfserr_lock_range;
- goto out;
- }
- BUG_ON(!filp);
- locks_init_lock(&file_lock);
- file_lock.fl_type = F_UNLCK;
- file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
- file_lock.fl_pid = current->tgid;
- file_lock.fl_file = filp;
- file_lock.fl_flags = FL_POSIX;
- file_lock.fl_lmops = &nfsd_posix_mng_ops;
- file_lock.fl_start = locku->lu_offset;
-
- file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
- nfs4_transform_lock_offset(&file_lock);
-
- /*
- * Try to unlock the file in the VFS.
- */
- err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
- if (err) {
- dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
- goto out_nfserr;
- }
- /*
- * OK, unlock succeeded; the only thing left to do is update the stateid.
- */
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
-
-out:
- if (!cstate->replay_owner)
- nfs4_unlock_state();
- return status;
-
-out_nfserr:
- status = nfserrno(err);
- goto out;
-}
-
-/*
- * returns
- * 1: locks held by lockowner
- * 0: no locks held by lockowner
- */
-static int
-check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
-{
- struct file_lock **flpp;
- struct inode *inode = filp->fi_inode;
- int status = 0;
-
- lock_flocks();
- for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
- if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
- status = 1;
- goto out;
- }
- }
-out:
- unlock_flocks();
- return status;
-}
-
-__be32
-nfsd4_release_lockowner(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate,
- struct nfsd4_release_lockowner *rlockowner)
-{
- clientid_t *clid = &rlockowner->rl_clientid;
- struct nfs4_stateowner *sop;
- struct nfs4_lockowner *lo;
- struct nfs4_ol_stateid *stp;
- struct xdr_netobj *owner = &rlockowner->rl_owner;
- struct list_head matches;
- unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
- __be32 status;
-
- dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
- clid->cl_boot, clid->cl_id);
-
- /* XXX check for lease expiration */
-
- status = nfserr_stale_clientid;
- if (STALE_CLIENTID(clid))
- return status;
-
- nfs4_lock_state();
-
- status = nfserr_locks_held;
- INIT_LIST_HEAD(&matches);
-
- list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) {
- if (sop->so_is_open_owner)
- continue;
- if (!same_owner_str(sop, owner, clid))
- continue;
- list_for_each_entry(stp, &sop->so_stateids,
- st_perstateowner) {
- lo = lockowner(sop);
- if (check_for_locks(stp->st_file, lo))
- goto out;
- list_add(&lo->lo_list, &matches);
- }
- }
- /* Clients probably won't expect us to return with some (but not all)
- * of the lockowner state released; so don't release any until all
- * have been checked. */
- status = nfs_ok;
- while (!list_empty(&matches)) {
- lo = list_entry(matches.next, struct nfs4_lockowner,
- lo_list);
- /* unhash_stateowner deletes so_perclient only
- * for openowners. */
- list_del(&lo->lo_list);
- release_lockowner(lo);
- }
-out:
- nfs4_unlock_state();
- return status;
-}
-
-static inline struct nfs4_client_reclaim *
-alloc_reclaim(void)
-{
- return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
-}
-
-int
-nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
-{
- unsigned int strhashval = clientstr_hashval(name);
- struct nfs4_client *clp;
-
- clp = find_confirmed_client_by_str(name, strhashval);
- if (!clp)
- return 0;
- return test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
-}
-
-/*
- * failure => all reset bets are off, nfserr_no_grace...
- */
-int
-nfs4_client_to_reclaim(const char *name)
-{
- unsigned int strhashval;
- struct nfs4_client_reclaim *crp = NULL;
-
- dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
- crp = alloc_reclaim();
- if (!crp)
- return 0;
- strhashval = clientstr_hashval(name);
- INIT_LIST_HEAD(&crp->cr_strhash);
- list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
- memcpy(crp->cr_recdir, name, HEXDIR_LEN);
- reclaim_str_hashtbl_size++;
- return 1;
-}
-
-void
-nfs4_release_reclaim(void)
-{
- struct nfs4_client_reclaim *crp = NULL;
- int i;
-
- for (i = 0; i < CLIENT_HASH_SIZE; i++) {
- while (!list_empty(&reclaim_str_hashtbl[i])) {
- crp = list_entry(reclaim_str_hashtbl[i].next,
- struct nfs4_client_reclaim, cr_strhash);
- list_del(&crp->cr_strhash);
- kfree(crp);
- reclaim_str_hashtbl_size--;
- }
- }
- BUG_ON(reclaim_str_hashtbl_size);
-}
-
-/*
- * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
-struct nfs4_client_reclaim *
-nfsd4_find_reclaim_client(struct nfs4_client *clp)
-{
- unsigned int strhashval;
- struct nfs4_client_reclaim *crp = NULL;
-
- dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n",
- clp->cl_name.len, clp->cl_name.data,
- clp->cl_recdir);
-
- /* find clp->cl_name in reclaim_str_hashtbl */
- strhashval = clientstr_hashval(clp->cl_recdir);
- list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
- if (same_name(crp->cr_recdir, clp->cl_recdir)) {
- return crp;
- }
- }
- return NULL;
-}
-
-/*
-* Called from OPEN. Look for clientid in reclaim list.
-*/
-__be32
-nfs4_check_open_reclaim(clientid_t *clid)
-{
- struct nfs4_client *clp;
-
- /* find clientid in conf_id_hashtbl */
- clp = find_confirmed_client(clid);
- if (clp == NULL)
- return nfserr_reclaim_bad;
-
- return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok;
-}
-
-#ifdef CONFIG_NFSD_FAULT_INJECTION
-
-void nfsd_forget_clients(u64 num)
-{
- struct nfs4_client *clp, *next;
- int count = 0;
-
- nfs4_lock_state();
- list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
- nfsd4_client_record_remove(clp);
- expire_client(clp);
- if (++count == num)
- break;
- }
- nfs4_unlock_state();
-
- printk(KERN_INFO "NFSD: Forgot %d clients", count);
-}
-
-static void release_lockowner_sop(struct nfs4_stateowner *sop)
-{
- release_lockowner(lockowner(sop));
-}
-
-static void release_openowner_sop(struct nfs4_stateowner *sop)
-{
- release_openowner(openowner(sop));
-}
-
-static int nfsd_release_n_owners(u64 num, bool is_open_owner,
- void (*release_sop)(struct nfs4_stateowner *))
-{
- int i, count = 0;
- struct nfs4_stateowner *sop, *next;
-
- for (i = 0; i < OWNER_HASH_SIZE; i++) {
- list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) {
- if (sop->so_is_open_owner != is_open_owner)
- continue;
- release_sop(sop);
- if (++count == num)
- return count;
- }
- }
- return count;
-}
-
-void nfsd_forget_locks(u64 num)
-{
- int count;
-
- nfs4_lock_state();
- count = nfsd_release_n_owners(num, false, release_lockowner_sop);
- nfs4_unlock_state();
-
- printk(KERN_INFO "NFSD: Forgot %d locks", count);
-}
-
-void nfsd_forget_openowners(u64 num)
-{
- int count;
-
- nfs4_lock_state();
- count = nfsd_release_n_owners(num, true, release_openowner_sop);
- nfs4_unlock_state();
-
- printk(KERN_INFO "NFSD: Forgot %d open owners", count);
-}
-
-int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *))
-{
- int i, count = 0;
- struct nfs4_file *fp, *fnext;
- struct nfs4_delegation *dp, *dnext;
-
- for (i = 0; i < FILE_HASH_SIZE; i++) {
- list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) {
- list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) {
- deleg_func(dp);
- if (++count == num)
- return count;
- }
- }
- }
-
- return count;
-}
-
-void nfsd_forget_delegations(u64 num)
-{
- unsigned int count;
-
- nfs4_lock_state();
- count = nfsd_process_n_delegations(num, unhash_delegation);
- nfs4_unlock_state();
-
- printk(KERN_INFO "NFSD: Forgot %d delegations", count);
-}
-
-void nfsd_recall_delegations(u64 num)
-{
- unsigned int count;
-
- nfs4_lock_state();
- spin_lock(&recall_lock);
- count = nfsd_process_n_delegations(num, nfsd_break_one_deleg);
- spin_unlock(&recall_lock);
- nfs4_unlock_state();
-
- printk(KERN_INFO "NFSD: Recalled %d delegations", count);
-}
-
-#endif /* CONFIG_NFSD_FAULT_INJECTION */
-
-/* initialization to perform at module load time: */
-
-void
-nfs4_state_init(void)
-{
- int i;
-
- for (i = 0; i < CLIENT_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&conf_id_hashtbl[i]);
- INIT_LIST_HEAD(&conf_str_hashtbl[i]);
- INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
- INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
- INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
- }
- for (i = 0; i < SESSION_HASH_SIZE; i++)
- INIT_LIST_HEAD(&sessionid_hashtbl[i]);
- for (i = 0; i < FILE_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&file_hashtbl[i]);
- }
- for (i = 0; i < OWNER_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
- }
- for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
- INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]);
- INIT_LIST_HEAD(&close_lru);
- INIT_LIST_HEAD(&client_lru);
- INIT_LIST_HEAD(&del_recall_lru);
- reclaim_str_hashtbl_size = 0;
-}
-
-/*
- * Since the lifetime of a delegation isn't limited to that of an open, a
- * client may quite reasonably hang on to a delegation as long as it has
- * the inode cached. This becomes an obvious problem the first time a
- * client's inode cache approaches the size of the server's total memory.
- *
- * For now we avoid this problem by imposing a hard limit on the number
- * of delegations, which varies according to the server's memory size.
- */
-static void
-set_max_delegations(void)
-{
- /*
- * Allow at most 4 delegations per megabyte of RAM. Quick
- * estimates suggest that in the worst case (where every delegation
- * is for a different inode), a delegation could take about 1.5K,
- * giving a worst case usage of about 6% of memory.
- */
- max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
-}
-
-/* initialization to perform when the nfsd service is started: */
-
-int
-nfs4_state_start(void)
-{
- int ret;
-
- /*
- * FIXME: For now, we hang most of the pernet global stuff off of
- * init_net until nfsd is fully containerized. Eventually, we'll
- * need to pass a net pointer into this function, take a reference
- * to that instead and then do most of the rest of this on a per-net
- * basis.
- */
- get_net(&init_net);
- nfsd4_client_tracking_init(&init_net);
- boot_time = get_seconds();
- locks_start_grace(&nfsd4_manager);
- printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
- nfsd4_grace);
- ret = set_callback_cred();
- if (ret) {
- ret = -ENOMEM;
- goto out_recovery;
- }
- laundry_wq = create_singlethread_workqueue("nfsd4");
- if (laundry_wq == NULL) {
- ret = -ENOMEM;
- goto out_recovery;
- }
- ret = nfsd4_create_callback_queue();
- if (ret)
- goto out_free_laundry;
- queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ);
- set_max_delegations();
- return 0;
-out_free_laundry:
- destroy_workqueue(laundry_wq);
-out_recovery:
- nfsd4_client_tracking_exit(&init_net);
- put_net(&init_net);
- return ret;
-}
-
-static void
-__nfs4_state_shutdown(void)
-{
- int i;
- struct nfs4_client *clp = NULL;
- struct nfs4_delegation *dp = NULL;
- struct list_head *pos, *next, reaplist;
-
- 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);
- expire_client(clp);
- }
- while (!list_empty(&unconf_str_hashtbl[i])) {
- clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
- expire_client(clp);
- }
- }
- INIT_LIST_HEAD(&reaplist);
- spin_lock(&recall_lock);
- list_for_each_safe(pos, next, &del_recall_lru) {
- dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
- list_move(&dp->dl_recall_lru, &reaplist);
- }
- spin_unlock(&recall_lock);
- list_for_each_safe(pos, next, &reaplist) {
- dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
- unhash_delegation(dp);
- }
-
- nfsd4_client_tracking_exit(&init_net);
- put_net(&init_net);
-}
-
-void
-nfs4_state_shutdown(void)
-{
- cancel_delayed_work_sync(&laundromat_work);
- destroy_workqueue(laundry_wq);
- locks_end_grace(&nfsd4_manager);
- nfs4_lock_state();
- __nfs4_state_shutdown();
- nfs4_unlock_state();
- nfsd4_destroy_callback_queue();
-}
-
-static void
-get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
-{
- if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
- memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
-}
-
-static void
-put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
-{
- if (cstate->minorversion) {
- memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
- SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
- }
-}
-
-void
-clear_current_stateid(struct nfsd4_compound_state *cstate)
-{
- CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
-}
-
-/*
- * functions to set current state id
- */
-void
-nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
-{
- put_stateid(cstate, &odp->od_stateid);
-}
-
-void
-nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
-{
- put_stateid(cstate, &open->op_stateid);
-}
-
-void
-nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
-{
- put_stateid(cstate, &close->cl_stateid);
-}
-
-void
-nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock)
-{
- put_stateid(cstate, &lock->lk_resp_stateid);
-}
-
-/*
- * functions to consume current state id
- */
-
-void
-nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp)
-{
- get_stateid(cstate, &odp->od_stateid);
-}
-
-void
-nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp)
-{
- get_stateid(cstate, &drp->dr_stateid);
-}
-
-void
-nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp)
-{
- get_stateid(cstate, &fsp->fr_stateid);
-}
-
-void
-nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr)
-{
- get_stateid(cstate, &setattr->sa_stateid);
-}
-
-void
-nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close)
-{
- get_stateid(cstate, &close->cl_stateid);
-}
-
-void
-nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku)
-{
- get_stateid(cstate, &locku->lu_stateid);
-}
-
-void
-nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read)
-{
- get_stateid(cstate, &read->rd_stateid);
-}
-
-void
-nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write)
-{
- get_stateid(cstate, &write->wr_stateid);
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/nfs4xdr.c b/ANDROID_3.4.5/fs/nfsd/nfs4xdr.c
deleted file mode 100644
index 74c00bc9..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfs4xdr.c
+++ /dev/null
@@ -1,3671 +0,0 @@
-/*
- * Server-side XDR for NFSv4
- *
- * Copyright (c) 2002 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Kendrick Smith <kmsmith@umich.edu>
- * Andy Adamson <andros@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * TODO: Neil Brown made the following observation: We currently
- * initially reserve NFSD_BUFSIZE space on the transmit queue and
- * never release any of that until the request is complete.
- * It would be good to calculate a new maximum response size while
- * decoding the COMPOUND, and call svc_reserve with this number
- * at the end of nfs4svc_decode_compoundargs.
- */
-
-#include <linux/slab.h>
-#include <linux/namei.h>
-#include <linux/statfs.h>
-#include <linux/utsname.h>
-#include <linux/pagemap.h>
-#include <linux/sunrpc/svcauth_gss.h>
-
-#include "idmap.h"
-#include "acl.h"
-#include "xdr4.h"
-#include "vfs.h"
-#include "state.h"
-#include "cache.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_XDR
-
-/*
- * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
- * directory in order to indicate to the client that a filesystem boundary is present
- * We use a fixed fsid for a referral
- */
-#define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL
-#define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL
-
-static __be32
-check_filename(char *str, int len, __be32 err)
-{
- int i;
-
- if (len == 0)
- return nfserr_inval;
- if (isdotent(str, len))
- return err;
- for (i = 0; i < len; i++)
- if (str[i] == '/')
- return err;
- return 0;
-}
-
-#define DECODE_HEAD \
- __be32 *p; \
- __be32 status
-#define DECODE_TAIL \
- status = 0; \
-out: \
- return status; \
-xdr_error: \
- dprintk("NFSD: xdr error (%s:%d)\n", \
- __FILE__, __LINE__); \
- status = nfserr_bad_xdr; \
- goto out
-
-#define READ32(x) (x) = ntohl(*p++)
-#define READ64(x) do { \
- (x) = (u64)ntohl(*p++) << 32; \
- (x) |= ntohl(*p++); \
-} while (0)
-#define READTIME(x) do { \
- p++; \
- (x) = ntohl(*p++); \
- p++; \
-} while (0)
-#define READMEM(x,nbytes) do { \
- x = (char *)p; \
- p += XDR_QUADLEN(nbytes); \
-} while (0)
-#define SAVEMEM(x,nbytes) do { \
- if (!(x = (p==argp->tmp || p == argp->tmpp) ? \
- savemem(argp, p, nbytes) : \
- (char *)p)) { \
- dprintk("NFSD: xdr error (%s:%d)\n", \
- __FILE__, __LINE__); \
- goto xdr_error; \
- } \
- p += XDR_QUADLEN(nbytes); \
-} while (0)
-#define COPYMEM(x,nbytes) do { \
- memcpy((x), p, nbytes); \
- p += XDR_QUADLEN(nbytes); \
-} while (0)
-
-/* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */
-#define READ_BUF(nbytes) do { \
- if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) { \
- p = argp->p; \
- argp->p += XDR_QUADLEN(nbytes); \
- } else if (!(p = read_buf(argp, nbytes))) { \
- dprintk("NFSD: xdr error (%s:%d)\n", \
- __FILE__, __LINE__); \
- goto xdr_error; \
- } \
-} while (0)
-
-static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
-{
- /* We want more bytes than seem to be available.
- * Maybe we need a new page, maybe we have just run out
- */
- unsigned int avail = (char *)argp->end - (char *)argp->p;
- __be32 *p;
- if (avail + argp->pagelen < nbytes)
- return NULL;
- if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */
- return NULL;
- /* ok, we can do it with the current plus the next page */
- if (nbytes <= sizeof(argp->tmp))
- p = argp->tmp;
- else {
- kfree(argp->tmpp);
- p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL);
- if (!p)
- return NULL;
-
- }
- /*
- * The following memcpy is safe because read_buf is always
- * called with nbytes > avail, and the two cases above both
- * guarantee p points to at least nbytes bytes.
- */
- memcpy(p, argp->p, avail);
- /* step to next page */
- argp->p = page_address(argp->pagelist[0]);
- argp->pagelist++;
- if (argp->pagelen < PAGE_SIZE) {
- argp->end = argp->p + (argp->pagelen>>2);
- argp->pagelen = 0;
- } else {
- argp->end = argp->p + (PAGE_SIZE>>2);
- argp->pagelen -= PAGE_SIZE;
- }
- memcpy(((char*)p)+avail, argp->p, (nbytes - avail));
- argp->p += XDR_QUADLEN(nbytes - avail);
- return p;
-}
-
-static int zero_clientid(clientid_t *clid)
-{
- return (clid->cl_boot == 0) && (clid->cl_id == 0);
-}
-
-static int
-defer_free(struct nfsd4_compoundargs *argp,
- void (*release)(const void *), void *p)
-{
- struct tmpbuf *tb;
-
- tb = kmalloc(sizeof(*tb), GFP_KERNEL);
- if (!tb)
- return -ENOMEM;
- tb->buf = p;
- tb->release = release;
- tb->next = argp->to_free;
- argp->to_free = tb;
- return 0;
-}
-
-static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
-{
- if (p == argp->tmp) {
- p = kmemdup(argp->tmp, nbytes, GFP_KERNEL);
- if (!p)
- return NULL;
- } else {
- BUG_ON(p != argp->tmpp);
- argp->tmpp = NULL;
- }
- if (defer_free(argp, kfree, p)) {
- kfree(p);
- return NULL;
- } else
- return (char *)p;
-}
-
-static __be32
-nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
-{
- u32 bmlen;
- DECODE_HEAD;
-
- bmval[0] = 0;
- bmval[1] = 0;
- bmval[2] = 0;
-
- READ_BUF(4);
- READ32(bmlen);
- if (bmlen > 1000)
- goto xdr_error;
-
- READ_BUF(bmlen << 2);
- if (bmlen > 0)
- READ32(bmval[0]);
- if (bmlen > 1)
- READ32(bmval[1]);
- if (bmlen > 2)
- READ32(bmval[2]);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
- struct iattr *iattr, struct nfs4_acl **acl)
-{
- int expected_len, len = 0;
- u32 dummy32;
- char *buf;
- int host_err;
-
- DECODE_HEAD;
- iattr->ia_valid = 0;
- if ((status = nfsd4_decode_bitmap(argp, bmval)))
- return status;
-
- READ_BUF(4);
- READ32(expected_len);
-
- if (bmval[0] & FATTR4_WORD0_SIZE) {
- READ_BUF(8);
- len += 8;
- READ64(iattr->ia_size);
- iattr->ia_valid |= ATTR_SIZE;
- }
- if (bmval[0] & FATTR4_WORD0_ACL) {
- int nace;
- struct nfs4_ace *ace;
-
- READ_BUF(4); len += 4;
- READ32(nace);
-
- if (nace > NFS4_ACL_MAX)
- return nfserr_resource;
-
- *acl = nfs4_acl_new(nace);
- if (*acl == NULL) {
- host_err = -ENOMEM;
- goto out_nfserr;
- }
- defer_free(argp, kfree, *acl);
-
- (*acl)->naces = nace;
- for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
- READ_BUF(16); len += 16;
- READ32(ace->type);
- READ32(ace->flag);
- READ32(ace->access_mask);
- READ32(dummy32);
- READ_BUF(dummy32);
- len += XDR_QUADLEN(dummy32) << 2;
- READMEM(buf, dummy32);
- ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
- status = nfs_ok;
- if (ace->whotype != NFS4_ACL_WHO_NAMED)
- ace->who = 0;
- else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
- status = nfsd_map_name_to_gid(argp->rqstp,
- buf, dummy32, &ace->who);
- else
- status = nfsd_map_name_to_uid(argp->rqstp,
- buf, dummy32, &ace->who);
- if (status)
- return status;
- }
- } else
- *acl = NULL;
- if (bmval[1] & FATTR4_WORD1_MODE) {
- READ_BUF(4);
- len += 4;
- READ32(iattr->ia_mode);
- iattr->ia_mode &= (S_IFMT | S_IALLUGO);
- iattr->ia_valid |= ATTR_MODE;
- }
- if (bmval[1] & FATTR4_WORD1_OWNER) {
- READ_BUF(4);
- len += 4;
- READ32(dummy32);
- READ_BUF(dummy32);
- len += (XDR_QUADLEN(dummy32) << 2);
- READMEM(buf, dummy32);
- if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
- return status;
- iattr->ia_valid |= ATTR_UID;
- }
- if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {
- READ_BUF(4);
- len += 4;
- READ32(dummy32);
- READ_BUF(dummy32);
- len += (XDR_QUADLEN(dummy32) << 2);
- READMEM(buf, dummy32);
- if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
- return status;
- iattr->ia_valid |= ATTR_GID;
- }
- if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
- READ_BUF(4);
- len += 4;
- READ32(dummy32);
- switch (dummy32) {
- case NFS4_SET_TO_CLIENT_TIME:
- /* We require the high 32 bits of 'seconds' to be 0, and we ignore
- all 32 bits of 'nseconds'. */
- READ_BUF(12);
- len += 12;
- READ32(dummy32);
- if (dummy32)
- return nfserr_inval;
- READ32(iattr->ia_atime.tv_sec);
- READ32(iattr->ia_atime.tv_nsec);
- if (iattr->ia_atime.tv_nsec >= (u32)1000000000)
- return nfserr_inval;
- iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
- break;
- case NFS4_SET_TO_SERVER_TIME:
- iattr->ia_valid |= ATTR_ATIME;
- break;
- default:
- goto xdr_error;
- }
- }
- if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
- READ_BUF(4);
- len += 4;
- READ32(dummy32);
- switch (dummy32) {
- case NFS4_SET_TO_CLIENT_TIME:
- /* We require the high 32 bits of 'seconds' to be 0, and we ignore
- all 32 bits of 'nseconds'. */
- READ_BUF(12);
- len += 12;
- READ32(dummy32);
- if (dummy32)
- return nfserr_inval;
- READ32(iattr->ia_mtime.tv_sec);
- READ32(iattr->ia_mtime.tv_nsec);
- if (iattr->ia_mtime.tv_nsec >= (u32)1000000000)
- return nfserr_inval;
- iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
- break;
- case NFS4_SET_TO_SERVER_TIME:
- iattr->ia_valid |= ATTR_MTIME;
- break;
- default:
- goto xdr_error;
- }
- }
- if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
- || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
- || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
- READ_BUF(expected_len - len);
- else if (len != expected_len)
- goto xdr_error;
-
- DECODE_TAIL;
-
-out_nfserr:
- status = nfserrno(host_err);
- goto out;
-}
-
-static __be32
-nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid)
-{
- DECODE_HEAD;
-
- READ_BUF(sizeof(stateid_t));
- READ32(sid->si_generation);
- COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(access->ac_req_access);
-
- DECODE_TAIL;
-}
-
-static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
-{
- DECODE_HEAD;
-
- READ_BUF(NFS4_MAX_SESSIONID_LEN + 8);
- COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
- READ32(bcts->dir);
- /* XXX: skipping ctsa_use_conn_in_rdma_mode. Perhaps Tom Tucker
- * could help us figure out we should be using it. */
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(close->cl_seqid);
- return nfsd4_decode_stateid(argp, &close->cl_stateid);
-
- DECODE_TAIL;
-}
-
-
-static __be32
-nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
-{
- DECODE_HEAD;
-
- READ_BUF(12);
- READ64(commit->co_offset);
- READ32(commit->co_count);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(create->cr_type);
- switch (create->cr_type) {
- case NF4LNK:
- READ_BUF(4);
- READ32(create->cr_linklen);
- READ_BUF(create->cr_linklen);
- SAVEMEM(create->cr_linkname, create->cr_linklen);
- break;
- case NF4BLK:
- case NF4CHR:
- READ_BUF(8);
- READ32(create->cr_specdata1);
- READ32(create->cr_specdata2);
- break;
- case NF4SOCK:
- case NF4FIFO:
- case NF4DIR:
- default:
- break;
- }
-
- READ_BUF(4);
- READ32(create->cr_namelen);
- READ_BUF(create->cr_namelen);
- SAVEMEM(create->cr_name, create->cr_namelen);
- if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
- return status;
-
- status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
- &create->cr_acl);
- if (status)
- goto out;
-
- DECODE_TAIL;
-}
-
-static inline __be32
-nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
-{
- return nfsd4_decode_stateid(argp, &dr->dr_stateid);
-}
-
-static inline __be32
-nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
-{
- return nfsd4_decode_bitmap(argp, getattr->ga_bmval);
-}
-
-static __be32
-nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(link->li_namelen);
- READ_BUF(link->li_namelen);
- SAVEMEM(link->li_name, link->li_namelen);
- if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval)))
- return status;
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
-{
- DECODE_HEAD;
-
- /*
- * type, reclaim(boolean), offset, length, new_lock_owner(boolean)
- */
- READ_BUF(28);
- READ32(lock->lk_type);
- if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT))
- goto xdr_error;
- READ32(lock->lk_reclaim);
- READ64(lock->lk_offset);
- READ64(lock->lk_length);
- READ32(lock->lk_is_new);
-
- if (lock->lk_is_new) {
- READ_BUF(4);
- READ32(lock->lk_new_open_seqid);
- status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid);
- if (status)
- return status;
- READ_BUF(8 + sizeof(clientid_t));
- READ32(lock->lk_new_lock_seqid);
- COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
- READ32(lock->lk_new_owner.len);
- READ_BUF(lock->lk_new_owner.len);
- READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
- } else {
- status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid);
- if (status)
- return status;
- READ_BUF(4);
- READ32(lock->lk_old_lock_seqid);
- }
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
-{
- DECODE_HEAD;
-
- READ_BUF(32);
- READ32(lockt->lt_type);
- if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT))
- goto xdr_error;
- READ64(lockt->lt_offset);
- READ64(lockt->lt_length);
- COPYMEM(&lockt->lt_clientid, 8);
- READ32(lockt->lt_owner.len);
- READ_BUF(lockt->lt_owner.len);
- READMEM(lockt->lt_owner.data, lockt->lt_owner.len);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
-{
- DECODE_HEAD;
-
- READ_BUF(8);
- READ32(locku->lu_type);
- if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
- goto xdr_error;
- READ32(locku->lu_seqid);
- status = nfsd4_decode_stateid(argp, &locku->lu_stateid);
- if (status)
- return status;
- READ_BUF(16);
- READ64(locku->lu_offset);
- READ64(locku->lu_length);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(lookup->lo_len);
- READ_BUF(lookup->lo_len);
- SAVEMEM(lookup->lo_name, lookup->lo_len);
- if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent)))
- return status;
-
- DECODE_TAIL;
-}
-
-static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when)
-{
- __be32 *p;
- u32 w;
-
- READ_BUF(4);
- READ32(w);
- *share_access = w & NFS4_SHARE_ACCESS_MASK;
- *deleg_want = w & NFS4_SHARE_WANT_MASK;
- if (deleg_when)
- *deleg_when = w & NFS4_SHARE_WHEN_MASK;
-
- switch (w & NFS4_SHARE_ACCESS_MASK) {
- case NFS4_SHARE_ACCESS_READ:
- case NFS4_SHARE_ACCESS_WRITE:
- case NFS4_SHARE_ACCESS_BOTH:
- break;
- default:
- return nfserr_bad_xdr;
- }
- w &= ~NFS4_SHARE_ACCESS_MASK;
- if (!w)
- return nfs_ok;
- if (!argp->minorversion)
- return nfserr_bad_xdr;
- switch (w & NFS4_SHARE_WANT_MASK) {
- case NFS4_SHARE_WANT_NO_PREFERENCE:
- case NFS4_SHARE_WANT_READ_DELEG:
- case NFS4_SHARE_WANT_WRITE_DELEG:
- case NFS4_SHARE_WANT_ANY_DELEG:
- case NFS4_SHARE_WANT_NO_DELEG:
- case NFS4_SHARE_WANT_CANCEL:
- break;
- default:
- return nfserr_bad_xdr;
- }
- w &= ~NFS4_SHARE_WANT_MASK;
- if (!w)
- return nfs_ok;
-
- if (!deleg_when) /* open_downgrade */
- return nfserr_inval;
- switch (w) {
- case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL:
- case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED:
- case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL |
- NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED):
- return nfs_ok;
- }
-xdr_error:
- return nfserr_bad_xdr;
-}
-
-static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x)
-{
- __be32 *p;
-
- READ_BUF(4);
- READ32(*x);
- /* Note: unlinke access bits, deny bits may be zero. */
- if (*x & ~NFS4_SHARE_DENY_BOTH)
- return nfserr_bad_xdr;
- return nfs_ok;
-xdr_error:
- return nfserr_bad_xdr;
-}
-
-static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o)
-{
- __be32 *p;
-
- READ_BUF(4);
- READ32(o->len);
-
- if (o->len == 0 || o->len > NFS4_OPAQUE_LIMIT)
- return nfserr_bad_xdr;
-
- READ_BUF(o->len);
- SAVEMEM(o->data, o->len);
- return nfs_ok;
-xdr_error:
- return nfserr_bad_xdr;
-}
-
-static __be32
-nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
-{
- DECODE_HEAD;
- u32 dummy;
-
- memset(open->op_bmval, 0, sizeof(open->op_bmval));
- open->op_iattr.ia_valid = 0;
- open->op_openowner = NULL;
-
- /* seqid, share_access, share_deny, clientid, ownerlen */
- READ_BUF(4);
- READ32(open->op_seqid);
- /* decode, yet ignore deleg_when until supported */
- status = nfsd4_decode_share_access(argp, &open->op_share_access,
- &open->op_deleg_want, &dummy);
- if (status)
- goto xdr_error;
- status = nfsd4_decode_share_deny(argp, &open->op_share_deny);
- if (status)
- goto xdr_error;
- READ_BUF(sizeof(clientid_t));
- COPYMEM(&open->op_clientid, sizeof(clientid_t));
- status = nfsd4_decode_opaque(argp, &open->op_owner);
- if (status)
- goto xdr_error;
- READ_BUF(4);
- READ32(open->op_create);
- switch (open->op_create) {
- case NFS4_OPEN_NOCREATE:
- break;
- case NFS4_OPEN_CREATE:
- READ_BUF(4);
- READ32(open->op_createmode);
- switch (open->op_createmode) {
- case NFS4_CREATE_UNCHECKED:
- case NFS4_CREATE_GUARDED:
- status = nfsd4_decode_fattr(argp, open->op_bmval,
- &open->op_iattr, &open->op_acl);
- if (status)
- goto out;
- break;
- case NFS4_CREATE_EXCLUSIVE:
- READ_BUF(NFS4_VERIFIER_SIZE);
- COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
- break;
- case NFS4_CREATE_EXCLUSIVE4_1:
- if (argp->minorversion < 1)
- goto xdr_error;
- READ_BUF(NFS4_VERIFIER_SIZE);
- COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
- status = nfsd4_decode_fattr(argp, open->op_bmval,
- &open->op_iattr, &open->op_acl);
- if (status)
- goto out;
- break;
- default:
- goto xdr_error;
- }
- break;
- default:
- goto xdr_error;
- }
-
- /* open_claim */
- READ_BUF(4);
- READ32(open->op_claim_type);
- switch (open->op_claim_type) {
- case NFS4_OPEN_CLAIM_NULL:
- case NFS4_OPEN_CLAIM_DELEGATE_PREV:
- READ_BUF(4);
- READ32(open->op_fname.len);
- READ_BUF(open->op_fname.len);
- SAVEMEM(open->op_fname.data, open->op_fname.len);
- if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
- return status;
- break;
- case NFS4_OPEN_CLAIM_PREVIOUS:
- READ_BUF(4);
- READ32(open->op_delegate_type);
- break;
- case NFS4_OPEN_CLAIM_DELEGATE_CUR:
- status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
- if (status)
- return status;
- READ_BUF(4);
- READ32(open->op_fname.len);
- READ_BUF(open->op_fname.len);
- SAVEMEM(open->op_fname.data, open->op_fname.len);
- if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
- return status;
- break;
- case NFS4_OPEN_CLAIM_FH:
- case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
- if (argp->minorversion < 1)
- goto xdr_error;
- /* void */
- break;
- case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
- if (argp->minorversion < 1)
- goto xdr_error;
- status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
- if (status)
- return status;
- break;
- default:
- goto xdr_error;
- }
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
-{
- DECODE_HEAD;
-
- status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
- if (status)
- return status;
- READ_BUF(4);
- READ32(open_conf->oc_seqid);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
-{
- DECODE_HEAD;
-
- status = nfsd4_decode_stateid(argp, &open_down->od_stateid);
- if (status)
- return status;
- READ_BUF(4);
- READ32(open_down->od_seqid);
- status = nfsd4_decode_share_access(argp, &open_down->od_share_access,
- &open_down->od_deleg_want, NULL);
- if (status)
- return status;
- status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny);
- if (status)
- return status;
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(putfh->pf_fhlen);
- if (putfh->pf_fhlen > NFS4_FHSIZE)
- goto xdr_error;
- READ_BUF(putfh->pf_fhlen);
- SAVEMEM(putfh->pf_fhval, putfh->pf_fhlen);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
-{
- DECODE_HEAD;
-
- status = nfsd4_decode_stateid(argp, &read->rd_stateid);
- if (status)
- return status;
- READ_BUF(12);
- READ64(read->rd_offset);
- READ32(read->rd_length);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
-{
- DECODE_HEAD;
-
- READ_BUF(24);
- READ64(readdir->rd_cookie);
- COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data));
- READ32(readdir->rd_dircount); /* just in case you needed a useless field... */
- READ32(readdir->rd_maxcount);
- if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval)))
- goto out;
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(remove->rm_namelen);
- READ_BUF(remove->rm_namelen);
- SAVEMEM(remove->rm_name, remove->rm_namelen);
- if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent)))
- return status;
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(rename->rn_snamelen);
- READ_BUF(rename->rn_snamelen + 4);
- SAVEMEM(rename->rn_sname, rename->rn_snamelen);
- READ32(rename->rn_tnamelen);
- READ_BUF(rename->rn_tnamelen);
- SAVEMEM(rename->rn_tname, rename->rn_tnamelen);
- if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent)))
- return status;
- if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval)))
- return status;
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
-{
- DECODE_HEAD;
-
- READ_BUF(sizeof(clientid_t));
- COPYMEM(clientid, sizeof(clientid_t));
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
- struct nfsd4_secinfo *secinfo)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(secinfo->si_namelen);
- READ_BUF(secinfo->si_namelen);
- SAVEMEM(secinfo->si_name, secinfo->si_namelen);
- status = check_filename(secinfo->si_name, secinfo->si_namelen,
- nfserr_noent);
- if (status)
- return status;
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
- struct nfsd4_secinfo_no_name *sin)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(sin->sin_style);
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
-{
- __be32 status;
-
- status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
- if (status)
- return status;
- return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
- &setattr->sa_acl);
-}
-
-static __be32
-nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
-{
- DECODE_HEAD;
-
- READ_BUF(NFS4_VERIFIER_SIZE);
- COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE);
-
- status = nfsd4_decode_opaque(argp, &setclientid->se_name);
- if (status)
- return nfserr_bad_xdr;
- READ_BUF(8);
- READ32(setclientid->se_callback_prog);
- READ32(setclientid->se_callback_netid_len);
-
- READ_BUF(setclientid->se_callback_netid_len + 4);
- SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len);
- READ32(setclientid->se_callback_addr_len);
-
- READ_BUF(setclientid->se_callback_addr_len + 4);
- SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len);
- READ32(setclientid->se_callback_ident);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
-{
- DECODE_HEAD;
-
- READ_BUF(8 + NFS4_VERIFIER_SIZE);
- COPYMEM(&scd_c->sc_clientid, 8);
- COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE);
-
- DECODE_TAIL;
-}
-
-/* Also used for NVERIFY */
-static __be32
-nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
-{
-#if 0
- struct nfsd4_compoundargs save = {
- .p = argp->p,
- .end = argp->end,
- .rqstp = argp->rqstp,
- };
- u32 ve_bmval[2];
- struct iattr ve_iattr; /* request */
- struct nfs4_acl *ve_acl; /* request */
-#endif
- DECODE_HEAD;
-
- if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval)))
- goto out;
-
- /* For convenience's sake, we compare raw xdr'd attributes in
- * nfsd4_proc_verify; however we still decode here just to return
- * correct error in case of bad xdr. */
-#if 0
- status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl);
- if (status == nfserr_inval) {
- status = nfserrno(status);
- goto out;
- }
-#endif
- READ_BUF(4);
- READ32(verify->ve_attrlen);
- READ_BUF(verify->ve_attrlen);
- SAVEMEM(verify->ve_attrval, verify->ve_attrlen);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
-{
- int avail;
- int v;
- int len;
- DECODE_HEAD;
-
- status = nfsd4_decode_stateid(argp, &write->wr_stateid);
- if (status)
- return status;
- READ_BUF(16);
- READ64(write->wr_offset);
- READ32(write->wr_stable_how);
- if (write->wr_stable_how > 2)
- goto xdr_error;
- READ32(write->wr_buflen);
-
- /* Sorry .. no magic macros for this.. *
- * READ_BUF(write->wr_buflen);
- * SAVEMEM(write->wr_buf, write->wr_buflen);
- */
- avail = (char*)argp->end - (char*)argp->p;
- if (avail + argp->pagelen < write->wr_buflen) {
- dprintk("NFSD: xdr error (%s:%d)\n",
- __FILE__, __LINE__);
- goto xdr_error;
- }
- argp->rqstp->rq_vec[0].iov_base = p;
- argp->rqstp->rq_vec[0].iov_len = avail;
- v = 0;
- len = write->wr_buflen;
- while (len > argp->rqstp->rq_vec[v].iov_len) {
- len -= argp->rqstp->rq_vec[v].iov_len;
- v++;
- argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]);
- argp->pagelist++;
- if (argp->pagelen >= PAGE_SIZE) {
- argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE;
- argp->pagelen -= PAGE_SIZE;
- } else {
- argp->rqstp->rq_vec[v].iov_len = argp->pagelen;
- argp->pagelen -= len;
- }
- }
- argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len);
- argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
- argp->rqstp->rq_vec[v].iov_len = len;
- write->wr_vlen = v+1;
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
-{
- DECODE_HEAD;
-
- READ_BUF(12);
- COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t));
- READ32(rlockowner->rl_owner.len);
- READ_BUF(rlockowner->rl_owner.len);
- READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len);
-
- if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid))
- return nfserr_inval;
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
- struct nfsd4_exchange_id *exid)
-{
- int dummy, tmp;
- DECODE_HEAD;
-
- READ_BUF(NFS4_VERIFIER_SIZE);
- COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE);
-
- status = nfsd4_decode_opaque(argp, &exid->clname);
- if (status)
- return nfserr_bad_xdr;
-
- READ_BUF(4);
- READ32(exid->flags);
-
- /* Ignore state_protect4_a */
- READ_BUF(4);
- READ32(exid->spa_how);
- switch (exid->spa_how) {
- case SP4_NONE:
- break;
- case SP4_MACH_CRED:
- /* spo_must_enforce */
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy * 4);
- p += dummy;
-
- /* spo_must_allow */
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy * 4);
- p += dummy;
- break;
- case SP4_SSV:
- /* ssp_ops */
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy * 4);
- p += dummy;
-
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy * 4);
- p += dummy;
-
- /* ssp_hash_algs<> */
- READ_BUF(4);
- READ32(tmp);
- while (tmp--) {
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy);
- p += XDR_QUADLEN(dummy);
- }
-
- /* ssp_encr_algs<> */
- READ_BUF(4);
- READ32(tmp);
- while (tmp--) {
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy);
- p += XDR_QUADLEN(dummy);
- }
-
- /* ssp_window and ssp_num_gss_handles */
- READ_BUF(8);
- READ32(dummy);
- READ32(dummy);
- break;
- default:
- goto xdr_error;
- }
-
- /* Ignore Implementation ID */
- READ_BUF(4); /* nfs_impl_id4 array length */
- READ32(dummy);
-
- if (dummy > 1)
- goto xdr_error;
-
- if (dummy == 1) {
- /* nii_domain */
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy);
- p += XDR_QUADLEN(dummy);
-
- /* nii_name */
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy);
- p += XDR_QUADLEN(dummy);
-
- /* nii_date */
- READ_BUF(12);
- p += 3;
- }
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
- struct nfsd4_create_session *sess)
-{
- DECODE_HEAD;
-
- u32 dummy;
- char *machine_name;
- int i;
- int nr_secflavs;
-
- READ_BUF(16);
- COPYMEM(&sess->clientid, 8);
- READ32(sess->seqid);
- READ32(sess->flags);
-
- /* Fore channel attrs */
- READ_BUF(28);
- READ32(dummy); /* headerpadsz is always 0 */
- READ32(sess->fore_channel.maxreq_sz);
- READ32(sess->fore_channel.maxresp_sz);
- READ32(sess->fore_channel.maxresp_cached);
- READ32(sess->fore_channel.maxops);
- READ32(sess->fore_channel.maxreqs);
- READ32(sess->fore_channel.nr_rdma_attrs);
- if (sess->fore_channel.nr_rdma_attrs == 1) {
- READ_BUF(4);
- READ32(sess->fore_channel.rdma_attrs);
- } else if (sess->fore_channel.nr_rdma_attrs > 1) {
- dprintk("Too many fore channel attr bitmaps!\n");
- goto xdr_error;
- }
-
- /* Back channel attrs */
- READ_BUF(28);
- READ32(dummy); /* headerpadsz is always 0 */
- READ32(sess->back_channel.maxreq_sz);
- READ32(sess->back_channel.maxresp_sz);
- READ32(sess->back_channel.maxresp_cached);
- READ32(sess->back_channel.maxops);
- READ32(sess->back_channel.maxreqs);
- READ32(sess->back_channel.nr_rdma_attrs);
- if (sess->back_channel.nr_rdma_attrs == 1) {
- READ_BUF(4);
- READ32(sess->back_channel.rdma_attrs);
- } else if (sess->back_channel.nr_rdma_attrs > 1) {
- dprintk("Too many back channel attr bitmaps!\n");
- goto xdr_error;
- }
-
- READ_BUF(8);
- READ32(sess->callback_prog);
-
- /* callback_sec_params4 */
- READ32(nr_secflavs);
- for (i = 0; i < nr_secflavs; ++i) {
- READ_BUF(4);
- READ32(dummy);
- switch (dummy) {
- case RPC_AUTH_NULL:
- /* Nothing to read */
- break;
- case RPC_AUTH_UNIX:
- READ_BUF(8);
- /* stamp */
- READ32(dummy);
-
- /* machine name */
- READ32(dummy);
- READ_BUF(dummy);
- SAVEMEM(machine_name, dummy);
-
- /* uid, gid */
- READ_BUF(8);
- READ32(sess->uid);
- READ32(sess->gid);
-
- /* more gids */
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy * 4);
- break;
- case RPC_AUTH_GSS:
- dprintk("RPC_AUTH_GSS callback secflavor "
- "not supported!\n");
- READ_BUF(8);
- /* gcbp_service */
- READ32(dummy);
- /* gcbp_handle_from_server */
- READ32(dummy);
- READ_BUF(dummy);
- p += XDR_QUADLEN(dummy);
- /* gcbp_handle_from_client */
- READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy);
- break;
- default:
- dprintk("Illegal callback secflavor\n");
- return nfserr_inval;
- }
- }
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
- struct nfsd4_destroy_session *destroy_session)
-{
- DECODE_HEAD;
- READ_BUF(NFS4_MAX_SESSIONID_LEN);
- COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
- struct nfsd4_free_stateid *free_stateid)
-{
- DECODE_HEAD;
-
- READ_BUF(sizeof(stateid_t));
- READ32(free_stateid->fr_stateid.si_generation);
- COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
- struct nfsd4_sequence *seq)
-{
- DECODE_HEAD;
-
- READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
- COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
- READ32(seq->seqid);
- READ32(seq->slotid);
- READ32(seq->maxslots);
- READ32(seq->cachethis);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
-{
- int i;
- __be32 *p, status;
- struct nfsd4_test_stateid_id *stateid;
-
- READ_BUF(4);
- test_stateid->ts_num_ids = ntohl(*p++);
-
- INIT_LIST_HEAD(&test_stateid->ts_stateid_list);
-
- for (i = 0; i < test_stateid->ts_num_ids; i++) {
- stateid = kmalloc(sizeof(struct nfsd4_test_stateid_id), GFP_KERNEL);
- if (!stateid) {
- status = nfserrno(-ENOMEM);
- goto out;
- }
-
- defer_free(argp, kfree, stateid);
- INIT_LIST_HEAD(&stateid->ts_id_list);
- list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
-
- status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid);
- if (status)
- goto out;
- }
-
- status = 0;
-out:
- return status;
-xdr_error:
- dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__);
- status = nfserr_bad_xdr;
- goto out;
-}
-
-static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc)
-{
- DECODE_HEAD;
-
- READ_BUF(8);
- COPYMEM(&dc->clientid, 8);
-
- DECODE_TAIL;
-}
-
-static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc)
-{
- DECODE_HEAD;
-
- READ_BUF(4);
- READ32(rc->rca_one_fs);
-
- DECODE_TAIL;
-}
-
-static __be32
-nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p)
-{
- return nfs_ok;
-}
-
-static __be32
-nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p)
-{
- return nfserr_notsupp;
-}
-
-typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);
-
-static nfsd4_dec nfsd4_dec_ops[] = {
- [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
- [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
- [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
- [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
- [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
- [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
- [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
- [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
- [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
- [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
- [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
- [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
- [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
- [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
- [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
- [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
- [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
- [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
- [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
- [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
- [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew,
- [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
- [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
- [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid,
- [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm,
- [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
- [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
- [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
-};
-
-static nfsd4_dec nfsd41_dec_ops[] = {
- [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
- [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
- [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
- [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
- [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
- [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
- [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
- [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
- [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
- [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
- [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
- [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
- [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
- [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
- [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
- [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
- [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
- [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
- [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
- [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
- [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
- [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
- [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
- [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
- [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp,
-
- /* new operations for NFSv4.1 */
- [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
- [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
- [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
- [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
- [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid,
- [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
- [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
- [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid,
- [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid,
- [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
-};
-
-struct nfsd4_minorversion_ops {
- nfsd4_dec *decoders;
- int nops;
-};
-
-static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
- [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
- [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
-};
-
-static __be32
-nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
-{
- DECODE_HEAD;
- struct nfsd4_op *op;
- struct nfsd4_minorversion_ops *ops;
- bool cachethis = false;
- int i;
-
- /*
- * XXX: According to spec, we should check the tag
- * for UTF-8 compliance. I'm postponing this for
- * now because it seems that some clients do use
- * binary tags.
- */
- READ_BUF(4);
- READ32(argp->taglen);
- READ_BUF(argp->taglen + 8);
- SAVEMEM(argp->tag, argp->taglen);
- READ32(argp->minorversion);
- READ32(argp->opcnt);
-
- if (argp->taglen > NFSD4_MAX_TAGLEN)
- goto xdr_error;
- if (argp->opcnt > 100)
- goto xdr_error;
-
- if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
- argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
- if (!argp->ops) {
- argp->ops = argp->iops;
- dprintk("nfsd: couldn't allocate room for COMPOUND\n");
- goto xdr_error;
- }
- }
-
- if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion))
- argp->opcnt = 0;
-
- ops = &nfsd4_minorversion[argp->minorversion];
- for (i = 0; i < argp->opcnt; i++) {
- op = &argp->ops[i];
- op->replay = NULL;
-
- /*
- * We can't use READ_BUF() here because we need to handle
- * a missing opcode as an OP_WRITE + 1. So we need to check
- * to see if we're truly at the end of our buffer or if there
- * is another page we need to flip to.
- */
-
- if (argp->p == argp->end) {
- if (argp->pagelen < 4) {
- /* There isn't an opcode still on the wire */
- op->opnum = OP_WRITE + 1;
- op->status = nfserr_bad_xdr;
- argp->opcnt = i+1;
- break;
- }
-
- /*
- * False alarm. We just hit a page boundary, but there
- * is still data available. Move pointer across page
- * boundary. *snip from READ_BUF*
- */
- argp->p = page_address(argp->pagelist[0]);
- argp->pagelist++;
- if (argp->pagelen < PAGE_SIZE) {
- argp->end = argp->p + (argp->pagelen>>2);
- argp->pagelen = 0;
- } else {
- argp->end = argp->p + (PAGE_SIZE>>2);
- argp->pagelen -= PAGE_SIZE;
- }
- }
- op->opnum = ntohl(*argp->p++);
-
- if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP)
- op->status = ops->decoders[op->opnum](argp, &op->u);
- else {
- op->opnum = OP_ILLEGAL;
- op->status = nfserr_op_illegal;
- }
-
- if (op->status) {
- argp->opcnt = i+1;
- break;
- }
- /*
- * We'll try to cache the result in the DRC if any one
- * op in the compound wants to be cached:
- */
- cachethis |= nfsd4_cache_this_op(op);
- }
- /* Sessions make the DRC unnecessary: */
- if (argp->minorversion)
- cachethis = false;
- argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
-
- DECODE_TAIL;
-}
-
-#define WRITE32(n) *p++ = htonl(n)
-#define WRITE64(n) do { \
- *p++ = htonl((u32)((n) >> 32)); \
- *p++ = htonl((u32)(n)); \
-} while (0)
-#define WRITEMEM(ptr,nbytes) do { if (nbytes > 0) { \
- *(p + XDR_QUADLEN(nbytes) -1) = 0; \
- memcpy(p, ptr, nbytes); \
- p += XDR_QUADLEN(nbytes); \
-}} while (0)
-
-static void write32(__be32 **p, u32 n)
-{
- *(*p)++ = n;
-}
-
-static void write64(__be32 **p, u64 n)
-{
- write32(p, (u32)(n >> 32));
- write32(p, (u32)n);
-}
-
-static void write_change(__be32 **p, struct kstat *stat, struct inode *inode)
-{
- if (IS_I_VERSION(inode)) {
- write64(p, inode->i_version);
- } else {
- write32(p, stat->ctime.tv_sec);
- write32(p, stat->ctime.tv_nsec);
- }
-}
-
-static void write_cinfo(__be32 **p, struct nfsd4_change_info *c)
-{
- write32(p, c->atomic);
- if (c->change_supported) {
- write64(p, c->before_change);
- write64(p, c->after_change);
- } else {
- write32(p, c->before_ctime_sec);
- write32(p, c->before_ctime_nsec);
- write32(p, c->after_ctime_sec);
- write32(p, c->after_ctime_nsec);
- }
-}
-
-#define RESERVE_SPACE(nbytes) do { \
- p = resp->p; \
- BUG_ON(p + XDR_QUADLEN(nbytes) > resp->end); \
-} while (0)
-#define ADJUST_ARGS() resp->p = p
-
-/*
- * Header routine to setup seqid operation replay cache
- */
-#define ENCODE_SEQID_OP_HEAD \
- __be32 *save; \
- \
- save = resp->p;
-
-/*
- * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This
- * is where sequence id's are incremented, and the replay cache is filled.
- * Note that we increment sequence id's here, at the last moment, so we're sure
- * we know whether the error to be returned is a sequence id mutating error.
- */
-
-static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, __be32 nfserr)
-{
- struct nfs4_stateowner *stateowner = resp->cstate.replay_owner;
-
- if (seqid_mutating_err(ntohl(nfserr)) && stateowner) {
- stateowner->so_seqid++;
- stateowner->so_replay.rp_status = nfserr;
- stateowner->so_replay.rp_buflen =
- (char *)resp->p - (char *)save;
- memcpy(stateowner->so_replay.rp_buf, save,
- stateowner->so_replay.rp_buflen);
- nfsd4_purge_closed_stateid(stateowner);
- }
-}
-
-/* Encode as an array of strings the string given with components
- * separated @sep.
- */
-static __be32 nfsd4_encode_components(char sep, char *components,
- __be32 **pp, int *buflen)
-{
- __be32 *p = *pp;
- __be32 *countp = p;
- int strlen, count=0;
- char *str, *end;
-
- dprintk("nfsd4_encode_components(%s)\n", components);
- if ((*buflen -= 4) < 0)
- return nfserr_resource;
- WRITE32(0); /* We will fill this in with @count later */
- end = str = components;
- while (*end) {
- for (; *end && (*end != sep); end++)
- ; /* Point to end of component */
- strlen = end - str;
- if (strlen) {
- if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0)
- return nfserr_resource;
- WRITE32(strlen);
- WRITEMEM(str, strlen);
- count++;
- }
- else
- end++;
- str = end;
- }
- *pp = p;
- p = countp;
- WRITE32(count);
- return 0;
-}
-
-/*
- * encode a location element of a fs_locations structure
- */
-static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
- __be32 **pp, int *buflen)
-{
- __be32 status;
- __be32 *p = *pp;
-
- status = nfsd4_encode_components(':', location->hosts, &p, buflen);
- if (status)
- return status;
- status = nfsd4_encode_components('/', location->path, &p, buflen);
- if (status)
- return status;
- *pp = p;
- return 0;
-}
-
-/*
- * Encode a path in RFC3530 'pathname4' format
- */
-static __be32 nfsd4_encode_path(const struct path *root,
- const struct path *path, __be32 **pp, int *buflen)
-{
- struct path cur = {
- .mnt = path->mnt,
- .dentry = path->dentry,
- };
- __be32 *p = *pp;
- struct dentry **components = NULL;
- unsigned int ncomponents = 0;
- __be32 err = nfserr_jukebox;
-
- dprintk("nfsd4_encode_components(");
-
- path_get(&cur);
- /* First walk the path up to the nfsd root, and store the
- * dentries/path components in an array.
- */
- for (;;) {
- if (cur.dentry == root->dentry && cur.mnt == root->mnt)
- break;
- if (cur.dentry == cur.mnt->mnt_root) {
- if (follow_up(&cur))
- continue;
- goto out_free;
- }
- if ((ncomponents & 15) == 0) {
- struct dentry **new;
- new = krealloc(components,
- sizeof(*new) * (ncomponents + 16),
- GFP_KERNEL);
- if (!new)
- goto out_free;
- components = new;
- }
- components[ncomponents++] = cur.dentry;
- cur.dentry = dget_parent(cur.dentry);
- }
-
- *buflen -= 4;
- if (*buflen < 0)
- goto out_free;
- WRITE32(ncomponents);
-
- while (ncomponents) {
- struct dentry *dentry = components[ncomponents - 1];
- unsigned int len = dentry->d_name.len;
-
- *buflen -= 4 + (XDR_QUADLEN(len) << 2);
- if (*buflen < 0)
- goto out_free;
- WRITE32(len);
- WRITEMEM(dentry->d_name.name, len);
- dprintk("/%s", dentry->d_name.name);
- dput(dentry);
- ncomponents--;
- }
-
- *pp = p;
- err = 0;
-out_free:
- dprintk(")\n");
- while (ncomponents)
- dput(components[--ncomponents]);
- kfree(components);
- path_put(&cur);
- return err;
-}
-
-static __be32 nfsd4_encode_fsloc_fsroot(struct svc_rqst *rqstp,
- const struct path *path, __be32 **pp, int *buflen)
-{
- struct svc_export *exp_ps;
- __be32 res;
-
- exp_ps = rqst_find_fsidzero_export(rqstp);
- if (IS_ERR(exp_ps))
- return nfserrno(PTR_ERR(exp_ps));
- res = nfsd4_encode_path(&exp_ps->ex_path, path, pp, buflen);
- exp_put(exp_ps);
- return res;
-}
-
-/*
- * encode a fs_locations structure
- */
-static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
- struct svc_export *exp,
- __be32 **pp, int *buflen)
-{
- __be32 status;
- int i;
- __be32 *p = *pp;
- struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
-
- status = nfsd4_encode_fsloc_fsroot(rqstp, &exp->ex_path, &p, buflen);
- if (status)
- return status;
- if ((*buflen -= 4) < 0)
- return nfserr_resource;
- WRITE32(fslocs->locations_count);
- for (i=0; i<fslocs->locations_count; i++) {
- status = nfsd4_encode_fs_location4(&fslocs->locations[i],
- &p, buflen);
- if (status)
- return status;
- }
- *pp = p;
- return 0;
-}
-
-static u32 nfs4_file_type(umode_t mode)
-{
- switch (mode & S_IFMT) {
- case S_IFIFO: return NF4FIFO;
- case S_IFCHR: return NF4CHR;
- case S_IFDIR: return NF4DIR;
- case S_IFBLK: return NF4BLK;
- case S_IFLNK: return NF4LNK;
- case S_IFREG: return NF4REG;
- case S_IFSOCK: return NF4SOCK;
- default: return NF4BAD;
- };
-}
-
-static __be32
-nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
- __be32 **p, int *buflen)
-{
- int status;
-
- if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4)
- return nfserr_resource;
- if (whotype != NFS4_ACL_WHO_NAMED)
- status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1));
- else if (group)
- status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1));
- else
- status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1));
- if (status < 0)
- return nfserrno(status);
- *p = xdr_encode_opaque(*p, NULL, status);
- *buflen -= (XDR_QUADLEN(status) << 2) + 4;
- BUG_ON(*buflen < 0);
- return 0;
-}
-
-static inline __be32
-nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen)
-{
- return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen);
-}
-
-static inline __be32
-nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen)
-{
- return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen);
-}
-
-static inline __be32
-nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
- __be32 **p, int *buflen)
-{
- return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
-}
-
-#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
- FATTR4_WORD0_RDATTR_ERROR)
-#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
-
-static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
-{
- /* As per referral draft: */
- if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
- *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
- if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
- *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
- *rdattr_err = NFSERR_MOVED;
- else
- return nfserr_moved;
- }
- *bmval0 &= WORD0_ABSENT_FS_ATTRS;
- *bmval1 &= WORD1_ABSENT_FS_ATTRS;
- return 0;
-}
-
-/*
- * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
- * ourselves.
- *
- * @countp is the buffer size in _words_; upon successful return this becomes
- * replaced with the number of words written.
- */
-__be32
-nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
- struct svc_rqst *rqstp, int ignore_crossmnt)
-{
- u32 bmval0 = bmval[0];
- u32 bmval1 = bmval[1];
- u32 bmval2 = bmval[2];
- struct kstat stat;
- struct svc_fh tempfh;
- struct kstatfs statfs;
- int buflen = *countp << 2;
- __be32 *attrlenp;
- u32 dummy;
- u64 dummy64;
- u32 rdattr_err = 0;
- __be32 *p = buffer;
- __be32 status;
- int err;
- int aclsupport = 0;
- struct nfs4_acl *acl = NULL;
- struct nfsd4_compoundres *resp = rqstp->rq_resp;
- u32 minorversion = resp->cstate.minorversion;
- struct path path = {
- .mnt = exp->ex_path.mnt,
- .dentry = dentry,
- };
-
- BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
- BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion));
- BUG_ON(bmval1 & ~nfsd_suppattrs1(minorversion));
- BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
-
- if (exp->ex_fslocs.migrated) {
- BUG_ON(bmval[2]);
- status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
- if (status)
- goto out;
- }
-
- err = vfs_getattr(exp->ex_path.mnt, dentry, &stat);
- if (err)
- goto out_nfserr;
- if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL |
- FATTR4_WORD0_MAXNAME)) ||
- (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
- FATTR4_WORD1_SPACE_TOTAL))) {
- err = vfs_statfs(&path, &statfs);
- if (err)
- goto out_nfserr;
- }
- if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
- fh_init(&tempfh, NFS4_FHSIZE);
- status = fh_compose(&tempfh, exp, dentry, NULL);
- if (status)
- goto out;
- fhp = &tempfh;
- }
- if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
- | FATTR4_WORD0_SUPPORTED_ATTRS)) {
- err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
- aclsupport = (err == 0);
- if (bmval0 & FATTR4_WORD0_ACL) {
- if (err == -EOPNOTSUPP)
- bmval0 &= ~FATTR4_WORD0_ACL;
- else if (err == -EINVAL) {
- status = nfserr_attrnotsupp;
- goto out;
- } else if (err != 0)
- goto out_nfserr;
- }
- }
-
- if (bmval2) {
- if ((buflen -= 16) < 0)
- goto out_resource;
- WRITE32(3);
- WRITE32(bmval0);
- WRITE32(bmval1);
- WRITE32(bmval2);
- } else if (bmval1) {
- if ((buflen -= 12) < 0)
- goto out_resource;
- WRITE32(2);
- WRITE32(bmval0);
- WRITE32(bmval1);
- } else {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE32(1);
- WRITE32(bmval0);
- }
- attrlenp = p++; /* to be backfilled later */
-
- if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
- u32 word0 = nfsd_suppattrs0(minorversion);
- u32 word1 = nfsd_suppattrs1(minorversion);
- u32 word2 = nfsd_suppattrs2(minorversion);
-
- if (!aclsupport)
- word0 &= ~FATTR4_WORD0_ACL;
- if (!word2) {
- if ((buflen -= 12) < 0)
- goto out_resource;
- WRITE32(2);
- WRITE32(word0);
- WRITE32(word1);
- } else {
- if ((buflen -= 16) < 0)
- goto out_resource;
- WRITE32(3);
- WRITE32(word0);
- WRITE32(word1);
- WRITE32(word2);
- }
- }
- if (bmval0 & FATTR4_WORD0_TYPE) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- dummy = nfs4_file_type(stat.mode);
- if (dummy == NF4BAD)
- goto out_serverfault;
- WRITE32(dummy);
- }
- if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
- WRITE32(NFS4_FH_PERSISTENT);
- else
- WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
- }
- if (bmval0 & FATTR4_WORD0_CHANGE) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- write_change(&p, &stat, dentry->d_inode);
- }
- if (bmval0 & FATTR4_WORD0_SIZE) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE64(stat.size);
- }
- if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(1);
- }
- if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(1);
- }
- if (bmval0 & FATTR4_WORD0_NAMED_ATTR) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(0);
- }
- if (bmval0 & FATTR4_WORD0_FSID) {
- if ((buflen -= 16) < 0)
- goto out_resource;
- if (exp->ex_fslocs.migrated) {
- WRITE64(NFS4_REFERRAL_FSID_MAJOR);
- WRITE64(NFS4_REFERRAL_FSID_MINOR);
- } else switch(fsid_source(fhp)) {
- case FSIDSOURCE_FSID:
- WRITE64((u64)exp->ex_fsid);
- WRITE64((u64)0);
- break;
- case FSIDSOURCE_DEV:
- WRITE32(0);
- WRITE32(MAJOR(stat.dev));
- WRITE32(0);
- WRITE32(MINOR(stat.dev));
- break;
- case FSIDSOURCE_UUID:
- WRITEMEM(exp->ex_uuid, 16);
- break;
- }
- }
- if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(0);
- }
- if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(nfsd4_lease);
- }
- if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(rdattr_err);
- }
- if (bmval0 & FATTR4_WORD0_ACL) {
- struct nfs4_ace *ace;
-
- if (acl == NULL) {
- if ((buflen -= 4) < 0)
- goto out_resource;
-
- WRITE32(0);
- goto out_acl;
- }
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(acl->naces);
-
- for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
- if ((buflen -= 4*3) < 0)
- goto out_resource;
- WRITE32(ace->type);
- WRITE32(ace->flag);
- WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL);
- status = nfsd4_encode_aclname(rqstp, ace->whotype,
- ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP,
- &p, &buflen);
- if (status == nfserr_resource)
- goto out_resource;
- if (status)
- goto out;
- }
- }
-out_acl:
- if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(aclsupport ?
- ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
- }
- if (bmval0 & FATTR4_WORD0_CANSETTIME) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(1);
- }
- if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(1);
- }
- if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(1);
- }
- if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(1);
- }
- if (bmval0 & FATTR4_WORD0_FILEHANDLE) {
- buflen -= (XDR_QUADLEN(fhp->fh_handle.fh_size) << 2) + 4;
- if (buflen < 0)
- goto out_resource;
- WRITE32(fhp->fh_handle.fh_size);
- WRITEMEM(&fhp->fh_handle.fh_base, fhp->fh_handle.fh_size);
- }
- if (bmval0 & FATTR4_WORD0_FILEID) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE64(stat.ino);
- }
- if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE64((u64) statfs.f_ffree);
- }
- if (bmval0 & FATTR4_WORD0_FILES_FREE) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE64((u64) statfs.f_ffree);
- }
- if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE64((u64) statfs.f_files);
- }
- if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
- status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen);
- if (status == nfserr_resource)
- goto out_resource;
- if (status)
- goto out;
- }
- if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(1);
- }
- if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE64(~(u64)0);
- }
- if (bmval0 & FATTR4_WORD0_MAXLINK) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(255);
- }
- if (bmval0 & FATTR4_WORD0_MAXNAME) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(statfs.f_namelen);
- }
- if (bmval0 & FATTR4_WORD0_MAXREAD) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE64((u64) svc_max_payload(rqstp));
- }
- if (bmval0 & FATTR4_WORD0_MAXWRITE) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE64((u64) svc_max_payload(rqstp));
- }
- if (bmval1 & FATTR4_WORD1_MODE) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(stat.mode & S_IALLUGO);
- }
- if (bmval1 & FATTR4_WORD1_NO_TRUNC) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(1);
- }
- if (bmval1 & FATTR4_WORD1_NUMLINKS) {
- if ((buflen -= 4) < 0)
- goto out_resource;
- WRITE32(stat.nlink);
- }
- if (bmval1 & FATTR4_WORD1_OWNER) {
- status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen);
- if (status == nfserr_resource)
- goto out_resource;
- if (status)
- goto out;
- }
- if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
- status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen);
- if (status == nfserr_resource)
- goto out_resource;
- if (status)
- goto out;
- }
- if (bmval1 & FATTR4_WORD1_RAWDEV) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- WRITE32((u32) MAJOR(stat.rdev));
- WRITE32((u32) MINOR(stat.rdev));
- }
- if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize;
- WRITE64(dummy64);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize;
- WRITE64(dummy64);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize;
- WRITE64(dummy64);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_USED) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- dummy64 = (u64)stat.blocks << 9;
- WRITE64(dummy64);
- }
- if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
- if ((buflen -= 12) < 0)
- goto out_resource;
- WRITE32(0);
- WRITE32(stat.atime.tv_sec);
- WRITE32(stat.atime.tv_nsec);
- }
- if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
- if ((buflen -= 12) < 0)
- goto out_resource;
- WRITE32(0);
- WRITE32(1);
- WRITE32(0);
- }
- if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
- if ((buflen -= 12) < 0)
- goto out_resource;
- WRITE32(0);
- WRITE32(stat.ctime.tv_sec);
- WRITE32(stat.ctime.tv_nsec);
- }
- if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
- if ((buflen -= 12) < 0)
- goto out_resource;
- WRITE32(0);
- WRITE32(stat.mtime.tv_sec);
- WRITE32(stat.mtime.tv_nsec);
- }
- if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
- if ((buflen -= 8) < 0)
- goto out_resource;
- /*
- * Get parent's attributes if not ignoring crossmount
- * and this is the root of a cross-mounted filesystem.
- */
- if (ignore_crossmnt == 0 &&
- dentry == exp->ex_path.mnt->mnt_root) {
- struct path path = exp->ex_path;
- path_get(&path);
- while (follow_up(&path)) {
- if (path.dentry != path.mnt->mnt_root)
- break;
- }
- err = vfs_getattr(path.mnt, path.dentry, &stat);
- path_put(&path);
- if (err)
- goto out_nfserr;
- }
- WRITE64(stat.ino);
- }
- if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
- WRITE32(3);
- WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
- WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD1);
- WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD2);
- }
-
- *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
- *countp = p - buffer;
- status = nfs_ok;
-
-out:
- kfree(acl);
- if (fhp == &tempfh)
- fh_put(&tempfh);
- return status;
-out_nfserr:
- status = nfserrno(err);
- goto out;
-out_resource:
- *countp = 0;
- status = nfserr_resource;
- goto out;
-out_serverfault:
- status = nfserr_serverfault;
- goto out;
-}
-
-static inline int attributes_need_mount(u32 *bmval)
-{
- if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME))
- return 1;
- if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID)
- return 1;
- return 0;
-}
-
-static __be32
-nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
- const char *name, int namlen, __be32 *p, int *buflen)
-{
- struct svc_export *exp = cd->rd_fhp->fh_export;
- struct dentry *dentry;
- __be32 nfserr;
- int ignore_crossmnt = 0;
-
- dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
- if (IS_ERR(dentry))
- return nfserrno(PTR_ERR(dentry));
- if (!dentry->d_inode) {
- /*
- * nfsd_buffered_readdir drops the i_mutex between
- * readdir and calling this callback, leaving a window
- * where this directory entry could have gone away.
- */
- dput(dentry);
- return nfserr_noent;
- }
-
- exp_get(exp);
- /*
- * In the case of a mountpoint, the client may be asking for
- * attributes that are only properties of the underlying filesystem
- * as opposed to the cross-mounted file system. In such a case,
- * we will not follow the cross mount and will fill the attribtutes
- * directly from the mountpoint dentry.
- */
- if (nfsd_mountpoint(dentry, exp)) {
- int err;
-
- if (!(exp->ex_flags & NFSEXP_V4ROOT)
- && !attributes_need_mount(cd->rd_bmval)) {
- ignore_crossmnt = 1;
- goto out_encode;
- }
- /*
- * Why the heck aren't we just using nfsd_lookup??
- * Different "."/".." handling? Something else?
- * At least, add a comment here to explain....
- */
- err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
- if (err) {
- nfserr = nfserrno(err);
- goto out_put;
- }
- nfserr = check_nfsd_access(exp, cd->rd_rqstp);
- if (nfserr)
- goto out_put;
-
- }
-out_encode:
- nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
- cd->rd_rqstp, ignore_crossmnt);
-out_put:
- dput(dentry);
- exp_put(exp);
- return nfserr;
-}
-
-static __be32 *
-nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
-{
- __be32 *attrlenp;
-
- if (buflen < 6)
- return NULL;
- *p++ = htonl(2);
- *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
- *p++ = htonl(0); /* bmval1 */
-
- attrlenp = p++;
- *p++ = nfserr; /* no htonl */
- *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
- return p;
-}
-
-static int
-nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type)
-{
- struct readdir_cd *ccd = ccdv;
- struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
- int buflen;
- __be32 *p = cd->buffer;
- __be32 *cookiep;
- __be32 nfserr = nfserr_toosmall;
-
- /* In nfsv4, "." and ".." never make it onto the wire.. */
- if (name && isdotent(name, namlen)) {
- cd->common.err = nfs_ok;
- return 0;
- }
-
- if (cd->offset)
- xdr_encode_hyper(cd->offset, (u64) offset);
-
- buflen = cd->buflen - 4 - XDR_QUADLEN(namlen);
- if (buflen < 0)
- goto fail;
-
- *p++ = xdr_one; /* mark entry present */
- cookiep = p;
- p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
- p = xdr_encode_array(p, name, namlen); /* name length & name */
-
- nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, p, &buflen);
- switch (nfserr) {
- case nfs_ok:
- p += buflen;
- break;
- case nfserr_resource:
- nfserr = nfserr_toosmall;
- goto fail;
- case nfserr_noent:
- goto skip_entry;
- default:
- /*
- * If the client requested the RDATTR_ERROR attribute,
- * we stuff the error code into this attribute
- * and continue. If this attribute was not requested,
- * then in accordance with the spec, we fail the
- * entire READDIR operation(!)
- */
- if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR))
- goto fail;
- p = nfsd4_encode_rdattr_error(p, buflen, nfserr);
- if (p == NULL) {
- nfserr = nfserr_toosmall;
- goto fail;
- }
- }
- cd->buflen -= (p - cd->buffer);
- cd->buffer = p;
- cd->offset = cookiep;
-skip_entry:
- cd->common.err = nfs_ok;
- return 0;
-fail:
- cd->common.err = nfserr;
- return -EINVAL;
-}
-
-static void
-nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid)
-{
- __be32 *p;
-
- RESERVE_SPACE(sizeof(stateid_t));
- WRITE32(sid->si_generation);
- WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
- ADJUST_ARGS();
-}
-
-static __be32
-nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(8);
- WRITE32(access->ac_supported);
- WRITE32(access->ac_resp_access);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8);
- WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
- WRITE32(bcts->dir);
- /* XXX: ? */
- WRITE32(0);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
-{
- ENCODE_SEQID_OP_HEAD;
-
- if (!nfserr)
- nfsd4_encode_stateid(resp, &close->cl_stateid);
-
- encode_seqid_op_tail(resp, save, nfserr);
- return nfserr;
-}
-
-
-static __be32
-nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(NFS4_VERIFIER_SIZE);
- WRITEMEM(commit->co_verf.data, NFS4_VERIFIER_SIZE);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(32);
- write_cinfo(&p, &create->cr_cinfo);
- WRITE32(2);
- WRITE32(create->cr_bmval[0]);
- WRITE32(create->cr_bmval[1]);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
-{
- struct svc_fh *fhp = getattr->ga_fhp;
- int buflen;
-
- if (nfserr)
- return nfserr;
-
- buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
- nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
- resp->p, &buflen, getattr->ga_bmval,
- resp->rqstp, 0);
- if (!nfserr)
- resp->p += buflen;
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
-{
- struct svc_fh *fhp = *fhpp;
- unsigned int len;
- __be32 *p;
-
- if (!nfserr) {
- len = fhp->fh_handle.fh_size;
- RESERVE_SPACE(len + 4);
- WRITE32(len);
- WRITEMEM(&fhp->fh_handle.fh_base, len);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-/*
-* Including all fields other than the name, a LOCK4denied structure requires
-* 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes.
-*/
-static void
-nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld)
-{
- struct xdr_netobj *conf = &ld->ld_owner;
- __be32 *p;
-
- RESERVE_SPACE(32 + XDR_LEN(conf->len));
- WRITE64(ld->ld_start);
- WRITE64(ld->ld_length);
- WRITE32(ld->ld_type);
- if (conf->len) {
- WRITEMEM(&ld->ld_clientid, 8);
- WRITE32(conf->len);
- WRITEMEM(conf->data, conf->len);
- kfree(conf->data);
- } else { /* non - nfsv4 lock in conflict, no clientid nor owner */
- WRITE64((u64)0); /* clientid */
- WRITE32(0); /* length of owner name */
- }
- ADJUST_ARGS();
-}
-
-static __be32
-nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
-{
- ENCODE_SEQID_OP_HEAD;
-
- if (!nfserr)
- nfsd4_encode_stateid(resp, &lock->lk_resp_stateid);
- else if (nfserr == nfserr_denied)
- nfsd4_encode_lock_denied(resp, &lock->lk_denied);
-
- encode_seqid_op_tail(resp, save, nfserr);
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
-{
- if (nfserr == nfserr_denied)
- nfsd4_encode_lock_denied(resp, &lockt->lt_denied);
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
-{
- ENCODE_SEQID_OP_HEAD;
-
- if (!nfserr)
- nfsd4_encode_stateid(resp, &locku->lu_stateid);
-
- encode_seqid_op_tail(resp, save, nfserr);
- return nfserr;
-}
-
-
-static __be32
-nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(20);
- write_cinfo(&p, &link->li_cinfo);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-
-static __be32
-nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
-{
- __be32 *p;
- ENCODE_SEQID_OP_HEAD;
-
- if (nfserr)
- goto out;
-
- nfsd4_encode_stateid(resp, &open->op_stateid);
- RESERVE_SPACE(40);
- write_cinfo(&p, &open->op_cinfo);
- WRITE32(open->op_rflags);
- WRITE32(2);
- WRITE32(open->op_bmval[0]);
- WRITE32(open->op_bmval[1]);
- WRITE32(open->op_delegate_type);
- ADJUST_ARGS();
-
- switch (open->op_delegate_type) {
- case NFS4_OPEN_DELEGATE_NONE:
- break;
- case NFS4_OPEN_DELEGATE_READ:
- nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
- RESERVE_SPACE(20);
- WRITE32(open->op_recall);
-
- /*
- * TODO: ACE's in delegations
- */
- WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
- WRITE32(0);
- WRITE32(0);
- WRITE32(0); /* XXX: is NULL principal ok? */
- ADJUST_ARGS();
- break;
- case NFS4_OPEN_DELEGATE_WRITE:
- nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
- RESERVE_SPACE(32);
- WRITE32(0);
-
- /*
- * TODO: space_limit's in delegations
- */
- WRITE32(NFS4_LIMIT_SIZE);
- WRITE32(~(u32)0);
- WRITE32(~(u32)0);
-
- /*
- * TODO: ACE's in delegations
- */
- WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
- WRITE32(0);
- WRITE32(0);
- WRITE32(0); /* XXX: is NULL principal ok? */
- ADJUST_ARGS();
- break;
- case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */
- switch (open->op_why_no_deleg) {
- case WND4_CONTENTION:
- case WND4_RESOURCE:
- RESERVE_SPACE(8);
- WRITE32(open->op_why_no_deleg);
- WRITE32(0); /* deleg signaling not supported yet */
- break;
- default:
- RESERVE_SPACE(4);
- WRITE32(open->op_why_no_deleg);
- }
- ADJUST_ARGS();
- break;
- default:
- BUG();
- }
- /* XXX save filehandle here */
-out:
- encode_seqid_op_tail(resp, save, nfserr);
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
-{
- ENCODE_SEQID_OP_HEAD;
-
- if (!nfserr)
- nfsd4_encode_stateid(resp, &oc->oc_resp_stateid);
-
- encode_seqid_op_tail(resp, save, nfserr);
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
-{
- ENCODE_SEQID_OP_HEAD;
-
- if (!nfserr)
- nfsd4_encode_stateid(resp, &od->od_stateid);
-
- encode_seqid_op_tail(resp, save, nfserr);
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_read *read)
-{
- u32 eof;
- int v, pn;
- unsigned long maxcount;
- long len;
- __be32 *p;
-
- if (nfserr)
- return nfserr;
- if (resp->xbuf->page_len)
- return nfserr_resource;
-
- RESERVE_SPACE(8); /* eof flag and byte count */
-
- maxcount = svc_max_payload(resp->rqstp);
- if (maxcount > read->rd_length)
- maxcount = read->rd_length;
-
- len = maxcount;
- v = 0;
- while (len > 0) {
- pn = resp->rqstp->rq_resused++;
- resp->rqstp->rq_vec[v].iov_base =
- page_address(resp->rqstp->rq_respages[pn]);
- resp->rqstp->rq_vec[v].iov_len =
- len < PAGE_SIZE ? len : PAGE_SIZE;
- v++;
- len -= PAGE_SIZE;
- }
- read->rd_vlen = v;
-
- nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp,
- read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
- &maxcount);
-
- if (nfserr)
- return nfserr;
- eof = (read->rd_offset + maxcount >=
- read->rd_fhp->fh_dentry->d_inode->i_size);
-
- WRITE32(eof);
- WRITE32(maxcount);
- ADJUST_ARGS();
- resp->xbuf->head[0].iov_len = (char*)p
- - (char*)resp->xbuf->head[0].iov_base;
- resp->xbuf->page_len = maxcount;
-
- /* Use rest of head for padding and remaining ops: */
- resp->xbuf->tail[0].iov_base = p;
- resp->xbuf->tail[0].iov_len = 0;
- if (maxcount&3) {
- RESERVE_SPACE(4);
- WRITE32(0);
- resp->xbuf->tail[0].iov_base += maxcount&3;
- resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
- ADJUST_ARGS();
- }
- return 0;
-}
-
-static __be32
-nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
-{
- int maxcount;
- char *page;
- __be32 *p;
-
- if (nfserr)
- return nfserr;
- if (resp->xbuf->page_len)
- return nfserr_resource;
-
- page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
-
- maxcount = PAGE_SIZE;
- RESERVE_SPACE(4);
-
- /*
- * XXX: By default, the ->readlink() VFS op will truncate symlinks
- * if they would overflow the buffer. Is this kosher in NFSv4? If
- * not, one easy fix is: if ->readlink() precisely fills the buffer,
- * assume that truncation occurred, and return NFS4ERR_RESOURCE.
- */
- nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, page, &maxcount);
- if (nfserr == nfserr_isdir)
- return nfserr_inval;
- if (nfserr)
- return nfserr;
-
- WRITE32(maxcount);
- ADJUST_ARGS();
- resp->xbuf->head[0].iov_len = (char*)p
- - (char*)resp->xbuf->head[0].iov_base;
- resp->xbuf->page_len = maxcount;
-
- /* Use rest of head for padding and remaining ops: */
- resp->xbuf->tail[0].iov_base = p;
- resp->xbuf->tail[0].iov_len = 0;
- if (maxcount&3) {
- RESERVE_SPACE(4);
- WRITE32(0);
- resp->xbuf->tail[0].iov_base += maxcount&3;
- resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
- ADJUST_ARGS();
- }
- return 0;
-}
-
-static __be32
-nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
-{
- int maxcount;
- loff_t offset;
- __be32 *page, *savep, *tailbase;
- __be32 *p;
-
- if (nfserr)
- return nfserr;
- if (resp->xbuf->page_len)
- return nfserr_resource;
-
- RESERVE_SPACE(NFS4_VERIFIER_SIZE);
- savep = p;
-
- /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
- WRITE32(0);
- WRITE32(0);
- ADJUST_ARGS();
- resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
- tailbase = p;
-
- maxcount = PAGE_SIZE;
- if (maxcount > readdir->rd_maxcount)
- maxcount = readdir->rd_maxcount;
-
- /*
- * Convert from bytes to words, account for the two words already
- * written, make sure to leave two words at the end for the next
- * pointer and eof field.
- */
- maxcount = (maxcount >> 2) - 4;
- if (maxcount < 0) {
- nfserr = nfserr_toosmall;
- goto err_no_verf;
- }
-
- page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
- readdir->common.err = 0;
- readdir->buflen = maxcount;
- readdir->buffer = page;
- readdir->offset = NULL;
-
- offset = readdir->rd_cookie;
- nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp,
- &offset,
- &readdir->common, nfsd4_encode_dirent);
- if (nfserr == nfs_ok &&
- readdir->common.err == nfserr_toosmall &&
- readdir->buffer == page)
- nfserr = nfserr_toosmall;
- if (nfserr)
- goto err_no_verf;
-
- if (readdir->offset)
- xdr_encode_hyper(readdir->offset, offset);
-
- p = readdir->buffer;
- *p++ = 0; /* no more entries */
- *p++ = htonl(readdir->common.err == nfserr_eof);
- resp->xbuf->page_len = ((char*)p) - (char*)page_address(
- resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
-
- /* Use rest of head for padding and remaining ops: */
- resp->xbuf->tail[0].iov_base = tailbase;
- resp->xbuf->tail[0].iov_len = 0;
- resp->p = resp->xbuf->tail[0].iov_base;
- resp->end = resp->p + (PAGE_SIZE - resp->xbuf->head[0].iov_len)/4;
-
- return 0;
-err_no_verf:
- p = savep;
- ADJUST_ARGS();
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(20);
- write_cinfo(&p, &remove->rm_cinfo);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(40);
- write_cinfo(&p, &rename->rn_sinfo);
- write_cinfo(&p, &rename->rn_tinfo);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-static __be32
-nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
- __be32 nfserr,struct svc_export *exp)
-{
- int i = 0;
- u32 nflavs;
- struct exp_flavor_info *flavs;
- struct exp_flavor_info def_flavs[2];
- __be32 *p;
-
- if (nfserr)
- goto out;
- if (exp->ex_nflavors) {
- flavs = exp->ex_flavors;
- nflavs = exp->ex_nflavors;
- } else { /* Handling of some defaults in absence of real secinfo: */
- flavs = def_flavs;
- if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
- nflavs = 2;
- flavs[0].pseudoflavor = RPC_AUTH_UNIX;
- flavs[1].pseudoflavor = RPC_AUTH_NULL;
- } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
- nflavs = 1;
- flavs[0].pseudoflavor
- = svcauth_gss_flavor(exp->ex_client);
- } else {
- nflavs = 1;
- flavs[0].pseudoflavor
- = exp->ex_client->flavour->flavour;
- }
- }
-
- RESERVE_SPACE(4);
- WRITE32(nflavs);
- ADJUST_ARGS();
- for (i = 0; i < nflavs; i++) {
- u32 flav = flavs[i].pseudoflavor;
- struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
-
- if (gm) {
- RESERVE_SPACE(4);
- WRITE32(RPC_AUTH_GSS);
- ADJUST_ARGS();
- RESERVE_SPACE(4 + gm->gm_oid.len);
- WRITE32(gm->gm_oid.len);
- WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
- ADJUST_ARGS();
- RESERVE_SPACE(4);
- WRITE32(0); /* qop */
- ADJUST_ARGS();
- RESERVE_SPACE(4);
- WRITE32(gss_pseudoflavor_to_service(gm, flav));
- ADJUST_ARGS();
- gss_mech_put(gm);
- } else {
- RESERVE_SPACE(4);
- WRITE32(flav);
- ADJUST_ARGS();
- }
- }
-out:
- if (exp)
- exp_put(exp);
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_secinfo *secinfo)
-{
- return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->si_exp);
-}
-
-static __be32
-nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_secinfo_no_name *secinfo)
-{
- return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->sin_exp);
-}
-
-/*
- * The SETATTR encode routine is special -- it always encodes a bitmap,
- * regardless of the error status.
- */
-static __be32
-nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
-{
- __be32 *p;
-
- RESERVE_SPACE(12);
- if (nfserr) {
- WRITE32(2);
- WRITE32(0);
- WRITE32(0);
- }
- else {
- WRITE32(2);
- WRITE32(setattr->sa_bmval[0]);
- WRITE32(setattr->sa_bmval[1]);
- }
- ADJUST_ARGS();
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(8 + NFS4_VERIFIER_SIZE);
- WRITEMEM(&scd->se_clientid, 8);
- WRITEMEM(&scd->se_confirm, NFS4_VERIFIER_SIZE);
- ADJUST_ARGS();
- }
- else if (nfserr == nfserr_clid_inuse) {
- RESERVE_SPACE(8);
- WRITE32(0);
- WRITE32(0);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
-{
- __be32 *p;
-
- if (!nfserr) {
- RESERVE_SPACE(16);
- WRITE32(write->wr_bytes_written);
- WRITE32(write->wr_how_written);
- WRITEMEM(write->wr_verifier.data, NFS4_VERIFIER_SIZE);
- ADJUST_ARGS();
- }
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr,
- struct nfsd4_exchange_id *exid)
-{
- __be32 *p;
- char *major_id;
- char *server_scope;
- int major_id_sz;
- int server_scope_sz;
- uint64_t minor_id = 0;
-
- if (nfserr)
- return nfserr;
-
- major_id = utsname()->nodename;
- major_id_sz = strlen(major_id);
- server_scope = utsname()->nodename;
- server_scope_sz = strlen(server_scope);
-
- RESERVE_SPACE(
- 8 /* eir_clientid */ +
- 4 /* eir_sequenceid */ +
- 4 /* eir_flags */ +
- 4 /* spr_how (SP4_NONE) */ +
- 8 /* so_minor_id */ +
- 4 /* so_major_id.len */ +
- (XDR_QUADLEN(major_id_sz) * 4) +
- 4 /* eir_server_scope.len */ +
- (XDR_QUADLEN(server_scope_sz) * 4) +
- 4 /* eir_server_impl_id.count (0) */);
-
- WRITEMEM(&exid->clientid, 8);
- WRITE32(exid->seqid);
- WRITE32(exid->flags);
-
- /* state_protect4_r. Currently only support SP4_NONE */
- BUG_ON(exid->spa_how != SP4_NONE);
- WRITE32(exid->spa_how);
-
- /* The server_owner struct */
- WRITE64(minor_id); /* Minor id */
- /* major id */
- WRITE32(major_id_sz);
- WRITEMEM(major_id, major_id_sz);
-
- /* Server scope */
- WRITE32(server_scope_sz);
- WRITEMEM(server_scope, server_scope_sz);
-
- /* Implementation id */
- WRITE32(0); /* zero length nfs_impl_id4 array */
- ADJUST_ARGS();
- return 0;
-}
-
-static __be32
-nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr,
- struct nfsd4_create_session *sess)
-{
- __be32 *p;
-
- if (nfserr)
- return nfserr;
-
- RESERVE_SPACE(24);
- WRITEMEM(sess->sessionid.data, NFS4_MAX_SESSIONID_LEN);
- WRITE32(sess->seqid);
- WRITE32(sess->flags);
- ADJUST_ARGS();
-
- RESERVE_SPACE(28);
- WRITE32(0); /* headerpadsz */
- WRITE32(sess->fore_channel.maxreq_sz);
- WRITE32(sess->fore_channel.maxresp_sz);
- WRITE32(sess->fore_channel.maxresp_cached);
- WRITE32(sess->fore_channel.maxops);
- WRITE32(sess->fore_channel.maxreqs);
- WRITE32(sess->fore_channel.nr_rdma_attrs);
- ADJUST_ARGS();
-
- if (sess->fore_channel.nr_rdma_attrs) {
- RESERVE_SPACE(4);
- WRITE32(sess->fore_channel.rdma_attrs);
- ADJUST_ARGS();
- }
-
- RESERVE_SPACE(28);
- WRITE32(0); /* headerpadsz */
- WRITE32(sess->back_channel.maxreq_sz);
- WRITE32(sess->back_channel.maxresp_sz);
- WRITE32(sess->back_channel.maxresp_cached);
- WRITE32(sess->back_channel.maxops);
- WRITE32(sess->back_channel.maxreqs);
- WRITE32(sess->back_channel.nr_rdma_attrs);
- ADJUST_ARGS();
-
- if (sess->back_channel.nr_rdma_attrs) {
- RESERVE_SPACE(4);
- WRITE32(sess->back_channel.rdma_attrs);
- ADJUST_ARGS();
- }
- return 0;
-}
-
-static __be32
-nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
- struct nfsd4_destroy_session *destroy_session)
-{
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
- struct nfsd4_free_stateid *free_stateid)
-{
- __be32 *p;
-
- if (nfserr)
- return nfserr;
-
- RESERVE_SPACE(4);
- WRITE32(nfserr);
- ADJUST_ARGS();
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
- struct nfsd4_sequence *seq)
-{
- __be32 *p;
-
- if (nfserr)
- return nfserr;
-
- RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 20);
- WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
- WRITE32(seq->seqid);
- WRITE32(seq->slotid);
- /* Note slotid's are numbered from zero: */
- WRITE32(seq->maxslots - 1); /* sr_highest_slotid */
- WRITE32(seq->maxslots - 1); /* sr_target_highest_slotid */
- WRITE32(seq->status_flags);
-
- ADJUST_ARGS();
- resp->cstate.datap = p; /* DRC cache data pointer */
- return 0;
-}
-
-__be32
-nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
- struct nfsd4_test_stateid *test_stateid)
-{
- struct nfsd4_test_stateid_id *stateid, *next;
- __be32 *p;
-
- RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids));
- *p++ = htonl(test_stateid->ts_num_ids);
-
- list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) {
- *p++ = stateid->ts_id_status;
- }
-
- ADJUST_ARGS();
- return nfserr;
-}
-
-static __be32
-nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
-{
- return nfserr;
-}
-
-typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
-
-/*
- * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1
- * since we don't need to filter out obsolete ops as this is
- * done in the decoding phase.
- */
-static nfsd4_enc nfsd4_enc_ops[] = {
- [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
- [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
- [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit,
- [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create,
- [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr,
- [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh,
- [OP_LINK] = (nfsd4_enc)nfsd4_encode_link,
- [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock,
- [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt,
- [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku,
- [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open,
- [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm,
- [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade,
- [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_READ] = (nfsd4_enc)nfsd4_encode_read,
- [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir,
- [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink,
- [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove,
- [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename,
- [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo,
- [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr,
- [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid,
- [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write,
- [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop,
-
- /* NFSv4.1 operations */
- [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
- [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
- [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
- [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session,
- [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_free_stateid,
- [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
- [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
- [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid,
- [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop,
-};
-
-/*
- * Calculate the total amount of memory that the compound response has taken
- * after encoding the current operation with pad.
- *
- * pad: if operation is non-idempotent, pad was calculate by op_rsize_bop()
- * which was specified at nfsd4_operation, else pad is zero.
- *
- * Compare this length to the session se_fmaxresp_sz and se_fmaxresp_cached.
- *
- * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so
- * will be at least a page and will therefore hold the xdr_buf head.
- */
-int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
-{
- struct xdr_buf *xb = &resp->rqstp->rq_res;
- struct nfsd4_session *session = NULL;
- struct nfsd4_slot *slot = resp->cstate.slot;
- u32 length, tlen = 0;
-
- if (!nfsd4_has_session(&resp->cstate))
- return 0;
-
- session = resp->cstate.session;
- if (session == NULL)
- return 0;
-
- if (xb->page_len == 0) {
- length = (char *)resp->p - (char *)xb->head[0].iov_base + pad;
- } else {
- if (xb->tail[0].iov_base && xb->tail[0].iov_len > 0)
- tlen = (char *)resp->p - (char *)xb->tail[0].iov_base;
-
- length = xb->head[0].iov_len + xb->page_len + tlen + pad;
- }
- dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__,
- length, xb->page_len, tlen, pad);
-
- if (length > session->se_fchannel.maxresp_sz)
- return nfserr_rep_too_big;
-
- if ((slot->sl_flags & NFSD4_SLOT_CACHETHIS) &&
- length > session->se_fchannel.maxresp_cached)
- return nfserr_rep_too_big_to_cache;
-
- return 0;
-}
-
-void
-nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
-{
- __be32 *statp;
- __be32 *p;
-
- RESERVE_SPACE(8);
- WRITE32(op->opnum);
- statp = p++; /* to be backfilled at the end */
- ADJUST_ARGS();
-
- if (op->opnum == OP_ILLEGAL)
- goto status;
- BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
- !nfsd4_enc_ops[op->opnum]);
- op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u);
- /* nfsd4_check_drc_limit guarantees enough room for error status */
- if (!op->status)
- op->status = nfsd4_check_resp_size(resp, 0);
-status:
- /*
- * Note: We write the status directly, instead of using WRITE32(),
- * since it is already in network byte order.
- */
- *statp = op->status;
-}
-
-/*
- * Encode the reply stored in the stateowner reply cache
- *
- * XDR note: do not encode rp->rp_buflen: the buffer contains the
- * previously sent already encoded operation.
- *
- * called with nfs4_lock_state() held
- */
-void
-nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
-{
- __be32 *p;
- struct nfs4_replay *rp = op->replay;
-
- BUG_ON(!rp);
-
- RESERVE_SPACE(8);
- WRITE32(op->opnum);
- *p++ = rp->rp_status; /* already xdr'ed */
- ADJUST_ARGS();
-
- RESERVE_SPACE(rp->rp_buflen);
- WRITEMEM(rp->rp_buf, rp->rp_buflen);
- ADJUST_ARGS();
-}
-
-int
-nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
-{
- return xdr_ressize_check(rqstp, p);
-}
-
-int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
-{
- struct svc_rqst *rqstp = rq;
- struct nfsd4_compoundargs *args = rqstp->rq_argp;
-
- if (args->ops != args->iops) {
- kfree(args->ops);
- args->ops = args->iops;
- }
- kfree(args->tmpp);
- args->tmpp = NULL;
- while (args->to_free) {
- struct tmpbuf *tb = args->to_free;
- args->to_free = tb->next;
- tb->release(tb->buf);
- kfree(tb);
- }
- return 1;
-}
-
-int
-nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
-{
- args->p = p;
- args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
- args->pagelist = rqstp->rq_arg.pages;
- args->pagelen = rqstp->rq_arg.page_len;
- args->tmpp = NULL;
- args->to_free = NULL;
- args->ops = args->iops;
- args->rqstp = rqstp;
-
- return !nfsd4_decode_compound(args);
-}
-
-int
-nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp)
-{
- /*
- * All that remains is to write the tag and operation count...
- */
- struct nfsd4_compound_state *cs = &resp->cstate;
- struct kvec *iov;
- p = resp->tagp;
- *p++ = htonl(resp->taglen);
- memcpy(p, resp->tag, resp->taglen);
- p += XDR_QUADLEN(resp->taglen);
- *p++ = htonl(resp->opcnt);
-
- if (rqstp->rq_res.page_len)
- iov = &rqstp->rq_res.tail[0];
- else
- iov = &rqstp->rq_res.head[0];
- iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
- BUG_ON(iov->iov_len > PAGE_SIZE);
- if (nfsd4_has_session(cs)) {
- if (cs->status != nfserr_replay_cache) {
- nfsd4_store_cache_entry(resp);
- cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
- }
- /* Renew the clientid on success and on replay */
- release_session_client(cs->session);
- nfsd4_put_session(cs->session);
- }
- return 1;
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/ANDROID_3.4.5/fs/nfsd/nfscache.c b/ANDROID_3.4.5/fs/nfsd/nfscache.c
deleted file mode 100644
index 2cbac34a..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfscache.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Request reply cache. This is currently a global cache, but this may
- * change in the future and be a per-client cache.
- *
- * This code is heavily inspired by the 44BSD implementation, although
- * it does things a bit differently.
- *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/slab.h>
-
-#include "nfsd.h"
-#include "cache.h"
-
-/* Size of reply cache. Common values are:
- * 4.3BSD: 128
- * 4.4BSD: 256
- * Solaris2: 1024
- * DEC Unix: 512-4096
- */
-#define CACHESIZE 1024
-#define HASHSIZE 64
-
-static struct hlist_head * cache_hash;
-static struct list_head lru_head;
-static int cache_disabled = 1;
-
-/*
- * Calculate the hash index from an XID.
- */
-static inline u32 request_hash(u32 xid)
-{
- u32 h = xid;
- h ^= (xid >> 24);
- return h & (HASHSIZE-1);
-}
-
-static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
-
-/*
- * locking for the reply cache:
- * A cache entry is "single use" if c_state == RC_INPROG
- * Otherwise, it when accessing _prev or _next, the lock must be held.
- */
-static DEFINE_SPINLOCK(cache_lock);
-
-int nfsd_reply_cache_init(void)
-{
- struct svc_cacherep *rp;
- int i;
-
- INIT_LIST_HEAD(&lru_head);
- i = CACHESIZE;
- while (i) {
- rp = kmalloc(sizeof(*rp), GFP_KERNEL);
- if (!rp)
- goto out_nomem;
- list_add(&rp->c_lru, &lru_head);
- rp->c_state = RC_UNUSED;
- rp->c_type = RC_NOCACHE;
- INIT_HLIST_NODE(&rp->c_hash);
- i--;
- }
-
- cache_hash = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
- if (!cache_hash)
- goto out_nomem;
-
- cache_disabled = 0;
- return 0;
-out_nomem:
- printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
- nfsd_reply_cache_shutdown();
- return -ENOMEM;
-}
-
-void nfsd_reply_cache_shutdown(void)
-{
- struct svc_cacherep *rp;
-
- while (!list_empty(&lru_head)) {
- rp = list_entry(lru_head.next, struct svc_cacherep, c_lru);
- if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF)
- kfree(rp->c_replvec.iov_base);
- list_del(&rp->c_lru);
- kfree(rp);
- }
-
- cache_disabled = 1;
-
- kfree (cache_hash);
- cache_hash = NULL;
-}
-
-/*
- * Move cache entry to end of LRU list
- */
-static void
-lru_put_end(struct svc_cacherep *rp)
-{
- list_move_tail(&rp->c_lru, &lru_head);
-}
-
-/*
- * Move a cache entry from one hash list to another
- */
-static void
-hash_refile(struct svc_cacherep *rp)
-{
- hlist_del_init(&rp->c_hash);
- hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid));
-}
-
-/*
- * Try to find an entry matching the current call in the cache. When none
- * is found, we grab the oldest unlocked entry off the LRU list.
- * Note that no operation within the loop may sleep.
- */
-int
-nfsd_cache_lookup(struct svc_rqst *rqstp)
-{
- struct hlist_node *hn;
- struct hlist_head *rh;
- struct svc_cacherep *rp;
- __be32 xid = rqstp->rq_xid;
- u32 proto = rqstp->rq_prot,
- vers = rqstp->rq_vers,
- proc = rqstp->rq_proc;
- unsigned long age;
- int type = rqstp->rq_cachetype;
- int rtn;
-
- rqstp->rq_cacherep = NULL;
- if (cache_disabled || type == RC_NOCACHE) {
- nfsdstats.rcnocache++;
- return RC_DOIT;
- }
-
- spin_lock(&cache_lock);
- rtn = RC_DOIT;
-
- rh = &cache_hash[request_hash(xid)];
- hlist_for_each_entry(rp, hn, rh, c_hash) {
- if (rp->c_state != RC_UNUSED &&
- xid == rp->c_xid && proc == rp->c_proc &&
- proto == rp->c_prot && vers == rp->c_vers &&
- time_before(jiffies, rp->c_timestamp + 120*HZ) &&
- memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, sizeof(rp->c_addr))==0) {
- nfsdstats.rchits++;
- goto found_entry;
- }
- }
- nfsdstats.rcmisses++;
-
- /* This loop shouldn't take more than a few iterations normally */
- {
- int safe = 0;
- list_for_each_entry(rp, &lru_head, c_lru) {
- if (rp->c_state != RC_INPROG)
- break;
- if (safe++ > CACHESIZE) {
- printk("nfsd: loop in repcache LRU list\n");
- cache_disabled = 1;
- goto out;
- }
- }
- }
-
- /* All entries on the LRU are in-progress. This should not happen */
- if (&rp->c_lru == &lru_head) {
- static int complaints;
-
- printk(KERN_WARNING "nfsd: all repcache entries locked!\n");
- if (++complaints > 5) {
- printk(KERN_WARNING "nfsd: disabling repcache.\n");
- cache_disabled = 1;
- }
- goto out;
- }
-
- rqstp->rq_cacherep = rp;
- rp->c_state = RC_INPROG;
- rp->c_xid = xid;
- rp->c_proc = proc;
- memcpy(&rp->c_addr, svc_addr_in(rqstp), sizeof(rp->c_addr));
- rp->c_prot = proto;
- rp->c_vers = vers;
- rp->c_timestamp = jiffies;
-
- hash_refile(rp);
-
- /* release any buffer */
- if (rp->c_type == RC_REPLBUFF) {
- kfree(rp->c_replvec.iov_base);
- rp->c_replvec.iov_base = NULL;
- }
- rp->c_type = RC_NOCACHE;
- out:
- spin_unlock(&cache_lock);
- return rtn;
-
-found_entry:
- /* We found a matching entry which is either in progress or done. */
- age = jiffies - rp->c_timestamp;
- rp->c_timestamp = jiffies;
- lru_put_end(rp);
-
- rtn = RC_DROPIT;
- /* Request being processed or excessive rexmits */
- if (rp->c_state == RC_INPROG || age < RC_DELAY)
- goto out;
-
- /* From the hall of fame of impractical attacks:
- * Is this a user who tries to snoop on the cache? */
- rtn = RC_DOIT;
- if (!rqstp->rq_secure && rp->c_secure)
- goto out;
-
- /* Compose RPC reply header */
- switch (rp->c_type) {
- case RC_NOCACHE:
- break;
- case RC_REPLSTAT:
- svc_putu32(&rqstp->rq_res.head[0], rp->c_replstat);
- rtn = RC_REPLY;
- break;
- case RC_REPLBUFF:
- if (!nfsd_cache_append(rqstp, &rp->c_replvec))
- goto out; /* should not happen */
- rtn = RC_REPLY;
- break;
- default:
- printk(KERN_WARNING "nfsd: bad repcache type %d\n", rp->c_type);
- rp->c_state = RC_UNUSED;
- }
-
- goto out;
-}
-
-/*
- * Update a cache entry. This is called from nfsd_dispatch when
- * the procedure has been executed and the complete reply is in
- * rqstp->rq_res.
- *
- * We're copying around data here rather than swapping buffers because
- * the toplevel loop requires max-sized buffers, which would be a waste
- * of memory for a cache with a max reply size of 100 bytes (diropokres).
- *
- * If we should start to use different types of cache entries tailored
- * specifically for attrstat and fh's, we may save even more space.
- *
- * Also note that a cachetype of RC_NOCACHE can legally be passed when
- * nfsd failed to encode a reply that otherwise would have been cached.
- * In this case, nfsd_cache_update is called with statp == NULL.
- */
-void
-nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
-{
- struct svc_cacherep *rp;
- struct kvec *resv = &rqstp->rq_res.head[0], *cachv;
- int len;
-
- if (!(rp = rqstp->rq_cacherep) || cache_disabled)
- return;
-
- len = resv->iov_len - ((char*)statp - (char*)resv->iov_base);
- len >>= 2;
-
- /* Don't cache excessive amounts of data and XDR failures */
- if (!statp || len > (256 >> 2)) {
- rp->c_state = RC_UNUSED;
- return;
- }
-
- switch (cachetype) {
- case RC_REPLSTAT:
- if (len != 1)
- printk("nfsd: RC_REPLSTAT/reply len %d!\n",len);
- rp->c_replstat = *statp;
- break;
- case RC_REPLBUFF:
- cachv = &rp->c_replvec;
- cachv->iov_base = kmalloc(len << 2, GFP_KERNEL);
- if (!cachv->iov_base) {
- spin_lock(&cache_lock);
- rp->c_state = RC_UNUSED;
- spin_unlock(&cache_lock);
- return;
- }
- cachv->iov_len = len << 2;
- memcpy(cachv->iov_base, statp, len << 2);
- break;
- }
- spin_lock(&cache_lock);
- lru_put_end(rp);
- rp->c_secure = rqstp->rq_secure;
- rp->c_type = cachetype;
- rp->c_state = RC_DONE;
- rp->c_timestamp = jiffies;
- spin_unlock(&cache_lock);
- return;
-}
-
-/*
- * Copy cached reply to current reply buffer. Should always fit.
- * FIXME as reply is in a page, we should just attach the page, and
- * keep a refcount....
- */
-static int
-nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *data)
-{
- struct kvec *vec = &rqstp->rq_res.head[0];
-
- if (vec->iov_len + data->iov_len > PAGE_SIZE) {
- printk(KERN_WARNING "nfsd: cached reply too large (%Zd).\n",
- data->iov_len);
- return 0;
- }
- memcpy((char*)vec->iov_base + vec->iov_len, data->iov_base, data->iov_len);
- vec->iov_len += data->iov_len;
- return 1;
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/nfsctl.c b/ANDROID_3.4.5/fs/nfsd/nfsctl.c
deleted file mode 100644
index 3ab12eb2..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfsctl.c
+++ /dev/null
@@ -1,1218 +0,0 @@
-/*
- * Syscall interface to knfsd.
- *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/slab.h>
-#include <linux/namei.h>
-#include <linux/ctype.h>
-
-#include <linux/sunrpc/svcsock.h>
-#include <linux/lockd/lockd.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/gss_api.h>
-#include <linux/sunrpc/gss_krb5_enctypes.h>
-#include <linux/sunrpc/rpc_pipe_fs.h>
-#include <linux/module.h>
-
-#include "idmap.h"
-#include "nfsd.h"
-#include "cache.h"
-#include "fault_inject.h"
-#include "netns.h"
-
-/*
- * We have a single directory with several nodes in it.
- */
-enum {
- NFSD_Root = 1,
- NFSD_List,
- NFSD_Export_features,
- NFSD_Fh,
- NFSD_FO_UnlockIP,
- NFSD_FO_UnlockFS,
- NFSD_Threads,
- NFSD_Pool_Threads,
- NFSD_Pool_Stats,
- NFSD_Versions,
- NFSD_Ports,
- NFSD_MaxBlkSize,
- NFSD_SupportedEnctypes,
- /*
- * The below MUST come last. Otherwise we leave a hole in nfsd_files[]
- * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
- */
-#ifdef CONFIG_NFSD_V4
- NFSD_Leasetime,
- NFSD_Gracetime,
- NFSD_RecoveryDir,
-#endif
-};
-
-/*
- * write() for these nodes.
- */
-static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
-static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
-static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
-static ssize_t write_threads(struct file *file, char *buf, size_t size);
-static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
-static ssize_t write_versions(struct file *file, char *buf, size_t size);
-static ssize_t write_ports(struct file *file, char *buf, size_t size);
-static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
-#ifdef CONFIG_NFSD_V4
-static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
-static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
-static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
-#endif
-
-static ssize_t (*write_op[])(struct file *, char *, size_t) = {
- [NFSD_Fh] = write_filehandle,
- [NFSD_FO_UnlockIP] = write_unlock_ip,
- [NFSD_FO_UnlockFS] = write_unlock_fs,
- [NFSD_Threads] = write_threads,
- [NFSD_Pool_Threads] = write_pool_threads,
- [NFSD_Versions] = write_versions,
- [NFSD_Ports] = write_ports,
- [NFSD_MaxBlkSize] = write_maxblksize,
-#ifdef CONFIG_NFSD_V4
- [NFSD_Leasetime] = write_leasetime,
- [NFSD_Gracetime] = write_gracetime,
- [NFSD_RecoveryDir] = write_recoverydir,
-#endif
-};
-
-static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
-{
- ino_t ino = file->f_path.dentry->d_inode->i_ino;
- char *data;
- ssize_t rv;
-
- if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
- return -EINVAL;
-
- data = simple_transaction_get(file, buf, size);
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- rv = write_op[ino](file, data, size);
- if (rv >= 0) {
- simple_transaction_set(file, rv);
- rv = size;
- }
- return rv;
-}
-
-static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
-{
- if (! file->private_data) {
- /* An attempt to read a transaction file without writing
- * causes a 0-byte write so that the file can return
- * state information
- */
- ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
- if (rv < 0)
- return rv;
- }
- return simple_transaction_read(file, buf, size, pos);
-}
-
-static const struct file_operations transaction_ops = {
- .write = nfsctl_transaction_write,
- .read = nfsctl_transaction_read,
- .release = simple_transaction_release,
- .llseek = default_llseek,
-};
-
-static int exports_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &nfs_exports_op);
-}
-
-static const struct file_operations exports_operations = {
- .open = exports_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
- .owner = THIS_MODULE,
-};
-
-static int export_features_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
- return 0;
-}
-
-static int export_features_open(struct inode *inode, struct file *file)
-{
- return single_open(file, export_features_show, NULL);
-}
-
-static struct file_operations export_features_operations = {
- .open = export_features_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
-static int supported_enctypes_show(struct seq_file *m, void *v)
-{
- seq_printf(m, KRB5_SUPPORTED_ENCTYPES);
- return 0;
-}
-
-static int supported_enctypes_open(struct inode *inode, struct file *file)
-{
- return single_open(file, supported_enctypes_show, NULL);
-}
-
-static struct file_operations supported_enctypes_ops = {
- .open = supported_enctypes_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
-
-extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
-extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
-
-static const struct file_operations pool_stats_operations = {
- .open = nfsd_pool_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = nfsd_pool_stats_release,
- .owner = THIS_MODULE,
-};
-
-/*----------------------------------------------------------------------------*/
-/*
- * payload - write methods
- */
-
-
-/**
- * write_unlock_ip - Release all locks used by a client
- *
- * Experimental.
- *
- * Input:
- * buf: '\n'-terminated C string containing a
- * presentation format IP address
- * size: length of C string in @buf
- * Output:
- * On success: returns zero if all specified locks were released;
- * returns one if one or more locks were not released
- * On error: return code is negative errno value
- */
-static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
-{
- struct sockaddr_storage address;
- struct sockaddr *sap = (struct sockaddr *)&address;
- size_t salen = sizeof(address);
- char *fo_path;
-
- /* sanity check */
- if (size == 0)
- return -EINVAL;
-
- if (buf[size-1] != '\n')
- return -EINVAL;
-
- fo_path = buf;
- if (qword_get(&buf, fo_path, size) < 0)
- return -EINVAL;
-
- if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0)
- return -EINVAL;
-
- return nlmsvc_unlock_all_by_ip(sap);
-}
-
-/**
- * write_unlock_fs - Release all locks on a local file system
- *
- * Experimental.
- *
- * Input:
- * buf: '\n'-terminated C string containing the
- * absolute pathname of a local file system
- * size: length of C string in @buf
- * Output:
- * On success: returns zero if all specified locks were released;
- * returns one if one or more locks were not released
- * On error: return code is negative errno value
- */
-static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
-{
- struct path path;
- char *fo_path;
- int error;
-
- /* sanity check */
- if (size == 0)
- return -EINVAL;
-
- if (buf[size-1] != '\n')
- return -EINVAL;
-
- fo_path = buf;
- if (qword_get(&buf, fo_path, size) < 0)
- return -EINVAL;
-
- error = kern_path(fo_path, 0, &path);
- if (error)
- return error;
-
- /*
- * XXX: Needs better sanity checking. Otherwise we could end up
- * releasing locks on the wrong file system.
- *
- * For example:
- * 1. Does the path refer to a directory?
- * 2. Is that directory a mount point, or
- * 3. Is that directory the root of an exported file system?
- */
- error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
-
- path_put(&path);
- return error;
-}
-
-/**
- * write_filehandle - Get a variable-length NFS file handle by path
- *
- * On input, the buffer contains a '\n'-terminated C string comprised of
- * three alphanumeric words separated by whitespace. The string may
- * contain escape sequences.
- *
- * Input:
- * buf:
- * domain: client domain name
- * path: export pathname
- * maxsize: numeric maximum size of
- * @buf
- * size: length of C string in @buf
- * Output:
- * On success: passed-in buffer filled with '\n'-terminated C
- * string containing a ASCII hex text version
- * of the NFS file handle;
- * return code is the size in bytes of the string
- * On error: return code is negative errno value
- */
-static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
-{
- char *dname, *path;
- int uninitialized_var(maxsize);
- char *mesg = buf;
- int len;
- struct auth_domain *dom;
- struct knfsd_fh fh;
-
- if (size == 0)
- return -EINVAL;
-
- if (buf[size-1] != '\n')
- return -EINVAL;
- buf[size-1] = 0;
-
- dname = mesg;
- len = qword_get(&mesg, dname, size);
- if (len <= 0)
- return -EINVAL;
-
- path = dname+len+1;
- len = qword_get(&mesg, path, size);
- if (len <= 0)
- return -EINVAL;
-
- len = get_int(&mesg, &maxsize);
- if (len)
- return len;
-
- if (maxsize < NFS_FHSIZE)
- return -EINVAL;
- if (maxsize > NFS3_FHSIZE)
- maxsize = NFS3_FHSIZE;
-
- if (qword_get(&mesg, mesg, size)>0)
- return -EINVAL;
-
- /* we have all the words, they are in buf.. */
- dom = unix_domain_find(dname);
- if (!dom)
- return -ENOMEM;
-
- len = exp_rootfh(dom, path, &fh, maxsize);
- auth_domain_put(dom);
- if (len)
- return len;
-
- mesg = buf;
- len = SIMPLE_TRANSACTION_LIMIT;
- qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
- mesg[-1] = '\n';
- return mesg - buf;
-}
-
-/**
- * write_threads - Start NFSD, or report the current number of running threads
- *
- * Input:
- * buf: ignored
- * size: zero
- * Output:
- * On success: passed-in buffer filled with '\n'-terminated C
- * string numeric value representing the number of
- * running NFSD threads;
- * return code is the size in bytes of the string
- * On error: return code is zero
- *
- * OR
- *
- * Input:
- * buf: C string containing an unsigned
- * integer value representing the
- * number of NFSD threads to start
- * size: non-zero length of C string in @buf
- * Output:
- * On success: NFS service is started;
- * passed-in buffer filled with '\n'-terminated C
- * string numeric value representing the number of
- * running NFSD threads;
- * return code is the size in bytes of the string
- * On error: return code is zero or a negative errno value
- */
-static ssize_t write_threads(struct file *file, char *buf, size_t size)
-{
- char *mesg = buf;
- int rv;
- if (size > 0) {
- int newthreads;
- rv = get_int(&mesg, &newthreads);
- if (rv)
- return rv;
- if (newthreads < 0)
- return -EINVAL;
- rv = nfsd_svc(NFS_PORT, newthreads);
- if (rv < 0)
- return rv;
- } else
- rv = nfsd_nrthreads();
-
- return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
-}
-
-/**
- * write_pool_threads - Set or report the current number of threads per pool
- *
- * Input:
- * buf: ignored
- * size: zero
- *
- * OR
- *
- * Input:
- * buf: C string containing whitespace-
- * separated unsigned integer values
- * representing the number of NFSD
- * threads to start in each pool
- * size: non-zero length of C string in @buf
- * Output:
- * On success: passed-in buffer filled with '\n'-terminated C
- * string containing integer values representing the
- * number of NFSD threads in each pool;
- * return code is the size in bytes of the string
- * On error: return code is zero or a negative errno value
- */
-static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
-{
- /* if size > 0, look for an array of number of threads per node
- * and apply them then write out number of threads per node as reply
- */
- char *mesg = buf;
- int i;
- int rv;
- int len;
- int npools;
- int *nthreads;
-
- mutex_lock(&nfsd_mutex);
- npools = nfsd_nrpools();
- if (npools == 0) {
- /*
- * NFS is shut down. The admin can start it by
- * writing to the threads file but NOT the pool_threads
- * file, sorry. Report zero threads.
- */
- mutex_unlock(&nfsd_mutex);
- strcpy(buf, "0\n");
- return strlen(buf);
- }
-
- nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
- rv = -ENOMEM;
- if (nthreads == NULL)
- goto out_free;
-
- if (size > 0) {
- for (i = 0; i < npools; i++) {
- rv = get_int(&mesg, &nthreads[i]);
- if (rv == -ENOENT)
- break; /* fewer numbers than pools */
- if (rv)
- goto out_free; /* syntax error */
- rv = -EINVAL;
- if (nthreads[i] < 0)
- goto out_free;
- }
- rv = nfsd_set_nrthreads(i, nthreads);
- if (rv)
- goto out_free;
- }
-
- rv = nfsd_get_nrthreads(npools, nthreads);
- if (rv)
- goto out_free;
-
- mesg = buf;
- size = SIMPLE_TRANSACTION_LIMIT;
- for (i = 0; i < npools && size > 0; i++) {
- snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
- len = strlen(mesg);
- size -= len;
- mesg += len;
- }
- rv = mesg - buf;
-out_free:
- kfree(nthreads);
- mutex_unlock(&nfsd_mutex);
- return rv;
-}
-
-static ssize_t __write_versions(struct file *file, char *buf, size_t size)
-{
- char *mesg = buf;
- char *vers, *minorp, sign;
- int len, num, remaining;
- unsigned minor;
- ssize_t tlen = 0;
- char *sep;
-
- if (size>0) {
- if (nfsd_serv)
- /* Cannot change versions without updating
- * nfsd_serv->sv_xdrsize, and reallocing
- * rq_argp and rq_resp
- */
- return -EBUSY;
- if (buf[size-1] != '\n')
- return -EINVAL;
- buf[size-1] = 0;
-
- vers = mesg;
- len = qword_get(&mesg, vers, size);
- if (len <= 0) return -EINVAL;
- do {
- sign = *vers;
- if (sign == '+' || sign == '-')
- num = simple_strtol((vers+1), &minorp, 0);
- else
- num = simple_strtol(vers, &minorp, 0);
- if (*minorp == '.') {
- if (num < 4)
- return -EINVAL;
- minor = simple_strtoul(minorp+1, NULL, 0);
- if (minor == 0)
- return -EINVAL;
- if (nfsd_minorversion(minor, sign == '-' ?
- NFSD_CLEAR : NFSD_SET) < 0)
- return -EINVAL;
- goto next;
- }
- switch(num) {
- case 2:
- case 3:
- case 4:
- nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
- break;
- default:
- return -EINVAL;
- }
- next:
- vers += len + 1;
- } while ((len = qword_get(&mesg, vers, size)) > 0);
- /* If all get turned off, turn them back on, as
- * having no versions is BAD
- */
- nfsd_reset_versions();
- }
-
- /* Now write current state into reply buffer */
- len = 0;
- sep = "";
- remaining = SIMPLE_TRANSACTION_LIMIT;
- for (num=2 ; num <= 4 ; num++)
- if (nfsd_vers(num, NFSD_AVAIL)) {
- len = snprintf(buf, remaining, "%s%c%d", sep,
- nfsd_vers(num, NFSD_TEST)?'+':'-',
- num);
- sep = " ";
-
- if (len > remaining)
- break;
- remaining -= len;
- buf += len;
- tlen += len;
- }
- if (nfsd_vers(4, NFSD_AVAIL))
- for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
- minor++) {
- len = snprintf(buf, remaining, " %c4.%u",
- (nfsd_vers(4, NFSD_TEST) &&
- nfsd_minorversion(minor, NFSD_TEST)) ?
- '+' : '-',
- minor);
-
- if (len > remaining)
- break;
- remaining -= len;
- buf += len;
- tlen += len;
- }
-
- len = snprintf(buf, remaining, "\n");
- if (len > remaining)
- return -EINVAL;
- return tlen + len;
-}
-
-/**
- * write_versions - Set or report the available NFS protocol versions
- *
- * Input:
- * buf: ignored
- * size: zero
- * Output:
- * On success: passed-in buffer filled with '\n'-terminated C
- * string containing positive or negative integer
- * values representing the current status of each
- * protocol version;
- * return code is the size in bytes of the string
- * On error: return code is zero or a negative errno value
- *
- * OR
- *
- * Input:
- * buf: C string containing whitespace-
- * separated positive or negative
- * integer values representing NFS
- * protocol versions to enable ("+n")
- * or disable ("-n")
- * size: non-zero length of C string in @buf
- * Output:
- * On success: status of zero or more protocol versions has
- * been updated; passed-in buffer filled with
- * '\n'-terminated C string containing positive
- * or negative integer values representing the
- * current status of each protocol version;
- * return code is the size in bytes of the string
- * On error: return code is zero or a negative errno value
- */
-static ssize_t write_versions(struct file *file, char *buf, size_t size)
-{
- ssize_t rv;
-
- mutex_lock(&nfsd_mutex);
- rv = __write_versions(file, buf, size);
- mutex_unlock(&nfsd_mutex);
- return rv;
-}
-
-/*
- * Zero-length write. Return a list of NFSD's current listener
- * transports.
- */
-static ssize_t __write_ports_names(char *buf)
-{
- if (nfsd_serv == NULL)
- return 0;
- return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
-}
-
-/*
- * A single 'fd' number was written, in which case it must be for
- * a socket of a supported family/protocol, and we use it as an
- * nfsd listener.
- */
-static ssize_t __write_ports_addfd(char *buf)
-{
- char *mesg = buf;
- int fd, err;
- struct net *net = &init_net;
-
- err = get_int(&mesg, &fd);
- if (err != 0 || fd < 0)
- return -EINVAL;
-
- err = nfsd_create_serv();
- if (err != 0)
- return err;
-
- err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
- if (err < 0) {
- if (nfsd_serv->sv_nrthreads == 1)
- svc_shutdown_net(nfsd_serv, net);
- svc_destroy(nfsd_serv);
- return err;
- }
-
- /* Decrease the count, but don't shut down the service */
- nfsd_serv->sv_nrthreads--;
- return err;
-}
-
-/*
- * A '-' followed by the 'name' of a socket means we close the socket.
- */
-static ssize_t __write_ports_delfd(char *buf)
-{
- char *toclose;
- int len = 0;
-
- toclose = kstrdup(buf + 1, GFP_KERNEL);
- if (toclose == NULL)
- return -ENOMEM;
-
- if (nfsd_serv != NULL)
- len = svc_sock_names(nfsd_serv, buf,
- SIMPLE_TRANSACTION_LIMIT, toclose);
- kfree(toclose);
- return len;
-}
-
-/*
- * A transport listener is added by writing it's transport name and
- * a port number.
- */
-static ssize_t __write_ports_addxprt(char *buf)
-{
- char transport[16];
- struct svc_xprt *xprt;
- int port, err;
- struct net *net = &init_net;
-
- if (sscanf(buf, "%15s %4u", transport, &port) != 2)
- return -EINVAL;
-
- if (port < 1 || port > USHRT_MAX)
- return -EINVAL;
-
- err = nfsd_create_serv();
- if (err != 0)
- return err;
-
- err = svc_create_xprt(nfsd_serv, transport, net,
- PF_INET, port, SVC_SOCK_ANONYMOUS);
- if (err < 0)
- goto out_err;
-
- err = svc_create_xprt(nfsd_serv, transport, net,
- PF_INET6, port, SVC_SOCK_ANONYMOUS);
- if (err < 0 && err != -EAFNOSUPPORT)
- goto out_close;
-
- /* Decrease the count, but don't shut down the service */
- nfsd_serv->sv_nrthreads--;
- return 0;
-out_close:
- xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port);
- if (xprt != NULL) {
- svc_close_xprt(xprt);
- svc_xprt_put(xprt);
- }
-out_err:
- if (nfsd_serv->sv_nrthreads == 1)
- svc_shutdown_net(nfsd_serv, net);
- svc_destroy(nfsd_serv);
- return err;
-}
-
-/*
- * A transport listener is removed by writing a "-", it's transport
- * name, and it's port number.
- */
-static ssize_t __write_ports_delxprt(char *buf)
-{
- struct svc_xprt *xprt;
- char transport[16];
- int port;
-
- if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
- return -EINVAL;
-
- if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
- return -EINVAL;
-
- xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port);
- if (xprt == NULL)
- return -ENOTCONN;
-
- svc_close_xprt(xprt);
- svc_xprt_put(xprt);
- return 0;
-}
-
-static ssize_t __write_ports(struct file *file, char *buf, size_t size)
-{
- if (size == 0)
- return __write_ports_names(buf);
-
- if (isdigit(buf[0]))
- return __write_ports_addfd(buf);
-
- if (buf[0] == '-' && isdigit(buf[1]))
- return __write_ports_delfd(buf);
-
- if (isalpha(buf[0]))
- return __write_ports_addxprt(buf);
-
- if (buf[0] == '-' && isalpha(buf[1]))
- return __write_ports_delxprt(buf);
-
- return -EINVAL;
-}
-
-/**
- * write_ports - Pass a socket file descriptor or transport name to listen on
- *
- * Input:
- * buf: ignored
- * size: zero
- * Output:
- * On success: passed-in buffer filled with a '\n'-terminated C
- * string containing a whitespace-separated list of
- * named NFSD listeners;
- * return code is the size in bytes of the string
- * On error: return code is zero or a negative errno value
- *
- * OR
- *
- * Input:
- * buf: C string containing an unsigned
- * integer value representing a bound
- * but unconnected socket that is to be
- * used as an NFSD listener; listen(3)
- * must be called for a SOCK_STREAM
- * socket, otherwise it is ignored
- * size: non-zero length of C string in @buf
- * Output:
- * On success: NFS service is started;
- * passed-in buffer filled with a '\n'-terminated C
- * string containing a unique alphanumeric name of
- * the listener;
- * return code is the size in bytes of the string
- * On error: return code is a negative errno value
- *
- * OR
- *
- * Input:
- * buf: C string containing a "-" followed
- * by an integer value representing a
- * previously passed in socket file
- * descriptor
- * size: non-zero length of C string in @buf
- * Output:
- * On success: NFS service no longer listens on that socket;
- * passed-in buffer filled with a '\n'-terminated C
- * string containing a unique name of the listener;
- * return code is the size in bytes of the string
- * On error: return code is a negative errno value
- *
- * OR
- *
- * Input:
- * buf: C string containing a transport
- * name and an unsigned integer value
- * representing the port to listen on,
- * separated by whitespace
- * size: non-zero length of C string in @buf
- * Output:
- * On success: returns zero; NFS service is started
- * On error: return code is a negative errno value
- *
- * OR
- *
- * Input:
- * buf: C string containing a "-" followed
- * by a transport name and an unsigned
- * integer value representing the port
- * to listen on, separated by whitespace
- * size: non-zero length of C string in @buf
- * Output:
- * On success: returns zero; NFS service no longer listens
- * on that transport
- * On error: return code is a negative errno value
- */
-static ssize_t write_ports(struct file *file, char *buf, size_t size)
-{
- ssize_t rv;
-
- mutex_lock(&nfsd_mutex);
- rv = __write_ports(file, buf, size);
- mutex_unlock(&nfsd_mutex);
- return rv;
-}
-
-
-int nfsd_max_blksize;
-
-/**
- * write_maxblksize - Set or report the current NFS blksize
- *
- * Input:
- * buf: ignored
- * size: zero
- *
- * OR
- *
- * Input:
- * buf: C string containing an unsigned
- * integer value representing the new
- * NFS blksize
- * size: non-zero length of C string in @buf
- * Output:
- * On success: passed-in buffer filled with '\n'-terminated C string
- * containing numeric value of the current NFS blksize
- * setting;
- * return code is the size in bytes of the string
- * On error: return code is zero or a negative errno value
- */
-static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
-{
- char *mesg = buf;
- if (size > 0) {
- int bsize;
- int rv = get_int(&mesg, &bsize);
- if (rv)
- return rv;
- /* force bsize into allowed range and
- * required alignment.
- */
- if (bsize < 1024)
- bsize = 1024;
- if (bsize > NFSSVC_MAXBLKSIZE)
- bsize = NFSSVC_MAXBLKSIZE;
- bsize &= ~(1024-1);
- mutex_lock(&nfsd_mutex);
- if (nfsd_serv) {
- mutex_unlock(&nfsd_mutex);
- return -EBUSY;
- }
- nfsd_max_blksize = bsize;
- mutex_unlock(&nfsd_mutex);
- }
-
- return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
- nfsd_max_blksize);
-}
-
-#ifdef CONFIG_NFSD_V4
-static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
-{
- char *mesg = buf;
- int rv, i;
-
- if (size > 0) {
- if (nfsd_serv)
- return -EBUSY;
- rv = get_int(&mesg, &i);
- if (rv)
- return rv;
- /*
- * Some sanity checking. We don't have a reason for
- * these particular numbers, but problems with the
- * extremes are:
- * - Too short: the briefest network outage may
- * cause clients to lose all their locks. Also,
- * the frequent polling may be wasteful.
- * - Too long: do you really want reboot recovery
- * to take more than an hour? Or to make other
- * clients wait an hour before being able to
- * revoke a dead client's locks?
- */
- if (i < 10 || i > 3600)
- return -EINVAL;
- *time = i;
- }
-
- return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
-}
-
-static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
-{
- ssize_t rv;
-
- mutex_lock(&nfsd_mutex);
- rv = __nfsd4_write_time(file, buf, size, time);
- mutex_unlock(&nfsd_mutex);
- return rv;
-}
-
-/**
- * write_leasetime - Set or report the current NFSv4 lease time
- *
- * Input:
- * buf: ignored
- * size: zero
- *
- * OR
- *
- * Input:
- * buf: C string containing an unsigned
- * integer value representing the new
- * NFSv4 lease expiry time
- * size: non-zero length of C string in @buf
- * Output:
- * On success: passed-in buffer filled with '\n'-terminated C
- * string containing unsigned integer value of the
- * current lease expiry time;
- * return code is the size in bytes of the string
- * On error: return code is zero or a negative errno value
- */
-static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
-{
- return nfsd4_write_time(file, buf, size, &nfsd4_lease);
-}
-
-/**
- * write_gracetime - Set or report current NFSv4 grace period time
- *
- * As above, but sets the time of the NFSv4 grace period.
- *
- * Note this should never be set to less than the *previous*
- * lease-period time, but we don't try to enforce this. (In the common
- * case (a new boot), we don't know what the previous lease time was
- * anyway.)
- */
-static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
-{
- return nfsd4_write_time(file, buf, size, &nfsd4_grace);
-}
-
-extern char *nfs4_recoverydir(void);
-
-static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
-{
- char *mesg = buf;
- char *recdir;
- int len, status;
-
- if (size > 0) {
- if (nfsd_serv)
- return -EBUSY;
- if (size > PATH_MAX || buf[size-1] != '\n')
- return -EINVAL;
- buf[size-1] = 0;
-
- recdir = mesg;
- len = qword_get(&mesg, recdir, size);
- if (len <= 0)
- return -EINVAL;
-
- status = nfs4_reset_recoverydir(recdir);
- if (status)
- return status;
- }
-
- return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
- nfs4_recoverydir());
-}
-
-/**
- * write_recoverydir - Set or report the pathname of the recovery directory
- *
- * Input:
- * buf: ignored
- * size: zero
- *
- * OR
- *
- * Input:
- * buf: C string containing the pathname
- * of the directory on a local file
- * system containing permanent NFSv4
- * recovery data
- * size: non-zero length of C string in @buf
- * Output:
- * On success: passed-in buffer filled with '\n'-terminated C string
- * containing the current recovery pathname setting;
- * return code is the size in bytes of the string
- * On error: return code is zero or a negative errno value
- */
-static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
-{
- ssize_t rv;
-
- mutex_lock(&nfsd_mutex);
- rv = __write_recoverydir(file, buf, size);
- mutex_unlock(&nfsd_mutex);
- return rv;
-}
-
-#endif
-
-/*----------------------------------------------------------------------------*/
-/*
- * populating the filesystem.
- */
-
-static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
-{
- static struct tree_descr nfsd_files[] = {
- [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
- [NFSD_Export_features] = {"export_features",
- &export_features_operations, S_IRUGO},
- [NFSD_FO_UnlockIP] = {"unlock_ip",
- &transaction_ops, S_IWUSR|S_IRUSR},
- [NFSD_FO_UnlockFS] = {"unlock_filesystem",
- &transaction_ops, S_IWUSR|S_IRUSR},
- [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
- [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
- [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
- [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
- [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
- [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
- [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
-#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
- [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
-#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
-#ifdef CONFIG_NFSD_V4
- [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
- [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
- [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
-#endif
- /* last one */ {""}
- };
- return simple_fill_super(sb, 0x6e667364, nfsd_files);
-}
-
-static struct dentry *nfsd_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
-{
- return mount_single(fs_type, flags, data, nfsd_fill_super);
-}
-
-static struct file_system_type nfsd_fs_type = {
- .owner = THIS_MODULE,
- .name = "nfsd",
- .mount = nfsd_mount,
- .kill_sb = kill_litter_super,
-};
-
-#ifdef CONFIG_PROC_FS
-static int create_proc_exports_entry(void)
-{
- struct proc_dir_entry *entry;
-
- entry = proc_mkdir("fs/nfs", NULL);
- if (!entry)
- return -ENOMEM;
- entry = proc_create("exports", 0, entry, &exports_operations);
- if (!entry)
- return -ENOMEM;
- return 0;
-}
-#else /* CONFIG_PROC_FS */
-static int create_proc_exports_entry(void)
-{
- return 0;
-}
-#endif
-
-int nfsd_net_id;
-static struct pernet_operations nfsd_net_ops = {
- .id = &nfsd_net_id,
- .size = sizeof(struct nfsd_net),
-};
-
-static int __init init_nfsd(void)
-{
- int retval;
- printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
-
- retval = register_cld_notifier();
- if (retval)
- return retval;
- retval = register_pernet_subsys(&nfsd_net_ops);
- if (retval < 0)
- goto out_unregister_notifier;
- retval = nfsd4_init_slabs();
- if (retval)
- goto out_unregister_pernet;
- nfs4_state_init();
- retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
- if (retval)
- goto out_free_slabs;
- nfsd_stat_init(); /* Statistics */
- retval = nfsd_reply_cache_init();
- if (retval)
- goto out_free_stat;
- retval = nfsd_export_init();
- if (retval)
- goto out_free_cache;
- nfsd_lockd_init(); /* lockd->nfsd callbacks */
- retval = nfsd_idmap_init();
- if (retval)
- goto out_free_lockd;
- retval = create_proc_exports_entry();
- if (retval)
- goto out_free_idmap;
- retval = register_filesystem(&nfsd_fs_type);
- if (retval)
- goto out_free_all;
- return 0;
-out_free_all:
- remove_proc_entry("fs/nfs/exports", NULL);
- remove_proc_entry("fs/nfs", NULL);
-out_free_idmap:
- nfsd_idmap_shutdown();
-out_free_lockd:
- nfsd_lockd_shutdown();
- nfsd_export_shutdown();
-out_free_cache:
- nfsd_reply_cache_shutdown();
-out_free_stat:
- nfsd_stat_shutdown();
- nfsd_fault_inject_cleanup();
-out_free_slabs:
- nfsd4_free_slabs();
-out_unregister_pernet:
- unregister_pernet_subsys(&nfsd_net_ops);
-out_unregister_notifier:
- unregister_cld_notifier();
- return retval;
-}
-
-static void __exit exit_nfsd(void)
-{
- nfsd_export_shutdown();
- nfsd_reply_cache_shutdown();
- remove_proc_entry("fs/nfs/exports", NULL);
- remove_proc_entry("fs/nfs", NULL);
- nfsd_stat_shutdown();
- nfsd_lockd_shutdown();
- nfsd_idmap_shutdown();
- nfsd4_free_slabs();
- nfsd_fault_inject_cleanup();
- unregister_filesystem(&nfsd_fs_type);
- unregister_pernet_subsys(&nfsd_net_ops);
- unregister_cld_notifier();
-}
-
-MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
-MODULE_LICENSE("GPL");
-module_init(init_nfsd)
-module_exit(exit_nfsd)
diff --git a/ANDROID_3.4.5/fs/nfsd/nfsd.h b/ANDROID_3.4.5/fs/nfsd/nfsd.h
deleted file mode 100644
index 1671429f..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfsd.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Hodge-podge collection of knfsd-related stuff.
- * I will sort this out later.
- *
- * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef LINUX_NFSD_NFSD_H
-#define LINUX_NFSD_NFSD_H
-
-#include <linux/types.h>
-#include <linux/mount.h>
-
-#include <linux/nfs.h>
-#include <linux/nfs2.h>
-#include <linux/nfs3.h>
-#include <linux/nfs4.h>
-#include <linux/sunrpc/msg_prot.h>
-
-#include <linux/nfsd/debug.h>
-#include <linux/nfsd/export.h>
-#include <linux/nfsd/stats.h>
-
-/*
- * nfsd version
- */
-#define NFSD_SUPPORTED_MINOR_VERSION 1
-/*
- * Maximum blocksizes supported by daemon under various circumstances.
- */
-#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD
-/* NFSv2 is limited by the protocol specification, see RFC 1094 */
-#define NFSSVC_MAXBLKSIZE_V2 (8*1024)
-
-
-/*
- * Largest number of bytes we need to allocate for an NFS
- * call or reply. Used to control buffer sizes. We use
- * the length of v3 WRITE, READDIR and READDIR replies
- * which are an RPC header, up to 26 XDR units of reply
- * data, and some page data.
- *
- * Note that accuracy here doesn't matter too much as the
- * size is rounded up to a page size when allocating space.
- */
-#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE)
-
-struct readdir_cd {
- __be32 err; /* 0, nfserr, or nfserr_eof */
-};
-
-
-extern struct svc_program nfsd_program;
-extern struct svc_version nfsd_version2, nfsd_version3,
- nfsd_version4;
-extern u32 nfsd_supported_minorversion;
-extern struct mutex nfsd_mutex;
-extern struct svc_serv *nfsd_serv;
-extern spinlock_t nfsd_drc_lock;
-extern unsigned int nfsd_drc_max_mem;
-extern unsigned int nfsd_drc_mem_used;
-
-extern const struct seq_operations nfs_exports_op;
-
-/*
- * Function prototypes.
- */
-int nfsd_svc(unsigned short port, int nrservs);
-int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
-
-int nfsd_nrthreads(void);
-int nfsd_nrpools(void);
-int nfsd_get_nrthreads(int n, int *);
-int nfsd_set_nrthreads(int n, int *);
-
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-#ifdef CONFIG_NFSD_V2_ACL
-extern struct svc_version nfsd_acl_version2;
-#else
-#define nfsd_acl_version2 NULL
-#endif
-#ifdef CONFIG_NFSD_V3_ACL
-extern struct svc_version nfsd_acl_version3;
-#else
-#define nfsd_acl_version3 NULL
-#endif
-#endif
-
-enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
-int nfsd_vers(int vers, enum vers_op change);
-int nfsd_minorversion(u32 minorversion, enum vers_op change);
-void nfsd_reset_versions(void);
-int nfsd_create_serv(void);
-
-extern int nfsd_max_blksize;
-
-static inline int nfsd_v4client(struct svc_rqst *rq)
-{
- return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
-}
-
-/*
- * NFSv4 State
- */
-#ifdef CONFIG_NFSD_V4
-extern unsigned int max_delegations;
-void nfs4_state_init(void);
-int nfsd4_init_slabs(void);
-void nfsd4_free_slabs(void);
-int nfs4_state_start(void);
-void nfs4_state_shutdown(void);
-void nfs4_reset_lease(time_t leasetime);
-int nfs4_reset_recoverydir(char *recdir);
-#else
-static inline void nfs4_state_init(void) { }
-static inline int nfsd4_init_slabs(void) { return 0; }
-static inline void nfsd4_free_slabs(void) { }
-static inline int nfs4_state_start(void) { return 0; }
-static inline void nfs4_state_shutdown(void) { }
-static inline void nfs4_reset_lease(time_t leasetime) { }
-static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
-#endif
-
-/*
- * lockd binding
- */
-void nfsd_lockd_init(void);
-void nfsd_lockd_shutdown(void);
-
-
-/*
- * These macros provide pre-xdr'ed values for faster operation.
- */
-#define nfs_ok cpu_to_be32(NFS_OK)
-#define nfserr_perm cpu_to_be32(NFSERR_PERM)
-#define nfserr_noent cpu_to_be32(NFSERR_NOENT)
-#define nfserr_io cpu_to_be32(NFSERR_IO)
-#define nfserr_nxio cpu_to_be32(NFSERR_NXIO)
-#define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN)
-#define nfserr_acces cpu_to_be32(NFSERR_ACCES)
-#define nfserr_exist cpu_to_be32(NFSERR_EXIST)
-#define nfserr_xdev cpu_to_be32(NFSERR_XDEV)
-#define nfserr_nodev cpu_to_be32(NFSERR_NODEV)
-#define nfserr_notdir cpu_to_be32(NFSERR_NOTDIR)
-#define nfserr_isdir cpu_to_be32(NFSERR_ISDIR)
-#define nfserr_inval cpu_to_be32(NFSERR_INVAL)
-#define nfserr_fbig cpu_to_be32(NFSERR_FBIG)
-#define nfserr_nospc cpu_to_be32(NFSERR_NOSPC)
-#define nfserr_rofs cpu_to_be32(NFSERR_ROFS)
-#define nfserr_mlink cpu_to_be32(NFSERR_MLINK)
-#define nfserr_opnotsupp cpu_to_be32(NFSERR_OPNOTSUPP)
-#define nfserr_nametoolong cpu_to_be32(NFSERR_NAMETOOLONG)
-#define nfserr_notempty cpu_to_be32(NFSERR_NOTEMPTY)
-#define nfserr_dquot cpu_to_be32(NFSERR_DQUOT)
-#define nfserr_stale cpu_to_be32(NFSERR_STALE)
-#define nfserr_remote cpu_to_be32(NFSERR_REMOTE)
-#define nfserr_wflush cpu_to_be32(NFSERR_WFLUSH)
-#define nfserr_badhandle cpu_to_be32(NFSERR_BADHANDLE)
-#define nfserr_notsync cpu_to_be32(NFSERR_NOT_SYNC)
-#define nfserr_badcookie cpu_to_be32(NFSERR_BAD_COOKIE)
-#define nfserr_notsupp cpu_to_be32(NFSERR_NOTSUPP)
-#define nfserr_toosmall cpu_to_be32(NFSERR_TOOSMALL)
-#define nfserr_serverfault cpu_to_be32(NFSERR_SERVERFAULT)
-#define nfserr_badtype cpu_to_be32(NFSERR_BADTYPE)
-#define nfserr_jukebox cpu_to_be32(NFSERR_JUKEBOX)
-#define nfserr_denied cpu_to_be32(NFSERR_DENIED)
-#define nfserr_deadlock cpu_to_be32(NFSERR_DEADLOCK)
-#define nfserr_expired cpu_to_be32(NFSERR_EXPIRED)
-#define nfserr_bad_cookie cpu_to_be32(NFSERR_BAD_COOKIE)
-#define nfserr_same cpu_to_be32(NFSERR_SAME)
-#define nfserr_clid_inuse cpu_to_be32(NFSERR_CLID_INUSE)
-#define nfserr_stale_clientid cpu_to_be32(NFSERR_STALE_CLIENTID)
-#define nfserr_resource cpu_to_be32(NFSERR_RESOURCE)
-#define nfserr_moved cpu_to_be32(NFSERR_MOVED)
-#define nfserr_nofilehandle cpu_to_be32(NFSERR_NOFILEHANDLE)
-#define nfserr_minor_vers_mismatch cpu_to_be32(NFSERR_MINOR_VERS_MISMATCH)
-#define nfserr_share_denied cpu_to_be32(NFSERR_SHARE_DENIED)
-#define nfserr_stale_stateid cpu_to_be32(NFSERR_STALE_STATEID)
-#define nfserr_old_stateid cpu_to_be32(NFSERR_OLD_STATEID)
-#define nfserr_bad_stateid cpu_to_be32(NFSERR_BAD_STATEID)
-#define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID)
-#define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK)
-#define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME)
-#define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE)
-#define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH)
-#define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP)
-#define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR)
-#define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE)
-#define nfserr_badowner cpu_to_be32(NFSERR_BADOWNER)
-#define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD)
-#define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL)
-#define nfserr_grace cpu_to_be32(NFSERR_GRACE)
-#define nfserr_no_grace cpu_to_be32(NFSERR_NO_GRACE)
-#define nfserr_reclaim_bad cpu_to_be32(NFSERR_RECLAIM_BAD)
-#define nfserr_badname cpu_to_be32(NFSERR_BADNAME)
-#define nfserr_cb_path_down cpu_to_be32(NFSERR_CB_PATH_DOWN)
-#define nfserr_locked cpu_to_be32(NFSERR_LOCKED)
-#define nfserr_wrongsec cpu_to_be32(NFSERR_WRONGSEC)
-#define nfserr_badiomode cpu_to_be32(NFS4ERR_BADIOMODE)
-#define nfserr_badlayout cpu_to_be32(NFS4ERR_BADLAYOUT)
-#define nfserr_bad_session_digest cpu_to_be32(NFS4ERR_BAD_SESSION_DIGEST)
-#define nfserr_badsession cpu_to_be32(NFS4ERR_BADSESSION)
-#define nfserr_badslot cpu_to_be32(NFS4ERR_BADSLOT)
-#define nfserr_complete_already cpu_to_be32(NFS4ERR_COMPLETE_ALREADY)
-#define nfserr_conn_not_bound_to_session cpu_to_be32(NFS4ERR_CONN_NOT_BOUND_TO_SESSION)
-#define nfserr_deleg_already_wanted cpu_to_be32(NFS4ERR_DELEG_ALREADY_WANTED)
-#define nfserr_back_chan_busy cpu_to_be32(NFS4ERR_BACK_CHAN_BUSY)
-#define nfserr_layouttrylater cpu_to_be32(NFS4ERR_LAYOUTTRYLATER)
-#define nfserr_layoutunavailable cpu_to_be32(NFS4ERR_LAYOUTUNAVAILABLE)
-#define nfserr_nomatching_layout cpu_to_be32(NFS4ERR_NOMATCHING_LAYOUT)
-#define nfserr_recallconflict cpu_to_be32(NFS4ERR_RECALLCONFLICT)
-#define nfserr_unknown_layouttype cpu_to_be32(NFS4ERR_UNKNOWN_LAYOUTTYPE)
-#define nfserr_seq_misordered cpu_to_be32(NFS4ERR_SEQ_MISORDERED)
-#define nfserr_sequence_pos cpu_to_be32(NFS4ERR_SEQUENCE_POS)
-#define nfserr_req_too_big cpu_to_be32(NFS4ERR_REQ_TOO_BIG)
-#define nfserr_rep_too_big cpu_to_be32(NFS4ERR_REP_TOO_BIG)
-#define nfserr_rep_too_big_to_cache cpu_to_be32(NFS4ERR_REP_TOO_BIG_TO_CACHE)
-#define nfserr_retry_uncached_rep cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP)
-#define nfserr_unsafe_compound cpu_to_be32(NFS4ERR_UNSAFE_COMPOUND)
-#define nfserr_too_many_ops cpu_to_be32(NFS4ERR_TOO_MANY_OPS)
-#define nfserr_op_not_in_session cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION)
-#define nfserr_hash_alg_unsupp cpu_to_be32(NFS4ERR_HASH_ALG_UNSUPP)
-#define nfserr_clientid_busy cpu_to_be32(NFS4ERR_CLIENTID_BUSY)
-#define nfserr_pnfs_io_hole cpu_to_be32(NFS4ERR_PNFS_IO_HOLE)
-#define nfserr_seq_false_retry cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY)
-#define nfserr_bad_high_slot cpu_to_be32(NFS4ERR_BAD_HIGH_SLOT)
-#define nfserr_deadsession cpu_to_be32(NFS4ERR_DEADSESSION)
-#define nfserr_encr_alg_unsupp cpu_to_be32(NFS4ERR_ENCR_ALG_UNSUPP)
-#define nfserr_pnfs_no_layout cpu_to_be32(NFS4ERR_PNFS_NO_LAYOUT)
-#define nfserr_not_only_op cpu_to_be32(NFS4ERR_NOT_ONLY_OP)
-#define nfserr_wrong_cred cpu_to_be32(NFS4ERR_WRONG_CRED)
-#define nfserr_wrong_type cpu_to_be32(NFS4ERR_WRONG_TYPE)
-#define nfserr_dirdeleg_unavail cpu_to_be32(NFS4ERR_DIRDELEG_UNAVAIL)
-#define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG)
-#define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT)
-#define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED)
-
-/* error codes for internal use */
-/* if a request fails due to kmalloc failure, it gets dropped.
- * Client should resend eventually
- */
-#define nfserr_dropit cpu_to_be32(30000)
-/* end-of-file indicator in readdir */
-#define nfserr_eof cpu_to_be32(30001)
-/* replay detected */
-#define nfserr_replay_me cpu_to_be32(11001)
-/* nfs41 replay detected */
-#define nfserr_replay_cache cpu_to_be32(11002)
-
-/* Check for dir entries '.' and '..' */
-#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
-
-/*
- * Time of server startup
- */
-extern struct timeval nfssvc_boot;
-
-#ifdef CONFIG_NFSD_V4
-
-extern time_t nfsd4_lease;
-extern time_t nfsd4_grace;
-
-/* before processing a COMPOUND operation, we have to check that there
- * is enough space in the buffer for XDR encode to succeed. otherwise,
- * we might process an operation with side effects, and be unable to
- * tell the client that the operation succeeded.
- *
- * COMPOUND_SLACK_SPACE - this is the minimum bytes of buffer space
- * needed to encode an "ordinary" _successful_ operation. (GETATTR,
- * READ, READDIR, and READLINK have their own buffer checks.) if we
- * fall below this level, we fail the next operation with NFS4ERR_RESOURCE.
- *
- * COMPOUND_ERR_SLACK_SPACE - this is the minimum bytes of buffer space
- * needed to encode an operation which has failed with NFS4ERR_RESOURCE.
- * care is taken to ensure that we never fall below this level for any
- * reason.
- */
-#define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */
-#define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */
-
-#define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */
-
-/*
- * The following attributes are currently not supported by the NFSv4 server:
- * ARCHIVE (deprecated anyway)
- * HIDDEN (unlikely to be supported any time soon)
- * MIMETYPE (unlikely to be supported any time soon)
- * QUOTA_* (will be supported in a forthcoming patch)
- * SYSTEM (unlikely to be supported any time soon)
- * TIME_BACKUP (unlikely to be supported any time soon)
- * TIME_CREATE (unlikely to be supported any time soon)
- */
-#define NFSD4_SUPPORTED_ATTRS_WORD0 \
-(FATTR4_WORD0_SUPPORTED_ATTRS | FATTR4_WORD0_TYPE | FATTR4_WORD0_FH_EXPIRE_TYPE \
- | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_LINK_SUPPORT \
- | FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR | FATTR4_WORD0_FSID \
- | FATTR4_WORD0_UNIQUE_HANDLES | FATTR4_WORD0_LEASE_TIME | FATTR4_WORD0_RDATTR_ERROR \
- | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \
- | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \
- | FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \
- | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \
- | FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \
- | FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL)
-
-#define NFSD4_SUPPORTED_ATTRS_WORD1 \
-(FATTR4_WORD1_MODE | FATTR4_WORD1_NO_TRUNC | FATTR4_WORD1_NUMLINKS \
- | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \
- | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \
- | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \
- | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \
- | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
-
-#define NFSD4_SUPPORTED_ATTRS_WORD2 0
-
-#define NFSD4_1_SUPPORTED_ATTRS_WORD0 \
- NFSD4_SUPPORTED_ATTRS_WORD0
-
-#define NFSD4_1_SUPPORTED_ATTRS_WORD1 \
- NFSD4_SUPPORTED_ATTRS_WORD1
-
-#define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
- (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
-
-static inline u32 nfsd_suppattrs0(u32 minorversion)
-{
- return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
- : NFSD4_SUPPORTED_ATTRS_WORD0;
-}
-
-static inline u32 nfsd_suppattrs1(u32 minorversion)
-{
- return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD1
- : NFSD4_SUPPORTED_ATTRS_WORD1;
-}
-
-static inline u32 nfsd_suppattrs2(u32 minorversion)
-{
- return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
- : NFSD4_SUPPORTED_ATTRS_WORD2;
-}
-
-/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
-#define NFSD_WRITEONLY_ATTRS_WORD1 \
- (FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
-
-/* These are the only attrs allowed in CREATE/OPEN/SETATTR. */
-#define NFSD_WRITEABLE_ATTRS_WORD0 \
- (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
-#define NFSD_WRITEABLE_ATTRS_WORD1 \
- (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
- | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
-#define NFSD_WRITEABLE_ATTRS_WORD2 0
-
-#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
- NFSD_WRITEABLE_ATTRS_WORD0
-/*
- * we currently store the exclusive create verifier in the v_{a,m}time
- * attributes so the client can't set these at create time using EXCLUSIVE4_1
- */
-#define NFSD_SUPPATTR_EXCLCREAT_WORD1 \
- (NFSD_WRITEABLE_ATTRS_WORD1 & \
- ~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET))
-#define NFSD_SUPPATTR_EXCLCREAT_WORD2 \
- NFSD_WRITEABLE_ATTRS_WORD2
-
-extern int nfsd4_is_junction(struct dentry *dentry);
-extern int register_cld_notifier(void);
-extern void unregister_cld_notifier(void);
-#else /* CONFIG_NFSD_V4 */
-static inline int nfsd4_is_junction(struct dentry *dentry)
-{
- return 0;
-}
-
-#define register_cld_notifier() 0
-#define unregister_cld_notifier() do { } while(0)
-
-#endif /* CONFIG_NFSD_V4 */
-
-#endif /* LINUX_NFSD_NFSD_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/nfsfh.c b/ANDROID_3.4.5/fs/nfsd/nfsfh.c
deleted file mode 100644
index 68454e75..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfsfh.c
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- * NFS server file handle treatment.
- *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
- * Portions Copyright (C) 1999 G. Allen Morris III <gam3@acm.org>
- * Extensive rewrite by Neil Brown <neilb@cse.unsw.edu.au> Southern-Spring 1999
- * ... and again Southern-Winter 2001 to support export_operations
- */
-
-#include <linux/exportfs.h>
-
-#include <linux/sunrpc/svcauth_gss.h>
-#include "nfsd.h"
-#include "vfs.h"
-#include "auth.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_FH
-
-
-/*
- * our acceptability function.
- * if NOSUBTREECHECK, accept anything
- * if not, require that we can walk up to exp->ex_dentry
- * doing some checks on the 'x' bits
- */
-static int nfsd_acceptable(void *expv, struct dentry *dentry)
-{
- struct svc_export *exp = expv;
- int rv;
- struct dentry *tdentry;
- struct dentry *parent;
-
- if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
- return 1;
-
- tdentry = dget(dentry);
- while (tdentry != exp->ex_path.dentry && !IS_ROOT(tdentry)) {
- /* make sure parents give x permission to user */
- int err;
- parent = dget_parent(tdentry);
- err = inode_permission(parent->d_inode, MAY_EXEC);
- if (err < 0) {
- dput(parent);
- break;
- }
- dput(tdentry);
- tdentry = parent;
- }
- if (tdentry != exp->ex_path.dentry)
- dprintk("nfsd_acceptable failed at %p %s\n", tdentry, tdentry->d_name.name);
- rv = (tdentry == exp->ex_path.dentry);
- dput(tdentry);
- return rv;
-}
-
-/* Type check. The correct error return for type mismatches does not seem to be
- * generally agreed upon. SunOS seems to use EISDIR if file isn't S_IFREG; a
- * comment in the NFSv3 spec says this is incorrect (implementation notes for
- * the write call).
- */
-static inline __be32
-nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, umode_t requested)
-{
- mode &= S_IFMT;
-
- if (requested == 0) /* the caller doesn't care */
- return nfs_ok;
- if (mode == requested)
- return nfs_ok;
- /*
- * v4 has an error more specific than err_notdir which we should
- * return in preference to err_notdir:
- */
- if (rqstp->rq_vers == 4 && mode == S_IFLNK)
- return nfserr_symlink;
- if (requested == S_IFDIR)
- return nfserr_notdir;
- if (mode == S_IFDIR)
- return nfserr_isdir;
- return nfserr_inval;
-}
-
-static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
- struct svc_export *exp)
-{
- int flags = nfsexp_flags(rqstp, exp);
-
- /* Check if the request originated from a secure port. */
- if (!rqstp->rq_secure && !(flags & NFSEXP_INSECURE_PORT)) {
- RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
- dprintk(KERN_WARNING
- "nfsd: request from insecure port %s!\n",
- svc_print_addr(rqstp, buf, sizeof(buf)));
- return nfserr_perm;
- }
-
- /* Set user creds for this exportpoint */
- return nfserrno(nfsd_setuser(rqstp, exp));
-}
-
-static inline __be32 check_pseudo_root(struct svc_rqst *rqstp,
- struct dentry *dentry, struct svc_export *exp)
-{
- if (!(exp->ex_flags & NFSEXP_V4ROOT))
- return nfs_ok;
- /*
- * v2/v3 clients have no need for the V4ROOT export--they use
- * the mount protocl instead; also, further V4ROOT checks may be
- * in v4-specific code, in which case v2/v3 clients could bypass
- * them.
- */
- if (!nfsd_v4client(rqstp))
- return nfserr_stale;
- /*
- * We're exposing only the directories and symlinks that have to be
- * traversed on the way to real exports:
- */
- if (unlikely(!S_ISDIR(dentry->d_inode->i_mode) &&
- !S_ISLNK(dentry->d_inode->i_mode)))
- return nfserr_stale;
- /*
- * A pseudoroot export gives permission to access only one
- * single directory; the kernel has to make another upcall
- * before granting access to anything else under it:
- */
- if (unlikely(dentry != exp->ex_path.dentry))
- return nfserr_stale;
- return nfs_ok;
-}
-
-/*
- * Use the given filehandle to look up the corresponding export and
- * dentry. On success, the results are used to set fh_export and
- * fh_dentry.
- */
-static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
-{
- struct knfsd_fh *fh = &fhp->fh_handle;
- struct fid *fid = NULL, sfid;
- struct svc_export *exp;
- struct dentry *dentry;
- int fileid_type;
- int data_left = fh->fh_size/4;
- __be32 error;
-
- error = nfserr_stale;
- if (rqstp->rq_vers > 2)
- error = nfserr_badhandle;
- if (rqstp->rq_vers == 4 && fh->fh_size == 0)
- return nfserr_nofilehandle;
-
- if (fh->fh_version == 1) {
- int len;
-
- if (--data_left < 0)
- return error;
- if (fh->fh_auth_type != 0)
- return error;
- len = key_len(fh->fh_fsid_type) / 4;
- if (len == 0)
- return error;
- if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
- /* deprecated, convert to type 3 */
- len = key_len(FSID_ENCODE_DEV)/4;
- fh->fh_fsid_type = FSID_ENCODE_DEV;
- fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
- fh->fh_fsid[1] = fh->fh_fsid[2];
- }
- data_left -= len;
- if (data_left < 0)
- return error;
- exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth);
- fid = (struct fid *)(fh->fh_auth + len);
- } else {
- __u32 tfh[2];
- dev_t xdev;
- ino_t xino;
-
- if (fh->fh_size != NFS_FHSIZE)
- return error;
- /* assume old filehandle format */
- xdev = old_decode_dev(fh->ofh_xdev);
- xino = u32_to_ino_t(fh->ofh_xino);
- mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
- exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
- }
-
- error = nfserr_stale;
- if (PTR_ERR(exp) == -ENOENT)
- return error;
-
- if (IS_ERR(exp))
- return nfserrno(PTR_ERR(exp));
-
- if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
- /* Elevate privileges so that the lack of 'r' or 'x'
- * permission on some parent directory will
- * not stop exportfs_decode_fh from being able
- * to reconnect a directory into the dentry cache.
- * The same problem can affect "SUBTREECHECK" exports,
- * but as nfsd_acceptable depends on correct
- * access control settings being in effect, we cannot
- * fix that case easily.
- */
- struct cred *new = prepare_creds();
- if (!new)
- return nfserrno(-ENOMEM);
- new->cap_effective =
- cap_raise_nfsd_set(new->cap_effective,
- new->cap_permitted);
- put_cred(override_creds(new));
- put_cred(new);
- } else {
- error = nfsd_setuser_and_check_port(rqstp, exp);
- if (error)
- goto out;
- }
-
- /*
- * Look up the dentry using the NFS file handle.
- */
- error = nfserr_stale;
- if (rqstp->rq_vers > 2)
- error = nfserr_badhandle;
-
- if (fh->fh_version != 1) {
- sfid.i32.ino = fh->ofh_ino;
- sfid.i32.gen = fh->ofh_generation;
- sfid.i32.parent_ino = fh->ofh_dirino;
- fid = &sfid;
- data_left = 3;
- if (fh->ofh_dirino == 0)
- fileid_type = FILEID_INO32_GEN;
- else
- fileid_type = FILEID_INO32_GEN_PARENT;
- } else
- fileid_type = fh->fh_fileid_type;
-
- if (fileid_type == FILEID_ROOT)
- dentry = dget(exp->ex_path.dentry);
- else {
- dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
- data_left, fileid_type,
- nfsd_acceptable, exp);
- }
- if (dentry == NULL)
- goto out;
- if (IS_ERR(dentry)) {
- if (PTR_ERR(dentry) != -EINVAL)
- error = nfserrno(PTR_ERR(dentry));
- goto out;
- }
-
- if (S_ISDIR(dentry->d_inode->i_mode) &&
- (dentry->d_flags & DCACHE_DISCONNECTED)) {
- printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- }
-
- fhp->fh_dentry = dentry;
- fhp->fh_export = exp;
- return 0;
-out:
- exp_put(exp);
- return error;
-}
-
-/**
- * fh_verify - filehandle lookup and access checking
- * @rqstp: pointer to current rpc request
- * @fhp: filehandle to be verified
- * @type: expected type of object pointed to by filehandle
- * @access: type of access needed to object
- *
- * Look up a dentry from the on-the-wire filehandle, check the client's
- * access to the export, and set the current task's credentials.
- *
- * Regardless of success or failure of fh_verify(), fh_put() should be
- * called on @fhp when the caller is finished with the filehandle.
- *
- * fh_verify() may be called multiple times on a given filehandle, for
- * example, when processing an NFSv4 compound. The first call will look
- * up a dentry using the on-the-wire filehandle. Subsequent calls will
- * skip the lookup and just perform the other checks and possibly change
- * the current task's credentials.
- *
- * @type specifies the type of object expected using one of the S_IF*
- * constants defined in include/linux/stat.h. The caller may use zero
- * to indicate that it doesn't care, or a negative integer to indicate
- * that it expects something not of the given type.
- *
- * @access is formed from the NFSD_MAY_* constants defined in
- * include/linux/nfsd/nfsd.h.
- */
-__be32
-fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
-{
- struct svc_export *exp;
- struct dentry *dentry;
- __be32 error;
-
- dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
-
- if (!fhp->fh_dentry) {
- error = nfsd_set_fh_dentry(rqstp, fhp);
- if (error)
- goto out;
- }
- dentry = fhp->fh_dentry;
- exp = fhp->fh_export;
- /*
- * We still have to do all these permission checks, even when
- * fh_dentry is already set:
- * - fh_verify may be called multiple times with different
- * "access" arguments (e.g. nfsd_proc_create calls
- * fh_verify(...,NFSD_MAY_EXEC) first, then later (in
- * nfsd_create) calls fh_verify(...,NFSD_MAY_CREATE).
- * - in the NFSv4 case, the filehandle may have been filled
- * in by fh_compose, and given a dentry, but further
- * compound operations performed with that filehandle
- * still need permissions checks. In the worst case, a
- * mountpoint crossing may have changed the export
- * options, and we may now need to use a different uid
- * (for example, if different id-squashing options are in
- * effect on the new filesystem).
- */
- error = check_pseudo_root(rqstp, dentry, exp);
- if (error)
- goto out;
-
- error = nfsd_setuser_and_check_port(rqstp, exp);
- if (error)
- goto out;
-
- error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type);
- if (error)
- goto out;
-
- /*
- * pseudoflavor restrictions are not enforced on NLM,
- * which clients virtually always use auth_sys for,
- * even while using RPCSEC_GSS for NFS.
- */
- if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
- goto skip_pseudoflavor_check;
- /*
- * Clients may expect to be able to use auth_sys during mount,
- * even if they use gss for everything else; see section 2.3.2
- * of rfc 2623.
- */
- if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
- && exp->ex_path.dentry == dentry)
- goto skip_pseudoflavor_check;
-
- error = check_nfsd_access(exp, rqstp);
- if (error)
- goto out;
-
-skip_pseudoflavor_check:
- /* Finally, check access permissions. */
- error = nfsd_permission(rqstp, exp, dentry, access);
-
- if (error) {
- dprintk("fh_verify: %s/%s permission failure, "
- "acc=%x, error=%d\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name,
- access, ntohl(error));
- }
-out:
- if (error == nfserr_stale)
- nfsdstats.fh_stale++;
- return error;
-}
-
-
-/*
- * Compose a file handle for an NFS reply.
- *
- * Note that when first composed, the dentry may not yet have
- * an inode. In this case a call to fh_update should be made
- * before the fh goes out on the wire ...
- */
-static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry)
-{
- if (dentry != exp->ex_path.dentry) {
- struct fid *fid = (struct fid *)
- (fhp->fh_handle.fh_auth + fhp->fh_handle.fh_size/4 - 1);
- int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
- int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
-
- fhp->fh_handle.fh_fileid_type =
- exportfs_encode_fh(dentry, fid, &maxsize, subtreecheck);
- fhp->fh_handle.fh_size += maxsize * 4;
- } else {
- fhp->fh_handle.fh_fileid_type = FILEID_ROOT;
- }
-}
-
-/*
- * for composing old style file handles
- */
-static inline void _fh_update_old(struct dentry *dentry,
- struct svc_export *exp,
- struct knfsd_fh *fh)
-{
- fh->ofh_ino = ino_t_to_u32(dentry->d_inode->i_ino);
- fh->ofh_generation = dentry->d_inode->i_generation;
- if (S_ISDIR(dentry->d_inode->i_mode) ||
- (exp->ex_flags & NFSEXP_NOSUBTREECHECK))
- fh->ofh_dirino = 0;
-}
-
-static bool is_root_export(struct svc_export *exp)
-{
- return exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root;
-}
-
-static struct super_block *exp_sb(struct svc_export *exp)
-{
- return exp->ex_path.dentry->d_inode->i_sb;
-}
-
-static bool fsid_type_ok_for_exp(u8 fsid_type, struct svc_export *exp)
-{
- switch (fsid_type) {
- case FSID_DEV:
- if (!old_valid_dev(exp_sb(exp)->s_dev))
- return 0;
- /* FALL THROUGH */
- case FSID_MAJOR_MINOR:
- case FSID_ENCODE_DEV:
- return exp_sb(exp)->s_type->fs_flags & FS_REQUIRES_DEV;
- case FSID_NUM:
- return exp->ex_flags & NFSEXP_FSID;
- case FSID_UUID8:
- case FSID_UUID16:
- if (!is_root_export(exp))
- return 0;
- /* fall through */
- case FSID_UUID4_INUM:
- case FSID_UUID16_INUM:
- return exp->ex_uuid != NULL;
- }
- return 1;
-}
-
-
-static void set_version_and_fsid_type(struct svc_fh *fhp, struct svc_export *exp, struct svc_fh *ref_fh)
-{
- u8 version;
- u8 fsid_type;
-retry:
- version = 1;
- if (ref_fh && ref_fh->fh_export == exp) {
- version = ref_fh->fh_handle.fh_version;
- fsid_type = ref_fh->fh_handle.fh_fsid_type;
-
- ref_fh = NULL;
-
- switch (version) {
- case 0xca:
- fsid_type = FSID_DEV;
- break;
- case 1:
- break;
- default:
- goto retry;
- }
-
- /*
- * As the fsid -> filesystem mapping was guided by
- * user-space, there is no guarantee that the filesystem
- * actually supports that fsid type. If it doesn't we
- * loop around again without ref_fh set.
- */
- if (!fsid_type_ok_for_exp(fsid_type, exp))
- goto retry;
- } else if (exp->ex_flags & NFSEXP_FSID) {
- fsid_type = FSID_NUM;
- } else if (exp->ex_uuid) {
- if (fhp->fh_maxsize >= 64) {
- if (is_root_export(exp))
- fsid_type = FSID_UUID16;
- else
- fsid_type = FSID_UUID16_INUM;
- } else {
- if (is_root_export(exp))
- fsid_type = FSID_UUID8;
- else
- fsid_type = FSID_UUID4_INUM;
- }
- } else if (!old_valid_dev(exp_sb(exp)->s_dev))
- /* for newer device numbers, we must use a newer fsid format */
- fsid_type = FSID_ENCODE_DEV;
- else
- fsid_type = FSID_DEV;
- fhp->fh_handle.fh_version = version;
- if (version)
- fhp->fh_handle.fh_fsid_type = fsid_type;
-}
-
-__be32
-fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
- struct svc_fh *ref_fh)
-{
- /* ref_fh is a reference file handle.
- * if it is non-null and for the same filesystem, then we should compose
- * a filehandle which is of the same version, where possible.
- * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca
- * Then create a 32byte filehandle using nfs_fhbase_old
- *
- */
-
- struct inode * inode = dentry->d_inode;
- struct dentry *parent = dentry->d_parent;
- __u32 *datap;
- dev_t ex_dev = exp_sb(exp)->s_dev;
-
- dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
- MAJOR(ex_dev), MINOR(ex_dev),
- (long) exp->ex_path.dentry->d_inode->i_ino,
- parent->d_name.name, dentry->d_name.name,
- (inode ? inode->i_ino : 0));
-
- /* Choose filehandle version and fsid type based on
- * the reference filehandle (if it is in the same export)
- * or the export options.
- */
- set_version_and_fsid_type(fhp, exp, ref_fh);
-
- if (ref_fh == fhp)
- fh_put(ref_fh);
-
- if (fhp->fh_locked || fhp->fh_dentry) {
- printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
- parent->d_name.name, dentry->d_name.name);
- }
- if (fhp->fh_maxsize < NFS_FHSIZE)
- printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n",
- fhp->fh_maxsize,
- parent->d_name.name, dentry->d_name.name);
-
- fhp->fh_dentry = dget(dentry); /* our internal copy */
- fhp->fh_export = exp;
- cache_get(&exp->h);
-
- if (fhp->fh_handle.fh_version == 0xca) {
- /* old style filehandle please */
- memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
- fhp->fh_handle.fh_size = NFS_FHSIZE;
- fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
- fhp->fh_handle.ofh_dev = old_encode_dev(ex_dev);
- fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
- fhp->fh_handle.ofh_xino =
- ino_t_to_u32(exp->ex_path.dentry->d_inode->i_ino);
- fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry));
- if (inode)
- _fh_update_old(dentry, exp, &fhp->fh_handle);
- } else {
- int len;
- fhp->fh_handle.fh_auth_type = 0;
- datap = fhp->fh_handle.fh_auth+0;
- mk_fsid(fhp->fh_handle.fh_fsid_type, datap, ex_dev,
- exp->ex_path.dentry->d_inode->i_ino,
- exp->ex_fsid, exp->ex_uuid);
-
- len = key_len(fhp->fh_handle.fh_fsid_type);
- datap += len/4;
- fhp->fh_handle.fh_size = 4 + len;
-
- if (inode)
- _fh_update(fhp, exp, dentry);
- if (fhp->fh_handle.fh_fileid_type == 255) {
- fh_put(fhp);
- return nfserr_opnotsupp;
- }
- }
-
- return 0;
-}
-
-/*
- * Update file handle information after changing a dentry.
- * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
- */
-__be32
-fh_update(struct svc_fh *fhp)
-{
- struct dentry *dentry;
-
- if (!fhp->fh_dentry)
- goto out_bad;
-
- dentry = fhp->fh_dentry;
- if (!dentry->d_inode)
- goto out_negative;
- if (fhp->fh_handle.fh_version != 1) {
- _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
- } else {
- if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT)
- goto out;
-
- _fh_update(fhp, fhp->fh_export, dentry);
- if (fhp->fh_handle.fh_fileid_type == 255)
- return nfserr_opnotsupp;
- }
-out:
- return 0;
-
-out_bad:
- printk(KERN_ERR "fh_update: fh not verified!\n");
- goto out;
-out_negative:
- printk(KERN_ERR "fh_update: %s/%s still negative!\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- goto out;
-}
-
-/*
- * Release a file handle.
- */
-void
-fh_put(struct svc_fh *fhp)
-{
- struct dentry * dentry = fhp->fh_dentry;
- struct svc_export * exp = fhp->fh_export;
- if (dentry) {
- fh_unlock(fhp);
- fhp->fh_dentry = NULL;
- dput(dentry);
-#ifdef CONFIG_NFSD_V3
- fhp->fh_pre_saved = 0;
- fhp->fh_post_saved = 0;
-#endif
- }
- if (exp) {
- cache_put(&exp->h, &svc_export_cache);
- fhp->fh_export = NULL;
- }
- return;
-}
-
-/*
- * Shorthand for dprintk()'s
- */
-char * SVCFH_fmt(struct svc_fh *fhp)
-{
- struct knfsd_fh *fh = &fhp->fh_handle;
-
- static char buf[80];
- sprintf(buf, "%d: %08x %08x %08x %08x %08x %08x",
- fh->fh_size,
- fh->fh_base.fh_pad[0],
- fh->fh_base.fh_pad[1],
- fh->fh_base.fh_pad[2],
- fh->fh_base.fh_pad[3],
- fh->fh_base.fh_pad[4],
- fh->fh_base.fh_pad[5]);
- return buf;
-}
-
-enum fsid_source fsid_source(struct svc_fh *fhp)
-{
- if (fhp->fh_handle.fh_version != 1)
- return FSIDSOURCE_DEV;
- switch(fhp->fh_handle.fh_fsid_type) {
- case FSID_DEV:
- case FSID_ENCODE_DEV:
- case FSID_MAJOR_MINOR:
- if (exp_sb(fhp->fh_export)->s_type->fs_flags & FS_REQUIRES_DEV)
- return FSIDSOURCE_DEV;
- break;
- case FSID_NUM:
- if (fhp->fh_export->ex_flags & NFSEXP_FSID)
- return FSIDSOURCE_FSID;
- break;
- default:
- break;
- }
- /* either a UUID type filehandle, or the filehandle doesn't
- * match the export.
- */
- if (fhp->fh_export->ex_flags & NFSEXP_FSID)
- return FSIDSOURCE_FSID;
- if (fhp->fh_export->ex_uuid)
- return FSIDSOURCE_UUID;
- return FSIDSOURCE_DEV;
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/nfsfh.h b/ANDROID_3.4.5/fs/nfsd/nfsfh.h
deleted file mode 100644
index e5e6707b..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfsfh.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> */
-
-#ifndef _LINUX_NFSD_FH_INT_H
-#define _LINUX_NFSD_FH_INT_H
-
-#include <linux/nfsd/nfsfh.h>
-
-enum nfsd_fsid {
- FSID_DEV = 0,
- FSID_NUM,
- FSID_MAJOR_MINOR,
- FSID_ENCODE_DEV,
- FSID_UUID4_INUM,
- FSID_UUID8,
- FSID_UUID16,
- FSID_UUID16_INUM,
-};
-
-enum fsid_source {
- FSIDSOURCE_DEV,
- FSIDSOURCE_FSID,
- FSIDSOURCE_UUID,
-};
-extern enum fsid_source fsid_source(struct svc_fh *fhp);
-
-
-/* This might look a little large to "inline" but in all calls except
- * one, 'vers' is constant so moste of the function disappears.
- */
-static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
- u32 fsid, unsigned char *uuid)
-{
- u32 *up;
- switch(vers) {
- case FSID_DEV:
- fsidv[0] = htonl((MAJOR(dev)<<16) |
- MINOR(dev));
- fsidv[1] = ino_t_to_u32(ino);
- break;
- case FSID_NUM:
- fsidv[0] = fsid;
- break;
- case FSID_MAJOR_MINOR:
- fsidv[0] = htonl(MAJOR(dev));
- fsidv[1] = htonl(MINOR(dev));
- fsidv[2] = ino_t_to_u32(ino);
- break;
-
- case FSID_ENCODE_DEV:
- fsidv[0] = new_encode_dev(dev);
- fsidv[1] = ino_t_to_u32(ino);
- break;
-
- case FSID_UUID4_INUM:
- /* 4 byte fsid and inode number */
- up = (u32*)uuid;
- fsidv[0] = ino_t_to_u32(ino);
- fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3];
- break;
-
- case FSID_UUID8:
- /* 8 byte fsid */
- up = (u32*)uuid;
- fsidv[0] = up[0] ^ up[2];
- fsidv[1] = up[1] ^ up[3];
- break;
-
- case FSID_UUID16:
- /* 16 byte fsid - NFSv3+ only */
- memcpy(fsidv, uuid, 16);
- break;
-
- case FSID_UUID16_INUM:
- /* 8 byte inode and 16 byte fsid */
- *(u64*)fsidv = (u64)ino;
- memcpy(fsidv+2, uuid, 16);
- break;
- default: BUG();
- }
-}
-
-static inline int key_len(int type)
-{
- switch(type) {
- case FSID_DEV: return 8;
- case FSID_NUM: return 4;
- case FSID_MAJOR_MINOR: return 12;
- case FSID_ENCODE_DEV: return 8;
- case FSID_UUID4_INUM: return 8;
- case FSID_UUID8: return 8;
- case FSID_UUID16: return 16;
- case FSID_UUID16_INUM: return 24;
- default: return 0;
- }
-}
-
-/*
- * Shorthand for dprintk()'s
- */
-extern char * SVCFH_fmt(struct svc_fh *fhp);
-
-/*
- * Function prototypes
- */
-__be32 fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int);
-__be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
-__be32 fh_update(struct svc_fh *);
-void fh_put(struct svc_fh *);
-
-static __inline__ struct svc_fh *
-fh_copy(struct svc_fh *dst, struct svc_fh *src)
-{
- WARN_ON(src->fh_dentry || src->fh_locked);
-
- *dst = *src;
- return dst;
-}
-
-static inline void
-fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src)
-{
- dst->fh_size = src->fh_size;
- memcpy(&dst->fh_base, &src->fh_base, src->fh_size);
-}
-
-static __inline__ struct svc_fh *
-fh_init(struct svc_fh *fhp, int maxsize)
-{
- memset(fhp, 0, sizeof(*fhp));
- fhp->fh_maxsize = maxsize;
- return fhp;
-}
-
-#ifdef CONFIG_NFSD_V3
-/*
- * Fill in the pre_op attr for the wcc data
- */
-static inline void
-fill_pre_wcc(struct svc_fh *fhp)
-{
- struct inode *inode;
-
- inode = fhp->fh_dentry->d_inode;
- if (!fhp->fh_pre_saved) {
- fhp->fh_pre_mtime = inode->i_mtime;
- fhp->fh_pre_ctime = inode->i_ctime;
- fhp->fh_pre_size = inode->i_size;
- fhp->fh_pre_change = inode->i_version;
- fhp->fh_pre_saved = 1;
- }
-}
-
-extern void fill_post_wcc(struct svc_fh *);
-#else
-#define fill_pre_wcc(ignored)
-#define fill_post_wcc(notused)
-#endif /* CONFIG_NFSD_V3 */
-
-
-/*
- * Lock a file handle/inode
- * NOTE: both fh_lock and fh_unlock are done "by hand" in
- * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once
- * so, any changes here should be reflected there.
- */
-
-static inline void
-fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
-{
- struct dentry *dentry = fhp->fh_dentry;
- struct inode *inode;
-
- BUG_ON(!dentry);
-
- if (fhp->fh_locked) {
- printk(KERN_WARNING "fh_lock: %s/%s already locked!\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- return;
- }
-
- inode = dentry->d_inode;
- mutex_lock_nested(&inode->i_mutex, subclass);
- fill_pre_wcc(fhp);
- fhp->fh_locked = 1;
-}
-
-static inline void
-fh_lock(struct svc_fh *fhp)
-{
- fh_lock_nested(fhp, I_MUTEX_NORMAL);
-}
-
-/*
- * Unlock a file handle/inode
- */
-static inline void
-fh_unlock(struct svc_fh *fhp)
-{
- if (fhp->fh_locked) {
- fill_post_wcc(fhp);
- mutex_unlock(&fhp->fh_dentry->d_inode->i_mutex);
- fhp->fh_locked = 0;
- }
-}
-
-#endif /* _LINUX_NFSD_FH_INT_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/nfsproc.c b/ANDROID_3.4.5/fs/nfsd/nfsproc.c
deleted file mode 100644
index e15dc45f..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfsproc.c
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * Process version 2 NFS requests.
- *
- * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/namei.h>
-
-#include "cache.h"
-#include "xdr.h"
-#include "vfs.h"
-
-typedef struct svc_rqst svc_rqst;
-typedef struct svc_buf svc_buf;
-
-#define NFSDDBG_FACILITY NFSDDBG_PROC
-
-
-static __be32
-nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
-{
- return nfs_ok;
-}
-
-static __be32
-nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
-{
- if (err) return err;
- return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt,
- resp->fh.fh_dentry,
- &resp->stat));
-}
-static __be32
-nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
-{
- if (err) return err;
- return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt,
- resp->fh.fh_dentry,
- &resp->stat));
-}
-/*
- * Get a file's attributes
- * N.B. After this call resp->fh needs an fh_put
- */
-static __be32
-nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
- struct nfsd_attrstat *resp)
-{
- __be32 nfserr;
- dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
-
- fh_copy(&resp->fh, &argp->fh);
- nfserr = fh_verify(rqstp, &resp->fh, 0,
- NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
- return nfsd_return_attrs(nfserr, resp);
-}
-
-/*
- * Set a file's attributes
- * N.B. After this call resp->fh needs an fh_put
- */
-static __be32
-nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
- struct nfsd_attrstat *resp)
-{
- __be32 nfserr;
- dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
- SVCFH_fmt(&argp->fh),
- argp->attrs.ia_valid, (long) argp->attrs.ia_size);
-
- fh_copy(&resp->fh, &argp->fh);
- nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0);
- return nfsd_return_attrs(nfserr, resp);
-}
-
-/*
- * Look up a path name component
- * Note: the dentry in the resp->fh may be negative if the file
- * doesn't exist yet.
- * N.B. After this call resp->fh needs an fh_put
- */
-static __be32
-nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
- struct nfsd_diropres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: LOOKUP %s %.*s\n",
- SVCFH_fmt(&argp->fh), argp->len, argp->name);
-
- fh_init(&resp->fh, NFS_FHSIZE);
- nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
- &resp->fh);
-
- fh_put(&argp->fh);
- return nfsd_return_dirop(nfserr, resp);
-}
-
-/*
- * Read a symlink.
- */
-static __be32
-nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
- struct nfsd_readlinkres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
-
- /* Read the symlink. */
- resp->len = NFS_MAXPATHLEN;
- nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
-
- fh_put(&argp->fh);
- return nfserr;
-}
-
-/*
- * Read a portion of a file.
- * N.B. After this call resp->fh needs an fh_put
- */
-static __be32
-nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
- struct nfsd_readres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: READ %s %d bytes at %d\n",
- SVCFH_fmt(&argp->fh),
- argp->count, argp->offset);
-
- /* Obtain buffer pointer for payload. 19 is 1 word for
- * status, 17 words for fattr, and 1 word for the byte count.
- */
-
- if (NFSSVC_MAXBLKSIZE_V2 < argp->count) {
- char buf[RPC_MAX_ADDRBUFLEN];
- printk(KERN_NOTICE
- "oversized read request from %s (%d bytes)\n",
- svc_print_addr(rqstp, buf, sizeof(buf)),
- argp->count);
- argp->count = NFSSVC_MAXBLKSIZE_V2;
- }
- svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
-
- resp->count = argp->count;
- nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
- argp->offset,
- rqstp->rq_vec, argp->vlen,
- &resp->count);
-
- if (nfserr) return nfserr;
- return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt,
- resp->fh.fh_dentry,
- &resp->stat));
-}
-
-/*
- * Write data to a file
- * N.B. After this call resp->fh needs an fh_put
- */
-static __be32
-nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
- struct nfsd_attrstat *resp)
-{
- __be32 nfserr;
- int stable = 1;
- unsigned long cnt = argp->len;
-
- dprintk("nfsd: WRITE %s %d bytes at %d\n",
- SVCFH_fmt(&argp->fh),
- argp->len, argp->offset);
-
- nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
- argp->offset,
- rqstp->rq_vec, argp->vlen,
- &cnt,
- &stable);
- return nfsd_return_attrs(nfserr, resp);
-}
-
-/*
- * CREATE processing is complicated. The keyword here is `overloaded.'
- * The parent directory is kept locked between the check for existence
- * and the actual create() call in compliance with VFS protocols.
- * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
- */
-static __be32
-nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
- struct nfsd_diropres *resp)
-{
- svc_fh *dirfhp = &argp->fh;
- svc_fh *newfhp = &resp->fh;
- struct iattr *attr = &argp->attrs;
- struct inode *inode;
- struct dentry *dchild;
- int type, mode;
- __be32 nfserr;
- dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
-
- dprintk("nfsd: CREATE %s %.*s\n",
- SVCFH_fmt(dirfhp), argp->len, argp->name);
-
- /* First verify the parent file handle */
- nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
- if (nfserr)
- goto done; /* must fh_put dirfhp even on error */
-
- /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
-
- nfserr = nfserr_acces;
- if (!argp->len)
- goto done;
- nfserr = nfserr_exist;
- if (isdotent(argp->name, argp->len))
- goto done;
- fh_lock_nested(dirfhp, I_MUTEX_PARENT);
- dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
- if (IS_ERR(dchild)) {
- nfserr = nfserrno(PTR_ERR(dchild));
- goto out_unlock;
- }
- fh_init(newfhp, NFS_FHSIZE);
- nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
- if (!nfserr && !dchild->d_inode)
- nfserr = nfserr_noent;
- dput(dchild);
- if (nfserr) {
- if (nfserr != nfserr_noent)
- goto out_unlock;
- /*
- * If the new file handle wasn't verified, we can't tell
- * whether the file exists or not. Time to bail ...
- */
- nfserr = nfserr_acces;
- if (!newfhp->fh_dentry) {
- printk(KERN_WARNING
- "nfsd_proc_create: file handle not verified\n");
- goto out_unlock;
- }
- }
-
- inode = newfhp->fh_dentry->d_inode;
-
- /* Unfudge the mode bits */
- if (attr->ia_valid & ATTR_MODE) {
- type = attr->ia_mode & S_IFMT;
- mode = attr->ia_mode & ~S_IFMT;
- if (!type) {
- /* no type, so if target exists, assume same as that,
- * else assume a file */
- if (inode) {
- type = inode->i_mode & S_IFMT;
- switch(type) {
- case S_IFCHR:
- case S_IFBLK:
- /* reserve rdev for later checking */
- rdev = inode->i_rdev;
- attr->ia_valid |= ATTR_SIZE;
-
- /* FALLTHROUGH */
- case S_IFIFO:
- /* this is probably a permission check..
- * at least IRIX implements perm checking on
- * echo thing > device-special-file-or-pipe
- * by doing a CREATE with type==0
- */
- nfserr = nfsd_permission(rqstp,
- newfhp->fh_export,
- newfhp->fh_dentry,
- NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
- if (nfserr && nfserr != nfserr_rofs)
- goto out_unlock;
- }
- } else
- type = S_IFREG;
- }
- } else if (inode) {
- type = inode->i_mode & S_IFMT;
- mode = inode->i_mode & ~S_IFMT;
- } else {
- type = S_IFREG;
- mode = 0; /* ??? */
- }
-
- attr->ia_valid |= ATTR_MODE;
- attr->ia_mode = mode;
-
- /* Special treatment for non-regular files according to the
- * gospel of sun micro
- */
- if (type != S_IFREG) {
- if (type != S_IFBLK && type != S_IFCHR) {
- rdev = 0;
- } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
- /* If you think you've seen the worst, grok this. */
- type = S_IFIFO;
- } else {
- /* Okay, char or block special */
- if (!rdev)
- rdev = wanted;
- }
-
- /* we've used the SIZE information, so discard it */
- attr->ia_valid &= ~ATTR_SIZE;
-
- /* Make sure the type and device matches */
- nfserr = nfserr_exist;
- if (inode && type != (inode->i_mode & S_IFMT))
- goto out_unlock;
- }
-
- nfserr = 0;
- if (!inode) {
- /* File doesn't exist. Create it and set attrs */
- nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
- attr, type, rdev, newfhp);
- } else if (type == S_IFREG) {
- dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
- argp->name, attr->ia_valid, (long) attr->ia_size);
- /* File already exists. We ignore all attributes except
- * size, so that creat() behaves exactly like
- * open(..., O_CREAT|O_TRUNC|O_WRONLY).
- */
- attr->ia_valid &= ATTR_SIZE;
- if (attr->ia_valid)
- nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time_t)0);
- }
-
-out_unlock:
- /* We don't really need to unlock, as fh_put does it. */
- fh_unlock(dirfhp);
-
-done:
- fh_put(dirfhp);
- return nfsd_return_dirop(nfserr, resp);
-}
-
-static __be32
-nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
- void *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh),
- argp->len, argp->name);
-
- /* Unlink. -SIFDIR means file must not be a directory */
- nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
- fh_put(&argp->fh);
- return nfserr;
-}
-
-static __be32
-nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
- void *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: RENAME %s %.*s -> \n",
- SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
- dprintk("nfsd: -> %s %.*s\n",
- SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
-
- nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
- &argp->tfh, argp->tname, argp->tlen);
- fh_put(&argp->ffh);
- fh_put(&argp->tfh);
- return nfserr;
-}
-
-static __be32
-nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
- void *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: LINK %s ->\n",
- SVCFH_fmt(&argp->ffh));
- dprintk("nfsd: %s %.*s\n",
- SVCFH_fmt(&argp->tfh),
- argp->tlen,
- argp->tname);
-
- nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
- &argp->ffh);
- fh_put(&argp->ffh);
- fh_put(&argp->tfh);
- return nfserr;
-}
-
-static __be32
-nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
- void *resp)
-{
- struct svc_fh newfh;
- __be32 nfserr;
-
- dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
- SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
- argp->tlen, argp->tname);
-
- fh_init(&newfh, NFS_FHSIZE);
- /*
- * Create the link, look up new file and set attrs.
- */
- nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
- argp->tname, argp->tlen,
- &newfh, &argp->attrs);
-
-
- fh_put(&argp->ffh);
- fh_put(&newfh);
- return nfserr;
-}
-
-/*
- * Make directory. This operation is not idempotent.
- * N.B. After this call resp->fh needs an fh_put
- */
-static __be32
-nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
- struct nfsd_diropres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
-
- if (resp->fh.fh_dentry) {
- printk(KERN_WARNING
- "nfsd_proc_mkdir: response already verified??\n");
- }
-
- argp->attrs.ia_valid &= ~ATTR_SIZE;
- fh_init(&resp->fh, NFS_FHSIZE);
- nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
- &argp->attrs, S_IFDIR, 0, &resp->fh);
- fh_put(&argp->fh);
- return nfsd_return_dirop(nfserr, resp);
-}
-
-/*
- * Remove a directory
- */
-static __be32
-nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
- void *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
-
- nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
- fh_put(&argp->fh);
- return nfserr;
-}
-
-/*
- * Read a portion of a directory.
- */
-static __be32
-nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
- struct nfsd_readdirres *resp)
-{
- int count;
- __be32 nfserr;
- loff_t offset;
-
- dprintk("nfsd: READDIR %s %d bytes at %d\n",
- SVCFH_fmt(&argp->fh),
- argp->count, argp->cookie);
-
- /* Shrink to the client read size */
- count = (argp->count >> 2) - 2;
-
- /* Make sure we've room for the NULL ptr & eof flag */
- count -= 2;
- if (count < 0)
- count = 0;
-
- resp->buffer = argp->buffer;
- resp->offset = NULL;
- resp->buflen = count;
- resp->common.err = nfs_ok;
- /* Read directory and encode entries on the fly */
- offset = argp->cookie;
- nfserr = nfsd_readdir(rqstp, &argp->fh, &offset,
- &resp->common, nfssvc_encode_entry);
-
- resp->count = resp->buffer - argp->buffer;
- if (resp->offset)
- *resp->offset = htonl(offset);
-
- fh_put(&argp->fh);
- return nfserr;
-}
-
-/*
- * Get file system info
- */
-static __be32
-nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
- struct nfsd_statfsres *resp)
-{
- __be32 nfserr;
-
- dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
-
- nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
- NFSD_MAY_BYPASS_GSS_ON_ROOT);
- fh_put(&argp->fh);
- return nfserr;
-}
-
-/*
- * NFSv2 Server procedures.
- * Only the results of non-idempotent operations are cached.
- */
-struct nfsd_void { int dummy; };
-
-#define ST 1 /* status */
-#define FH 8 /* filehandle */
-#define AT 18 /* attributes */
-
-static struct svc_procedure nfsd_procedures2[18] = {
- [NFSPROC_NULL] = {
- .pc_func = (svc_procfunc) nfsd_proc_null,
- .pc_decode = (kxdrproc_t) nfssvc_decode_void,
- .pc_encode = (kxdrproc_t) nfssvc_encode_void,
- .pc_argsize = sizeof(struct nfsd_void),
- .pc_ressize = sizeof(struct nfsd_void),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST,
- },
- [NFSPROC_GETATTR] = {
- .pc_func = (svc_procfunc) nfsd_proc_getattr,
- .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle,
- .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
- .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd_fhandle),
- .pc_ressize = sizeof(struct nfsd_attrstat),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+AT,
- },
- [NFSPROC_SETATTR] = {
- .pc_func = (svc_procfunc) nfsd_proc_setattr,
- .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
- .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd_sattrargs),
- .pc_ressize = sizeof(struct nfsd_attrstat),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+AT,
- },
- [NFSPROC_ROOT] = {
- .pc_decode = (kxdrproc_t) nfssvc_decode_void,
- .pc_encode = (kxdrproc_t) nfssvc_encode_void,
- .pc_argsize = sizeof(struct nfsd_void),
- .pc_ressize = sizeof(struct nfsd_void),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST,
- },
- [NFSPROC_LOOKUP] = {
- .pc_func = (svc_procfunc) nfsd_proc_lookup,
- .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
- .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd_diropargs),
- .pc_ressize = sizeof(struct nfsd_diropres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+FH+AT,
- },
- [NFSPROC_READLINK] = {
- .pc_func = (svc_procfunc) nfsd_proc_readlink,
- .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres,
- .pc_argsize = sizeof(struct nfsd_readlinkargs),
- .pc_ressize = sizeof(struct nfsd_readlinkres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
- },
- [NFSPROC_READ] = {
- .pc_func = (svc_procfunc) nfsd_proc_read,
- .pc_decode = (kxdrproc_t) nfssvc_decode_readargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_readres,
- .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd_readargs),
- .pc_ressize = sizeof(struct nfsd_readres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
- },
- [NFSPROC_WRITECACHE] = {
- .pc_decode = (kxdrproc_t) nfssvc_decode_void,
- .pc_encode = (kxdrproc_t) nfssvc_encode_void,
- .pc_argsize = sizeof(struct nfsd_void),
- .pc_ressize = sizeof(struct nfsd_void),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST,
- },
- [NFSPROC_WRITE] = {
- .pc_func = (svc_procfunc) nfsd_proc_write,
- .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
- .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd_writeargs),
- .pc_ressize = sizeof(struct nfsd_attrstat),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+AT,
- },
- [NFSPROC_CREATE] = {
- .pc_func = (svc_procfunc) nfsd_proc_create,
- .pc_decode = (kxdrproc_t) nfssvc_decode_createargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
- .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd_createargs),
- .pc_ressize = sizeof(struct nfsd_diropres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+FH+AT,
- },
- [NFSPROC_REMOVE] = {
- .pc_func = (svc_procfunc) nfsd_proc_remove,
- .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_void,
- .pc_argsize = sizeof(struct nfsd_diropargs),
- .pc_ressize = sizeof(struct nfsd_void),
- .pc_cachetype = RC_REPLSTAT,
- .pc_xdrressize = ST,
- },
- [NFSPROC_RENAME] = {
- .pc_func = (svc_procfunc) nfsd_proc_rename,
- .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_void,
- .pc_argsize = sizeof(struct nfsd_renameargs),
- .pc_ressize = sizeof(struct nfsd_void),
- .pc_cachetype = RC_REPLSTAT,
- .pc_xdrressize = ST,
- },
- [NFSPROC_LINK] = {
- .pc_func = (svc_procfunc) nfsd_proc_link,
- .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_void,
- .pc_argsize = sizeof(struct nfsd_linkargs),
- .pc_ressize = sizeof(struct nfsd_void),
- .pc_cachetype = RC_REPLSTAT,
- .pc_xdrressize = ST,
- },
- [NFSPROC_SYMLINK] = {
- .pc_func = (svc_procfunc) nfsd_proc_symlink,
- .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_void,
- .pc_argsize = sizeof(struct nfsd_symlinkargs),
- .pc_ressize = sizeof(struct nfsd_void),
- .pc_cachetype = RC_REPLSTAT,
- .pc_xdrressize = ST,
- },
- [NFSPROC_MKDIR] = {
- .pc_func = (svc_procfunc) nfsd_proc_mkdir,
- .pc_decode = (kxdrproc_t) nfssvc_decode_createargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
- .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd_createargs),
- .pc_ressize = sizeof(struct nfsd_diropres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+FH+AT,
- },
- [NFSPROC_RMDIR] = {
- .pc_func = (svc_procfunc) nfsd_proc_rmdir,
- .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_void,
- .pc_argsize = sizeof(struct nfsd_diropargs),
- .pc_ressize = sizeof(struct nfsd_void),
- .pc_cachetype = RC_REPLSTAT,
- .pc_xdrressize = ST,
- },
- [NFSPROC_READDIR] = {
- .pc_func = (svc_procfunc) nfsd_proc_readdir,
- .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs,
- .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres,
- .pc_argsize = sizeof(struct nfsd_readdirargs),
- .pc_ressize = sizeof(struct nfsd_readdirres),
- .pc_cachetype = RC_NOCACHE,
- },
- [NFSPROC_STATFS] = {
- .pc_func = (svc_procfunc) nfsd_proc_statfs,
- .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle,
- .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres,
- .pc_argsize = sizeof(struct nfsd_fhandle),
- .pc_ressize = sizeof(struct nfsd_statfsres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+5,
- },
-};
-
-
-struct svc_version nfsd_version2 = {
- .vs_vers = 2,
- .vs_nproc = 18,
- .vs_proc = nfsd_procedures2,
- .vs_dispatch = nfsd_dispatch,
- .vs_xdrsize = NFS2_SVC_XDRSIZE,
-};
-
-/*
- * Map errnos to NFS errnos.
- */
-__be32
-nfserrno (int errno)
-{
- static struct {
- __be32 nfserr;
- int syserr;
- } nfs_errtbl[] = {
- { nfs_ok, 0 },
- { nfserr_perm, -EPERM },
- { nfserr_noent, -ENOENT },
- { nfserr_io, -EIO },
- { nfserr_nxio, -ENXIO },
- { nfserr_acces, -EACCES },
- { nfserr_exist, -EEXIST },
- { nfserr_xdev, -EXDEV },
- { nfserr_mlink, -EMLINK },
- { nfserr_nodev, -ENODEV },
- { nfserr_notdir, -ENOTDIR },
- { nfserr_isdir, -EISDIR },
- { nfserr_inval, -EINVAL },
- { nfserr_fbig, -EFBIG },
- { nfserr_nospc, -ENOSPC },
- { nfserr_rofs, -EROFS },
- { nfserr_mlink, -EMLINK },
- { nfserr_nametoolong, -ENAMETOOLONG },
- { nfserr_notempty, -ENOTEMPTY },
-#ifdef EDQUOT
- { nfserr_dquot, -EDQUOT },
-#endif
- { nfserr_stale, -ESTALE },
- { nfserr_jukebox, -ETIMEDOUT },
- { nfserr_jukebox, -ERESTARTSYS },
- { nfserr_jukebox, -EAGAIN },
- { nfserr_jukebox, -EWOULDBLOCK },
- { nfserr_jukebox, -ENOMEM },
- { nfserr_io, -ETXTBSY },
- { nfserr_notsupp, -EOPNOTSUPP },
- { nfserr_toosmall, -ETOOSMALL },
- { nfserr_serverfault, -ESERVERFAULT },
- };
- int i;
-
- for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
- if (nfs_errtbl[i].syserr == errno)
- return nfs_errtbl[i].nfserr;
- }
- printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
- return nfserr_io;
-}
-
diff --git a/ANDROID_3.4.5/fs/nfsd/nfssvc.c b/ANDROID_3.4.5/fs/nfsd/nfssvc.c
deleted file mode 100644
index bcda12a3..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfssvc.c
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- * Central processing for nfsd.
- *
- * Authors: Olaf Kirch (okir@monad.swb.de)
- *
- * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/sched.h>
-#include <linux/freezer.h>
-#include <linux/module.h>
-#include <linux/fs_struct.h>
-#include <linux/swap.h>
-#include <linux/nsproxy.h>
-
-#include <linux/sunrpc/stats.h>
-#include <linux/sunrpc/svcsock.h>
-#include <linux/lockd/bind.h>
-#include <linux/nfsacl.h>
-#include <linux/seq_file.h>
-#include <net/net_namespace.h>
-#include "nfsd.h"
-#include "cache.h"
-#include "vfs.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_SVC
-
-extern struct svc_program nfsd_program;
-static int nfsd(void *vrqstp);
-struct timeval nfssvc_boot;
-
-/*
- * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
- * of the svc_serv struct. In particular, ->sv_nrthreads but also to some
- * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt
- *
- * If (out side the lock) nfsd_serv is non-NULL, then it must point to a
- * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number
- * of nfsd threads must exist and each must listed in ->sp_all_threads in each
- * entry of ->sv_pools[].
- *
- * Transitions of the thread count between zero and non-zero are of particular
- * interest since the svc_serv needs to be created and initialized at that
- * point, or freed.
- *
- * Finally, the nfsd_mutex also protects some of the global variables that are
- * accessed when nfsd starts and that are settable via the write_* routines in
- * nfsctl.c. In particular:
- *
- * user_recovery_dirname
- * user_lease_time
- * nfsd_versions
- */
-DEFINE_MUTEX(nfsd_mutex);
-struct svc_serv *nfsd_serv;
-
-/*
- * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used.
- * nfsd_drc_max_pages limits the total amount of memory available for
- * version 4.1 DRC caches.
- * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage.
- */
-spinlock_t nfsd_drc_lock;
-unsigned int nfsd_drc_max_mem;
-unsigned int nfsd_drc_mem_used;
-
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-static struct svc_stat nfsd_acl_svcstats;
-static struct svc_version * nfsd_acl_version[] = {
- [2] = &nfsd_acl_version2,
- [3] = &nfsd_acl_version3,
-};
-
-#define NFSD_ACL_MINVERS 2
-#define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version)
-static struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS];
-
-static struct svc_program nfsd_acl_program = {
- .pg_prog = NFS_ACL_PROGRAM,
- .pg_nvers = NFSD_ACL_NRVERS,
- .pg_vers = nfsd_acl_versions,
- .pg_name = "nfsacl",
- .pg_class = "nfsd",
- .pg_stats = &nfsd_acl_svcstats,
- .pg_authenticate = &svc_set_client,
-};
-
-static struct svc_stat nfsd_acl_svcstats = {
- .program = &nfsd_acl_program,
-};
-#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
-
-static struct svc_version * nfsd_version[] = {
- [2] = &nfsd_version2,
-#if defined(CONFIG_NFSD_V3)
- [3] = &nfsd_version3,
-#endif
-#if defined(CONFIG_NFSD_V4)
- [4] = &nfsd_version4,
-#endif
-};
-
-#define NFSD_MINVERS 2
-#define NFSD_NRVERS ARRAY_SIZE(nfsd_version)
-static struct svc_version *nfsd_versions[NFSD_NRVERS];
-
-struct svc_program nfsd_program = {
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
- .pg_next = &nfsd_acl_program,
-#endif
- .pg_prog = NFS_PROGRAM, /* program number */
- .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
- .pg_vers = nfsd_versions, /* version table */
- .pg_name = "nfsd", /* program name */
- .pg_class = "nfsd", /* authentication class */
- .pg_stats = &nfsd_svcstats, /* version table */
- .pg_authenticate = &svc_set_client, /* export authentication */
-
-};
-
-u32 nfsd_supported_minorversion;
-
-int nfsd_vers(int vers, enum vers_op change)
-{
- if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
- return 0;
- switch(change) {
- case NFSD_SET:
- nfsd_versions[vers] = nfsd_version[vers];
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
- if (vers < NFSD_ACL_NRVERS)
- nfsd_acl_versions[vers] = nfsd_acl_version[vers];
-#endif
- break;
- case NFSD_CLEAR:
- nfsd_versions[vers] = NULL;
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
- if (vers < NFSD_ACL_NRVERS)
- nfsd_acl_versions[vers] = NULL;
-#endif
- break;
- case NFSD_TEST:
- return nfsd_versions[vers] != NULL;
- case NFSD_AVAIL:
- return nfsd_version[vers] != NULL;
- }
- return 0;
-}
-
-int nfsd_minorversion(u32 minorversion, enum vers_op change)
-{
- if (minorversion > NFSD_SUPPORTED_MINOR_VERSION)
- return -1;
- switch(change) {
- case NFSD_SET:
- nfsd_supported_minorversion = minorversion;
- break;
- case NFSD_CLEAR:
- if (minorversion == 0)
- return -1;
- nfsd_supported_minorversion = minorversion - 1;
- break;
- case NFSD_TEST:
- return minorversion <= nfsd_supported_minorversion;
- case NFSD_AVAIL:
- return minorversion <= NFSD_SUPPORTED_MINOR_VERSION;
- }
- return 0;
-}
-
-/*
- * Maximum number of nfsd processes
- */
-#define NFSD_MAXSERVS 8192
-
-int nfsd_nrthreads(void)
-{
- int rv = 0;
- mutex_lock(&nfsd_mutex);
- if (nfsd_serv)
- rv = nfsd_serv->sv_nrthreads;
- mutex_unlock(&nfsd_mutex);
- return rv;
-}
-
-static int nfsd_init_socks(int port)
-{
- int error;
- if (!list_empty(&nfsd_serv->sv_permsocks))
- return 0;
-
- error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port,
- SVC_SOCK_DEFAULTS);
- if (error < 0)
- return error;
-
- error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port,
- SVC_SOCK_DEFAULTS);
- if (error < 0)
- return error;
-
- return 0;
-}
-
-static bool nfsd_up = false;
-
-static int nfsd_startup(unsigned short port, int nrservs)
-{
- int ret;
-
- if (nfsd_up)
- return 0;
- /*
- * Readahead param cache - will no-op if it already exists.
- * (Note therefore results will be suboptimal if number of
- * threads is modified after nfsd start.)
- */
- ret = nfsd_racache_init(2*nrservs);
- if (ret)
- return ret;
- ret = nfsd_init_socks(port);
- if (ret)
- goto out_racache;
- ret = lockd_up(&init_net);
- if (ret)
- goto out_racache;
- ret = nfs4_state_start();
- if (ret)
- goto out_lockd;
- nfsd_up = true;
- return 0;
-out_lockd:
- lockd_down(&init_net);
-out_racache:
- nfsd_racache_shutdown();
- return ret;
-}
-
-static void nfsd_shutdown(void)
-{
- /*
- * write_ports can create the server without actually starting
- * any threads--if we get shut down before any threads are
- * started, then nfsd_last_thread will be run before any of this
- * other initialization has been done.
- */
- if (!nfsd_up)
- return;
- nfs4_state_shutdown();
- lockd_down(&init_net);
- nfsd_racache_shutdown();
- nfsd_up = false;
-}
-
-static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
-{
- /* When last nfsd thread exits we need to do some clean-up */
- nfsd_serv = NULL;
- nfsd_shutdown();
-
- svc_rpcb_cleanup(serv, net);
-
- printk(KERN_WARNING "nfsd: last server has exited, flushing export "
- "cache\n");
- nfsd_export_flush();
-}
-
-void nfsd_reset_versions(void)
-{
- int found_one = 0;
- int i;
-
- for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
- if (nfsd_program.pg_vers[i])
- found_one = 1;
- }
-
- if (!found_one) {
- for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
- nfsd_program.pg_vers[i] = nfsd_version[i];
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
- for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
- nfsd_acl_program.pg_vers[i] =
- nfsd_acl_version[i];
-#endif
- }
-}
-
-/*
- * Each session guarantees a negotiated per slot memory cache for replies
- * which in turn consumes memory beyond the v2/v3/v4.0 server. A dedicated
- * NFSv4.1 server might want to use more memory for a DRC than a machine
- * with mutiple services.
- *
- * Impose a hard limit on the number of pages for the DRC which varies
- * according to the machines free pages. This is of course only a default.
- *
- * For now this is a #defined shift which could be under admin control
- * in the future.
- */
-static void set_max_drc(void)
-{
- #define NFSD_DRC_SIZE_SHIFT 10
- nfsd_drc_max_mem = (nr_free_buffer_pages()
- >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
- nfsd_drc_mem_used = 0;
- spin_lock_init(&nfsd_drc_lock);
- dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem);
-}
-
-static int nfsd_get_default_max_blksize(void)
-{
- struct sysinfo i;
- unsigned long long target;
- unsigned long ret;
-
- si_meminfo(&i);
- target = (i.totalram - i.totalhigh) << PAGE_SHIFT;
- /*
- * Aim for 1/4096 of memory per thread This gives 1MB on 4Gig
- * machines, but only uses 32K on 128M machines. Bottom out at
- * 8K on 32M and smaller. Of course, this is only a default.
- */
- target >>= 12;
-
- ret = NFSSVC_MAXBLKSIZE;
- while (ret > target && ret >= 8*1024*2)
- ret /= 2;
- return ret;
-}
-
-int nfsd_create_serv(void)
-{
- int error;
-
- WARN_ON(!mutex_is_locked(&nfsd_mutex));
- if (nfsd_serv) {
- svc_get(nfsd_serv);
- return 0;
- }
- if (nfsd_max_blksize == 0)
- nfsd_max_blksize = nfsd_get_default_max_blksize();
- nfsd_reset_versions();
- nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
- nfsd_last_thread, nfsd, THIS_MODULE);
- if (nfsd_serv == NULL)
- return -ENOMEM;
-
- error = svc_bind(nfsd_serv, current->nsproxy->net_ns);
- if (error < 0) {
- svc_destroy(nfsd_serv);
- return error;
- }
-
- set_max_drc();
- do_gettimeofday(&nfssvc_boot); /* record boot time */
- return 0;
-}
-
-int nfsd_nrpools(void)
-{
- if (nfsd_serv == NULL)
- return 0;
- else
- return nfsd_serv->sv_nrpools;
-}
-
-int nfsd_get_nrthreads(int n, int *nthreads)
-{
- int i = 0;
-
- if (nfsd_serv != NULL) {
- for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++)
- nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads;
- }
-
- return 0;
-}
-
-int nfsd_set_nrthreads(int n, int *nthreads)
-{
- int i = 0;
- int tot = 0;
- int err = 0;
- struct net *net = &init_net;
-
- WARN_ON(!mutex_is_locked(&nfsd_mutex));
-
- if (nfsd_serv == NULL || n <= 0)
- return 0;
-
- if (n > nfsd_serv->sv_nrpools)
- n = nfsd_serv->sv_nrpools;
-
- /* enforce a global maximum number of threads */
- tot = 0;
- for (i = 0; i < n; i++) {
- if (nthreads[i] > NFSD_MAXSERVS)
- nthreads[i] = NFSD_MAXSERVS;
- tot += nthreads[i];
- }
- if (tot > NFSD_MAXSERVS) {
- /* total too large: scale down requested numbers */
- for (i = 0; i < n && tot > 0; i++) {
- int new = nthreads[i] * NFSD_MAXSERVS / tot;
- tot -= (nthreads[i] - new);
- nthreads[i] = new;
- }
- for (i = 0; i < n && tot > 0; i++) {
- nthreads[i]--;
- tot--;
- }
- }
-
- /*
- * There must always be a thread in pool 0; the admin
- * can't shut down NFS completely using pool_threads.
- */
- if (nthreads[0] == 0)
- nthreads[0] = 1;
-
- /* apply the new numbers */
- svc_get(nfsd_serv);
- for (i = 0; i < n; i++) {
- err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
- nthreads[i]);
- if (err)
- break;
- }
-
- if (nfsd_serv->sv_nrthreads == 1)
- svc_shutdown_net(nfsd_serv, net);
- svc_destroy(nfsd_serv);
-
- return err;
-}
-
-/*
- * Adjust the number of threads and return the new number of threads.
- * This is also the function that starts the server if necessary, if
- * this is the first time nrservs is nonzero.
- */
-int
-nfsd_svc(unsigned short port, int nrservs)
-{
- int error;
- bool nfsd_up_before;
- struct net *net = &init_net;
-
- mutex_lock(&nfsd_mutex);
- dprintk("nfsd: creating service\n");
- if (nrservs <= 0)
- nrservs = 0;
- if (nrservs > NFSD_MAXSERVS)
- nrservs = NFSD_MAXSERVS;
- error = 0;
- if (nrservs == 0 && nfsd_serv == NULL)
- goto out;
-
- error = nfsd_create_serv();
- if (error)
- goto out;
-
- nfsd_up_before = nfsd_up;
-
- error = nfsd_startup(port, nrservs);
- if (error)
- goto out_destroy;
- error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
- if (error)
- goto out_shutdown;
- /* We are holding a reference to nfsd_serv which
- * we don't want to count in the return value,
- * so subtract 1
- */
- error = nfsd_serv->sv_nrthreads - 1;
-out_shutdown:
- if (error < 0 && !nfsd_up_before)
- nfsd_shutdown();
-out_destroy:
- if (nfsd_serv->sv_nrthreads == 1)
- svc_shutdown_net(nfsd_serv, net);
- svc_destroy(nfsd_serv); /* Release server */
-out:
- mutex_unlock(&nfsd_mutex);
- return error;
-}
-
-
-/*
- * This is the NFS server kernel thread
- */
-static int
-nfsd(void *vrqstp)
-{
- struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
- int err, preverr = 0;
-
- /* Lock module and set up kernel thread */
- mutex_lock(&nfsd_mutex);
-
- /* At this point, the thread shares current->fs
- * with the init process. We need to create files with a
- * umask of 0 instead of init's umask. */
- if (unshare_fs_struct() < 0) {
- printk("Unable to start nfsd thread: out of memory\n");
- goto out;
- }
-
- current->fs->umask = 0;
-
- /*
- * thread is spawned with all signals set to SIG_IGN, re-enable
- * the ones that will bring down the thread
- */
- allow_signal(SIGKILL);
- allow_signal(SIGHUP);
- allow_signal(SIGINT);
- allow_signal(SIGQUIT);
-
- nfsdstats.th_cnt++;
- mutex_unlock(&nfsd_mutex);
-
- /*
- * We want less throttling in balance_dirty_pages() so that nfs to
- * localhost doesn't cause nfsd to lock up due to all the client's
- * dirty pages.
- */
- current->flags |= PF_LESS_THROTTLE;
- set_freezable();
-
- /*
- * The main request loop
- */
- for (;;) {
- /*
- * Find a socket with data available and call its
- * recvfrom routine.
- */
- while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
- ;
- if (err == -EINTR)
- break;
- else if (err < 0) {
- if (err != preverr) {
- printk(KERN_WARNING "%s: unexpected error "
- "from svc_recv (%d)\n", __func__, -err);
- preverr = err;
- }
- schedule_timeout_uninterruptible(HZ);
- continue;
- }
-
- validate_process_creds();
- svc_process(rqstp);
- validate_process_creds();
- }
-
- /* Clear signals before calling svc_exit_thread() */
- flush_signals(current);
-
- mutex_lock(&nfsd_mutex);
- nfsdstats.th_cnt --;
-
-out:
- if (rqstp->rq_server->sv_nrthreads == 1)
- svc_shutdown_net(rqstp->rq_server, &init_net);
-
- /* Release the thread */
- svc_exit_thread(rqstp);
-
- /* Release module */
- mutex_unlock(&nfsd_mutex);
- module_put_and_exit(0);
- return 0;
-}
-
-static __be32 map_new_errors(u32 vers, __be32 nfserr)
-{
- if (nfserr == nfserr_jukebox && vers == 2)
- return nfserr_dropit;
- if (nfserr == nfserr_wrongsec && vers < 4)
- return nfserr_acces;
- return nfserr;
-}
-
-int
-nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
-{
- struct svc_procedure *proc;
- kxdrproc_t xdr;
- __be32 nfserr;
- __be32 *nfserrp;
-
- dprintk("nfsd_dispatch: vers %d proc %d\n",
- rqstp->rq_vers, rqstp->rq_proc);
- proc = rqstp->rq_procinfo;
-
- /*
- * Give the xdr decoder a chance to change this if it wants
- * (necessary in the NFSv4.0 compound case)
- */
- rqstp->rq_cachetype = proc->pc_cachetype;
- /* Decode arguments */
- xdr = proc->pc_decode;
- if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
- rqstp->rq_argp)) {
- dprintk("nfsd: failed to decode arguments!\n");
- *statp = rpc_garbage_args;
- return 1;
- }
-
- /* Check whether we have this call in the cache. */
- switch (nfsd_cache_lookup(rqstp)) {
- case RC_INTR:
- case RC_DROPIT:
- return 0;
- case RC_REPLY:
- return 1;
- case RC_DOIT:;
- /* do it */
- }
-
- /* need to grab the location to store the status, as
- * nfsv4 does some encoding while processing
- */
- nfserrp = rqstp->rq_res.head[0].iov_base
- + rqstp->rq_res.head[0].iov_len;
- rqstp->rq_res.head[0].iov_len += sizeof(__be32);
-
- /* Now call the procedure handler, and encode NFS status. */
- nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
- nfserr = map_new_errors(rqstp->rq_vers, nfserr);
- if (nfserr == nfserr_dropit || rqstp->rq_dropme) {
- dprintk("nfsd: Dropping request; may be revisited later\n");
- nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
- return 0;
- }
-
- if (rqstp->rq_proc != 0)
- *nfserrp++ = nfserr;
-
- /* Encode result.
- * For NFSv2, additional info is never returned in case of an error.
- */
- if (!(nfserr && rqstp->rq_vers == 2)) {
- xdr = proc->pc_encode;
- if (xdr && !xdr(rqstp, nfserrp,
- rqstp->rq_resp)) {
- /* Failed to encode result. Release cache entry */
- dprintk("nfsd: failed to encode result!\n");
- nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
- *statp = rpc_system_err;
- return 1;
- }
- }
-
- /* Store reply in cache. */
- nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
- return 1;
-}
-
-int nfsd_pool_stats_open(struct inode *inode, struct file *file)
-{
- int ret;
- mutex_lock(&nfsd_mutex);
- if (nfsd_serv == NULL) {
- mutex_unlock(&nfsd_mutex);
- return -ENODEV;
- }
- /* bump up the psudo refcount while traversing */
- svc_get(nfsd_serv);
- ret = svc_pool_stats_open(nfsd_serv, file);
- mutex_unlock(&nfsd_mutex);
- return ret;
-}
-
-int nfsd_pool_stats_release(struct inode *inode, struct file *file)
-{
- int ret = seq_release(inode, file);
- struct net *net = &init_net;
-
- mutex_lock(&nfsd_mutex);
- /* this function really, really should have been called svc_put() */
- if (nfsd_serv->sv_nrthreads == 1)
- svc_shutdown_net(nfsd_serv, net);
- svc_destroy(nfsd_serv);
- mutex_unlock(&nfsd_mutex);
- return ret;
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/nfsxdr.c b/ANDROID_3.4.5/fs/nfsd/nfsxdr.c
deleted file mode 100644
index 65ec595e..00000000
--- a/ANDROID_3.4.5/fs/nfsd/nfsxdr.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * XDR support for nfsd
- *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
- */
-
-#include "xdr.h"
-#include "auth.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_XDR
-
-/*
- * Mapping of S_IF* types to NFS file types
- */
-static u32 nfs_ftypes[] = {
- NFNON, NFCHR, NFCHR, NFBAD,
- NFDIR, NFBAD, NFBLK, NFBAD,
- NFREG, NFBAD, NFLNK, NFBAD,
- NFSOCK, NFBAD, NFLNK, NFBAD,
-};
-
-
-/*
- * XDR functions for basic NFS types
- */
-static __be32 *
-decode_fh(__be32 *p, struct svc_fh *fhp)
-{
- fh_init(fhp, NFS_FHSIZE);
- memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
- fhp->fh_handle.fh_size = NFS_FHSIZE;
-
- /* FIXME: Look up export pointer here and verify
- * Sun Secure RPC if requested */
- return p + (NFS_FHSIZE >> 2);
-}
-
-/* Helper function for NFSv2 ACL code */
-__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp)
-{
- return decode_fh(p, fhp);
-}
-
-static __be32 *
-encode_fh(__be32 *p, struct svc_fh *fhp)
-{
- memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
- return p + (NFS_FHSIZE>> 2);
-}
-
-/*
- * Decode a file name and make sure that the path contains
- * no slashes or null bytes.
- */
-static __be32 *
-decode_filename(__be32 *p, char **namp, unsigned int *lenp)
-{
- char *name;
- unsigned int i;
-
- if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
- for (i = 0, name = *namp; i < *lenp; i++, name++) {
- if (*name == '\0' || *name == '/')
- return NULL;
- }
- }
-
- return p;
-}
-
-static __be32 *
-decode_pathname(__be32 *p, char **namp, unsigned int *lenp)
-{
- char *name;
- unsigned int i;
-
- if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
- for (i = 0, name = *namp; i < *lenp; i++, name++) {
- if (*name == '\0')
- return NULL;
- }
- }
-
- return p;
-}
-
-static __be32 *
-decode_sattr(__be32 *p, struct iattr *iap)
-{
- u32 tmp, tmp1;
-
- iap->ia_valid = 0;
-
- /* Sun client bug compatibility check: some sun clients seem to
- * put 0xffff in the mode field when they mean 0xffffffff.
- * Quoting the 4.4BSD nfs server code: Nah nah nah nah na nah.
- */
- if ((tmp = ntohl(*p++)) != (u32)-1 && tmp != 0xffff) {
- iap->ia_valid |= ATTR_MODE;
- iap->ia_mode = tmp;
- }
- if ((tmp = ntohl(*p++)) != (u32)-1) {
- iap->ia_valid |= ATTR_UID;
- iap->ia_uid = tmp;
- }
- if ((tmp = ntohl(*p++)) != (u32)-1) {
- iap->ia_valid |= ATTR_GID;
- iap->ia_gid = tmp;
- }
- if ((tmp = ntohl(*p++)) != (u32)-1) {
- iap->ia_valid |= ATTR_SIZE;
- iap->ia_size = tmp;
- }
- tmp = ntohl(*p++); tmp1 = ntohl(*p++);
- if (tmp != (u32)-1 && tmp1 != (u32)-1) {
- iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
- iap->ia_atime.tv_sec = tmp;
- iap->ia_atime.tv_nsec = tmp1 * 1000;
- }
- tmp = ntohl(*p++); tmp1 = ntohl(*p++);
- if (tmp != (u32)-1 && tmp1 != (u32)-1) {
- iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
- iap->ia_mtime.tv_sec = tmp;
- iap->ia_mtime.tv_nsec = tmp1 * 1000;
- /*
- * Passing the invalid value useconds=1000000 for mtime
- * is a Sun convention for "set both mtime and atime to
- * current server time". It's needed to make permissions
- * checks for the "touch" program across v2 mounts to
- * Solaris and Irix boxes work correctly. See description of
- * sattr in section 6.1 of "NFS Illustrated" by
- * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
- */
- if (tmp1 == 1000000)
- iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
- }
- return p;
-}
-
-static __be32 *
-encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
- struct kstat *stat)
-{
- struct dentry *dentry = fhp->fh_dentry;
- int type;
- struct timespec time;
- u32 f;
-
- type = (stat->mode & S_IFMT);
-
- *p++ = htonl(nfs_ftypes[type >> 12]);
- *p++ = htonl((u32) stat->mode);
- *p++ = htonl((u32) stat->nlink);
- *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
- *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
-
- if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
- *p++ = htonl(NFS_MAXPATHLEN);
- } else {
- *p++ = htonl((u32) stat->size);
- }
- *p++ = htonl((u32) stat->blksize);
- if (S_ISCHR(type) || S_ISBLK(type))
- *p++ = htonl(new_encode_dev(stat->rdev));
- else
- *p++ = htonl(0xffffffff);
- *p++ = htonl((u32) stat->blocks);
- switch (fsid_source(fhp)) {
- default:
- case FSIDSOURCE_DEV:
- *p++ = htonl(new_encode_dev(stat->dev));
- break;
- case FSIDSOURCE_FSID:
- *p++ = htonl((u32) fhp->fh_export->ex_fsid);
- break;
- case FSIDSOURCE_UUID:
- f = ((u32*)fhp->fh_export->ex_uuid)[0];
- f ^= ((u32*)fhp->fh_export->ex_uuid)[1];
- f ^= ((u32*)fhp->fh_export->ex_uuid)[2];
- f ^= ((u32*)fhp->fh_export->ex_uuid)[3];
- *p++ = htonl(f);
- break;
- }
- *p++ = htonl((u32) stat->ino);
- *p++ = htonl((u32) stat->atime.tv_sec);
- *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
- lease_get_mtime(dentry->d_inode, &time);
- *p++ = htonl((u32) time.tv_sec);
- *p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0);
- *p++ = htonl((u32) stat->ctime.tv_sec);
- *p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0);
-
- return p;
-}
-
-/* Helper function for NFSv2 ACL code */
-__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
- struct kstat stat;
- vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, &stat);
- return encode_fattr(rqstp, p, fhp, &stat);
-}
-
-/*
- * XDR decode functions
- */
-int
-nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
-{
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_sattrargs *args)
-{
- p = decode_fh(p, &args->fh);
- if (!p)
- return 0;
- p = decode_sattr(p, &args->attrs);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_diropargs *args)
-{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len)))
- return 0;
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_readargs *args)
-{
- unsigned int len;
- int v,pn;
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
-
- args->offset = ntohl(*p++);
- len = args->count = ntohl(*p++);
- p++; /* totalcount - unused */
-
- if (len > NFSSVC_MAXBLKSIZE_V2)
- len = NFSSVC_MAXBLKSIZE_V2;
-
- /* set up somewhere to store response.
- * We take pages, put them on reslist and include in iovec
- */
- v=0;
- while (len > 0) {
- pn = rqstp->rq_resused++;
- rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
- rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
- len -= rqstp->rq_vec[v].iov_len;
- v++;
- }
- args->vlen = v;
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_writeargs *args)
-{
- unsigned int len, hdr, dlen;
- int v;
-
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
-
- p++; /* beginoffset */
- args->offset = ntohl(*p++); /* offset */
- p++; /* totalcount */
- len = args->len = ntohl(*p++);
- /*
- * The protocol specifies a maximum of 8192 bytes.
- */
- if (len > NFSSVC_MAXBLKSIZE_V2)
- return 0;
-
- /*
- * Check to make sure that we got the right number of
- * bytes.
- */
- hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
- dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
- - hdr;
-
- /*
- * Round the length of the data which was specified up to
- * the next multiple of XDR units and then compare that
- * against the length which was actually received.
- * Note that when RPCSEC/GSS (for example) is used, the
- * data buffer can be padded so dlen might be larger
- * than required. It must never be smaller.
- */
- if (dlen < XDR_QUADLEN(len)*4)
- return 0;
-
- rqstp->rq_vec[0].iov_base = (void*)p;
- rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
- v = 0;
- while (len > rqstp->rq_vec[v].iov_len) {
- len -= rqstp->rq_vec[v].iov_len;
- v++;
- rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
- rqstp->rq_vec[v].iov_len = PAGE_SIZE;
- }
- rqstp->rq_vec[v].iov_len = len;
- args->vlen = v + 1;
- return 1;
-}
-
-int
-nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_createargs *args)
-{
- if ( !(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len)))
- return 0;
- p = decode_sattr(p, &args->attrs);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_renameargs *args)
-{
- if (!(p = decode_fh(p, &args->ffh))
- || !(p = decode_filename(p, &args->fname, &args->flen))
- || !(p = decode_fh(p, &args->tfh))
- || !(p = decode_filename(p, &args->tname, &args->tlen)))
- return 0;
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_linkargs *args)
-{
- if (!(p = decode_fh(p, &args->ffh))
- || !(p = decode_fh(p, &args->tfh))
- || !(p = decode_filename(p, &args->tname, &args->tlen)))
- return 0;
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_symlinkargs *args)
-{
- if ( !(p = decode_fh(p, &args->ffh))
- || !(p = decode_filename(p, &args->fname, &args->flen))
- || !(p = decode_pathname(p, &args->tname, &args->tlen)))
- return 0;
- p = decode_sattr(p, &args->attrs);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-int
-nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_readdirargs *args)
-{
- if (!(p = decode_fh(p, &args->fh)))
- return 0;
- args->cookie = ntohl(*p++);
- args->count = ntohl(*p++);
- if (args->count > PAGE_SIZE)
- args->count = PAGE_SIZE;
-
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
-
- return xdr_argsize_check(rqstp, p);
-}
-
-/*
- * XDR encode functions
- */
-int
-nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
-{
- return xdr_ressize_check(rqstp, p);
-}
-
-int
-nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_attrstat *resp)
-{
- p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
- return xdr_ressize_check(rqstp, p);
-}
-
-int
-nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_diropres *resp)
-{
- p = encode_fh(p, &resp->fh);
- p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
- return xdr_ressize_check(rqstp, p);
-}
-
-int
-nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_readlinkres *resp)
-{
- *p++ = htonl(resp->len);
- xdr_ressize_check(rqstp, p);
- rqstp->rq_res.page_len = resp->len;
- if (resp->len & 3) {
- /* need to pad the tail */
- rqstp->rq_res.tail[0].iov_base = p;
- *p = 0;
- rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
- }
- return 1;
-}
-
-int
-nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_readres *resp)
-{
- p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
- *p++ = htonl(resp->count);
- xdr_ressize_check(rqstp, p);
-
- /* now update rqstp->rq_res to reflect data as well */
- rqstp->rq_res.page_len = resp->count;
- if (resp->count & 3) {
- /* need to pad the tail */
- rqstp->rq_res.tail[0].iov_base = p;
- *p = 0;
- rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
- }
- return 1;
-}
-
-int
-nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_readdirres *resp)
-{
- xdr_ressize_check(rqstp, p);
- p = resp->buffer;
- *p++ = 0; /* no more entries */
- *p++ = htonl((resp->common.err == nfserr_eof));
- rqstp->rq_res.page_len = (((unsigned long)p-1) & ~PAGE_MASK)+1;
-
- return 1;
-}
-
-int
-nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_statfsres *resp)
-{
- struct kstatfs *stat = &resp->stats;
-
- *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */
- *p++ = htonl(stat->f_bsize);
- *p++ = htonl(stat->f_blocks);
- *p++ = htonl(stat->f_bfree);
- *p++ = htonl(stat->f_bavail);
- return xdr_ressize_check(rqstp, p);
-}
-
-int
-nfssvc_encode_entry(void *ccdv, const char *name,
- int namlen, loff_t offset, u64 ino, unsigned int d_type)
-{
- struct readdir_cd *ccd = ccdv;
- struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
- __be32 *p = cd->buffer;
- int buflen, slen;
-
- /*
- dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
- namlen, name, offset, ino);
- */
-
- if (offset > ~((u32) 0)) {
- cd->common.err = nfserr_fbig;
- return -EINVAL;
- }
- if (cd->offset)
- *cd->offset = htonl(offset);
- if (namlen > NFS2_MAXNAMLEN)
- namlen = NFS2_MAXNAMLEN;/* truncate filename */
-
- slen = XDR_QUADLEN(namlen);
- if ((buflen = cd->buflen - slen - 4) < 0) {
- cd->common.err = nfserr_toosmall;
- return -EINVAL;
- }
- if (ino > ~((u32) 0)) {
- cd->common.err = nfserr_fbig;
- return -EINVAL;
- }
- *p++ = xdr_one; /* mark entry present */
- *p++ = htonl((u32) ino); /* file id */
- p = xdr_encode_array(p, name, namlen);/* name length & name */
- cd->offset = p; /* remember pointer */
- *p++ = htonl(~0U); /* offset of next entry */
-
- cd->buflen = buflen;
- cd->buffer = p;
- cd->common.err = nfs_ok;
- return 0;
-}
-
-/*
- * XDR release functions
- */
-int
-nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
- struct nfsd_fhandle *resp)
-{
- fh_put(&resp->fh);
- return 1;
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/state.h b/ANDROID_3.4.5/fs/nfsd/state.h
deleted file mode 100644
index 89ab137d..00000000
--- a/ANDROID_3.4.5/fs/nfsd/state.h
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright (c) 2001 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Kendrick Smith <kmsmith@umich.edu>
- * Andy Adamson <andros@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#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"
-
-typedef struct {
- u32 cl_boot;
- u32 cl_id;
-} clientid_t;
-
-typedef struct {
- clientid_t so_clid;
- u32 so_id;
-} stateid_opaque_t;
-
-typedef struct {
- u32 si_generation;
- stateid_opaque_t si_opaque;
-} stateid_t;
-
-#define STATEID_FMT "(%08x/%08x/%08x/%08x)"
-#define STATEID_VAL(s) \
- (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 {
- void *cb_op;
- struct nfs4_client *cb_clp;
- struct list_head cb_per_client;
- u32 cb_minorversion;
- struct rpc_message cb_msg;
- const struct rpc_call_ops *cb_ops;
- struct work_struct cb_work;
- 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_file *dl_file;
- u32 dl_type;
- time_t dl_time;
-/* For recall: */
- struct knfsd_fh dl_fh;
- int dl_retries;
- struct nfsd4_callback dl_recall;
-};
-
-/* client delegation callback info */
-struct nfs4_cb_conn {
- /* SETCLIENTID info */
- struct sockaddr_storage cb_addr;
- struct sockaddr_storage cb_saddr;
- size_t cb_addrlen;
- u32 cb_prog; /* used only in 4.0 case;
- per-session otherwise */
- u32 cb_ident; /* minorversion 0 only */
- 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 */
-#define NFSD_MAX_OPS_PER_COMPOUND 16
-/* Maximum session per slot cache size */
-#define NFSD_SLOT_CACHE_SIZE 1024
-/* Maximum number of NFSD_SLOT_CACHE_SIZE slots per session */
-#define NFSD_CACHE_SIZE_SLOTS_PER_SESSION 32
-#define NFSD_MAX_MEM_PER_SESSION \
- (NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE)
-
-struct nfsd4_slot {
- u32 sl_seqid;
- __be32 sl_status;
- u32 sl_datalen;
- u16 sl_opcnt;
-#define NFSD4_SLOT_INUSE (1 << 0)
-#define NFSD4_SLOT_CACHETHIS (1 << 1)
-#define NFSD4_SLOT_INITIALIZED (1 << 2)
- u8 sl_flags;
- char sl_data[];
-};
-
-struct nfsd4_channel_attrs {
- u32 headerpadsz;
- u32 maxreq_sz;
- u32 maxresp_sz;
- u32 maxresp_cached;
- u32 maxops;
- u32 maxreqs;
- u32 nr_rdma_attrs;
- u32 rdma_attrs;
-};
-
-struct nfsd4_create_session {
- clientid_t clientid;
- struct nfs4_sessionid sessionid;
- u32 seqid;
- u32 flags;
- struct nfsd4_channel_attrs fore_channel;
- struct nfsd4_channel_attrs back_channel;
- u32 callback_prog;
- u32 uid;
- u32 gid;
-};
-
-struct nfsd4_bind_conn_to_session {
- struct nfs4_sessionid sessionid;
- u32 dir;
-};
-
-/* The single slot clientid cache structure */
-struct nfsd4_clid_slot {
- u32 sl_seqid;
- __be32 sl_status;
- struct nfsd4_create_session sl_cr_ses;
-};
-
-struct nfsd4_conn {
- struct list_head cn_persession;
- struct svc_xprt *cn_xprt;
- struct svc_xpt_user cn_xpt_user;
- struct nfsd4_session *cn_session;
-/* CDFC4_FORE, CDFC4_BACK: */
- unsigned char cn_flags;
-};
-
-struct nfsd4_session {
- struct kref se_ref;
- struct list_head se_hash; /* hash by sessionid */
- struct list_head se_perclnt;
- u32 se_flags;
- struct nfs4_client *se_client;
- struct nfs4_sessionid se_sessionid;
- struct nfsd4_channel_attrs se_fchannel;
- struct nfsd4_channel_attrs se_bchannel;
- struct list_head se_conns;
- u32 se_cb_prog;
- u32 se_cb_seq_nr;
- struct nfsd4_slot *se_slots[]; /* forward channel slots */
-};
-
-extern void nfsd4_put_session(struct nfsd4_session *ses);
-
-/* formatted contents of nfs4_sessionid */
-struct nfsd4_sessionid {
- clientid_t clientid;
- u32 sequence;
- u32 reserved;
-};
-
-#define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */
-
-/*
- * struct nfs4_client - one per client. Clientids live here.
- * o Each nfs4_client is hashed by clientid.
- *
- * o Each nfs4_clients is also hashed by name
- * (the opaque quantity initially sent by the client to identify itself).
- *
- * o cl_perclient list is used to ensure no dangling stateowner references
- * when we expire the nfs4_client
- */
-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 */
- char cl_recdir[HEXDIR_LEN]; /* recovery dir */
- nfs4_verifier cl_verifier; /* generated by client */
- time_t cl_time; /* time of last lease renewal */
- struct sockaddr_storage cl_addr; /* client ipaddress */
- u32 cl_flavor; /* setclientid pseudoflavor */
- char *cl_principal; /* setclientid principal name */
- struct svc_cred cl_cred; /* setclientid principal */
- clientid_t cl_clientid; /* generated by server */
- nfs4_verifier cl_confirm; /* generated by server */
- u32 cl_minorversion;
-
- /* for v4.0 and v4.1 callbacks: */
- struct nfs4_cb_conn cl_cb_conn;
-#define NFSD4_CLIENT_CB_UPDATE (0)
-#define NFSD4_CLIENT_CB_KILL (1)
-#define NFSD4_CLIENT_STABLE (2) /* client on stable storage */
-#define NFSD4_CLIENT_RECLAIM_COMPLETE (3) /* reclaim_complete done */
-#define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \
- 1 << NFSD4_CLIENT_CB_KILL)
- unsigned long cl_flags;
- struct rpc_clnt *cl_cb_client;
- u32 cl_cb_ident;
-#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;
- struct list_head cl_callbacks; /* list of in-progress callbacks */
-
- /* for all client information that callback code might need: */
- spinlock_t cl_lock;
-
- /* for nfs41 */
- struct list_head cl_sessions;
- struct nfsd4_clid_slot cl_cs_slot; /* create_session slot */
- u32 cl_exchange_flags;
- /* number of rpc's in progress over an associated session: */
- atomic_t cl_refcount;
-
- /* for nfs41 callbacks */
- /* We currently support a single back channel with a single slot */
- unsigned long cl_cb_slot_busy;
- struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */
- /* wait here for slots */
-};
-
-static inline void
-mark_client_expired(struct nfs4_client *clp)
-{
- clp->cl_time = 0;
-}
-
-static inline bool
-is_client_expired(struct nfs4_client *clp)
-{
- return clp->cl_time == 0;
-}
-
-/* struct nfs4_client_reset
- * one per old client. Populates reset_str_hashtbl. Filled from conf_id_hashtbl
- * upon lease reset, or from upcall to state_daemon (to read in state
- * from non-volitile storage) upon reboot.
- */
-struct nfs4_client_reclaim {
- struct list_head cr_strhash; /* hash by cr_name */
- char cr_recdir[HEXDIR_LEN]; /* recover dir */
-};
-
-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:
- * The OPEN response, typically the largest, requires
- * 4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) + 8(verifier) +
- * 4(deleg. type) + 8(deleg. stateid) + 4(deleg. recall flag) +
- * 20(deleg. space limit) + ~32(deleg. ace) = 112 bytes
- */
-
-#define NFSD4_REPLAY_ISIZE 112
-
-/*
- * Replay buffer, where the result of the last seqid-mutating operation
- * is cached.
- */
-struct nfs4_replay {
- __be32 rp_status;
- unsigned int rp_buflen;
- char *rp_buf;
- struct knfsd_fh rp_openfh;
- char rp_ibuf[NFSD4_REPLAY_ISIZE];
-};
-
-struct nfs4_stateowner {
- struct list_head so_strhash; /* hash by op_name */
- struct list_head so_stateids;
- 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 */
- 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_owner_ino_hash; /* hash by owner,file */
- 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
-* share_acces, share_deny on the file.
-*/
-struct nfs4_file {
- atomic_t fi_ref;
- struct list_head fi_hash; /* hash by "struct inode *" */
- struct list_head fi_stateids;
- struct list_head fi_delegations;
- /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
- struct file * fi_fds[3];
- /*
- * 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;
- bool fi_had_conflict;
-};
-
-/* XXX: for first cut may fall back on returning file that doesn't work
- * at all? */
-static inline struct file *find_writeable_file(struct nfs4_file *f)
-{
- if (f->fi_fds[O_WRONLY])
- return f->fi_fds[O_WRONLY];
- return f->fi_fds[O_RDWR];
-}
-
-static inline struct file *find_readable_file(struct nfs4_file *f)
-{
- if (f->fi_fds[O_RDONLY])
- return f->fi_fds[O_RDONLY];
- return f->fi_fds[O_RDWR];
-}
-
-static inline struct file *find_any_file(struct nfs4_file *f)
-{
- if (f->fi_fds[O_RDWR])
- return f->fi_fds[O_RDWR];
- else if (f->fi_fds[O_WRONLY])
- return f->fi_fds[O_WRONLY];
- else
- return f->fi_fds[O_RDONLY];
-}
-
-/* "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;
- unsigned long st_access_bmap;
- unsigned long st_deny_bmap;
- 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 RD_STATE 0x00000010
-#define WR_STATE 0x00000020
-
-struct nfsd4_compound_state;
-
-extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
- stateid_t *stateid, int flags, struct file **filp);
-extern void nfs4_lock_state(void);
-extern void nfs4_unlock_state(void);
-extern int nfs4_in_grace(void);
-extern void nfs4_release_reclaim(void);
-extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp);
-extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
-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);
-extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
-extern void nfsd4_do_callback_rpc(struct work_struct *);
-extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
-extern int nfsd4_create_callback_queue(void);
-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 int nfs4_client_to_reclaim(const char *name);
-extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
-extern void release_session_client(struct nfsd4_session *);
-extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
-extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
-
-/* nfs4recover operations */
-extern int nfsd4_client_tracking_init(struct net *net);
-extern void nfsd4_client_tracking_exit(struct net *net);
-extern void nfsd4_client_record_create(struct nfs4_client *clp);
-extern void nfsd4_client_record_remove(struct nfs4_client *clp);
-extern int nfsd4_client_record_check(struct nfs4_client *clp);
-extern void nfsd4_record_grace_done(struct net *net, time_t boot_time);
-#endif /* NFSD4_STATE_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/stats.c b/ANDROID_3.4.5/fs/nfsd/stats.c
deleted file mode 100644
index 6d4521fe..00000000
--- a/ANDROID_3.4.5/fs/nfsd/stats.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * procfs-based user access to knfsd statistics
- *
- * /proc/net/rpc/nfsd
- *
- * Format:
- * rc <hits> <misses> <nocache>
- * Statistsics for the reply cache
- * fh <stale> <total-lookups> <anonlookups> <dir-not-in-dcache> <nondir-not-in-dcache>
- * statistics for filehandle lookup
- * io <bytes-read> <bytes-written>
- * statistics for IO throughput
- * th <threads> <fullcnt> <10%-20%> <20%-30%> ... <90%-100%> <100%>
- * time (seconds) when nfsd thread usage above thresholds
- * and number of times that all threads were in use
- * ra cache-size <10% <20% <30% ... <100% not-found
- * number of times that read-ahead entry was found that deep in
- * the cache.
- * plus generic RPC stats (see net/sunrpc/stats.c)
- *
- * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/sunrpc/stats.h>
-#include <linux/nfsd/stats.h>
-#include <net/net_namespace.h>
-
-#include "nfsd.h"
-
-struct nfsd_stats nfsdstats;
-struct svc_stat nfsd_svcstats = {
- .program = &nfsd_program,
-};
-
-static int nfsd_proc_show(struct seq_file *seq, void *v)
-{
- int i;
-
- seq_printf(seq, "rc %u %u %u\nfh %u %u %u %u %u\nio %u %u\n",
- nfsdstats.rchits,
- nfsdstats.rcmisses,
- nfsdstats.rcnocache,
- nfsdstats.fh_stale,
- nfsdstats.fh_lookup,
- nfsdstats.fh_anon,
- nfsdstats.fh_nocache_dir,
- nfsdstats.fh_nocache_nondir,
- nfsdstats.io_read,
- nfsdstats.io_write);
- /* thread usage: */
- seq_printf(seq, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
- for (i=0; i<10; i++) {
- unsigned int jifs = nfsdstats.th_usage[i];
- unsigned int sec = jifs / HZ, msec = (jifs % HZ)*1000/HZ;
- seq_printf(seq, " %u.%03u", sec, msec);
- }
-
- /* newline and ra-cache */
- seq_printf(seq, "\nra %u", nfsdstats.ra_size);
- for (i=0; i<11; i++)
- seq_printf(seq, " %u", nfsdstats.ra_depth[i]);
- seq_putc(seq, '\n');
-
- /* show my rpc info */
- svc_seq_show(seq, &nfsd_svcstats);
-
-#ifdef CONFIG_NFSD_V4
- /* Show count for individual nfsv4 operations */
- /* Writing operation numbers 0 1 2 also for maintaining uniformity */
- seq_printf(seq,"proc4ops %u", LAST_NFS4_OP + 1);
- for (i = 0; i <= LAST_NFS4_OP; i++)
- seq_printf(seq, " %u", nfsdstats.nfs4_opcount[i]);
-
- seq_putc(seq, '\n');
-#endif
-
- return 0;
-}
-
-static int nfsd_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, nfsd_proc_show, NULL);
-}
-
-static const struct file_operations nfsd_proc_fops = {
- .owner = THIS_MODULE,
- .open = nfsd_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-void
-nfsd_stat_init(void)
-{
- svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops);
-}
-
-void
-nfsd_stat_shutdown(void)
-{
- svc_proc_unregister(&init_net, "nfsd");
-}
diff --git a/ANDROID_3.4.5/fs/nfsd/vfs.c b/ANDROID_3.4.5/fs/nfsd/vfs.c
deleted file mode 100644
index 56866615..00000000
--- a/ANDROID_3.4.5/fs/nfsd/vfs.c
+++ /dev/null
@@ -1,2318 +0,0 @@
-/*
- * File operations used by nfsd. Some of these have been ripped from
- * other parts of the kernel because they weren't exported, others
- * are partial duplicates with added or changed functionality.
- *
- * Note that several functions dget() the dentry upon which they want
- * to act, most notably those that create directory entries. Response
- * dentry's are dput()'d if necessary in the release callback.
- * So if you notice code paths that apparently fail to dput() the
- * dentry, don't worry--they have been taken care of.
- *
- * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de>
- * Zerocpy NFS support (C) 2002 Hirokazu Takahashi <taka@valinux.co.jp>
- */
-
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/splice.h>
-#include <linux/fcntl.h>
-#include <linux/namei.h>
-#include <linux/delay.h>
-#include <linux/fsnotify.h>
-#include <linux/posix_acl_xattr.h>
-#include <linux/xattr.h>
-#include <linux/jhash.h>
-#include <linux/ima.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-#include <linux/exportfs.h>
-#include <linux/writeback.h>
-
-#ifdef CONFIG_NFSD_V3
-#include "xdr3.h"
-#endif /* CONFIG_NFSD_V3 */
-
-#ifdef CONFIG_NFSD_V4
-#include "acl.h"
-#include "idmap.h"
-#endif /* CONFIG_NFSD_V4 */
-
-#include "nfsd.h"
-#include "vfs.h"
-
-#define NFSDDBG_FACILITY NFSDDBG_FILEOP
-
-
-/*
- * This is a cache of readahead params that help us choose the proper
- * readahead strategy. Initially, we set all readahead parameters to 0
- * and let the VFS handle things.
- * If you increase the number of cached files very much, you'll need to
- * add a hash table here.
- */
-struct raparms {
- struct raparms *p_next;
- unsigned int p_count;
- ino_t p_ino;
- dev_t p_dev;
- int p_set;
- struct file_ra_state p_ra;
- unsigned int p_hindex;
-};
-
-struct raparm_hbucket {
- struct raparms *pb_head;
- spinlock_t pb_lock;
-} ____cacheline_aligned_in_smp;
-
-#define RAPARM_HASH_BITS 4
-#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS)
-#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
-static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
-
-/*
- * Called from nfsd_lookup and encode_dirent. Check if we have crossed
- * a mount point.
- * Returns -EAGAIN or -ETIMEDOUT leaving *dpp and *expp unchanged,
- * or nfs_ok having possibly changed *dpp and *expp
- */
-int
-nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
- struct svc_export **expp)
-{
- struct svc_export *exp = *expp, *exp2 = NULL;
- struct dentry *dentry = *dpp;
- struct path path = {.mnt = mntget(exp->ex_path.mnt),
- .dentry = dget(dentry)};
- int err = 0;
-
- err = follow_down(&path);
- if (err < 0)
- goto out;
-
- exp2 = rqst_exp_get_by_name(rqstp, &path);
- if (IS_ERR(exp2)) {
- err = PTR_ERR(exp2);
- /*
- * We normally allow NFS clients to continue
- * "underneath" a mountpoint that is not exported.
- * The exception is V4ROOT, where no traversal is ever
- * allowed without an explicit export of the new
- * directory.
- */
- if (err == -ENOENT && !(exp->ex_flags & NFSEXP_V4ROOT))
- err = 0;
- path_put(&path);
- goto out;
- }
- if (nfsd_v4client(rqstp) ||
- (exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
- /* successfully crossed mount point */
- /*
- * This is subtle: path.dentry is *not* on path.mnt
- * at this point. The only reason we are safe is that
- * original mnt is pinned down by exp, so we should
- * put path *before* putting exp
- */
- *dpp = path.dentry;
- path.dentry = dentry;
- *expp = exp2;
- exp2 = exp;
- }
- path_put(&path);
- exp_put(exp2);
-out:
- return err;
-}
-
-static void follow_to_parent(struct path *path)
-{
- struct dentry *dp;
-
- while (path->dentry == path->mnt->mnt_root && follow_up(path))
- ;
- dp = dget_parent(path->dentry);
- dput(path->dentry);
- path->dentry = dp;
-}
-
-static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, struct svc_export **exp, struct dentry **dentryp)
-{
- struct svc_export *exp2;
- struct path path = {.mnt = mntget((*exp)->ex_path.mnt),
- .dentry = dget(dparent)};
-
- follow_to_parent(&path);
-
- exp2 = rqst_exp_parent(rqstp, &path);
- if (PTR_ERR(exp2) == -ENOENT) {
- *dentryp = dget(dparent);
- } else if (IS_ERR(exp2)) {
- path_put(&path);
- return PTR_ERR(exp2);
- } else {
- *dentryp = dget(path.dentry);
- exp_put(*exp);
- *exp = exp2;
- }
- path_put(&path);
- return 0;
-}
-
-/*
- * For nfsd purposes, we treat V4ROOT exports as though there was an
- * export at *every* directory.
- */
-int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp)
-{
- if (d_mountpoint(dentry))
- return 1;
- if (nfsd4_is_junction(dentry))
- return 1;
- if (!(exp->ex_flags & NFSEXP_V4ROOT))
- return 0;
- return dentry->d_inode != NULL;
-}
-
-__be32
-nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
- const char *name, unsigned int len,
- struct svc_export **exp_ret, struct dentry **dentry_ret)
-{
- struct svc_export *exp;
- struct dentry *dparent;
- struct dentry *dentry;
- int host_err;
-
- dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
-
- dparent = fhp->fh_dentry;
- exp = fhp->fh_export;
- exp_get(exp);
-
- /* Lookup the name, but don't follow links */
- if (isdotent(name, len)) {
- if (len==1)
- dentry = dget(dparent);
- else if (dparent != exp->ex_path.dentry)
- dentry = dget_parent(dparent);
- else if (!EX_NOHIDE(exp) && !nfsd_v4client(rqstp))
- dentry = dget(dparent); /* .. == . just like at / */
- else {
- /* checking mountpoint crossing is very different when stepping up */
- host_err = nfsd_lookup_parent(rqstp, dparent, &exp, &dentry);
- if (host_err)
- goto out_nfserr;
- }
- } else {
- fh_lock(fhp);
- dentry = lookup_one_len(name, dparent, len);
- host_err = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto out_nfserr;
- /*
- * check if we have crossed a mount point ...
- */
- if (nfsd_mountpoint(dentry, exp)) {
- if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
- dput(dentry);
- goto out_nfserr;
- }
- }
- }
- *dentry_ret = dentry;
- *exp_ret = exp;
- return 0;
-
-out_nfserr:
- exp_put(exp);
- return nfserrno(host_err);
-}
-
-/*
- * Look up one component of a pathname.
- * N.B. After this call _both_ fhp and resfh need an fh_put
- *
- * If the lookup would cross a mountpoint, and the mounted filesystem
- * is exported to the client with NFSEXP_NOHIDE, then the lookup is
- * accepted as it stands and the mounted directory is
- * returned. Otherwise the covered directory is returned.
- * NOTE: this mountpoint crossing is not supported properly by all
- * clients and is explicitly disallowed for NFSv3
- * NeilBrown <neilb@cse.unsw.edu.au>
- */
-__be32
-nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
- unsigned int len, struct svc_fh *resfh)
-{
- struct svc_export *exp;
- struct dentry *dentry;
- __be32 err;
-
- err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
- if (err)
- return err;
- err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
- if (err)
- return err;
- err = check_nfsd_access(exp, rqstp);
- if (err)
- goto out;
- /*
- * Note: we compose the file handle now, but as the
- * dentry may be negative, it may need to be updated.
- */
- err = fh_compose(resfh, exp, dentry, fhp);
- if (!err && !dentry->d_inode)
- err = nfserr_noent;
-out:
- dput(dentry);
- exp_put(exp);
- return err;
-}
-
-static int nfsd_break_lease(struct inode *inode)
-{
- if (!S_ISREG(inode->i_mode))
- return 0;
- return break_lease(inode, O_WRONLY | O_NONBLOCK);
-}
-
-/*
- * Commit metadata changes to stable storage.
- */
-static int
-commit_metadata(struct svc_fh *fhp)
-{
- struct inode *inode = fhp->fh_dentry->d_inode;
- const struct export_operations *export_ops = inode->i_sb->s_export_op;
-
- if (!EX_ISSYNC(fhp->fh_export))
- return 0;
-
- if (export_ops->commit_metadata)
- return export_ops->commit_metadata(inode);
- return sync_inode_metadata(inode, 1);
-}
-
-/*
- * Set various file attributes.
- * N.B. After this call fhp needs an fh_put
- */
-__be32
-nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
- int check_guard, time_t guardtime)
-{
- struct dentry *dentry;
- struct inode *inode;
- int accmode = NFSD_MAY_SATTR;
- umode_t ftype = 0;
- __be32 err;
- int host_err;
- int size_change = 0;
-
- if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
- accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
- if (iap->ia_valid & ATTR_SIZE)
- ftype = S_IFREG;
-
- /* Get inode */
- err = fh_verify(rqstp, fhp, ftype, accmode);
- if (err)
- goto out;
-
- dentry = fhp->fh_dentry;
- inode = dentry->d_inode;
-
- /* Ignore any mode updates on symlinks */
- if (S_ISLNK(inode->i_mode))
- iap->ia_valid &= ~ATTR_MODE;
-
- if (!iap->ia_valid)
- goto out;
-
- /*
- * NFSv2 does not differentiate between "set-[ac]time-to-now"
- * which only requires access, and "set-[ac]time-to-X" which
- * requires ownership.
- * So if it looks like it might be "set both to the same time which
- * is close to now", and if inode_change_ok fails, then we
- * convert to "set to now" instead of "set to explicit time"
- *
- * We only call inode_change_ok as the last test as technically
- * it is not an interface that we should be using. It is only
- * valid if the filesystem does not define it's own i_op->setattr.
- */
-#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
-#define MAX_TOUCH_TIME_ERROR (30*60)
- if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
- iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
- /*
- * Looks probable.
- *
- * Now just make sure time is in the right ballpark.
- * Solaris, at least, doesn't seem to care what the time
- * request is. We require it be within 30 minutes of now.
- */
- time_t delta = iap->ia_atime.tv_sec - get_seconds();
- if (delta < 0)
- delta = -delta;
- if (delta < MAX_TOUCH_TIME_ERROR &&
- inode_change_ok(inode, iap) != 0) {
- /*
- * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
- * This will cause notify_change to set these times
- * to "now"
- */
- iap->ia_valid &= ~BOTH_TIME_SET;
- }
- }
-
- /*
- * The size case is special.
- * It changes the file as well as the attributes.
- */
- if (iap->ia_valid & ATTR_SIZE) {
- if (iap->ia_size < inode->i_size) {
- err = nfsd_permission(rqstp, fhp->fh_export, dentry,
- NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE);
- if (err)
- goto out;
- }
-
- host_err = get_write_access(inode);
- if (host_err)
- goto out_nfserr;
-
- size_change = 1;
- host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
- if (host_err) {
- put_write_access(inode);
- goto out_nfserr;
- }
- }
-
- /* sanitize the mode change */
- if (iap->ia_valid & ATTR_MODE) {
- iap->ia_mode &= S_IALLUGO;
- iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
- }
-
- /* Revoke setuid/setgid on chown */
- if (!S_ISDIR(inode->i_mode) &&
- (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) ||
- ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid))) {
- iap->ia_valid |= ATTR_KILL_PRIV;
- if (iap->ia_valid & ATTR_MODE) {
- /* we're setting mode too, just clear the s*id bits */
- iap->ia_mode &= ~S_ISUID;
- if (iap->ia_mode & S_IXGRP)
- iap->ia_mode &= ~S_ISGID;
- } else {
- /* set ATTR_KILL_* bits and let VFS handle it */
- iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
- }
- }
-
- /* Change the attributes. */
-
- iap->ia_valid |= ATTR_CTIME;
-
- err = nfserr_notsync;
- if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
- host_err = nfsd_break_lease(inode);
- if (host_err)
- goto out_nfserr;
- fh_lock(fhp);
-
- host_err = notify_change(dentry, iap);
- err = nfserrno(host_err);
- fh_unlock(fhp);
- }
- if (size_change)
- put_write_access(inode);
- if (!err)
- commit_metadata(fhp);
-out:
- return err;
-
-out_nfserr:
- err = nfserrno(host_err);
- goto out;
-}
-
-#if defined(CONFIG_NFSD_V2_ACL) || \
- defined(CONFIG_NFSD_V3_ACL) || \
- defined(CONFIG_NFSD_V4)
-static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
-{
- ssize_t buflen;
- ssize_t ret;
-
- buflen = vfs_getxattr(dentry, key, NULL, 0);
- if (buflen <= 0)
- return buflen;
-
- *buf = kmalloc(buflen, GFP_KERNEL);
- if (!*buf)
- return -ENOMEM;
-
- ret = vfs_getxattr(dentry, key, *buf, buflen);
- if (ret < 0)
- kfree(*buf);
- return ret;
-}
-#endif
-
-#if defined(CONFIG_NFSD_V4)
-static int
-set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
-{
- int len;
- size_t buflen;
- char *buf = NULL;
- int error = 0;
-
- buflen = posix_acl_xattr_size(pacl->a_count);
- buf = kmalloc(buflen, GFP_KERNEL);
- error = -ENOMEM;
- if (buf == NULL)
- goto out;
-
- len = posix_acl_to_xattr(pacl, buf, buflen);
- if (len < 0) {
- error = len;
- goto out;
- }
-
- error = vfs_setxattr(dentry, key, buf, len, 0);
-out:
- kfree(buf);
- return error;
-}
-
-__be32
-nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct nfs4_acl *acl)
-{
- __be32 error;
- int host_error;
- struct dentry *dentry;
- struct inode *inode;
- struct posix_acl *pacl = NULL, *dpacl = NULL;
- unsigned int flags = 0;
-
- /* Get inode */
- error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
- if (error)
- return error;
-
- dentry = fhp->fh_dentry;
- inode = dentry->d_inode;
- if (S_ISDIR(inode->i_mode))
- flags = NFS4_ACL_DIR;
-
- host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
- if (host_error == -EINVAL) {
- return nfserr_attrnotsupp;
- } else if (host_error < 0)
- goto out_nfserr;
-
- host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
- if (host_error < 0)
- goto out_release;
-
- if (S_ISDIR(inode->i_mode))
- host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
-
-out_release:
- posix_acl_release(pacl);
- posix_acl_release(dpacl);
-out_nfserr:
- if (host_error == -EOPNOTSUPP)
- return nfserr_attrnotsupp;
- else
- return nfserrno(host_error);
-}
-
-static struct posix_acl *
-_get_posix_acl(struct dentry *dentry, char *key)
-{
- void *buf = NULL;
- struct posix_acl *pacl = NULL;
- int buflen;
-
- buflen = nfsd_getxattr(dentry, key, &buf);
- if (!buflen)
- buflen = -ENODATA;
- if (buflen <= 0)
- return ERR_PTR(buflen);
-
- pacl = posix_acl_from_xattr(buf, buflen);
- kfree(buf);
- return pacl;
-}
-
-int
-nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl)
-{
- struct inode *inode = dentry->d_inode;
- int error = 0;
- struct posix_acl *pacl = NULL, *dpacl = NULL;
- unsigned int flags = 0;
-
- pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS);
- if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA)
- pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
- if (IS_ERR(pacl)) {
- error = PTR_ERR(pacl);
- pacl = NULL;
- goto out;
- }
-
- if (S_ISDIR(inode->i_mode)) {
- dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT);
- if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA)
- dpacl = NULL;
- else if (IS_ERR(dpacl)) {
- error = PTR_ERR(dpacl);
- dpacl = NULL;
- goto out;
- }
- flags = NFS4_ACL_DIR;
- }
-
- *acl = nfs4_acl_posix_to_nfsv4(pacl, dpacl, flags);
- if (IS_ERR(*acl)) {
- error = PTR_ERR(*acl);
- *acl = NULL;
- }
- out:
- posix_acl_release(pacl);
- posix_acl_release(dpacl);
- return error;
-}
-
-/*
- * NFS junction information is stored in an extended attribute.
- */
-#define NFSD_JUNCTION_XATTR_NAME XATTR_TRUSTED_PREFIX "junction.nfs"
-
-/**
- * nfsd4_is_junction - Test if an object could be an NFS junction
- *
- * @dentry: object to test
- *
- * Returns 1 if "dentry" appears to contain NFS junction information.
- * Otherwise 0 is returned.
- */
-int nfsd4_is_junction(struct dentry *dentry)
-{
- struct inode *inode = dentry->d_inode;
-
- if (inode == NULL)
- return 0;
- if (inode->i_mode & S_IXUGO)
- return 0;
- if (!(inode->i_mode & S_ISVTX))
- return 0;
- if (vfs_getxattr(dentry, NFSD_JUNCTION_XATTR_NAME, NULL, 0) <= 0)
- return 0;
- return 1;
-}
-#endif /* defined(CONFIG_NFSD_V4) */
-
-#ifdef CONFIG_NFSD_V3
-/*
- * Check server access rights to a file system object
- */
-struct accessmap {
- u32 access;
- int how;
-};
-static struct accessmap nfs3_regaccess[] = {
- { NFS3_ACCESS_READ, NFSD_MAY_READ },
- { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC },
- { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_TRUNC },
- { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE },
-
- { 0, 0 }
-};
-
-static struct accessmap nfs3_diraccess[] = {
- { NFS3_ACCESS_READ, NFSD_MAY_READ },
- { NFS3_ACCESS_LOOKUP, NFSD_MAY_EXEC },
- { NFS3_ACCESS_MODIFY, NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC},
- { NFS3_ACCESS_EXTEND, NFSD_MAY_EXEC|NFSD_MAY_WRITE },
- { NFS3_ACCESS_DELETE, NFSD_MAY_REMOVE },
-
- { 0, 0 }
-};
-
-static struct accessmap nfs3_anyaccess[] = {
- /* Some clients - Solaris 2.6 at least, make an access call
- * to the server to check for access for things like /dev/null
- * (which really, the server doesn't care about). So
- * We provide simple access checking for them, looking
- * mainly at mode bits, and we make sure to ignore read-only
- * filesystem checks
- */
- { NFS3_ACCESS_READ, NFSD_MAY_READ },
- { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC },
- { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS },
- { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS },
-
- { 0, 0 }
-};
-
-__be32
-nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported)
-{
- struct accessmap *map;
- struct svc_export *export;
- struct dentry *dentry;
- u32 query, result = 0, sresult = 0;
- __be32 error;
-
- error = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
- if (error)
- goto out;
-
- export = fhp->fh_export;
- dentry = fhp->fh_dentry;
-
- if (S_ISREG(dentry->d_inode->i_mode))
- map = nfs3_regaccess;
- else if (S_ISDIR(dentry->d_inode->i_mode))
- map = nfs3_diraccess;
- else
- map = nfs3_anyaccess;
-
-
- query = *access;
- for (; map->access; map++) {
- if (map->access & query) {
- __be32 err2;
-
- sresult |= map->access;
-
- err2 = nfsd_permission(rqstp, export, dentry, map->how);
- switch (err2) {
- case nfs_ok:
- result |= map->access;
- break;
-
- /* the following error codes just mean the access was not allowed,
- * rather than an error occurred */
- case nfserr_rofs:
- case nfserr_acces:
- case nfserr_perm:
- /* simply don't "or" in the access bit. */
- break;
- default:
- error = err2;
- goto out;
- }
- }
- }
- *access = result;
- if (supported)
- *supported = sresult;
-
- out:
- return error;
-}
-#endif /* CONFIG_NFSD_V3 */
-
-static int nfsd_open_break_lease(struct inode *inode, int access)
-{
- unsigned int mode;
-
- if (access & NFSD_MAY_NOT_BREAK_LEASE)
- return 0;
- mode = (access & NFSD_MAY_WRITE) ? O_WRONLY : O_RDONLY;
- return break_lease(inode, mode | O_NONBLOCK);
-}
-
-/*
- * Open an existing file or directory.
- * The may_flags argument indicates the type of open (read/write/lock)
- * and additional flags.
- * N.B. After this call fhp needs an fh_put
- */
-__be32
-nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
- int may_flags, struct file **filp)
-{
- struct dentry *dentry;
- struct inode *inode;
- int flags = O_RDONLY|O_LARGEFILE;
- __be32 err;
- int host_err = 0;
-
- validate_process_creds();
-
- /*
- * If we get here, then the client has already done an "open",
- * and (hopefully) checked permission - so allow OWNER_OVERRIDE
- * in case a chmod has now revoked permission.
- */
- err = fh_verify(rqstp, fhp, type, may_flags | NFSD_MAY_OWNER_OVERRIDE);
- if (err)
- goto out;
-
- dentry = fhp->fh_dentry;
- inode = dentry->d_inode;
-
- /* Disallow write access to files with the append-only bit set
- * or any access when mandatory locking enabled
- */
- err = nfserr_perm;
- if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE))
- goto out;
- /*
- * We must ignore files (but only files) which might have mandatory
- * locks on them because there is no way to know if the accesser has
- * the lock.
- */
- if (S_ISREG((inode)->i_mode) && mandatory_lock(inode))
- goto out;
-
- if (!inode->i_fop)
- goto out;
-
- host_err = nfsd_open_break_lease(inode, may_flags);
- if (host_err) /* NOMEM or WOULDBLOCK */
- goto out_nfserr;
-
- if (may_flags & NFSD_MAY_WRITE) {
- if (may_flags & NFSD_MAY_READ)
- flags = O_RDWR|O_LARGEFILE;
- else
- flags = O_WRONLY|O_LARGEFILE;
- }
- *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
- flags, current_cred());
- if (IS_ERR(*filp))
- host_err = PTR_ERR(*filp);
- else {
- host_err = ima_file_check(*filp, may_flags);
-
- if (may_flags & NFSD_MAY_64BIT_COOKIE)
- (*filp)->f_mode |= FMODE_64BITHASH;
- else
- (*filp)->f_mode |= FMODE_32BITHASH;
- }
-
-out_nfserr:
- err = nfserrno(host_err);
-out:
- validate_process_creds();
- return err;
-}
-
-/*
- * Close a file.
- */
-void
-nfsd_close(struct file *filp)
-{
- fput(filp);
-}
-
-/*
- * Obtain the readahead parameters for the file
- * specified by (dev, ino).
- */
-
-static inline struct raparms *
-nfsd_get_raparms(dev_t dev, ino_t ino)
-{
- struct raparms *ra, **rap, **frap = NULL;
- int depth = 0;
- unsigned int hash;
- struct raparm_hbucket *rab;
-
- hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK;
- rab = &raparm_hash[hash];
-
- spin_lock(&rab->pb_lock);
- for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) {
- if (ra->p_ino == ino && ra->p_dev == dev)
- goto found;
- depth++;
- if (ra->p_count == 0)
- frap = rap;
- }
- depth = nfsdstats.ra_size;
- if (!frap) {
- spin_unlock(&rab->pb_lock);
- return NULL;
- }
- rap = frap;
- ra = *frap;
- ra->p_dev = dev;
- ra->p_ino = ino;
- ra->p_set = 0;
- ra->p_hindex = hash;
-found:
- if (rap != &rab->pb_head) {
- *rap = ra->p_next;
- ra->p_next = rab->pb_head;
- rab->pb_head = ra;
- }
- ra->p_count++;
- nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
- spin_unlock(&rab->pb_lock);
- return ra;
-}
-
-/*
- * Grab and keep cached pages associated with a file in the svc_rqst
- * so that they can be passed to the network sendmsg/sendpage routines
- * directly. They will be released after the sending has completed.
- */
-static int
-nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
- struct splice_desc *sd)
-{
- struct svc_rqst *rqstp = sd->u.data;
- struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
- struct page *page = buf->page;
- size_t size;
-
- size = sd->len;
-
- if (rqstp->rq_res.page_len == 0) {
- get_page(page);
- put_page(*pp);
- *pp = page;
- rqstp->rq_resused++;
- rqstp->rq_res.page_base = buf->offset;
- rqstp->rq_res.page_len = size;
- } else if (page != pp[-1]) {
- get_page(page);
- if (*pp)
- put_page(*pp);
- *pp = page;
- rqstp->rq_resused++;
- rqstp->rq_res.page_len += size;
- } else
- rqstp->rq_res.page_len += size;
-
- return size;
-}
-
-static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
- struct splice_desc *sd)
-{
- return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
-}
-
-static __be32
-nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
- loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
-{
- mm_segment_t oldfs;
- __be32 err;
- int host_err;
-
- err = nfserr_perm;
-
- if (file->f_op->splice_read && rqstp->rq_splice_ok) {
- struct splice_desc sd = {
- .len = 0,
- .total_len = *count,
- .pos = offset,
- .u.data = rqstp,
- };
-
- rqstp->rq_resused = 1;
- host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
- } else {
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
- set_fs(oldfs);
- }
-
- if (host_err >= 0) {
- nfsdstats.io_read += host_err;
- *count = host_err;
- err = 0;
- fsnotify_access(file);
- } else
- err = nfserrno(host_err);
- return err;
-}
-
-static void kill_suid(struct dentry *dentry)
-{
- struct iattr ia;
- ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
-
- mutex_lock(&dentry->d_inode->i_mutex);
- notify_change(dentry, &ia);
- mutex_unlock(&dentry->d_inode->i_mutex);
-}
-
-/*
- * Gathered writes: If another process is currently writing to the file,
- * there's a high chance this is another nfsd (triggered by a bulk write
- * from a client's biod). Rather than syncing the file with each write
- * request, we sleep for 10 msec.
- *
- * I don't know if this roughly approximates C. Juszak's idea of
- * gathered writes, but it's a nice and simple solution (IMHO), and it
- * seems to work:-)
- *
- * Note: we do this only in the NFSv2 case, since v3 and higher have a
- * better tool (separate unstable writes and commits) for solving this
- * problem.
- */
-static int wait_for_concurrent_writes(struct file *file)
-{
- struct inode *inode = file->f_path.dentry->d_inode;
- static ino_t last_ino;
- static dev_t last_dev;
- int err = 0;
-
- if (atomic_read(&inode->i_writecount) > 1
- || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) {
- dprintk("nfsd: write defer %d\n", task_pid_nr(current));
- msleep(10);
- dprintk("nfsd: write resume %d\n", task_pid_nr(current));
- }
-
- if (inode->i_state & I_DIRTY) {
- dprintk("nfsd: write sync %d\n", task_pid_nr(current));
- err = vfs_fsync(file, 0);
- }
- last_ino = inode->i_ino;
- last_dev = inode->i_sb->s_dev;
- return err;
-}
-
-static __be32
-nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
- loff_t offset, struct kvec *vec, int vlen,
- unsigned long *cnt, int *stablep)
-{
- struct svc_export *exp;
- struct dentry *dentry;
- struct inode *inode;
- mm_segment_t oldfs;
- __be32 err = 0;
- int host_err;
- int stable = *stablep;
- int use_wgather;
-
- dentry = file->f_path.dentry;
- inode = dentry->d_inode;
- exp = fhp->fh_export;
-
- /*
- * Request sync writes if
- * - the sync export option has been set, or
- * - the client requested O_SYNC behavior (NFSv3 feature).
- * - The file system doesn't support fsync().
- * When NFSv2 gathered writes have been configured for this volume,
- * flushing the data to disk is handled separately below.
- */
- use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp);
-
- if (!file->f_op->fsync) {/* COMMIT3 cannot work */
- stable = 2;
- *stablep = 2; /* FILE_SYNC */
- }
-
- if (!EX_ISSYNC(exp))
- stable = 0;
- if (stable && !use_wgather) {
- spin_lock(&file->f_lock);
- file->f_flags |= O_SYNC;
- spin_unlock(&file->f_lock);
- }
-
- /* Write the data. */
- oldfs = get_fs(); set_fs(KERNEL_DS);
- host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
- set_fs(oldfs);
- if (host_err < 0)
- goto out_nfserr;
- *cnt = host_err;
- nfsdstats.io_write += host_err;
- fsnotify_modify(file);
-
- /* clear setuid/setgid flag after write */
- if (inode->i_mode & (S_ISUID | S_ISGID))
- kill_suid(dentry);
-
- if (stable && use_wgather)
- host_err = wait_for_concurrent_writes(file);
-
-out_nfserr:
- dprintk("nfsd: write complete host_err=%d\n", host_err);
- if (host_err >= 0)
- err = 0;
- else
- err = nfserrno(host_err);
- return err;
-}
-
-/*
- * Read data from a file. count must contain the requested read count
- * on entry. On return, *count contains the number of bytes actually read.
- * N.B. After this call fhp needs an fh_put
- */
-__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
- loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
-{
- struct file *file;
- struct inode *inode;
- struct raparms *ra;
- __be32 err;
-
- err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
- if (err)
- return err;
-
- inode = file->f_path.dentry->d_inode;
-
- /* Get readahead parameters */
- ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
-
- if (ra && ra->p_set)
- file->f_ra = ra->p_ra;
-
- err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
-
- /* Write back readahead params */
- if (ra) {
- struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
- spin_lock(&rab->pb_lock);
- ra->p_ra = file->f_ra;
- ra->p_set = 1;
- ra->p_count--;
- spin_unlock(&rab->pb_lock);
- }
-
- nfsd_close(file);
- return err;
-}
-
-/* As above, but use the provided file descriptor. */
-__be32
-nfsd_read_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
- loff_t offset, struct kvec *vec, int vlen,
- unsigned long *count)
-{
- __be32 err;
-
- if (file) {
- err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
- NFSD_MAY_READ|NFSD_MAY_OWNER_OVERRIDE);
- if (err)
- goto out;
- err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
- } else /* Note file may still be NULL in NFSv4 special stateid case: */
- err = nfsd_read(rqstp, fhp, offset, vec, vlen, count);
-out:
- return err;
-}
-
-/*
- * Write data to a file.
- * The stable flag requests synchronous writes.
- * N.B. After this call fhp needs an fh_put
- */
-__be32
-nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
- loff_t offset, struct kvec *vec, int vlen, unsigned long *cnt,
- int *stablep)
-{
- __be32 err = 0;
-
- if (file) {
- err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
- NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE);
- if (err)
- goto out;
- err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt,
- stablep);
- } else {
- err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
- if (err)
- goto out;
-
- if (cnt)
- err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen,
- cnt, stablep);
- nfsd_close(file);
- }
-out:
- return err;
-}
-
-#ifdef CONFIG_NFSD_V3
-/*
- * Commit all pending writes to stable storage.
- *
- * Note: we only guarantee that data that lies within the range specified
- * by the 'offset' and 'count' parameters will be synced.
- *
- * Unfortunately we cannot lock the file to make sure we return full WCC
- * data to the client, as locking happens lower down in the filesystem.
- */
-__be32
-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
- loff_t offset, unsigned long count)
-{
- struct file *file;
- loff_t end = LLONG_MAX;
- __be32 err = nfserr_inval;
-
- if (offset < 0)
- goto out;
- if (count != 0) {
- end = offset + (loff_t)count - 1;
- if (end < offset)
- goto out;
- }
-
- err = nfsd_open(rqstp, fhp, S_IFREG,
- NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &file);
- if (err)
- goto out;
- if (EX_ISSYNC(fhp->fh_export)) {
- int err2 = vfs_fsync_range(file, offset, end, 0);
-
- if (err2 != -EINVAL)
- err = nfserrno(err2);
- else
- err = nfserr_notsupp;
- }
-
- nfsd_close(file);
-out:
- return err;
-}
-#endif /* CONFIG_NFSD_V3 */
-
-static __be32
-nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
- struct iattr *iap)
-{
- /*
- * Mode has already been set earlier in create:
- */
- iap->ia_valid &= ~ATTR_MODE;
- /*
- * Setting uid/gid works only for root. Irix appears to
- * send along the gid on create when it tries to implement
- * setgid directories via NFS:
- */
- if (current_fsuid() != 0)
- iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
- if (iap->ia_valid)
- return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
- return 0;
-}
-
-/* HPUX client sometimes creates a file in mode 000, and sets size to 0.
- * setting size to 0 may fail for some specific file systems by the permission
- * checking which requires WRITE permission but the mode is 000.
- * we ignore the resizing(to 0) on the just new created file, since the size is
- * 0 after file created.
- *
- * call this only after vfs_create() is called.
- * */
-static void
-nfsd_check_ignore_resizing(struct iattr *iap)
-{
- if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
- iap->ia_valid &= ~ATTR_SIZE;
-}
-
-/*
- * Create a file (regular, directory, device, fifo); UNIX sockets
- * not yet implemented.
- * If the response fh has been verified, the parent directory should
- * already be locked. Note that the parent directory is left locked.
- *
- * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
- */
-__be32
-nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
- char *fname, int flen, struct iattr *iap,
- int type, dev_t rdev, struct svc_fh *resfhp)
-{
- struct dentry *dentry, *dchild = NULL;
- struct inode *dirp;
- __be32 err;
- __be32 err2;
- int host_err;
-
- err = nfserr_perm;
- if (!flen)
- goto out;
- err = nfserr_exist;
- if (isdotent(fname, flen))
- goto out;
-
- err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
- if (err)
- goto out;
-
- dentry = fhp->fh_dentry;
- dirp = dentry->d_inode;
-
- err = nfserr_notdir;
- if (!dirp->i_op->lookup)
- goto out;
- /*
- * Check whether the response file handle has been verified yet.
- * If it has, the parent directory should already be locked.
- */
- if (!resfhp->fh_dentry) {
- /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
- fh_lock_nested(fhp, I_MUTEX_PARENT);
- dchild = lookup_one_len(fname, dentry, flen);
- host_err = PTR_ERR(dchild);
- if (IS_ERR(dchild))
- goto out_nfserr;
- err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
- if (err)
- goto out;
- } else {
- /* called from nfsd_proc_create */
- dchild = dget(resfhp->fh_dentry);
- if (!fhp->fh_locked) {
- /* not actually possible */
- printk(KERN_ERR
- "nfsd_create: parent %s/%s not locked!\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name);
- err = nfserr_io;
- goto out;
- }
- }
- /*
- * Make sure the child dentry is still negative ...
- */
- err = nfserr_exist;
- if (dchild->d_inode) {
- dprintk("nfsd_create: dentry %s/%s not negative!\n",
- dentry->d_name.name, dchild->d_name.name);
- goto out;
- }
-
- if (!(iap->ia_valid & ATTR_MODE))
- iap->ia_mode = 0;
- iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;
-
- err = nfserr_inval;
- if (!S_ISREG(type) && !S_ISDIR(type) && !special_file(type)) {
- printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n",
- type);
- goto out;
- }
-
- host_err = fh_want_write(fhp);
- if (host_err)
- goto out_nfserr;
-
- /*
- * Get the dir op function pointer.
- */
- err = 0;
- switch (type) {
- case S_IFREG:
- host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
- if (!host_err)
- nfsd_check_ignore_resizing(iap);
- break;
- case S_IFDIR:
- host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
- break;
- case S_IFCHR:
- case S_IFBLK:
- case S_IFIFO:
- case S_IFSOCK:
- host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
- break;
- }
- if (host_err < 0) {
- fh_drop_write(fhp);
- goto out_nfserr;
- }
-
- err = nfsd_create_setattr(rqstp, resfhp, iap);
-
- /*
- * nfsd_setattr already committed the child. Transactional filesystems
- * had a chance to commit changes for both parent and child
- * simultaneously making the following commit_metadata a noop.
- */
- err2 = nfserrno(commit_metadata(fhp));
- if (err2)
- err = err2;
- fh_drop_write(fhp);
- /*
- * Update the file handle to get the new inode info.
- */
- if (!err)
- err = fh_update(resfhp);
-out:
- if (dchild && !IS_ERR(dchild))
- dput(dchild);
- return err;
-
-out_nfserr:
- err = nfserrno(host_err);
- goto out;
-}
-
-#ifdef CONFIG_NFSD_V3
-
-static inline int nfsd_create_is_exclusive(int createmode)
-{
- return createmode == NFS3_CREATE_EXCLUSIVE
- || createmode == NFS4_CREATE_EXCLUSIVE4_1;
-}
-
-/*
- * NFSv3 and NFSv4 version of nfsd_create
- */
-__be32
-do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
- char *fname, int flen, struct iattr *iap,
- struct svc_fh *resfhp, int createmode, u32 *verifier,
- bool *truncp, bool *created)
-{
- struct dentry *dentry, *dchild = NULL;
- struct inode *dirp;
- __be32 err;
- int host_err;
- __u32 v_mtime=0, v_atime=0;
-
- err = nfserr_perm;
- if (!flen)
- goto out;
- err = nfserr_exist;
- if (isdotent(fname, flen))
- goto out;
- if (!(iap->ia_valid & ATTR_MODE))
- iap->ia_mode = 0;
- err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
- if (err)
- goto out;
-
- dentry = fhp->fh_dentry;
- dirp = dentry->d_inode;
-
- /* Get all the sanity checks out of the way before
- * we lock the parent. */
- err = nfserr_notdir;
- if (!dirp->i_op->lookup)
- goto out;
- fh_lock_nested(fhp, I_MUTEX_PARENT);
-
- /*
- * Compose the response file handle.
- */
- dchild = lookup_one_len(fname, dentry, flen);
- host_err = PTR_ERR(dchild);
- if (IS_ERR(dchild))
- goto out_nfserr;
-
- /* If file doesn't exist, check for permissions to create one */
- if (!dchild->d_inode) {
- err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
- if (err)
- goto out;
- }
-
- err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
- if (err)
- goto out;
-
- if (nfsd_create_is_exclusive(createmode)) {
- /* solaris7 gets confused (bugid 4218508) if these have
- * the high bit set, so just clear the high bits. If this is
- * ever changed to use different attrs for storing the
- * verifier, then do_open_lookup() will also need to be fixed
- * accordingly.
- */
- v_mtime = verifier[0]&0x7fffffff;
- v_atime = verifier[1]&0x7fffffff;
- }
-
- host_err = fh_want_write(fhp);
- if (host_err)
- goto out_nfserr;
- if (dchild->d_inode) {
- err = 0;
-
- switch (createmode) {
- case NFS3_CREATE_UNCHECKED:
- if (! S_ISREG(dchild->d_inode->i_mode))
- goto out;
- else if (truncp) {
- /* in nfsv4, we need to treat this case a little
- * differently. we don't want to truncate the
- * file now; this would be wrong if the OPEN
- * fails for some other reason. furthermore,
- * if the size is nonzero, we should ignore it
- * according to spec!
- */
- *truncp = (iap->ia_valid & ATTR_SIZE) && !iap->ia_size;
- }
- else {
- iap->ia_valid &= ATTR_SIZE;
- goto set_attr;
- }
- break;
- case NFS3_CREATE_EXCLUSIVE:
- if ( dchild->d_inode->i_mtime.tv_sec == v_mtime
- && dchild->d_inode->i_atime.tv_sec == v_atime
- && dchild->d_inode->i_size == 0 )
- break;
- case NFS4_CREATE_EXCLUSIVE4_1:
- if ( dchild->d_inode->i_mtime.tv_sec == v_mtime
- && dchild->d_inode->i_atime.tv_sec == v_atime
- && dchild->d_inode->i_size == 0 )
- goto set_attr;
- /* fallthru */
- case NFS3_CREATE_GUARDED:
- err = nfserr_exist;
- }
- fh_drop_write(fhp);
- goto out;
- }
-
- host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
- if (host_err < 0) {
- fh_drop_write(fhp);
- goto out_nfserr;
- }
- if (created)
- *created = 1;
-
- nfsd_check_ignore_resizing(iap);
-
- if (nfsd_create_is_exclusive(createmode)) {
- /* Cram the verifier into atime/mtime */
- iap->ia_valid = ATTR_MTIME|ATTR_ATIME
- | ATTR_MTIME_SET|ATTR_ATIME_SET;
- /* XXX someone who knows this better please fix it for nsec */
- iap->ia_mtime.tv_sec = v_mtime;
- iap->ia_atime.tv_sec = v_atime;
- iap->ia_mtime.tv_nsec = 0;
- iap->ia_atime.tv_nsec = 0;
- }
-
- set_attr:
- err = nfsd_create_setattr(rqstp, resfhp, iap);
-
- /*
- * nfsd_setattr already committed the child (and possibly also the parent).
- */
- if (!err)
- err = nfserrno(commit_metadata(fhp));
-
- fh_drop_write(fhp);
- /*
- * Update the filehandle to get the new inode info.
- */
- if (!err)
- err = fh_update(resfhp);
-
- out:
- fh_unlock(fhp);
- if (dchild && !IS_ERR(dchild))
- dput(dchild);
- return err;
-
- out_nfserr:
- err = nfserrno(host_err);
- goto out;
-}
-#endif /* CONFIG_NFSD_V3 */
-
-/*
- * Read a symlink. On entry, *lenp must contain the maximum path length that
- * fits into the buffer. On return, it contains the true length.
- * N.B. After this call fhp needs an fh_put
- */
-__be32
-nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
-{
- struct inode *inode;
- mm_segment_t oldfs;
- __be32 err;
- int host_err;
- struct path path;
-
- err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP);
- if (err)
- goto out;
-
- path.mnt = fhp->fh_export->ex_path.mnt;
- path.dentry = fhp->fh_dentry;
- inode = path.dentry->d_inode;
-
- err = nfserr_inval;
- if (!inode->i_op->readlink)
- goto out;
-
- touch_atime(&path);
- /* N.B. Why does this call need a get_fs()??
- * Remove the set_fs and watch the fireworks:-) --okir
- */
-
- oldfs = get_fs(); set_fs(KERNEL_DS);
- host_err = inode->i_op->readlink(path.dentry, buf, *lenp);
- set_fs(oldfs);
-
- if (host_err < 0)
- goto out_nfserr;
- *lenp = host_err;
- err = 0;
-out:
- return err;
-
-out_nfserr:
- err = nfserrno(host_err);
- goto out;
-}
-
-/*
- * Create a symlink and look up its inode
- * N.B. After this call _both_ fhp and resfhp need an fh_put
- */
-__be32
-nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
- char *fname, int flen,
- char *path, int plen,
- struct svc_fh *resfhp,
- struct iattr *iap)
-{
- struct dentry *dentry, *dnew;
- __be32 err, cerr;
- int host_err;
-
- err = nfserr_noent;
- if (!flen || !plen)
- goto out;
- err = nfserr_exist;
- if (isdotent(fname, flen))
- goto out;
-
- err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
- if (err)
- goto out;
- fh_lock(fhp);
- dentry = fhp->fh_dentry;
- dnew = lookup_one_len(fname, dentry, flen);
- host_err = PTR_ERR(dnew);
- if (IS_ERR(dnew))
- goto out_nfserr;
-
- host_err = fh_want_write(fhp);
- if (host_err)
- goto out_nfserr;
-
- if (unlikely(path[plen] != 0)) {
- char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
- if (path_alloced == NULL)
- host_err = -ENOMEM;
- else {
- strncpy(path_alloced, path, plen);
- path_alloced[plen] = 0;
- host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced);
- kfree(path_alloced);
- }
- } else
- host_err = vfs_symlink(dentry->d_inode, dnew, path);
- err = nfserrno(host_err);
- if (!err)
- err = nfserrno(commit_metadata(fhp));
- fh_unlock(fhp);
-
- fh_drop_write(fhp);
-
- cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
- dput(dnew);
- if (err==0) err = cerr;
-out:
- return err;
-
-out_nfserr:
- err = nfserrno(host_err);
- goto out;
-}
-
-/*
- * Create a hardlink
- * N.B. After this call _both_ ffhp and tfhp need an fh_put
- */
-__be32
-nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
- char *name, int len, struct svc_fh *tfhp)
-{
- struct dentry *ddir, *dnew, *dold;
- struct inode *dirp;
- __be32 err;
- int host_err;
-
- err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE);
- if (err)
- goto out;
- err = fh_verify(rqstp, tfhp, 0, NFSD_MAY_NOP);
- if (err)
- goto out;
- err = nfserr_isdir;
- if (S_ISDIR(tfhp->fh_dentry->d_inode->i_mode))
- goto out;
- err = nfserr_perm;
- if (!len)
- goto out;
- err = nfserr_exist;
- if (isdotent(name, len))
- goto out;
-
- fh_lock_nested(ffhp, I_MUTEX_PARENT);
- ddir = ffhp->fh_dentry;
- dirp = ddir->d_inode;
-
- dnew = lookup_one_len(name, ddir, len);
- host_err = PTR_ERR(dnew);
- if (IS_ERR(dnew))
- goto out_nfserr;
-
- dold = tfhp->fh_dentry;
-
- host_err = fh_want_write(tfhp);
- if (host_err) {
- err = nfserrno(host_err);
- goto out_dput;
- }
- err = nfserr_noent;
- if (!dold->d_inode)
- goto out_drop_write;
- host_err = nfsd_break_lease(dold->d_inode);
- if (host_err) {
- err = nfserrno(host_err);
- goto out_drop_write;
- }
- host_err = vfs_link(dold, dirp, dnew);
- if (!host_err) {
- err = nfserrno(commit_metadata(ffhp));
- if (!err)
- err = nfserrno(commit_metadata(tfhp));
- } else {
- if (host_err == -EXDEV && rqstp->rq_vers == 2)
- err = nfserr_acces;
- else
- err = nfserrno(host_err);
- }
-out_drop_write:
- fh_drop_write(tfhp);
-out_dput:
- dput(dnew);
-out_unlock:
- fh_unlock(ffhp);
-out:
- return err;
-
-out_nfserr:
- err = nfserrno(host_err);
- goto out_unlock;
-}
-
-/*
- * Rename a file
- * N.B. After this call _both_ ffhp and tfhp need an fh_put
- */
-__be32
-nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
- struct svc_fh *tfhp, char *tname, int tlen)
-{
- struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap;
- struct inode *fdir, *tdir;
- __be32 err;
- int host_err;
-
- err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_REMOVE);
- if (err)
- goto out;
- err = fh_verify(rqstp, tfhp, S_IFDIR, NFSD_MAY_CREATE);
- if (err)
- goto out;
-
- fdentry = ffhp->fh_dentry;
- fdir = fdentry->d_inode;
-
- tdentry = tfhp->fh_dentry;
- tdir = tdentry->d_inode;
-
- err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
- if (ffhp->fh_export != tfhp->fh_export)
- goto out;
-
- err = nfserr_perm;
- if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen))
- goto out;
-
- /* cannot use fh_lock as we need deadlock protective ordering
- * so do it by hand */
- trap = lock_rename(tdentry, fdentry);
- ffhp->fh_locked = tfhp->fh_locked = 1;
- fill_pre_wcc(ffhp);
- fill_pre_wcc(tfhp);
-
- odentry = lookup_one_len(fname, fdentry, flen);
- host_err = PTR_ERR(odentry);
- if (IS_ERR(odentry))
- goto out_nfserr;
-
- host_err = -ENOENT;
- if (!odentry->d_inode)
- goto out_dput_old;
- host_err = -EINVAL;
- if (odentry == trap)
- goto out_dput_old;
-
- ndentry = lookup_one_len(tname, tdentry, tlen);
- host_err = PTR_ERR(ndentry);
- if (IS_ERR(ndentry))
- goto out_dput_old;
- host_err = -ENOTEMPTY;
- if (ndentry == trap)
- goto out_dput_new;
-
- host_err = -EXDEV;
- if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt)
- goto out_dput_new;
- host_err = fh_want_write(ffhp);
- if (host_err)
- goto out_dput_new;
-
- 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;
- }
- host_err = vfs_rename(fdir, odentry, tdir, ndentry);
- if (!host_err) {
- host_err = commit_metadata(tfhp);
- if (!host_err)
- host_err = commit_metadata(ffhp);
- }
-out_drop_write:
- fh_drop_write(ffhp);
- out_dput_new:
- dput(ndentry);
- out_dput_old:
- dput(odentry);
- out_nfserr:
- err = nfserrno(host_err);
-
- /* we cannot reply on fh_unlock on the two filehandles,
- * as that would do the wrong thing if the two directories
- * were the same, so again we do it by hand
- */
- fill_post_wcc(ffhp);
- fill_post_wcc(tfhp);
- unlock_rename(tdentry, fdentry);
- ffhp->fh_locked = tfhp->fh_locked = 0;
-
-out:
- return err;
-}
-
-/*
- * Unlink a file or directory
- * N.B. After this call fhp needs an fh_put
- */
-__be32
-nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
- char *fname, int flen)
-{
- struct dentry *dentry, *rdentry;
- struct inode *dirp;
- __be32 err;
- int host_err;
-
- err = nfserr_acces;
- if (!flen || isdotent(fname, flen))
- goto out;
- err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_REMOVE);
- if (err)
- goto out;
-
- fh_lock_nested(fhp, I_MUTEX_PARENT);
- dentry = fhp->fh_dentry;
- dirp = dentry->d_inode;
-
- rdentry = lookup_one_len(fname, dentry, flen);
- host_err = PTR_ERR(rdentry);
- if (IS_ERR(rdentry))
- goto out_nfserr;
-
- if (!rdentry->d_inode) {
- dput(rdentry);
- err = nfserr_noent;
- goto out;
- }
-
- if (!type)
- type = rdentry->d_inode->i_mode & S_IFMT;
-
- host_err = fh_want_write(fhp);
- if (host_err)
- goto out_put;
-
- host_err = nfsd_break_lease(rdentry->d_inode);
- if (host_err)
- goto out_drop_write;
- if (type != S_IFDIR)
- host_err = vfs_unlink(dirp, rdentry);
- else
- host_err = vfs_rmdir(dirp, rdentry);
- if (!host_err)
- host_err = commit_metadata(fhp);
-out_drop_write:
- fh_drop_write(fhp);
-out_put:
- dput(rdentry);
-
-out_nfserr:
- err = nfserrno(host_err);
-out:
- return err;
-}
-
-/*
- * We do this buffering because we must not call back into the file
- * system's ->lookup() method from the filldir callback. That may well
- * deadlock a number of file systems.
- *
- * This is based heavily on the implementation of same in XFS.
- */
-struct buffered_dirent {
- u64 ino;
- loff_t offset;
- int namlen;
- unsigned int d_type;
- char name[];
-};
-
-struct readdir_data {
- char *dirent;
- size_t used;
- int full;
-};
-
-static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type)
-{
- struct readdir_data *buf = __buf;
- struct buffered_dirent *de = (void *)(buf->dirent + buf->used);
- unsigned int reclen;
-
- reclen = ALIGN(sizeof(struct buffered_dirent) + namlen, sizeof(u64));
- if (buf->used + reclen > PAGE_SIZE) {
- buf->full = 1;
- return -EINVAL;
- }
-
- de->namlen = namlen;
- de->offset = offset;
- de->ino = ino;
- de->d_type = d_type;
- memcpy(de->name, name, namlen);
- buf->used += reclen;
-
- return 0;
-}
-
-static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
- struct readdir_cd *cdp, loff_t *offsetp)
-{
- struct readdir_data buf;
- struct buffered_dirent *de;
- int host_err;
- int size;
- loff_t offset;
-
- buf.dirent = (void *)__get_free_page(GFP_KERNEL);
- if (!buf.dirent)
- return nfserrno(-ENOMEM);
-
- offset = *offsetp;
-
- while (1) {
- struct inode *dir_inode = file->f_path.dentry->d_inode;
- unsigned int reclen;
-
- cdp->err = nfserr_eof; /* will be cleared on successful read */
- buf.used = 0;
- buf.full = 0;
-
- host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf);
- if (buf.full)
- host_err = 0;
-
- if (host_err < 0)
- break;
-
- size = buf.used;
-
- if (!size)
- break;
-
- /*
- * Various filldir functions may end up calling back into
- * lookup_one_len() and the file system's ->lookup() method.
- * These expect i_mutex to be held, as it would within readdir.
- */
- host_err = mutex_lock_killable(&dir_inode->i_mutex);
- if (host_err)
- break;
-
- de = (struct buffered_dirent *)buf.dirent;
- while (size > 0) {
- offset = de->offset;
-
- if (func(cdp, de->name, de->namlen, de->offset,
- de->ino, de->d_type))
- break;
-
- if (cdp->err != nfs_ok)
- break;
-
- reclen = ALIGN(sizeof(*de) + de->namlen,
- sizeof(u64));
- size -= reclen;
- de = (struct buffered_dirent *)((char *)de + reclen);
- }
- mutex_unlock(&dir_inode->i_mutex);
- if (size > 0) /* We bailed out early */
- break;
-
- offset = vfs_llseek(file, 0, SEEK_CUR);
- }
-
- free_page((unsigned long)(buf.dirent));
-
- if (host_err)
- return nfserrno(host_err);
-
- *offsetp = offset;
- return cdp->err;
-}
-
-/*
- * Read entries from a directory.
- * The NFSv3/4 verifier we ignore for now.
- */
-__be32
-nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
- struct readdir_cd *cdp, filldir_t func)
-{
- __be32 err;
- struct file *file;
- loff_t offset = *offsetp;
- int may_flags = NFSD_MAY_READ;
-
- /* NFSv2 only supports 32 bit cookies */
- if (rqstp->rq_vers > 2)
- may_flags |= NFSD_MAY_64BIT_COOKIE;
-
- err = nfsd_open(rqstp, fhp, S_IFDIR, may_flags, &file);
- if (err)
- goto out;
-
- offset = vfs_llseek(file, offset, 0);
- if (offset < 0) {
- err = nfserrno((int)offset);
- goto out_close;
- }
-
- err = nfsd_buffered_readdir(file, func, cdp, offsetp);
-
- if (err == nfserr_eof || err == nfserr_toosmall)
- err = nfs_ok; /* can still be found in ->err */
-out_close:
- nfsd_close(file);
-out:
- return err;
-}
-
-/*
- * Get file system stats
- * N.B. After this call fhp needs an fh_put
- */
-__be32
-nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access)
-{
- __be32 err;
-
- err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access);
- if (!err) {
- struct path path = {
- .mnt = fhp->fh_export->ex_path.mnt,
- .dentry = fhp->fh_dentry,
- };
- if (vfs_statfs(&path, stat))
- err = nfserr_io;
- }
- return err;
-}
-
-static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp)
-{
- return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY;
-}
-
-/*
- * Check for a user's access permissions to this inode.
- */
-__be32
-nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
- struct dentry *dentry, int acc)
-{
- struct inode *inode = dentry->d_inode;
- int err;
-
- if ((acc & NFSD_MAY_MASK) == NFSD_MAY_NOP)
- return 0;
-#if 0
- dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
- acc,
- (acc & NFSD_MAY_READ)? " read" : "",
- (acc & NFSD_MAY_WRITE)? " write" : "",
- (acc & NFSD_MAY_EXEC)? " exec" : "",
- (acc & NFSD_MAY_SATTR)? " sattr" : "",
- (acc & NFSD_MAY_TRUNC)? " trunc" : "",
- (acc & NFSD_MAY_LOCK)? " lock" : "",
- (acc & NFSD_MAY_OWNER_OVERRIDE)? " owneroverride" : "",
- inode->i_mode,
- IS_IMMUTABLE(inode)? " immut" : "",
- IS_APPEND(inode)? " append" : "",
- __mnt_is_readonly(exp->ex_path.mnt)? " ro" : "");
- dprintk(" owner %d/%d user %d/%d\n",
- inode->i_uid, inode->i_gid, current_fsuid(), current_fsgid());
-#endif
-
- /* Normally we reject any write/sattr etc access on a read-only file
- * system. But if it is IRIX doing check on write-access for a
- * device special file, we ignore rofs.
- */
- if (!(acc & NFSD_MAY_LOCAL_ACCESS))
- if (acc & (NFSD_MAY_WRITE | NFSD_MAY_SATTR | NFSD_MAY_TRUNC)) {
- if (exp_rdonly(rqstp, exp) ||
- __mnt_is_readonly(exp->ex_path.mnt))
- return nfserr_rofs;
- if (/* (acc & NFSD_MAY_WRITE) && */ IS_IMMUTABLE(inode))
- return nfserr_perm;
- }
- if ((acc & NFSD_MAY_TRUNC) && IS_APPEND(inode))
- return nfserr_perm;
-
- if (acc & NFSD_MAY_LOCK) {
- /* If we cannot rely on authentication in NLM requests,
- * just allow locks, otherwise require read permission, or
- * ownership
- */
- if (exp->ex_flags & NFSEXP_NOAUTHNLM)
- return 0;
- else
- acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE;
- }
- /*
- * The file owner always gets access permission for accesses that
- * would normally be checked at open time. This is to make
- * file access work even when the client has done a fchmod(fd, 0).
- *
- * However, `cp foo bar' should fail nevertheless when bar is
- * readonly. A sensible way to do this might be to reject all
- * attempts to truncate a read-only file, because a creat() call
- * always implies file truncation.
- * ... but this isn't really fair. A process may reasonably call
- * ftruncate on an open file descriptor on a file with perm 000.
- * We must trust the client to do permission checking - using "ACCESS"
- * with NFSv3.
- */
- if ((acc & NFSD_MAY_OWNER_OVERRIDE) &&
- inode->i_uid == current_fsuid())
- return 0;
-
- /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
- err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));
-
- /* Allow read access to binaries even when mode 111 */
- if (err == -EACCES && S_ISREG(inode->i_mode) &&
- (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) ||
- acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC)))
- err = inode_permission(inode, MAY_EXEC);
-
- return err? nfserrno(err) : 0;
-}
-
-void
-nfsd_racache_shutdown(void)
-{
- struct raparms *raparm, *last_raparm;
- unsigned int i;
-
- dprintk("nfsd: freeing readahead buffers.\n");
-
- for (i = 0; i < RAPARM_HASH_SIZE; i++) {
- raparm = raparm_hash[i].pb_head;
- while(raparm) {
- last_raparm = raparm;
- raparm = raparm->p_next;
- kfree(last_raparm);
- }
- raparm_hash[i].pb_head = NULL;
- }
-}
-/*
- * Initialize readahead param cache
- */
-int
-nfsd_racache_init(int cache_size)
-{
- int i;
- int j = 0;
- int nperbucket;
- struct raparms **raparm = NULL;
-
-
- if (raparm_hash[0].pb_head)
- return 0;
- nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
- if (nperbucket < 2)
- nperbucket = 2;
- cache_size = nperbucket * RAPARM_HASH_SIZE;
-
- dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);
-
- for (i = 0; i < RAPARM_HASH_SIZE; i++) {
- spin_lock_init(&raparm_hash[i].pb_lock);
-
- raparm = &raparm_hash[i].pb_head;
- for (j = 0; j < nperbucket; j++) {
- *raparm = kzalloc(sizeof(struct raparms), GFP_KERNEL);
- if (!*raparm)
- goto out_nomem;
- raparm = &(*raparm)->p_next;
- }
- *raparm = NULL;
- }
-
- nfsdstats.ra_size = cache_size;
- return 0;
-
-out_nomem:
- dprintk("nfsd: kmalloc failed, freeing readahead buffers\n");
- nfsd_racache_shutdown();
- return -ENOMEM;
-}
-
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-struct posix_acl *
-nfsd_get_posix_acl(struct svc_fh *fhp, int type)
-{
- struct inode *inode = fhp->fh_dentry->d_inode;
- char *name;
- void *value = NULL;
- ssize_t size;
- struct posix_acl *acl;
-
- if (!IS_POSIXACL(inode))
- return ERR_PTR(-EOPNOTSUPP);
-
- switch (type) {
- case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
- break;
- case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
- break;
- default:
- return ERR_PTR(-EOPNOTSUPP);
- }
-
- size = nfsd_getxattr(fhp->fh_dentry, name, &value);
- if (size < 0)
- return ERR_PTR(size);
-
- acl = posix_acl_from_xattr(value, size);
- kfree(value);
- return acl;
-}
-
-int
-nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
-{
- struct inode *inode = fhp->fh_dentry->d_inode;
- char *name;
- void *value = NULL;
- size_t size;
- int error;
-
- if (!IS_POSIXACL(inode) ||
- !inode->i_op->setxattr || !inode->i_op->removexattr)
- return -EOPNOTSUPP;
- switch(type) {
- case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
- break;
- case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- if (acl && acl->a_count) {
- size = posix_acl_xattr_size(acl->a_count);
- value = kmalloc(size, GFP_KERNEL);
- if (!value)
- return -ENOMEM;
- error = posix_acl_to_xattr(acl, value, size);
- if (error < 0)
- goto getout;
- size = error;
- } else
- size = 0;
-
- error = fh_want_write(fhp);
- if (error)
- goto getout;
- if (size)
- error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);
- else {
- if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
- error = 0;
- else {
- error = vfs_removexattr(fhp->fh_dentry, name);
- if (error == -ENODATA)
- error = 0;
- }
- }
- fh_drop_write(fhp);
-
-getout:
- kfree(value);
- return error;
-}
-#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
diff --git a/ANDROID_3.4.5/fs/nfsd/vfs.h b/ANDROID_3.4.5/fs/nfsd/vfs.h
deleted file mode 100644
index ec0611b2..00000000
--- a/ANDROID_3.4.5/fs/nfsd/vfs.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef LINUX_NFSD_VFS_H
-#define LINUX_NFSD_VFS_H
-
-#include "nfsfh.h"
-
-/*
- * Flags for nfsd_permission
- */
-#define NFSD_MAY_NOP 0
-#define NFSD_MAY_EXEC 0x001 /* == MAY_EXEC */
-#define NFSD_MAY_WRITE 0x002 /* == MAY_WRITE */
-#define NFSD_MAY_READ 0x004 /* == MAY_READ */
-#define NFSD_MAY_SATTR 0x008
-#define NFSD_MAY_TRUNC 0x010
-#define NFSD_MAY_LOCK 0x020
-#define NFSD_MAY_MASK 0x03f
-
-/* extra hints to permission and open routines: */
-#define NFSD_MAY_OWNER_OVERRIDE 0x040
-#define NFSD_MAY_LOCAL_ACCESS 0x080 /* for device special files */
-#define NFSD_MAY_BYPASS_GSS_ON_ROOT 0x100
-#define NFSD_MAY_NOT_BREAK_LEASE 0x200
-#define NFSD_MAY_BYPASS_GSS 0x400
-#define NFSD_MAY_READ_IF_EXEC 0x800
-
-#define NFSD_MAY_64BIT_COOKIE 0x1000 /* 64 bit readdir cookies for >= NFSv3 */
-
-#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
-#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
-
-/*
- * Callback function for readdir
- */
-typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
-
-/* nfsd/vfs.c */
-int fh_lock_parent(struct svc_fh *, struct dentry *);
-int nfsd_racache_init(int);
-void nfsd_racache_shutdown(void);
-int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
- struct svc_export **expp);
-__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
- const char *, unsigned int, struct svc_fh *);
-__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
- const char *, unsigned int,
- struct svc_export **, struct dentry **);
-__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
- struct iattr *, int, time_t);
-int nfsd_mountpoint(struct dentry *, struct svc_export *);
-#ifdef CONFIG_NFSD_V4
-__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
- struct nfs4_acl *);
-int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
-#endif /* CONFIG_NFSD_V4 */
-__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
- char *name, int len, struct iattr *attrs,
- int type, dev_t rdev, struct svc_fh *res);
-#ifdef CONFIG_NFSD_V3
-__be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
-__be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *,
- char *name, int len, struct iattr *attrs,
- struct svc_fh *res, int createmode,
- u32 *verifier, bool *truncp, bool *created);
-__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
- loff_t, unsigned long);
-#endif /* CONFIG_NFSD_V3 */
-__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
- int, struct file **);
-void nfsd_close(struct file *);
-__be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
- loff_t, struct kvec *, int, unsigned long *);
-__be32 nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *,
- loff_t, struct kvec *, int, unsigned long *);
-__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
- loff_t, struct kvec *,int, unsigned long *, int *);
-__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
- char *, int *);
-__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
- char *name, int len, char *path, int plen,
- struct svc_fh *res, struct iattr *);
-__be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
- char *, int, struct svc_fh *);
-__be32 nfsd_rename(struct svc_rqst *,
- struct svc_fh *, char *, int,
- struct svc_fh *, char *, int);
-__be32 nfsd_remove(struct svc_rqst *,
- struct svc_fh *, char *, int);
-__be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
- char *name, int len);
-int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
- unsigned long size);
-__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
- loff_t *, struct readdir_cd *, filldir_t);
-__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
- struct kstatfs *, int access);
-
-int nfsd_notify_change(struct inode *, struct iattr *);
-__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
- struct dentry *, int);
-int nfsd_sync_dir(struct dentry *dp);
-
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
-int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
-#endif
-
-static inline int fh_want_write(struct svc_fh *fh)
-{
- return mnt_want_write(fh->fh_export->ex_path.mnt);
-}
-
-static inline void fh_drop_write(struct svc_fh *fh)
-{
- mnt_drop_write(fh->fh_export->ex_path.mnt);
-}
-
-#endif /* LINUX_NFSD_VFS_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/xdr.h b/ANDROID_3.4.5/fs/nfsd/xdr.h
deleted file mode 100644
index 53b1863d..00000000
--- a/ANDROID_3.4.5/fs/nfsd/xdr.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/* XDR types for nfsd. This is mainly a typing exercise. */
-
-#ifndef LINUX_NFSD_H
-#define LINUX_NFSD_H
-
-#include <linux/vfs.h>
-#include "nfsd.h"
-#include "nfsfh.h"
-
-struct nfsd_fhandle {
- struct svc_fh fh;
-};
-
-struct nfsd_sattrargs {
- struct svc_fh fh;
- struct iattr attrs;
-};
-
-struct nfsd_diropargs {
- struct svc_fh fh;
- char * name;
- unsigned int len;
-};
-
-struct nfsd_readargs {
- struct svc_fh fh;
- __u32 offset;
- __u32 count;
- int vlen;
-};
-
-struct nfsd_writeargs {
- svc_fh fh;
- __u32 offset;
- int len;
- int vlen;
-};
-
-struct nfsd_createargs {
- struct svc_fh fh;
- char * name;
- unsigned int len;
- struct iattr attrs;
-};
-
-struct nfsd_renameargs {
- struct svc_fh ffh;
- char * fname;
- unsigned int flen;
- struct svc_fh tfh;
- char * tname;
- unsigned int tlen;
-};
-
-struct nfsd_readlinkargs {
- struct svc_fh fh;
- char * buffer;
-};
-
-struct nfsd_linkargs {
- struct svc_fh ffh;
- struct svc_fh tfh;
- char * tname;
- unsigned int tlen;
-};
-
-struct nfsd_symlinkargs {
- struct svc_fh ffh;
- char * fname;
- unsigned int flen;
- char * tname;
- unsigned int tlen;
- struct iattr attrs;
-};
-
-struct nfsd_readdirargs {
- struct svc_fh fh;
- __u32 cookie;
- __u32 count;
- __be32 * buffer;
-};
-
-struct nfsd_attrstat {
- struct svc_fh fh;
- struct kstat stat;
-};
-
-struct nfsd_diropres {
- struct svc_fh fh;
- struct kstat stat;
-};
-
-struct nfsd_readlinkres {
- int len;
-};
-
-struct nfsd_readres {
- struct svc_fh fh;
- unsigned long count;
- struct kstat stat;
-};
-
-struct nfsd_readdirres {
- int count;
-
- struct readdir_cd common;
- __be32 * buffer;
- int buflen;
- __be32 * offset;
-};
-
-struct nfsd_statfsres {
- struct kstatfs stats;
-};
-
-/*
- * Storage requirements for XDR arguments and results.
- */
-union nfsd_xdrstore {
- struct nfsd_sattrargs sattr;
- struct nfsd_diropargs dirop;
- struct nfsd_readargs read;
- struct nfsd_writeargs write;
- struct nfsd_createargs create;
- struct nfsd_renameargs rename;
- struct nfsd_linkargs link;
- struct nfsd_symlinkargs symlink;
- struct nfsd_readdirargs readdir;
-};
-
-#define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore)
-
-
-int nfssvc_decode_void(struct svc_rqst *, __be32 *, void *);
-int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
-int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *,
- struct nfsd_sattrargs *);
-int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *,
- struct nfsd_diropargs *);
-int nfssvc_decode_readargs(struct svc_rqst *, __be32 *,
- struct nfsd_readargs *);
-int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *,
- struct nfsd_writeargs *);
-int nfssvc_decode_createargs(struct svc_rqst *, __be32 *,
- struct nfsd_createargs *);
-int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *,
- struct nfsd_renameargs *);
-int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *,
- struct nfsd_readlinkargs *);
-int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *,
- struct nfsd_linkargs *);
-int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *,
- struct nfsd_symlinkargs *);
-int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *,
- struct nfsd_readdirargs *);
-int nfssvc_encode_void(struct svc_rqst *, __be32 *, void *);
-int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd_attrstat *);
-int nfssvc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd_diropres *);
-int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd_readlinkres *);
-int nfssvc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd_readres *);
-int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *, struct nfsd_statfsres *);
-int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd_readdirres *);
-
-int nfssvc_encode_entry(void *, const char *name,
- int namlen, loff_t offset, u64 ino, unsigned int);
-
-int nfssvc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
-
-/* Helper functions for NFSv2 ACL code */
-__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp);
-__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp);
-
-#endif /* LINUX_NFSD_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/xdr3.h b/ANDROID_3.4.5/fs/nfsd/xdr3.h
deleted file mode 100644
index 7df980eb..00000000
--- a/ANDROID_3.4.5/fs/nfsd/xdr3.h
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * XDR types for NFSv3 in nfsd.
- *
- * Copyright (C) 1996-1998, Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef _LINUX_NFSD_XDR3_H
-#define _LINUX_NFSD_XDR3_H
-
-#include "xdr.h"
-
-struct nfsd3_sattrargs {
- struct svc_fh fh;
- struct iattr attrs;
- int check_guard;
- time_t guardtime;
-};
-
-struct nfsd3_diropargs {
- struct svc_fh fh;
- char * name;
- unsigned int len;
-};
-
-struct nfsd3_accessargs {
- struct svc_fh fh;
- unsigned int access;
-};
-
-struct nfsd3_readargs {
- struct svc_fh fh;
- __u64 offset;
- __u32 count;
- int vlen;
-};
-
-struct nfsd3_writeargs {
- svc_fh fh;
- __u64 offset;
- __u32 count;
- int stable;
- __u32 len;
- int vlen;
-};
-
-struct nfsd3_createargs {
- struct svc_fh fh;
- char * name;
- unsigned int len;
- int createmode;
- struct iattr attrs;
- __be32 * verf;
-};
-
-struct nfsd3_mknodargs {
- struct svc_fh fh;
- char * name;
- unsigned int len;
- __u32 ftype;
- __u32 major, minor;
- struct iattr attrs;
-};
-
-struct nfsd3_renameargs {
- struct svc_fh ffh;
- char * fname;
- unsigned int flen;
- struct svc_fh tfh;
- char * tname;
- unsigned int tlen;
-};
-
-struct nfsd3_readlinkargs {
- struct svc_fh fh;
- char * buffer;
-};
-
-struct nfsd3_linkargs {
- struct svc_fh ffh;
- struct svc_fh tfh;
- char * tname;
- unsigned int tlen;
-};
-
-struct nfsd3_symlinkargs {
- struct svc_fh ffh;
- char * fname;
- unsigned int flen;
- char * tname;
- unsigned int tlen;
- struct iattr attrs;
-};
-
-struct nfsd3_readdirargs {
- struct svc_fh fh;
- __u64 cookie;
- __u32 dircount;
- __u32 count;
- __be32 * verf;
- __be32 * buffer;
-};
-
-struct nfsd3_commitargs {
- struct svc_fh fh;
- __u64 offset;
- __u32 count;
-};
-
-struct nfsd3_getaclargs {
- struct svc_fh fh;
- int mask;
-};
-
-struct posix_acl;
-struct nfsd3_setaclargs {
- struct svc_fh fh;
- int mask;
- struct posix_acl *acl_access;
- struct posix_acl *acl_default;
-};
-
-struct nfsd3_attrstat {
- __be32 status;
- struct svc_fh fh;
- struct kstat stat;
-};
-
-/* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */
-struct nfsd3_diropres {
- __be32 status;
- struct svc_fh dirfh;
- struct svc_fh fh;
-};
-
-struct nfsd3_accessres {
- __be32 status;
- struct svc_fh fh;
- __u32 access;
-};
-
-struct nfsd3_readlinkres {
- __be32 status;
- struct svc_fh fh;
- __u32 len;
-};
-
-struct nfsd3_readres {
- __be32 status;
- struct svc_fh fh;
- unsigned long count;
- int eof;
-};
-
-struct nfsd3_writeres {
- __be32 status;
- struct svc_fh fh;
- unsigned long count;
- int committed;
-};
-
-struct nfsd3_renameres {
- __be32 status;
- struct svc_fh ffh;
- struct svc_fh tfh;
-};
-
-struct nfsd3_linkres {
- __be32 status;
- struct svc_fh tfh;
- struct svc_fh fh;
-};
-
-struct nfsd3_readdirres {
- __be32 status;
- struct svc_fh fh;
- int count;
- __be32 verf[2];
-
- struct readdir_cd common;
- __be32 * buffer;
- int buflen;
- __be32 * offset;
- __be32 * offset1;
- struct svc_rqst * rqstp;
-
-};
-
-struct nfsd3_fsstatres {
- __be32 status;
- struct kstatfs stats;
- __u32 invarsec;
-};
-
-struct nfsd3_fsinfores {
- __be32 status;
- __u32 f_rtmax;
- __u32 f_rtpref;
- __u32 f_rtmult;
- __u32 f_wtmax;
- __u32 f_wtpref;
- __u32 f_wtmult;
- __u32 f_dtpref;
- __u64 f_maxfilesize;
- __u32 f_properties;
-};
-
-struct nfsd3_pathconfres {
- __be32 status;
- __u32 p_link_max;
- __u32 p_name_max;
- __u32 p_no_trunc;
- __u32 p_chown_restricted;
- __u32 p_case_insensitive;
- __u32 p_case_preserving;
-};
-
-struct nfsd3_commitres {
- __be32 status;
- struct svc_fh fh;
-};
-
-struct nfsd3_getaclres {
- __be32 status;
- struct svc_fh fh;
- int mask;
- struct posix_acl *acl_access;
- struct posix_acl *acl_default;
-};
-
-/* dummy type for release */
-struct nfsd3_fhandle_pair {
- __u32 dummy;
- struct svc_fh fh1;
- struct svc_fh fh2;
-};
-
-/*
- * Storage requirements for XDR arguments and results.
- */
-union nfsd3_xdrstore {
- struct nfsd3_sattrargs sattrargs;
- struct nfsd3_diropargs diropargs;
- struct nfsd3_readargs readargs;
- struct nfsd3_writeargs writeargs;
- struct nfsd3_createargs createargs;
- struct nfsd3_renameargs renameargs;
- struct nfsd3_linkargs linkargs;
- struct nfsd3_symlinkargs symlinkargs;
- struct nfsd3_readdirargs readdirargs;
- struct nfsd3_diropres diropres;
- struct nfsd3_accessres accessres;
- struct nfsd3_readlinkres readlinkres;
- struct nfsd3_readres readres;
- struct nfsd3_writeres writeres;
- struct nfsd3_renameres renameres;
- struct nfsd3_linkres linkres;
- struct nfsd3_readdirres readdirres;
- struct nfsd3_fsstatres fsstatres;
- struct nfsd3_fsinfores fsinfores;
- struct nfsd3_pathconfres pathconfres;
- struct nfsd3_commitres commitres;
- struct nfsd3_getaclres getaclres;
-};
-
-#define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
-
-int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
-int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *,
- struct nfsd3_sattrargs *);
-int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *,
- struct nfsd3_diropargs *);
-int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *,
- struct nfsd3_accessargs *);
-int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *,
- struct nfsd3_readargs *);
-int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *,
- struct nfsd3_writeargs *);
-int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *,
- struct nfsd3_createargs *);
-int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *,
- struct nfsd3_createargs *);
-int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *,
- struct nfsd3_mknodargs *);
-int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *,
- struct nfsd3_renameargs *);
-int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *,
- struct nfsd3_readlinkargs *);
-int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *,
- struct nfsd3_linkargs *);
-int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *,
- struct nfsd3_symlinkargs *);
-int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *,
- struct nfsd3_readdirargs *);
-int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *,
- struct nfsd3_readdirargs *);
-int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *,
- struct nfsd3_commitargs *);
-int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
-int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *,
- struct nfsd3_attrstat *);
-int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *,
- struct nfsd3_attrstat *);
-int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *,
- struct nfsd3_diropres *);
-int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *,
- struct nfsd3_accessres *);
-int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *,
- struct nfsd3_readlinkres *);
-int nfs3svc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd3_readres *);
-int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *, struct nfsd3_writeres *);
-int nfs3svc_encode_createres(struct svc_rqst *, __be32 *,
- struct nfsd3_diropres *);
-int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *,
- struct nfsd3_renameres *);
-int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *,
- struct nfsd3_linkres *);
-int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *,
- struct nfsd3_readdirres *);
-int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *,
- struct nfsd3_fsstatres *);
-int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *,
- struct nfsd3_fsinfores *);
-int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *,
- struct nfsd3_pathconfres *);
-int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *,
- struct nfsd3_commitres *);
-
-int nfs3svc_release_fhandle(struct svc_rqst *, __be32 *,
- struct nfsd3_attrstat *);
-int nfs3svc_release_fhandle2(struct svc_rqst *, __be32 *,
- struct nfsd3_fhandle_pair *);
-int nfs3svc_encode_entry(void *, const char *name,
- int namlen, loff_t offset, u64 ino,
- unsigned int);
-int nfs3svc_encode_entry_plus(void *, const char *name,
- int namlen, loff_t offset, u64 ino,
- unsigned int);
-/* Helper functions for NFSv3 ACL code */
-__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p,
- struct svc_fh *fhp);
-__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp);
-
-
-#endif /* _LINUX_NFSD_XDR3_H */
diff --git a/ANDROID_3.4.5/fs/nfsd/xdr4.h b/ANDROID_3.4.5/fs/nfsd/xdr4.h
deleted file mode 100644
index 1b350159..00000000
--- a/ANDROID_3.4.5/fs/nfsd/xdr4.h
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Server-side types for NFSv4.
- *
- * Copyright (c) 2002 The Regents of the University of Michigan.
- * All rights reserved.
- *
- * Kendrick Smith <kmsmith@umich.edu>
- * Andy Adamson <andros@umich.edu>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef _LINUX_NFSD_XDR4_H
-#define _LINUX_NFSD_XDR4_H
-
-#include "state.h"
-#include "nfsd.h"
-
-#define NFSD4_MAX_TAGLEN 128
-#define XDR_LEN(n) (((n) + 3) & ~3)
-
-#define CURRENT_STATE_ID_FLAG (1<<0)
-#define SAVED_STATE_ID_FLAG (1<<1)
-
-#define SET_STATE_ID(c, f) ((c)->sid_flags |= (f))
-#define HAS_STATE_ID(c, f) ((c)->sid_flags & (f))
-#define CLEAR_STATE_ID(c, f) ((c)->sid_flags &= ~(f))
-
-struct nfsd4_compound_state {
- struct svc_fh current_fh;
- struct svc_fh save_fh;
- struct nfs4_stateowner *replay_owner;
- /* For sessions DRC */
- struct nfsd4_session *session;
- struct nfsd4_slot *slot;
- __be32 *datap;
- size_t iovlen;
- u32 minorversion;
- u32 status;
- stateid_t current_stateid;
- stateid_t save_stateid;
- /* to indicate current and saved state id presents */
- u32 sid_flags;
-};
-
-static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs)
-{
- return cs->slot != NULL;
-}
-
-struct nfsd4_change_info {
- u32 atomic;
- bool change_supported;
- u32 before_ctime_sec;
- u32 before_ctime_nsec;
- u64 before_change;
- u32 after_ctime_sec;
- u32 after_ctime_nsec;
- u64 after_change;
-};
-
-struct nfsd4_access {
- u32 ac_req_access; /* request */
- u32 ac_supported; /* response */
- u32 ac_resp_access; /* response */
-};
-
-struct nfsd4_close {
- u32 cl_seqid; /* request */
- stateid_t cl_stateid; /* request+response */
-};
-
-struct nfsd4_commit {
- u64 co_offset; /* request */
- u32 co_count; /* request */
- nfs4_verifier co_verf; /* response */
-};
-
-struct nfsd4_create {
- u32 cr_namelen; /* request */
- char * cr_name; /* request */
- u32 cr_type; /* request */
- union { /* request */
- struct {
- u32 namelen;
- char *name;
- } link; /* NF4LNK */
- struct {
- u32 specdata1;
- u32 specdata2;
- } dev; /* NF4BLK, NF4CHR */
- } u;
- u32 cr_bmval[3]; /* request */
- struct iattr cr_iattr; /* request */
- struct nfsd4_change_info cr_cinfo; /* response */
- struct nfs4_acl *cr_acl;
-};
-#define cr_linklen u.link.namelen
-#define cr_linkname u.link.name
-#define cr_specdata1 u.dev.specdata1
-#define cr_specdata2 u.dev.specdata2
-
-struct nfsd4_delegreturn {
- stateid_t dr_stateid;
-};
-
-struct nfsd4_getattr {
- u32 ga_bmval[3]; /* request */
- struct svc_fh *ga_fhp; /* response */
-};
-
-struct nfsd4_link {
- u32 li_namelen; /* request */
- char * li_name; /* request */
- struct nfsd4_change_info li_cinfo; /* response */
-};
-
-struct nfsd4_lock_denied {
- clientid_t ld_clientid;
- struct xdr_netobj ld_owner;
- u64 ld_start;
- u64 ld_length;
- u32 ld_type;
-};
-
-struct nfsd4_lock {
- /* request */
- u32 lk_type;
- u32 lk_reclaim; /* boolean */
- u64 lk_offset;
- u64 lk_length;
- u32 lk_is_new;
- union {
- struct {
- u32 open_seqid;
- stateid_t open_stateid;
- u32 lock_seqid;
- clientid_t clientid;
- struct xdr_netobj owner;
- } new;
- struct {
- stateid_t lock_stateid;
- u32 lock_seqid;
- } old;
- } v;
-
- /* response */
- union {
- struct {
- stateid_t stateid;
- } ok;
- struct nfsd4_lock_denied denied;
- } u;
-};
-#define lk_new_open_seqid v.new.open_seqid
-#define lk_new_open_stateid v.new.open_stateid
-#define lk_new_lock_seqid v.new.lock_seqid
-#define lk_new_clientid v.new.clientid
-#define lk_new_owner v.new.owner
-#define lk_old_lock_stateid v.old.lock_stateid
-#define lk_old_lock_seqid v.old.lock_seqid
-
-#define lk_rflags u.ok.rflags
-#define lk_resp_stateid u.ok.stateid
-#define lk_denied u.denied
-
-
-struct nfsd4_lockt {
- u32 lt_type;
- clientid_t lt_clientid;
- struct xdr_netobj lt_owner;
- u64 lt_offset;
- u64 lt_length;
- struct nfsd4_lock_denied lt_denied;
-};
-
-
-struct nfsd4_locku {
- u32 lu_type;
- u32 lu_seqid;
- stateid_t lu_stateid;
- u64 lu_offset;
- u64 lu_length;
-};
-
-
-struct nfsd4_lookup {
- u32 lo_len; /* request */
- char * lo_name; /* request */
-};
-
-struct nfsd4_putfh {
- u32 pf_fhlen; /* request */
- char *pf_fhval; /* request */
-};
-
-struct nfsd4_open {
- u32 op_claim_type; /* request */
- struct xdr_netobj op_fname; /* request - everything but CLAIM_PREV */
- u32 op_delegate_type; /* request - CLAIM_PREV only */
- stateid_t op_delegate_stateid; /* request - response */
- u32 op_why_no_deleg; /* response - DELEG_NONE_EXT only */
- u32 op_create; /* request */
- u32 op_createmode; /* request */
- u32 op_bmval[3]; /* request */
- struct iattr iattr; /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */
- nfs4_verifier op_verf __attribute__((aligned(32)));
- /* EXCLUSIVE4 */
- clientid_t op_clientid; /* request */
- struct xdr_netobj op_owner; /* request */
- u32 op_seqid; /* request */
- u32 op_share_access; /* request */
- u32 op_share_deny; /* request */
- u32 op_deleg_want; /* request */
- stateid_t op_stateid; /* response */
- u32 op_recall; /* recall */
- struct nfsd4_change_info op_cinfo; /* response */
- u32 op_rflags; /* response */
- bool op_truncate; /* used during processing */
- bool op_created; /* used during processing */
- struct nfs4_openowner *op_openowner; /* used during processing */
- struct nfs4_file *op_file; /* used during processing */
- struct nfs4_ol_stateid *op_stp; /* used during processing */
- struct nfs4_acl *op_acl;
-};
-#define op_iattr iattr
-
-struct nfsd4_open_confirm {
- stateid_t oc_req_stateid /* request */;
- u32 oc_seqid /* request */;
- stateid_t oc_resp_stateid /* response */;
-};
-
-struct nfsd4_open_downgrade {
- stateid_t od_stateid;
- u32 od_seqid;
- u32 od_share_access; /* request */
- u32 od_deleg_want; /* request */
- u32 od_share_deny; /* request */
-};
-
-
-struct nfsd4_read {
- stateid_t rd_stateid; /* request */
- u64 rd_offset; /* request */
- u32 rd_length; /* request */
- int rd_vlen;
- struct file *rd_filp;
-
- struct svc_rqst *rd_rqstp; /* response */
- struct svc_fh * rd_fhp; /* response */
-};
-
-struct nfsd4_readdir {
- u64 rd_cookie; /* request */
- nfs4_verifier rd_verf; /* request */
- u32 rd_dircount; /* request */
- u32 rd_maxcount; /* request */
- u32 rd_bmval[3]; /* request */
- struct svc_rqst *rd_rqstp; /* response */
- struct svc_fh * rd_fhp; /* response */
-
- struct readdir_cd common;
- __be32 * buffer;
- int buflen;
- __be32 * offset;
-};
-
-struct nfsd4_release_lockowner {
- clientid_t rl_clientid;
- struct xdr_netobj rl_owner;
-};
-struct nfsd4_readlink {
- struct svc_rqst *rl_rqstp; /* request */
- struct svc_fh * rl_fhp; /* request */
-};
-
-struct nfsd4_remove {
- u32 rm_namelen; /* request */
- char * rm_name; /* request */
- struct nfsd4_change_info rm_cinfo; /* response */
-};
-
-struct nfsd4_rename {
- u32 rn_snamelen; /* request */
- char * rn_sname; /* request */
- u32 rn_tnamelen; /* request */
- char * rn_tname; /* request */
- struct nfsd4_change_info rn_sinfo; /* response */
- struct nfsd4_change_info rn_tinfo; /* response */
-};
-
-struct nfsd4_secinfo {
- u32 si_namelen; /* request */
- char *si_name; /* request */
- struct svc_export *si_exp; /* response */
-};
-
-struct nfsd4_secinfo_no_name {
- u32 sin_style; /* request */
- struct svc_export *sin_exp; /* response */
-};
-
-struct nfsd4_setattr {
- stateid_t sa_stateid; /* request */
- u32 sa_bmval[3]; /* request */
- struct iattr sa_iattr; /* request */
- struct nfs4_acl *sa_acl;
-};
-
-struct nfsd4_setclientid {
- nfs4_verifier se_verf; /* request */
- struct xdr_netobj se_name;
- u32 se_callback_prog; /* request */
- u32 se_callback_netid_len; /* request */
- char * se_callback_netid_val; /* request */
- u32 se_callback_addr_len; /* request */
- char * se_callback_addr_val; /* request */
- u32 se_callback_ident; /* request */
- clientid_t se_clientid; /* response */
- nfs4_verifier se_confirm; /* response */
-};
-
-struct nfsd4_setclientid_confirm {
- clientid_t sc_clientid;
- nfs4_verifier sc_confirm;
-};
-
-struct nfsd4_saved_compoundargs {
- __be32 *p;
- __be32 *end;
- int pagelen;
- struct page **pagelist;
-};
-
-struct nfsd4_test_stateid_id {
- __be32 ts_id_status;
- stateid_t ts_id_stateid;
- struct list_head ts_id_list;
-};
-
-struct nfsd4_test_stateid {
- __be32 ts_num_ids;
- struct list_head ts_stateid_list;
-};
-
-struct nfsd4_free_stateid {
- stateid_t fr_stateid; /* request */
- __be32 fr_status; /* response */
-};
-
-/* also used for NVERIFY */
-struct nfsd4_verify {
- u32 ve_bmval[3]; /* request */
- u32 ve_attrlen; /* request */
- char * ve_attrval; /* request */
-};
-
-struct nfsd4_write {
- stateid_t wr_stateid; /* request */
- u64 wr_offset; /* request */
- u32 wr_stable_how; /* request */
- u32 wr_buflen; /* request */
- int wr_vlen;
-
- u32 wr_bytes_written; /* response */
- u32 wr_how_written; /* response */
- nfs4_verifier wr_verifier; /* response */
-};
-
-struct nfsd4_exchange_id {
- nfs4_verifier verifier;
- struct xdr_netobj clname;
- u32 flags;
- clientid_t clientid;
- u32 seqid;
- int spa_how;
-};
-
-struct nfsd4_sequence {
- struct nfs4_sessionid sessionid; /* request/response */
- u32 seqid; /* request/response */
- u32 slotid; /* request/response */
- u32 maxslots; /* request/response */
- u32 cachethis; /* request */
-#if 0
- u32 target_maxslots; /* response */
-#endif /* not yet */
- u32 status_flags; /* response */
-};
-
-struct nfsd4_destroy_session {
- struct nfs4_sessionid sessionid;
-};
-
-struct nfsd4_destroy_clientid {
- clientid_t clientid;
-};
-
-struct nfsd4_reclaim_complete {
- u32 rca_one_fs;
-};
-
-struct nfsd4_op {
- int opnum;
- __be32 status;
- union {
- struct nfsd4_access access;
- struct nfsd4_close close;
- struct nfsd4_commit commit;
- struct nfsd4_create create;
- struct nfsd4_delegreturn delegreturn;
- struct nfsd4_getattr getattr;
- struct svc_fh * getfh;
- struct nfsd4_link link;
- struct nfsd4_lock lock;
- struct nfsd4_lockt lockt;
- struct nfsd4_locku locku;
- struct nfsd4_lookup lookup;
- struct nfsd4_verify nverify;
- struct nfsd4_open open;
- struct nfsd4_open_confirm open_confirm;
- struct nfsd4_open_downgrade open_downgrade;
- struct nfsd4_putfh putfh;
- struct nfsd4_read read;
- struct nfsd4_readdir readdir;
- struct nfsd4_readlink readlink;
- struct nfsd4_remove remove;
- struct nfsd4_rename rename;
- clientid_t renew;
- struct nfsd4_secinfo secinfo;
- struct nfsd4_setattr setattr;
- struct nfsd4_setclientid setclientid;
- struct nfsd4_setclientid_confirm setclientid_confirm;
- struct nfsd4_verify verify;
- struct nfsd4_write write;
- struct nfsd4_release_lockowner release_lockowner;
-
- /* NFSv4.1 */
- struct nfsd4_exchange_id exchange_id;
- struct nfsd4_bind_conn_to_session bind_conn_to_session;
- struct nfsd4_create_session create_session;
- struct nfsd4_destroy_session destroy_session;
- struct nfsd4_sequence sequence;
- struct nfsd4_reclaim_complete reclaim_complete;
- struct nfsd4_test_stateid test_stateid;
- struct nfsd4_free_stateid free_stateid;
- } u;
- struct nfs4_replay * replay;
-};
-
-bool nfsd4_cache_this_op(struct nfsd4_op *);
-
-struct nfsd4_compoundargs {
- /* scratch variables for XDR decode */
- __be32 * p;
- __be32 * end;
- struct page ** pagelist;
- int pagelen;
- __be32 tmp[8];
- __be32 * tmpp;
- struct tmpbuf {
- struct tmpbuf *next;
- void (*release)(const void *);
- void *buf;
- } *to_free;
-
- struct svc_rqst *rqstp;
-
- u32 taglen;
- char * tag;
- u32 minorversion;
- u32 opcnt;
- struct nfsd4_op *ops;
- struct nfsd4_op iops[8];
- int cachetype;
-};
-
-struct nfsd4_compoundres {
- /* scratch variables for XDR encode */
- __be32 * p;
- __be32 * end;
- struct xdr_buf * xbuf;
- struct svc_rqst * rqstp;
-
- u32 taglen;
- char * tag;
- u32 opcnt;
- __be32 * tagp; /* tag, opcount encode location */
- struct nfsd4_compound_state cstate;
-};
-
-static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp)
-{
- struct nfsd4_compoundargs *args = resp->rqstp->rq_argp;
- return resp->opcnt == 1 && args->ops[0].opnum == OP_SEQUENCE;
-}
-
-static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
-{
- return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
- || nfsd4_is_solo_sequence(resp);
-}
-
-#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)
-
-static inline void
-set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
-{
- BUG_ON(!fhp->fh_pre_saved);
- cinfo->atomic = fhp->fh_post_saved;
- cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode);
-
- cinfo->before_change = fhp->fh_pre_change;
- cinfo->after_change = fhp->fh_post_change;
- cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
- cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
- cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec;
- cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec;
-
-}
-
-int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
-int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
- struct nfsd4_compoundargs *);
-int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
- struct nfsd4_compoundres *);
-int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32);
-void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
-void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
-__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry, __be32 *buffer, int *countp,
- u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
-extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *,
- struct nfsd4_setclientid *setclid);
-extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *,
- struct nfsd4_setclientid_confirm *setclientid_confirm);
-extern void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp);
-extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
- struct nfsd4_sequence *seq);
-extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
-extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *);
-extern __be32 nfsd4_create_session(struct svc_rqst *,
- struct nfsd4_compound_state *,
- struct nfsd4_create_session *);
-extern __be32 nfsd4_sequence(struct svc_rqst *,
- struct nfsd4_compound_state *,
- struct nfsd4_sequence *);
-extern __be32 nfsd4_destroy_session(struct svc_rqst *,
- struct nfsd4_compound_state *,
- struct nfsd4_destroy_session *);
-extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_destroy_clientid *);
-__be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *);
-extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
- struct nfsd4_open *open);
-extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
- struct svc_fh *current_fh, struct nfsd4_open *open);
-extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status);
-extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc);
-extern __be32 nfsd4_close(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *,
- struct nfsd4_close *close);
-extern __be32 nfsd4_open_downgrade(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *,
- struct nfsd4_open_downgrade *od);
-extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *,
- struct nfsd4_lock *lock);
-extern __be32 nfsd4_lockt(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *,
- struct nfsd4_lockt *lockt);
-extern __be32 nfsd4_locku(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *,
- struct nfsd4_locku *locku);
-extern __be32
-nfsd4_release_lockowner(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *,
- struct nfsd4_release_lockowner *rlockowner);
-extern int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp);
-extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
-extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *, clientid_t *clid);
-extern __be32 nfsd4_test_stateid(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *, struct nfsd4_test_stateid *test_stateid);
-extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */