Pull nfsd updates from Bruce Fields: "Highlights: - Add a new knfsd file cache, so that we don't have to open and close on each (NFSv2/v3) READ or WRITE. This can speed up read and write in some cases. It also replaces our readahead cache. - Prevent silent data loss on write errors, by treating write errors like server reboots for the purposes of write caching, thus forcing clients to resend their writes. - Tweak the code that allocates sessions to be more forgiving, so that NFSv4.1 mounts are less likely to hang when a server already has a lot of clients. - Eliminate an arbitrary limit on NFSv4 ACL sizes; they should now be limited only by the backend filesystem and the maximum RPC size. - Allow the server to enforce use of the correct kerberos credentials when a client reclaims state after a reboot. And some miscellaneous smaller bugfixes and cleanup" * tag 'nfsd-5.4' of git://linux-nfs.org/~bfields/linux: (34 commits) sunrpc: clean up indentation issue nfsd: fix nfs read eof detection nfsd: Make nfsd_reset_boot_verifier_locked static nfsd: degraded slot-count more gracefully as allocation nears exhaustion. nfsd: handle drc over-allocation gracefully. nfsd: add support for upcall version 2 nfsd: add a "GetVersion" upcall for nfsdcld nfsd: Reset the boot verifier on all write I/O errors nfsd: Don't garbage collect files that might contain write errors nfsd: Support the server resetting the boot verifier nfsd: nfsd_file cache entries should be per net namespace nfsd: eliminate an unnecessary acl size limit Deprecate nfsd fault injection nfsd: remove duplicated include from filecache.c nfsd: Fix the documentation for svcxdr_tmpalloc() nfsd: Fix up some unused variable warnings nfsd: close cached files prior to a REMOVE or RENAME that would replace target nfsd: rip out the raparms cache nfsd: have nfsd_test_lock use the nfsd_file cache nfsd: hook up nfs4_preprocess_stateid_op to the nfsd_file cache ...
Unified · Split
| @@ -327,6 +327,7 @@ void flush_delayed_fput(void) · 326 unmodified lines | ||
| 327 | 327 | { |
| 328 | 328 | delayed_fput(NULL); |
| 329 | 329 | } |
| 330 | +EXPORT_SYMBOL_GPL(flush_delayed_fput); | |
| 330 | 331 | |
| 331 | 332 | static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); |
| 332 | 333 | |
| @@ -212,6 +212,7 @@ struct file_lock_list_struct { · 211 unmodified lines | ||
| 212 | 212 | static DEFINE_PER_CPU(struct file_lock_list_struct, file_lock_list); |
| 213 | 213 | DEFINE_STATIC_PERCPU_RWSEM(file_rwsem); |
| 214 | 214 | |
| 215 | + | |
| 215 | 216 | /* |
| 216 | 217 | * The blocked_hash is used to find POSIX lock loops for deadlock detection. |
| 217 | 218 | * It is protected by blocked_lock_lock. |
| @@ -1991,6 +1992,64 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp, · 1773 unmodified lines | ||
| 1991 | 1992 | } |
| 1992 | 1993 | EXPORT_SYMBOL(generic_setlease); |
| 1993 | 1994 | |
| 1995 | +#if IS_ENABLED(CONFIG_SRCU) | |
| 1996 | +/* | |
| 1997 | + * Kernel subsystems can register to be notified on any attempt to set | |
| 1998 | + * a new lease with the lease_notifier_chain. This is used by (e.g.) nfsd | |
| 1999 | + * to close files that it may have cached when there is an attempt to set a | |
| 2000 | + * conflicting lease. | |
| 2001 | + */ | |
| 2002 | +static struct srcu_notifier_head lease_notifier_chain; | |
| 2003 | + | |
| 2004 | +static inline void | |
| 2005 | +lease_notifier_chain_init(void) | |
| 2006 | +{ | |
| 2007 | + srcu_init_notifier_head(&lease_notifier_chain); | |
| 2008 | +} | |
| 2009 | + | |
| 2010 | +static inline void | |
| 2011 | +setlease_notifier(long arg, struct file_lock *lease) | |
| 2012 | +{ | |
| 2013 | + if (arg != F_UNLCK) | |
| 2014 | + srcu_notifier_call_chain(&lease_notifier_chain, arg, lease); | |
| 2015 | +} | |
| 2016 | + | |
| 2017 | +int lease_register_notifier(struct notifier_block *nb) | |
| 2018 | +{ | |
| 2019 | + return srcu_notifier_chain_register(&lease_notifier_chain, nb); | |
| 2020 | +} | |
| 2021 | +EXPORT_SYMBOL_GPL(lease_register_notifier); | |
| 2022 | + | |
| 2023 | +void lease_unregister_notifier(struct notifier_block *nb) | |
| 2024 | +{ | |
| 2025 | + srcu_notifier_chain_unregister(&lease_notifier_chain, nb); | |
| 2026 | +} | |
| 2027 | +EXPORT_SYMBOL_GPL(lease_unregister_notifier); | |
| 2028 | + | |
| 2029 | +#else /* !IS_ENABLED(CONFIG_SRCU) */ | |
| 2030 | +static inline void | |
| 2031 | +lease_notifier_chain_init(void) | |
| 2032 | +{ | |
| 2033 | +} | |
| 2034 | + | |
| 2035 | +static inline void | |
| 2036 | +setlease_notifier(long arg, struct file_lock *lease) | |
| 2037 | +{ | |
| 2038 | +} | |
| 2039 | + | |
| 2040 | +int lease_register_notifier(struct notifier_block *nb) | |
| 2041 | +{ | |
| 2042 | + return 0; | |
| 2043 | +} | |
| 2044 | +EXPORT_SYMBOL_GPL(lease_register_notifier); | |
| 2045 | + | |
| 2046 | +void lease_unregister_notifier(struct notifier_block *nb) | |
| 2047 | +{ | |
| 2048 | +} | |
| 2049 | +EXPORT_SYMBOL_GPL(lease_unregister_notifier); | |
| 2050 | + | |
| 2051 | +#endif /* IS_ENABLED(CONFIG_SRCU) */ | |
| 2052 | + | |
| 1994 | 2053 | /** |
| 1995 | 2054 | * vfs_setlease - sets a lease on an open file |
| 1996 | 2055 | * @filp: file pointer |
| @@ -2011,6 +2070,8 @@ EXPORT_SYMBOL(generic_setlease); · 14 unmodified lines | ||
| 2011 | 2070 | int |
| 2012 | 2071 | vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) |
| 2013 | 2072 | { |
| 2073 | + if (lease) | |
| 2074 | + setlease_notifier(arg, *lease); | |
| 2014 | 2075 | if (filp->f_op->setlease) |
| 2015 | 2076 | return filp->f_op->setlease(filp, arg, lease, priv); |
| 2016 | 2077 | else |
| @@ -2924,6 +2985,7 @@ static int __init filelock_init(void) · 907 unmodified lines | ||
| 2924 | 2985 | INIT_HLIST_HEAD(&fll->hlist); |
| 2925 | 2986 | } |
| 2926 | 2987 | |
| 2988 | + lease_notifier_chain_init(); | |
| 2927 | 2989 | return 0; |
| 2928 | 2990 | } |
| 2929 | 2991 | core_initcall(filelock_init); |
| @@ -3,6 +3,7 @@ config NFSD · 2 unmodified lines | ||
| 3 | 3 | tristate "NFS server support" |
| 4 | 4 | depends on INET |
| 5 | 5 | depends on FILE_LOCKING |
| 6 | + depends on FSNOTIFY | |
| 6 | 7 | select LOCKD |
| 7 | 8 | select SUNRPC |
| 8 | 9 | select EXPORTFS |
| @@ -147,7 +148,7 @@ config NFSD_V4_SECURITY_LABEL · 138 unmodified lines | ||
| 147 | 148 | |
| 148 | 149 | config NFSD_FAULT_INJECTION |
| 149 | 150 | bool "NFS server manual fault injection" |
| 150 | − depends on NFSD_V4 && DEBUG_KERNEL && DEBUG_FS | |
| 151 | + depends on NFSD_V4 && DEBUG_KERNEL && DEBUG_FS && BROKEN | |
| 151 | 152 | help |
| 152 | 153 | This option enables support for manually injecting faults |
| 153 | 154 | into the NFS server. This is intended to be used for |
| @@ -11,7 +11,8 @@ obj-$(CONFIG_NFSD) += nfsd.o · 10 unmodified lines | ||
| 11 | 11 | nfsd-y += trace.o |
| 12 | 12 | |
| 13 | 13 | nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ |
| 14 | − export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o | |
| 14 | + export.o auth.o lockd.o nfscache.o nfsxdr.o \ | |
| 15 | + stats.o filecache.o | |
| 15 | 16 | nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o |
| 16 | 17 | nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o |
| 17 | 18 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o |
| @@ -39,14 +39,6 @@ struct nfs4_acl; · 38 unmodified lines | ||
| 39 | 39 | struct svc_fh; |
| 40 | 40 | struct svc_rqst; |
| 41 | 41 | |
| 42 | −/* | |
| 43 | − * Maximum ACL we'll accept from a client; chosen (somewhat | |
| 44 | − * arbitrarily) so that kmalloc'ing the ACL shouldn't require a | |
| 45 | − * high-order allocation. This allows 204 ACEs on x86_64: | |
| 46 | − */ | |
| 47 | −#define NFS4_ACL_MAX ((PAGE_SIZE - sizeof(struct nfs4_acl)) \ | |
| 48 | − / sizeof(struct nfs4_ace)) | |
| 49 | − | |
| 50 | 42 | int nfs4_acl_bytes(int entries); |
| 51 | 43 | int nfs4_acl_get_whotype(char *, u32); |
| 52 | 44 | __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who); |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | #include "blocklayoutxdr.h" |
| 17 | 17 | #include "pnfs.h" |
| 18 | +#include "filecache.h" | |
| 18 | 19 | |
| 19 | 20 | #define NFSDDBG_FACILITY NFSDDBG_PNFS |
| 20 | 21 | |
| @@ -404,7 +405,7 @@ static void · 383 unmodified lines | ||
| 404 | 405 | nfsd4_scsi_fence_client(struct nfs4_layout_stateid *ls) |
| 405 | 406 | { |
| 406 | 407 | struct nfs4_client *clp = ls->ls_stid.sc_client; |
| 407 | − struct block_device *bdev = ls->ls_file->f_path.mnt->mnt_sb->s_bdev; | |
| 408 | + struct block_device *bdev = ls->ls_file->nf_file->f_path.mnt->mnt_sb->s_bdev; | |
| 408 | 409 | |
| 409 | 410 | bdev->bd_disk->fops->pr_ops->pr_preempt(bdev, NFSD_MDS_PR_KEY, |
| 410 | 411 | nfsd4_scsi_pr_key(clp), 0, true); |
| @@ -22,6 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #include "nfsfh.h" |
| 23 | 23 | #include "netns.h" |
| 24 | 24 | #include "pnfs.h" |
| 25 | +#include "filecache.h" | |
| 25 | 26 | |
| 26 | 27 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT |
| 27 | 28 | |
| @@ -232,6 +233,17 @@ static struct cache_head *expkey_alloc(void) · 204 unmodified lines | ||
| 232 | 233 | return NULL; |
| 233 | 234 | } |
| 234 | 235 | |
| 236 | +static void expkey_flush(void) | |
| 237 | +{ | |
| 238 | + /* | |
| 239 | + * Take the nfsd_mutex here to ensure that the file cache is not | |
| 240 | + * destroyed while we're in the middle of flushing. | |
| 241 | + */ | |
| 242 | + mutex_lock(&nfsd_mutex); | |
| 243 | + nfsd_file_cache_purge(current->nsproxy->net_ns); | |
| 244 | + mutex_unlock(&nfsd_mutex); | |
| 245 | +} | |
| 246 | + | |
| 235 | 247 | static const struct cache_detail svc_expkey_cache_template = { |
| 236 | 248 | .owner = THIS_MODULE, |
| 237 | 249 | .hash_size = EXPKEY_HASHMAX, |
| @@ -244,6 +256,7 @@ static const struct cache_detail svc_expkey_cache_template = { · 6 unmodified lines | ||
| 244 | 256 | .init = expkey_init, |
| 245 | 257 | .update = expkey_update, |
| 246 | 258 | .alloc = expkey_alloc, |
| 259 | + .flush = expkey_flush, | |
| 247 | 260 | }; |
| 248 | 261 | |
| 249 | 262 | static int |
| @@ -0,0 +1,934 @@ | ||
| 1 | +/* | |
| 2 | + * Open file cache. | |
| 3 | + * | |
| 4 | + * (c) 2015 - Jeff Layton <jeff.layton@primarydata.com> | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#include <linux/hash.h> | |
| 8 | +#include <linux/slab.h> | |
| 9 | +#include <linux/file.h> | |
| 10 | +#include <linux/sched.h> | |
| 11 | +#include <linux/list_lru.h> | |
| 12 | +#include <linux/fsnotify_backend.h> | |
| 13 | +#include <linux/fsnotify.h> | |
| 14 | +#include <linux/seq_file.h> | |
| 15 | + | |
| 16 | +#include "vfs.h" | |
| 17 | +#include "nfsd.h" | |
| 18 | +#include "nfsfh.h" | |
| 19 | +#include "netns.h" | |
| 20 | +#include "filecache.h" | |
| 21 | +#include "trace.h" | |
| 22 | + | |
| 23 | +#define NFSDDBG_FACILITY NFSDDBG_FH | |
| 24 | + | |
| 25 | +/* FIXME: dynamically size this for the machine somehow? */ | |
| 26 | +#define NFSD_FILE_HASH_BITS 12 | |
| 27 | +#define NFSD_FILE_HASH_SIZE (1 << NFSD_FILE_HASH_BITS) | |
| 28 | +#define NFSD_LAUNDRETTE_DELAY (2 * HZ) | |
| 29 | + | |
| 30 | +#define NFSD_FILE_LRU_RESCAN (0) | |
| 31 | +#define NFSD_FILE_SHUTDOWN (1) | |
| 32 | +#define NFSD_FILE_LRU_THRESHOLD (4096UL) | |
| 33 | +#define NFSD_FILE_LRU_LIMIT (NFSD_FILE_LRU_THRESHOLD << 2) | |
| 34 | + | |
| 35 | +/* We only care about NFSD_MAY_READ/WRITE for this cache */ | |
| 36 | +#define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE) | |
| 37 | + | |
| 38 | +struct nfsd_fcache_bucket { | |
| 39 | + struct hlist_head nfb_head; | |
| 40 | + spinlock_t nfb_lock; | |
| 41 | + unsigned int nfb_count; | |
| 42 | + unsigned int nfb_maxcount; | |
| 43 | +}; | |
| 44 | + | |
| 45 | +static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); | |
| 46 | + | |
| 47 | +static struct kmem_cache *nfsd_file_slab; | |
| 48 | +static struct kmem_cache *nfsd_file_mark_slab; | |
| 49 | +static struct nfsd_fcache_bucket *nfsd_file_hashtbl; | |
| 50 | +static struct list_lru nfsd_file_lru; | |
| 51 | +static long nfsd_file_lru_flags; | |
| 52 | +static struct fsnotify_group *nfsd_file_fsnotify_group; | |
| 53 | +static atomic_long_t nfsd_filecache_count; | |
| 54 | +static struct delayed_work nfsd_filecache_laundrette; | |
| 55 | + | |
| 56 | +enum nfsd_file_laundrette_ctl { | |
| 57 | + NFSD_FILE_LAUNDRETTE_NOFLUSH = 0, | |
| 58 | + NFSD_FILE_LAUNDRETTE_MAY_FLUSH | |
| 59 | +}; | |
| 60 | + | |
| 61 | +static void | |
| 62 | +nfsd_file_schedule_laundrette(enum nfsd_file_laundrette_ctl ctl) | |
| 63 | +{ | |
| 64 | + long count = atomic_long_read(&nfsd_filecache_count); | |
| 65 | + | |
| 66 | + if (count == 0 || test_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags)) | |
| 67 | + return; | |
| 68 | + | |
| 69 | + /* Be more aggressive about scanning if over the threshold */ | |
| 70 | + if (count > NFSD_FILE_LRU_THRESHOLD) | |
| 71 | + mod_delayed_work(system_wq, &nfsd_filecache_laundrette, 0); | |
| 72 | + else | |
| 73 | + schedule_delayed_work(&nfsd_filecache_laundrette, NFSD_LAUNDRETTE_DELAY); | |
| 74 | + | |
| 75 | + if (ctl == NFSD_FILE_LAUNDRETTE_NOFLUSH) | |
| 76 | + return; | |
| 77 | + | |
| 78 | + /* ...and don't delay flushing if we're out of control */ | |
| 79 | + if (count >= NFSD_FILE_LRU_LIMIT) | |
| 80 | + flush_delayed_work(&nfsd_filecache_laundrette); | |
| 81 | +} | |
| 82 | + | |
| 83 | +static void | |
| 84 | +nfsd_file_slab_free(struct rcu_head *rcu) | |
| 85 | +{ | |
| 86 | + struct nfsd_file *nf = container_of(rcu, struct nfsd_file, nf_rcu); | |
| 87 | + | |
| 88 | + put_cred(nf->nf_cred); | |
| 89 | + kmem_cache_free(nfsd_file_slab, nf); | |
| 90 | +} | |
| 91 | + | |
| 92 | +static void | |
| 93 | +nfsd_file_mark_free(struct fsnotify_mark *mark) | |
| 94 | +{ | |
| 95 | + struct nfsd_file_mark *nfm = container_of(mark, struct nfsd_file_mark, | |
| 96 | + nfm_mark); | |
| 97 | + | |
| 98 | + kmem_cache_free(nfsd_file_mark_slab, nfm); | |
| 99 | +} | |
| 100 | + | |
| 101 | +static struct nfsd_file_mark * | |
| 102 | +nfsd_file_mark_get(struct nfsd_file_mark *nfm) | |
| 103 | +{ | |
| 104 | + if (!atomic_inc_not_zero(&nfm->nfm_ref)) | |
| 105 | + return NULL; | |
| 106 | + return nfm; | |
| 107 | +} | |
| 108 | + | |
| 109 | +static void | |
| 110 | +nfsd_file_mark_put(struct nfsd_file_mark *nfm) | |
| 111 | +{ | |
| 112 | + if (atomic_dec_and_test(&nfm->nfm_ref)) { | |
| 113 | + | |
| 114 | + fsnotify_destroy_mark(&nfm->nfm_mark, nfsd_file_fsnotify_group); | |
| 115 | + fsnotify_put_mark(&nfm->nfm_mark); | |
| 116 | + } | |
| 117 | +} | |
| 118 | + | |
| 119 | +static struct nfsd_file_mark * | |
| 120 | +nfsd_file_mark_find_or_create(struct nfsd_file *nf) | |
| 121 | +{ | |
| 122 | + int err; | |
| 123 | + struct fsnotify_mark *mark; | |
| 124 | + struct nfsd_file_mark *nfm = NULL, *new; | |
| 125 | + struct inode *inode = nf->nf_inode; | |
| 126 | + | |
| 127 | + do { | |
| 128 | + mutex_lock(&nfsd_file_fsnotify_group->mark_mutex); | |
| 129 | + mark = fsnotify_find_mark(&inode->i_fsnotify_marks, | |
| 130 | + nfsd_file_fsnotify_group); | |
| 131 | + if (mark) { | |
| 132 | + nfm = nfsd_file_mark_get(container_of(mark, | |
| 133 | + struct nfsd_file_mark, | |
| 134 | + nfm_mark)); | |
| 135 | + mutex_unlock(&nfsd_file_fsnotify_group->mark_mutex); | |
| 136 | + fsnotify_put_mark(mark); | |
| 137 | + if (likely(nfm)) | |
| 138 | + break; | |
| 139 | + } else | |
| 140 | + mutex_unlock(&nfsd_file_fsnotify_group->mark_mutex); | |
| 141 | + | |
| 142 | + /* allocate a new nfm */ | |
| 143 | + new = kmem_cache_alloc(nfsd_file_mark_slab, GFP_KERNEL); | |
| 144 | + if (!new) | |
| 145 | + return NULL; | |
| 146 | + fsnotify_init_mark(&new->nfm_mark, nfsd_file_fsnotify_group); | |
| 147 | + new->nfm_mark.mask = FS_ATTRIB|FS_DELETE_SELF; | |
| 148 | + atomic_set(&new->nfm_ref, 1); | |
| 149 | + | |
| 150 | + err = fsnotify_add_inode_mark(&new->nfm_mark, inode, 0); | |
| 151 | + | |
| 152 | + /* | |
| 153 | + * If the add was successful, then return the object. | |
| 154 | + * Otherwise, we need to put the reference we hold on the | |
| 155 | + * nfm_mark. The fsnotify code will take a reference and put | |
| 156 | + * it on failure, so we can't just free it directly. It's also | |
| 157 | + * not safe to call fsnotify_destroy_mark on it as the | |
| 158 | + * mark->group will be NULL. Thus, we can't let the nfm_ref | |
| 159 | + * counter drive the destruction at this point. | |
| 160 | + */ | |
| 161 | + if (likely(!err)) | |
| 162 | + nfm = new; | |
| 163 | + else | |
| 164 | + fsnotify_put_mark(&new->nfm_mark); | |
| 165 | + } while (unlikely(err == -EEXIST)); | |
| 166 | + | |
| 167 | + return nfm; | |
| 168 | +} | |
| 169 | + | |
| 170 | +static struct nfsd_file * | |
| 171 | +nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval, | |
| 172 | + struct net *net) | |
| 173 | +{ | |
| 174 | + struct nfsd_file *nf; | |
| 175 | + | |
| 176 | + nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL); | |
| 177 | + if (nf) { | |
| 178 | + INIT_HLIST_NODE(&nf->nf_node); | |
| 179 | + INIT_LIST_HEAD(&nf->nf_lru); | |
| 180 | + nf->nf_file = NULL; | |
| 181 | + nf->nf_cred = get_current_cred(); | |
| 182 | + nf->nf_net = net; | |
| 183 | + nf->nf_flags = 0; | |
| 184 | + nf->nf_inode = inode; | |
| 185 | + nf->nf_hashval = hashval; | |
| 186 | + atomic_set(&nf->nf_ref, 1); | |
| 187 | + nf->nf_may = may & NFSD_FILE_MAY_MASK; | |
| 188 | + if (may & NFSD_MAY_NOT_BREAK_LEASE) { | |
| 189 | + if (may & NFSD_MAY_WRITE) | |
| 190 | + __set_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags); | |
| 191 | + if (may & NFSD_MAY_READ) | |
| 192 | + __set_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags); | |
| 193 | + } | |
| 194 | + nf->nf_mark = NULL; | |
| 195 | + trace_nfsd_file_alloc(nf); | |
| 196 | + } | |
| 197 | + return nf; | |
| 198 | +} | |
| 199 | + | |
| 200 | +static bool | |
| 201 | +nfsd_file_free(struct nfsd_file *nf) | |
| 202 | +{ | |
| 203 | + bool flush = false; | |
| 204 | + | |
| 205 | + trace_nfsd_file_put_final(nf); | |
| 206 | + if (nf->nf_mark) | |
| 207 | + nfsd_file_mark_put(nf->nf_mark); | |
| 208 | + if (nf->nf_file) { | |
| 209 | + get_file(nf->nf_file); | |
| 210 | + filp_close(nf->nf_file, NULL); | |
| 211 | + fput(nf->nf_file); | |
| 212 | + flush = true; | |
| 213 | + } | |
| 214 | + call_rcu(&nf->nf_rcu, nfsd_file_slab_free); | |
| 215 | + return flush; | |
| 216 | +} | |
| 217 | + | |
| 218 | +static bool | |
| 219 | +nfsd_file_check_writeback(struct nfsd_file *nf) | |
| 220 | +{ | |
| 221 | + struct file *file = nf->nf_file; | |
| 222 | + struct address_space *mapping; | |
| 223 | + | |
| 224 | + if (!file || !(file->f_mode & FMODE_WRITE)) | |
| 225 | + return false; | |
| 226 | + mapping = file->f_mapping; | |
| 227 | + return mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) || | |
| 228 | + mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK); | |
| 229 | +} | |
| 230 | + | |
| 231 | +static int | |
| 232 | +nfsd_file_check_write_error(struct nfsd_file *nf) | |
| 233 | +{ | |
| 234 | + struct file *file = nf->nf_file; | |
| 235 | + | |
| 236 | + if (!file || !(file->f_mode & FMODE_WRITE)) | |
| 237 | + return 0; | |
| 238 | + return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err)); | |
| 239 | +} | |
| 240 | + | |
| 241 | +static bool | |
| 242 | +nfsd_file_in_use(struct nfsd_file *nf) | |
| 243 | +{ | |
| 244 | + return nfsd_file_check_writeback(nf) || | |
| 245 | + nfsd_file_check_write_error(nf); | |
| 246 | +} | |
| 247 | + | |
| 248 | +static void | |
| 249 | +nfsd_file_do_unhash(struct nfsd_file *nf) | |
| 250 | +{ | |
| 251 | + lockdep_assert_held(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); | |
| 252 | + | |
| 253 | + trace_nfsd_file_unhash(nf); | |
| 254 | + | |
| 255 | + if (nfsd_file_check_write_error(nf)) | |
| 256 | + nfsd_reset_boot_verifier(net_generic(nf->nf_net, nfsd_net_id)); | |
| 257 | + --nfsd_file_hashtbl[nf->nf_hashval].nfb_count; | |
| 258 | + hlist_del_rcu(&nf->nf_node); | |
| 259 | + if (!list_empty(&nf->nf_lru)) | |
| 260 | + list_lru_del(&nfsd_file_lru, &nf->nf_lru); | |
| 261 | + atomic_long_dec(&nfsd_filecache_count); | |
| 262 | +} | |
| 263 | + | |
| 264 | +static bool | |
| 265 | +nfsd_file_unhash(struct nfsd_file *nf) | |
| 266 | +{ | |
| 267 | + if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { | |
| 268 | + nfsd_file_do_unhash(nf); | |
| 269 | + return true; | |
| 270 | + } | |
| 271 | + return false; | |
| 272 | +} | |
| 273 | + | |
| 274 | +/* | |
| 275 | + * Return true if the file was unhashed. | |
| 276 | + */ | |
| 277 | +static bool | |
| 278 | +nfsd_file_unhash_and_release_locked(struct nfsd_file *nf, struct list_head *dispose) | |
| 279 | +{ | |
| 280 | + lockdep_assert_held(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); | |
| 281 | + | |
| 282 | + trace_nfsd_file_unhash_and_release_locked(nf); | |
| 283 | + if (!nfsd_file_unhash(nf)) | |
| 284 | + return false; | |
| 285 | + /* keep final reference for nfsd_file_lru_dispose */ | |
| 286 | + if (atomic_add_unless(&nf->nf_ref, -1, 1)) | |
| 287 | + return true; | |
| 288 | + | |
| 289 | + list_add(&nf->nf_lru, dispose); | |
| 290 | + return true; | |
| 291 | +} | |
| 292 | + | |
| 293 | +static int | |
| 294 | +nfsd_file_put_noref(struct nfsd_file *nf) | |
| 295 | +{ | |
| 296 | + int count; | |
| 297 | + trace_nfsd_file_put(nf); | |
| 298 | + | |
| 299 | + count = atomic_dec_return(&nf->nf_ref); | |
| 300 | + if (!count) { | |
| 301 | + WARN_ON(test_bit(NFSD_FILE_HASHED, &nf->nf_flags)); | |
| 302 | + nfsd_file_free(nf); | |
| 303 | + } | |
| 304 | + return count; | |
| 305 | +} | |
| 306 | + | |
| 307 | +void | |
| 308 | +nfsd_file_put(struct nfsd_file *nf) | |
| 309 | +{ | |
| 310 | + bool is_hashed = test_bit(NFSD_FILE_HASHED, &nf->nf_flags) != 0; | |
| 311 | + bool unused = !nfsd_file_in_use(nf); | |
| 312 | + | |
| 313 | + set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); | |
| 314 | + if (nfsd_file_put_noref(nf) == 1 && is_hashed && unused) | |
| 315 | + nfsd_file_schedule_laundrette(NFSD_FILE_LAUNDRETTE_MAY_FLUSH); | |
| 316 | +} | |
| 317 | + | |
| 318 | +struct nfsd_file * | |
| 319 | +nfsd_file_get(struct nfsd_file *nf) | |
| 320 | +{ | |
| 321 | + if (likely(atomic_inc_not_zero(&nf->nf_ref))) | |
| 322 | + return nf; | |
| 323 | + return NULL; | |
| 324 | +} | |
| 325 | + | |
| 326 | +static void | |
| 327 | +nfsd_file_dispose_list(struct list_head *dispose) | |
| 328 | +{ | |
| 329 | + struct nfsd_file *nf; | |
| 330 | + | |
| 331 | + while(!list_empty(dispose)) { | |
| 332 | + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); | |
| 333 | + list_del(&nf->nf_lru); | |
| 334 | + nfsd_file_put_noref(nf); | |
| 335 | + } | |
| 336 | +} | |
| 337 | + | |
| 338 | +static void | |
| 339 | +nfsd_file_dispose_list_sync(struct list_head *dispose) | |
| 340 | +{ | |
| 341 | + bool flush = false; | |
| 342 | + struct nfsd_file *nf; | |
| 343 | + | |
| 344 | + while(!list_empty(dispose)) { | |
| 345 | + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); | |
| 346 | + list_del(&nf->nf_lru); | |
| 347 | + if (!atomic_dec_and_test(&nf->nf_ref)) | |
| 348 | + continue; | |
| 349 | + if (nfsd_file_free(nf)) | |
| 350 | + flush = true; | |
| 351 | + } | |
| 352 | + if (flush) | |
| 353 | + flush_delayed_fput(); | |
| 354 | +} | |
| 355 | + | |
| 356 | +/* | |
| 357 | + * Note this can deadlock with nfsd_file_cache_purge. | |
| 358 | + */ | |
| 359 | +static enum lru_status | |
| 360 | +nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, | |
| 361 | + spinlock_t *lock, void *arg) | |
| 362 | + __releases(lock) | |
| 363 | + __acquires(lock) | |
| 364 | +{ | |
| 365 | + struct list_head *head = arg; | |
| 366 | + struct nfsd_file *nf = list_entry(item, struct nfsd_file, nf_lru); | |
| 367 | + | |
| 368 | + /* | |
| 369 | + * Do a lockless refcount check. The hashtable holds one reference, so | |
| 370 | + * we look to see if anything else has a reference, or if any have | |
| 371 | + * been put since the shrinker last ran. Those don't get unhashed and | |
| 372 | + * released. | |
| 373 | + * | |
| 374 | + * Note that in the put path, we set the flag and then decrement the | |
| 375 | + * counter. Here we check the counter and then test and clear the flag. | |
| 376 | + * That order is deliberate to ensure that we can do this locklessly. | |
| 377 | + */ | |
| 378 | + if (atomic_read(&nf->nf_ref) > 1) | |
| 379 | + goto out_skip; | |
| 380 | + | |
| 381 | + /* | |
| 382 | + * Don't throw out files that are still undergoing I/O or | |
| 383 | + * that have uncleared errors pending. | |
| 384 | + */ | |
| 385 | + if (nfsd_file_check_writeback(nf)) | |
| 386 | + goto out_skip; | |
| 387 | + | |
| 388 | + if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) | |
| 389 | + goto out_rescan; | |
| 390 | + | |
| 391 | + if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) | |
| 392 | + goto out_skip; | |
| 393 | + | |
| 394 | + list_lru_isolate_move(lru, &nf->nf_lru, head); | |
| 395 | + return LRU_REMOVED; | |
| 396 | +out_rescan: | |
| 397 | + set_bit(NFSD_FILE_LRU_RESCAN, &nfsd_file_lru_flags); | |
| 398 | +out_skip: | |
| 399 | + return LRU_SKIP; | |
| 400 | +} | |
| 401 | + | |
| 402 | +static void | |
| 403 | +nfsd_file_lru_dispose(struct list_head *head) | |
| 404 | +{ | |
| 405 | + while(!list_empty(head)) { | |
| 406 | + struct nfsd_file *nf = list_first_entry(head, | |
| 407 | + struct nfsd_file, nf_lru); | |
| 408 | + list_del_init(&nf->nf_lru); | |
| 409 | + spin_lock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); | |
| 410 | + nfsd_file_do_unhash(nf); | |
| 411 | + spin_unlock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); | |
| 412 | + nfsd_file_put_noref(nf); | |
| 413 | + } | |
| 414 | +} | |
| 415 | + | |
| 416 | +static unsigned long | |
| 417 | +nfsd_file_lru_count(struct shrinker *s, struct shrink_control *sc) | |
| 418 | +{ | |
| 419 | + return list_lru_count(&nfsd_file_lru); | |
| 420 | +} | |
| 421 | + | |
| 422 | +static unsigned long | |
| 423 | +nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc) | |
| 424 | +{ | |
| 425 | + LIST_HEAD(head); | |
| 426 | + unsigned long ret; | |
| 427 | + | |
| 428 | + ret = list_lru_shrink_walk(&nfsd_file_lru, sc, nfsd_file_lru_cb, &head); | |
| 429 | + nfsd_file_lru_dispose(&head); | |
| 430 | + return ret; | |
| 431 | +} | |
| 432 | + | |
| 433 | +static struct shrinker nfsd_file_shrinker = { | |
| 434 | + .scan_objects = nfsd_file_lru_scan, | |
| 435 | + .count_objects = nfsd_file_lru_count, | |
| 436 | + .seeks = 1, | |
| 437 | +}; | |
| 438 | + | |
| 439 | +static void | |
| 440 | +__nfsd_file_close_inode(struct inode *inode, unsigned int hashval, | |
| 441 | + struct list_head *dispose) | |
| 442 | +{ | |
| 443 | + struct nfsd_file *nf; | |
| 444 | + struct hlist_node *tmp; | |
| 445 | + | |
| 446 | + spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); | |
| 447 | + hlist_for_each_entry_safe(nf, tmp, &nfsd_file_hashtbl[hashval].nfb_head, nf_node) { | |
| 448 | + if (inode == nf->nf_inode) | |
| 449 | + nfsd_file_unhash_and_release_locked(nf, dispose); | |
| 450 | + } | |
| 451 | + spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); | |
| 452 | +} | |
| 453 | + | |
| 454 | +/** | |
| 455 | + * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file | |
| 456 | + * @inode: inode of the file to attempt to remove | |
| 457 | + * | |
| 458 | + * Walk the whole hash bucket, looking for any files that correspond to "inode". | |
| 459 | + * If any do, then unhash them and put the hashtable reference to them and | |
| 460 | + * destroy any that had their last reference put. Also ensure that any of the | |
| 461 | + * fputs also have their final __fput done as well. | |
| 462 | + */ | |
| 463 | +void | |
| 464 | +nfsd_file_close_inode_sync(struct inode *inode) | |
| 465 | +{ | |
| 466 | + unsigned int hashval = (unsigned int)hash_long(inode->i_ino, | |
| 467 | + NFSD_FILE_HASH_BITS); | |
| 468 | + LIST_HEAD(dispose); | |
| 469 | + | |
| 470 | + __nfsd_file_close_inode(inode, hashval, &dispose); | |
| 471 | + trace_nfsd_file_close_inode_sync(inode, hashval, !list_empty(&dispose)); | |
| 472 | + nfsd_file_dispose_list_sync(&dispose); | |
| 473 | +} | |
| 474 | + | |
| 475 | +/** | |
| 476 | + * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file | |
| 477 | + * @inode: inode of the file to attempt to remove | |
| 478 | + * | |
| 479 | + * Walk the whole hash bucket, looking for any files that correspond to "inode". | |
| 480 | + * If any do, then unhash them and put the hashtable reference to them and | |
| 481 | + * destroy any that had their last reference put. | |
| 482 | + */ | |
| 483 | +static void | |
| 484 | +nfsd_file_close_inode(struct inode *inode) | |
| 485 | +{ | |
| 486 | + unsigned int hashval = (unsigned int)hash_long(inode->i_ino, | |
| 487 | + NFSD_FILE_HASH_BITS); | |
| 488 | + LIST_HEAD(dispose); | |
| 489 | + | |
| 490 | + __nfsd_file_close_inode(inode, hashval, &dispose); | |
| 491 | + trace_nfsd_file_close_inode(inode, hashval, !list_empty(&dispose)); | |
| 492 | + nfsd_file_dispose_list(&dispose); | |
| 493 | +} | |
| 494 | + | |
| 495 | +/** | |
| 496 | + * nfsd_file_delayed_close - close unused nfsd_files | |
| 497 | + * @work: dummy | |
| 498 | + * | |
| 499 | + * Walk the LRU list and close any entries that have not been used since | |
| 500 | + * the last scan. | |
| 501 | + * | |
| 502 | + * Note this can deadlock with nfsd_file_cache_purge. | |
| 503 | + */ | |
| 504 | +static void | |
| 505 | +nfsd_file_delayed_close(struct work_struct *work) | |
| 506 | +{ | |
| 507 | + LIST_HEAD(head); | |
| 508 | + | |
| 509 | + list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb, &head, LONG_MAX); | |
| 510 | + | |
| 511 | + if (test_and_clear_bit(NFSD_FILE_LRU_RESCAN, &nfsd_file_lru_flags)) | |
| 512 | + nfsd_file_schedule_laundrette(NFSD_FILE_LAUNDRETTE_NOFLUSH); | |
| 513 | + | |
| 514 | + if (!list_empty(&head)) { | |
| 515 | + nfsd_file_lru_dispose(&head); | |
| 516 | + flush_delayed_fput(); | |
| 517 | + } | |
| 518 | +} | |
| 519 | + | |
| 520 | +static int | |
| 521 | +nfsd_file_lease_notifier_call(struct notifier_block *nb, unsigned long arg, | |
| 522 | + void *data) | |
| 523 | +{ | |
| 524 | + struct file_lock *fl = data; | |
| 525 | + | |
| 526 | + /* Only close files for F_SETLEASE leases */ | |
| 527 | + if (fl->fl_flags & FL_LEASE) | |
| 528 | + nfsd_file_close_inode_sync(file_inode(fl->fl_file)); | |
| 529 | + return 0; | |
| 530 | +} | |
| 531 | + | |
| 532 | +static struct notifier_block nfsd_file_lease_notifier = { | |
| 533 | + .notifier_call = nfsd_file_lease_notifier_call, | |
| 534 | +}; | |
| 535 | + | |
| 536 | +static int | |
| 537 | +nfsd_file_fsnotify_handle_event(struct fsnotify_group *group, | |
| 538 | + struct inode *inode, | |
| 539 | + u32 mask, const void *data, int data_type, | |
| 540 | + const struct qstr *file_name, u32 cookie, | |
| 541 | + struct fsnotify_iter_info *iter_info) | |
| 542 | +{ | |
| 543 | + trace_nfsd_file_fsnotify_handle_event(inode, mask); | |
| 544 | + | |
| 545 | + /* Should be no marks on non-regular files */ | |
| 546 | + if (!S_ISREG(inode->i_mode)) { | |
| 547 | + WARN_ON_ONCE(1); | |
| 548 | + return 0; | |
| 549 | + } | |
| 550 | + | |
| 551 | + /* don't close files if this was not the last link */ | |
| 552 | + if (mask & FS_ATTRIB) { | |
| 553 | + if (inode->i_nlink) | |
| 554 | + return 0; | |
| 555 | + } | |
| 556 | + | |
| 557 | + nfsd_file_close_inode(inode); | |
| 558 | + return 0; | |
| 559 | +} | |
| 560 | + | |
| 561 | + | |
| 562 | +static const struct fsnotify_ops nfsd_file_fsnotify_ops = { | |
| 563 | + .handle_event = nfsd_file_fsnotify_handle_event, | |
| 564 | + .free_mark = nfsd_file_mark_free, | |
| 565 | +}; | |
| 566 | + | |
| 567 | +int | |
| 568 | +nfsd_file_cache_init(void) | |
| 569 | +{ | |
| 570 | + int ret = -ENOMEM; | |
| 571 | + unsigned int i; | |
| 572 | + | |
| 573 | + clear_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags); | |
| 574 | + | |
| 575 | + if (nfsd_file_hashtbl) | |
| 576 | + return 0; | |
| 577 | + | |
| 578 | + nfsd_file_hashtbl = kcalloc(NFSD_FILE_HASH_SIZE, | |
| 579 | + sizeof(*nfsd_file_hashtbl), GFP_KERNEL); | |
| 580 | + if (!nfsd_file_hashtbl) { | |
| 581 | + pr_err("nfsd: unable to allocate nfsd_file_hashtbl\n"); | |
| 582 | + goto out_err; | |
| 583 | + } | |
| 584 | + | |
| 585 | + nfsd_file_slab = kmem_cache_create("nfsd_file", | |
| 586 | + sizeof(struct nfsd_file), 0, 0, NULL); | |
| 587 | + if (!nfsd_file_slab) { | |
| 588 | + pr_err("nfsd: unable to create nfsd_file_slab\n"); | |
| 589 | + goto out_err; | |
| 590 | + } | |
| 591 | + | |
| 592 | + nfsd_file_mark_slab = kmem_cache_create("nfsd_file_mark", | |
| 593 | + sizeof(struct nfsd_file_mark), 0, 0, NULL); | |
| 594 | + if (!nfsd_file_mark_slab) { | |
| 595 | + pr_err("nfsd: unable to create nfsd_file_mark_slab\n"); | |
| 596 | + goto out_err; | |
| 597 | + } | |
| 598 | + | |
| 599 | + | |
| 600 | + ret = list_lru_init(&nfsd_file_lru); | |
| 601 | + if (ret) { | |
| 602 | + pr_err("nfsd: failed to init nfsd_file_lru: %d\n", ret); | |
| 603 | + goto out_err; | |
| 604 | + } | |
| 605 | + | |
| 606 | + ret = register_shrinker(&nfsd_file_shrinker); | |
| 607 | + if (ret) { | |
| 608 | + pr_err("nfsd: failed to register nfsd_file_shrinker: %d\n", ret); | |
| 609 | + goto out_lru; | |
| 610 | + } | |
| 611 | + | |
| 612 | + ret = lease_register_notifier(&nfsd_file_lease_notifier); | |
| 613 | + if (ret) { | |
| 614 | + pr_err("nfsd: unable to register lease notifier: %d\n", ret); | |
| 615 | + goto out_shrinker; | |
| 616 | + } | |
| 617 | + | |
| 618 | + nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops); | |
| 619 | + if (IS_ERR(nfsd_file_fsnotify_group)) { | |
| 620 | + pr_err("nfsd: unable to create fsnotify group: %ld\n", | |
| 621 | + PTR_ERR(nfsd_file_fsnotify_group)); | |
| 622 | + nfsd_file_fsnotify_group = NULL; | |
| 623 | + goto out_notifier; | |
| 624 | + } | |
| 625 | + | |
| 626 | + for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { | |
| 627 | + INIT_HLIST_HEAD(&nfsd_file_hashtbl[i].nfb_head); | |
| 628 | + spin_lock_init(&nfsd_file_hashtbl[i].nfb_lock); | |
| 629 | + } | |
| 630 | + | |
| 631 | + INIT_DELAYED_WORK(&nfsd_filecache_laundrette, nfsd_file_delayed_close); | |
| 632 | +out: | |
| 633 | + return ret; | |
| 634 | +out_notifier: | |
| 635 | + lease_unregister_notifier(&nfsd_file_lease_notifier); | |
| 636 | +out_shrinker: | |
| 637 | + unregister_shrinker(&nfsd_file_shrinker); | |
| 638 | +out_lru: | |
| 639 | + list_lru_destroy(&nfsd_file_lru); | |
| 640 | +out_err: | |
| 641 | + kmem_cache_destroy(nfsd_file_slab); | |
| 642 | + nfsd_file_slab = NULL; | |
| 643 | + kmem_cache_destroy(nfsd_file_mark_slab); | |
| 644 | + nfsd_file_mark_slab = NULL; | |
| 645 | + kfree(nfsd_file_hashtbl); | |
| 646 | + nfsd_file_hashtbl = NULL; | |
| 647 | + goto out; | |
| 648 | +} | |
| 649 | + | |
| 650 | +/* | |
| 651 | + * Note this can deadlock with nfsd_file_lru_cb. | |
| 652 | + */ | |
| 653 | +void | |
| 654 | +nfsd_file_cache_purge(struct net *net) | |
| 655 | +{ | |
| 656 | + unsigned int i; | |
| 657 | + struct nfsd_file *nf; | |
| 658 | + struct hlist_node *next; | |
| 659 | + LIST_HEAD(dispose); | |
| 660 | + bool del; | |
| 661 | + | |
| 662 | + if (!nfsd_file_hashtbl) | |
| 663 | + return; | |
| 664 | + | |
| 665 | + for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { | |
| 666 | + struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i]; | |
| 667 | + | |
| 668 | + spin_lock(&nfb->nfb_lock); | |
| 669 | + hlist_for_each_entry_safe(nf, next, &nfb->nfb_head, nf_node) { | |
| 670 | + if (net && nf->nf_net != net) | |
| 671 | + continue; | |
| 672 | + del = nfsd_file_unhash_and_release_locked(nf, &dispose); | |
| 673 | + | |
| 674 | + /* | |
| 675 | + * Deadlock detected! Something marked this entry as | |
| 676 | + * unhased, but hasn't removed it from the hash list. | |
| 677 | + */ | |
| 678 | + WARN_ON_ONCE(!del); | |
| 679 | + } | |
| 680 | + spin_unlock(&nfb->nfb_lock); | |
| 681 | + nfsd_file_dispose_list(&dispose); | |
| 682 | + } | |
| 683 | +} | |
| 684 | + | |
| 685 | +void | |
| 686 | +nfsd_file_cache_shutdown(void) | |
| 687 | +{ | |
| 688 | + LIST_HEAD(dispose); | |
| 689 | + | |
| 690 | + set_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags); | |
| 691 | + | |
| 692 | + lease_unregister_notifier(&nfsd_file_lease_notifier); | |
| 693 | + unregister_shrinker(&nfsd_file_shrinker); | |
| 694 | + /* | |
| 695 | + * make sure all callers of nfsd_file_lru_cb are done before | |
| 696 | + * calling nfsd_file_cache_purge | |
| 697 | + */ | |
| 698 | + cancel_delayed_work_sync(&nfsd_filecache_laundrette); | |
| 699 | + nfsd_file_cache_purge(NULL); | |
| 700 | + list_lru_destroy(&nfsd_file_lru); | |
| 701 | + rcu_barrier(); | |
| 702 | + fsnotify_put_group(nfsd_file_fsnotify_group); | |
| 703 | + nfsd_file_fsnotify_group = NULL; | |
| 704 | + kmem_cache_destroy(nfsd_file_slab); | |
| 705 | + nfsd_file_slab = NULL; | |
| 706 | + fsnotify_wait_marks_destroyed(); | |
| 707 | + kmem_cache_destroy(nfsd_file_mark_slab); | |
| 708 | + nfsd_file_mark_slab = NULL; | |
| 709 | + kfree(nfsd_file_hashtbl); | |
| 710 | + nfsd_file_hashtbl = NULL; | |
| 711 | +} | |
| 712 | + | |
| 713 | +static bool | |
| 714 | +nfsd_match_cred(const struct cred *c1, const struct cred *c2) | |
| 715 | +{ | |
| 716 | + int i; | |
| 717 | + | |
| 718 | + if (!uid_eq(c1->fsuid, c2->fsuid)) | |
| 719 | + return false; | |
| 720 | + if (!gid_eq(c1->fsgid, c2->fsgid)) | |
| 721 | + return false; | |
| 722 | + if (c1->group_info == NULL || c2->group_info == NULL) | |
| 723 | + return c1->group_info == c2->group_info; | |
| 724 | + if (c1->group_info->ngroups != c2->group_info->ngroups) | |
| 725 | + return false; | |
| 726 | + for (i = 0; i < c1->group_info->ngroups; i++) { | |
| 727 | + if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i])) | |
| 728 | + return false; | |
| 729 | + } | |
| 730 | + return true; | |
| 731 | +} | |
| 732 | + | |
| 733 | +static struct nfsd_file * | |
| 734 | +nfsd_file_find_locked(struct inode *inode, unsigned int may_flags, | |
| 735 | + unsigned int hashval, struct net *net) | |
| 736 | +{ | |
| 737 | + struct nfsd_file *nf; | |
| 738 | + unsigned char need = may_flags & NFSD_FILE_MAY_MASK; | |
| 739 | + | |
| 740 | + hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head, | |
| 741 | + nf_node) { | |
| 742 | + if ((need & nf->nf_may) != need) | |
| 743 | + continue; | |
| 744 | + if (nf->nf_inode != inode) | |
| 745 | + continue; | |
| 746 | + if (nf->nf_net != net) | |
| 747 | + continue; | |
| 748 | + if (!nfsd_match_cred(nf->nf_cred, current_cred())) | |
| 749 | + continue; | |
| 750 | + if (nfsd_file_get(nf) != NULL) | |
| 751 | + return nf; | |
| 752 | + } | |
| 753 | + return NULL; | |
| 754 | +} | |
| 755 | + | |
| 756 | +/** | |
| 757 | + * nfsd_file_is_cached - are there any cached open files for this fh? | |
| 758 | + * @inode: inode of the file to check | |
| 759 | + * | |
| 760 | + * Scan the hashtable for open files that match this fh. Returns true if there | |
| 761 | + * are any, and false if not. | |
| 762 | + */ | |
| 763 | +bool | |
| 764 | +nfsd_file_is_cached(struct inode *inode) | |
| 765 | +{ | |
| 766 | + bool ret = false; | |
| 767 | + struct nfsd_file *nf; | |
| 768 | + unsigned int hashval; | |
| 769 | + | |
| 770 | + hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS); | |
| 771 | + | |
| 772 | + rcu_read_lock(); | |
| 773 | + hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head, | |
| 774 | + nf_node) { | |
| 775 | + if (inode == nf->nf_inode) { | |
| 776 | + ret = true; | |
| 777 | + break; | |
| 778 | + } | |
| 779 | + } | |
| 780 | + rcu_read_unlock(); | |
| 781 | + trace_nfsd_file_is_cached(inode, hashval, (int)ret); | |
| 782 | + return ret; | |
| 783 | +} | |
| 784 | + | |
| 785 | +__be32 | |
| 786 | +nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, | |
| 787 | + unsigned int may_flags, struct nfsd_file **pnf) | |
| 788 | +{ | |
| 789 | + __be32 status; | |
| 790 | + struct net *net = SVC_NET(rqstp); | |
| 791 | + struct nfsd_file *nf, *new; | |
| 792 | + struct inode *inode; | |
| 793 | + unsigned int hashval; | |
| 794 | + | |
| 795 | + /* FIXME: skip this if fh_dentry is already set? */ | |
| 796 | + status = fh_verify(rqstp, fhp, S_IFREG, | |
| 797 | + may_flags|NFSD_MAY_OWNER_OVERRIDE); | |
| 798 | + if (status != nfs_ok) | |
| 799 | + return status; | |
| 800 | + | |
| 801 | + inode = d_inode(fhp->fh_dentry); | |
| 802 | + hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS); | |
| 803 | +retry: | |
| 804 | + rcu_read_lock(); | |
| 805 | + nf = nfsd_file_find_locked(inode, may_flags, hashval, net); | |
| 806 | + rcu_read_unlock(); | |
| 807 | + if (nf) | |
| 808 | + goto wait_for_construction; | |
| 809 | + | |
| 810 | + new = nfsd_file_alloc(inode, may_flags, hashval, net); | |
| 811 | + if (!new) { | |
| 812 | + trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags, | |
| 813 | + NULL, nfserr_jukebox); | |
| 814 | + return nfserr_jukebox; | |
| 815 | + } | |
| 816 | + | |
| 817 | + spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); | |
| 818 | + nf = nfsd_file_find_locked(inode, may_flags, hashval, net); | |
| 819 | + if (nf == NULL) | |
| 820 | + goto open_file; | |
| 821 | + spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); | |
| 822 | + nfsd_file_slab_free(&new->nf_rcu); | |
| 823 | + | |
| 824 | +wait_for_construction: | |
| 825 | + wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE); | |
| 826 | + | |
| 827 | + /* Did construction of this file fail? */ | |
| 828 | + if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { | |
| 829 | + nfsd_file_put_noref(nf); | |
| 830 | + goto retry; | |
| 831 | + } | |
| 832 | + | |
| 833 | + this_cpu_inc(nfsd_file_cache_hits); | |
| 834 | + | |
| 835 | + if (!(may_flags & NFSD_MAY_NOT_BREAK_LEASE)) { | |
| 836 | + bool write = (may_flags & NFSD_MAY_WRITE); | |
| 837 | + | |
| 838 | + if (test_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags) || | |
| 839 | + (test_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags) && write)) { | |
| 840 | + status = nfserrno(nfsd_open_break_lease( | |
| 841 | + file_inode(nf->nf_file), may_flags)); | |
| 842 | + if (status == nfs_ok) { | |
| 843 | + clear_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags); | |
| 844 | + if (write) | |
| 845 | + clear_bit(NFSD_FILE_BREAK_WRITE, | |
| 846 | + &nf->nf_flags); | |
| 847 | + } | |
| 848 | + } | |
| 849 | + } | |
| 850 | +out: | |
| 851 | + if (status == nfs_ok) { | |
| 852 | + *pnf = nf; | |
| 853 | + } else { | |
| 854 | + nfsd_file_put(nf); | |
| 855 | + nf = NULL; | |
| 856 | + } | |
| 857 | + | |
| 858 | + trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags, nf, status); | |
| 859 | + return status; | |
| 860 | +open_file: | |
| 861 | + nf = new; | |
| 862 | + /* Take reference for the hashtable */ | |
| 863 | + atomic_inc(&nf->nf_ref); | |
| 864 | + __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); | |
| 865 | + __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); | |
| 866 | + list_lru_add(&nfsd_file_lru, &nf->nf_lru); | |
| 867 | + hlist_add_head_rcu(&nf->nf_node, &nfsd_file_hashtbl[hashval].nfb_head); | |
| 868 | + ++nfsd_file_hashtbl[hashval].nfb_count; | |
| 869 | + nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount, | |
| 870 | + nfsd_file_hashtbl[hashval].nfb_count); | |
| 871 | + spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); | |
| 872 | + atomic_long_inc(&nfsd_filecache_count); | |
| 873 | + | |
| 874 | + nf->nf_mark = nfsd_file_mark_find_or_create(nf); | |
| 875 | + if (nf->nf_mark) | |
| 876 | + status = nfsd_open_verified(rqstp, fhp, S_IFREG, | |
| 877 | + may_flags, &nf->nf_file); | |
| 878 | + else | |
| 879 | + status = nfserr_jukebox; | |
| 880 | + /* | |
| 881 | + * If construction failed, or we raced with a call to unlink() | |
| 882 | + * then unhash. | |
| 883 | + */ | |
| 884 | + if (status != nfs_ok || inode->i_nlink == 0) { | |
| 885 | + bool do_free; | |
| 886 | + spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); | |
| 887 | + do_free = nfsd_file_unhash(nf); | |
| 888 | + spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); | |
| 889 | + if (do_free) | |
| 890 | + nfsd_file_put_noref(nf); | |
| 891 | + } | |
| 892 | + clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags); | |
| 893 | + smp_mb__after_atomic(); | |
| 894 | + wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING); | |
| 895 | + goto out; | |
| 896 | +} | |
| 897 | + | |
| 898 | +/* | |
| 899 | + * Note that fields may be added, removed or reordered in the future. Programs | |
| 900 | + * scraping this file for info should test the labels to ensure they're | |
| 901 | + * getting the correct field. | |
| 902 | + */ | |
| 903 | +static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) | |
| 904 | +{ | |
| 905 | + unsigned int i, count = 0, longest = 0; | |
| 906 | + unsigned long hits = 0; | |
| 907 | + | |
| 908 | + /* | |
| 909 | + * No need for spinlocks here since we're not terribly interested in | |
| 910 | + * accuracy. We do take the nfsd_mutex simply to ensure that we | |
| 911 | + * don't end up racing with server shutdown | |
| 912 | + */ | |
| 913 | + mutex_lock(&nfsd_mutex); | |
| 914 | + if (nfsd_file_hashtbl) { | |
| 915 | + for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { | |
| 916 | + count += nfsd_file_hashtbl[i].nfb_count; | |
| 917 | + longest = max(longest, nfsd_file_hashtbl[i].nfb_count); | |
| 918 | + } | |
| 919 | + } | |
| 920 | + mutex_unlock(&nfsd_mutex); | |
| 921 | + | |
| 922 | + for_each_possible_cpu(i) | |
| 923 | + hits += per_cpu(nfsd_file_cache_hits, i); | |
| 924 | + | |
| 925 | + seq_printf(m, "total entries: %u\n", count); | |
| 926 | + seq_printf(m, "longest chain: %u\n", longest); | |
| 927 | + seq_printf(m, "cache hits: %lu\n", hits); | |
| 928 | + return 0; | |
| 929 | +} | |
| 930 | + | |
| 931 | +int nfsd_file_cache_stats_open(struct inode *inode, struct file *file) | |
| 932 | +{ | |
| 933 | + return single_open(file, nfsd_file_cache_stats_show, NULL); | |
| 934 | +} | |
| @@ -0,0 +1,61 @@ | ||
| 1 | +#ifndef _FS_NFSD_FILECACHE_H | |
| 2 | +#define _FS_NFSD_FILECACHE_H | |
| 3 | + | |
| 4 | +#include <linux/fsnotify_backend.h> | |
| 5 | + | |
| 6 | +/* | |
| 7 | + * This is the fsnotify_mark container that nfsd attaches to the files that it | |
| 8 | + * is holding open. Note that we have a separate refcount here aside from the | |
| 9 | + * one in the fsnotify_mark. We only want a single fsnotify_mark attached to | |
| 10 | + * the inode, and for each nfsd_file to hold a reference to it. | |
| 11 | + * | |
| 12 | + * The fsnotify_mark is itself refcounted, but that's not sufficient to tell us | |
| 13 | + * how to put that reference. If there are still outstanding nfsd_files that | |
| 14 | + * reference the mark, then we would want to call fsnotify_put_mark on it. | |
| 15 | + * If there were not, then we'd need to call fsnotify_destroy_mark. Since we | |
| 16 | + * can't really tell the difference, we use the nfm_mark to keep track of how | |
| 17 | + * many nfsd_files hold references to the mark. When that counter goes to zero | |
| 18 | + * then we know to call fsnotify_destroy_mark on it. | |
| 19 | + */ | |
| 20 | +struct nfsd_file_mark { | |
| 21 | + struct fsnotify_mark nfm_mark; | |
| 22 | + atomic_t nfm_ref; | |
| 23 | +}; | |
| 24 | + | |
| 25 | +/* | |
| 26 | + * A representation of a file that has been opened by knfsd. These are hashed | |
| 27 | + * in the hashtable by inode pointer value. Note that this object doesn't | |
| 28 | + * hold a reference to the inode by itself, so the nf_inode pointer should | |
| 29 | + * never be dereferenced, only used for comparison. | |
| 30 | + */ | |
| 31 | +struct nfsd_file { | |
| 32 | + struct hlist_node nf_node; | |
| 33 | + struct list_head nf_lru; | |
| 34 | + struct rcu_head nf_rcu; | |
| 35 | + struct file *nf_file; | |
| 36 | + const struct cred *nf_cred; | |
| 37 | + struct net *nf_net; | |
| 38 | +#define NFSD_FILE_HASHED (0) | |
| 39 | +#define NFSD_FILE_PENDING (1) | |
| 40 | +#define NFSD_FILE_BREAK_READ (2) | |
| 41 | +#define NFSD_FILE_BREAK_WRITE (3) | |
| 42 | +#define NFSD_FILE_REFERENCED (4) | |
| 43 | + unsigned long nf_flags; | |
| 44 | + struct inode *nf_inode; | |
| 45 | + unsigned int nf_hashval; | |
| 46 | + atomic_t nf_ref; | |
| 47 | + unsigned char nf_may; | |
| 48 | + struct nfsd_file_mark *nf_mark; | |
| 49 | +}; | |
| 50 | + | |
| 51 | +int nfsd_file_cache_init(void); | |
| 52 | +void nfsd_file_cache_purge(struct net *); | |
| 53 | +void nfsd_file_cache_shutdown(void); | |
| 54 | +void nfsd_file_put(struct nfsd_file *nf); | |
| 55 | +struct nfsd_file *nfsd_file_get(struct nfsd_file *nf); | |
| 56 | +void nfsd_file_close_inode_sync(struct inode *inode); | |
| 57 | +bool nfsd_file_is_cached(struct inode *inode); | |
| 58 | +__be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, | |
| 59 | + unsigned int may_flags, struct nfsd_file **nfp); | |
| 60 | +int nfsd_file_cache_stats_open(struct inode *, struct file *); | |
| 61 | +#endif /* _FS_NFSD_FILECACHE_H */ | |
| @@ -104,6 +104,7 @@ struct nfsd_net { · 103 unmodified lines | ||
| 104 | 104 | |
| 105 | 105 | /* Time of server startup */ |
| 106 | 106 | struct timespec64 nfssvc_boot; |
| 107 | + seqlock_t boot_lock; | |
| 107 | 108 | |
| 108 | 109 | /* |
| 109 | 110 | * Max number of connections this nfsd container will allow. Defaults |
| @@ -179,4 +180,7 @@ struct nfsd_net { · 69 unmodified lines | ||
| 179 | 180 | extern void nfsd_netns_free_versions(struct nfsd_net *nn); |
| 180 | 181 | |
| 181 | 182 | extern unsigned int nfsd_net_id; |
| 183 | + | |
| 184 | +void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn); | |
| 185 | +void nfsd_reset_boot_verifier(struct nfsd_net *nn); | |
| 182 | 186 | #endif /* __NFSD_NETNS_H__ */ |
| @@ -172,13 +172,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp) · 171 unmodified lines | ||
| 172 | 172 | nfserr = nfsd_read(rqstp, &resp->fh, |
| 173 | 173 | argp->offset, |
| 174 | 174 | rqstp->rq_vec, argp->vlen, |
| 175 | − &resp->count); | |
| 176 | − if (nfserr == 0) { | |
| 177 | − struct inode *inode = d_inode(resp->fh.fh_dentry); | |
| 178 | − resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset, | |
| 179 | − inode->i_size); | |
| 180 | − } | |
| 181 | − | |
| 175 | + &resp->count, | |
| 176 | + &resp->eof); | |
| 182 | 177 | RETURN_STATUS(nfserr); |
| 183 | 178 | } |
| 184 | 179 | |
| @@ -27,6 +27,7 @@ static u32 nfs3_ftypes[] = { · 26 unmodified lines | ||
| 27 | 27 | NF3SOCK, NF3BAD, NF3LNK, NF3BAD, |
| 28 | 28 | }; |
| 29 | 29 | |
| 30 | + | |
| 30 | 31 | /* |
| 31 | 32 | * XDR functions for basic NFS types |
| 32 | 33 | */ |
| @@ -751,14 +752,16 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) · 718 unmodified lines | ||
| 751 | 752 | { |
| 752 | 753 | struct nfsd3_writeres *resp = rqstp->rq_resp; |
| 753 | 754 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
| 755 | + __be32 verf[2]; | |
| 754 | 756 | |
| 755 | 757 | p = encode_wcc_data(rqstp, p, &resp->fh); |
| 756 | 758 | if (resp->status == 0) { |
| 757 | 759 | *p++ = htonl(resp->count); |
| 758 | 760 | *p++ = htonl(resp->committed); |
| 759 | 761 | /* unique identifier, y2038 overflow can be ignored */ |
| 760 | − *p++ = htonl((u32)nn->nfssvc_boot.tv_sec); | |
| 761 | − *p++ = htonl(nn->nfssvc_boot.tv_nsec); | |
| 762 | + nfsd_copy_boot_verifier(verf, nn); | |
| 763 | + *p++ = verf[0]; | |
| 764 | + *p++ = verf[1]; | |
| 762 | 765 | } |
| 763 | 766 | return xdr_ressize_check(rqstp, p); |
| 764 | 767 | } |
| @@ -1125,13 +1128,15 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) · 360 unmodified lines | ||
| 1125 | 1128 | { |
| 1126 | 1129 | struct nfsd3_commitres *resp = rqstp->rq_resp; |
| 1127 | 1130 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
| 1131 | + __be32 verf[2]; | |
| 1128 | 1132 | |
| 1129 | 1133 | p = encode_wcc_data(rqstp, p, &resp->fh); |
| 1130 | 1134 | /* Write verifier */ |
| 1131 | 1135 | if (resp->status == 0) { |
| 1132 | 1136 | /* unique identifier, y2038 overflow can be ignored */ |
| 1133 | − *p++ = htonl((u32)nn->nfssvc_boot.tv_sec); | |
| 1134 | − *p++ = htonl(nn->nfssvc_boot.tv_nsec); | |
| 1137 | + nfsd_copy_boot_verifier(verf, nn); | |
| 1138 | + *p++ = verf[0]; | |
| 1139 | + *p++ = verf[1]; | |
| 1135 | 1140 | } |
| 1136 | 1141 | return xdr_ressize_check(rqstp, p); |
| 1137 | 1142 | } |
| @@ -512,11 +512,9 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, · 511 unmodified lines | ||
| 512 | 512 | if (unlikely(status)) |
| 513 | 513 | return status; |
| 514 | 514 | |
| 515 | − if (cb != NULL) { | |
| 516 | − status = decode_cb_sequence4res(xdr, cb); | |
| 517 | − if (unlikely(status || cb->cb_seq_status)) | |
| 518 | − return status; | |
| 519 | − } | |
| 515 | + status = decode_cb_sequence4res(xdr, cb); | |
| 516 | + if (unlikely(status || cb->cb_seq_status)) | |
| 517 | + return status; | |
| 520 | 518 | |
| 521 | 519 | return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status); |
| 522 | 520 | } |
| @@ -604,11 +602,10 @@ static int nfs4_xdr_dec_cb_layout(struct rpc_rqst *rqstp, · 81 unmodified lines | ||
| 604 | 602 | if (unlikely(status)) |
| 605 | 603 | return status; |
| 606 | 604 | |
| 607 | − if (cb) { | |
| 608 | − status = decode_cb_sequence4res(xdr, cb); | |
| 609 | − if (unlikely(status || cb->cb_seq_status)) | |
| 610 | − return status; | |
| 611 | − } | |
| 605 | + status = decode_cb_sequence4res(xdr, cb); | |
| 606 | + if (unlikely(status || cb->cb_seq_status)) | |
| 607 | + return status; | |
| 608 | + | |
| 612 | 609 | return decode_cb_op_status(xdr, OP_CB_LAYOUTRECALL, &cb->cb_status); |
| 613 | 610 | } |
| 614 | 611 | #endif /* CONFIG_NFSD_PNFS */ |
| @@ -663,11 +660,10 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp, · 48 unmodified lines | ||
| 663 | 660 | if (unlikely(status)) |
| 664 | 661 | return status; |
| 665 | 662 | |
| 666 | − if (cb) { | |
| 667 | − status = decode_cb_sequence4res(xdr, cb); | |
| 668 | − if (unlikely(status || cb->cb_seq_status)) | |
| 669 | − return status; | |
| 670 | − } | |
| 663 | + status = decode_cb_sequence4res(xdr, cb); | |
| 664 | + if (unlikely(status || cb->cb_seq_status)) | |
| 665 | + return status; | |
| 666 | + | |
| 671 | 667 | return decode_cb_op_status(xdr, OP_CB_NOTIFY_LOCK, &cb->cb_status); |
| 672 | 668 | } |
| 673 | 669 | |
| @@ -759,11 +755,10 @@ static int nfs4_xdr_dec_cb_offload(struct rpc_rqst *rqstp, · 85 unmodified lines | ||
| 759 | 755 | if (unlikely(status)) |
| 760 | 756 | return status; |
| 761 | 757 | |
| 762 | − if (cb) { | |
| 763 | − status = decode_cb_sequence4res(xdr, cb); | |
| 764 | − if (unlikely(status || cb->cb_seq_status)) | |
| 765 | − return status; | |
| 766 | − } | |
| 758 | + status = decode_cb_sequence4res(xdr, cb); | |
| 759 | + if (unlikely(status || cb->cb_seq_status)) | |
| 760 | + return status; | |
| 761 | + | |
| 767 | 762 | return decode_cb_op_status(xdr, OP_CB_OFFLOAD, &cb->cb_status); |
| 768 | 763 | } |
| 769 | 764 | /* |
| @@ -169,8 +169,8 @@ nfsd4_free_layout_stateid(struct nfs4_stid *stid) · 168 unmodified lines | ||
| 169 | 169 | spin_unlock(&fp->fi_lock); |
| 170 | 170 | |
| 171 | 171 | if (!nfsd4_layout_ops[ls->ls_layout_type]->disable_recalls) |
| 172 | − vfs_setlease(ls->ls_file, F_UNLCK, NULL, (void **)&ls); | |
| 173 | − fput(ls->ls_file); | |
| 172 | + vfs_setlease(ls->ls_file->nf_file, F_UNLCK, NULL, (void **)&ls); | |
| 173 | + nfsd_file_put(ls->ls_file); | |
| 174 | 174 | |
| 175 | 175 | if (ls->ls_recalled) |
| 176 | 176 | atomic_dec(&ls->ls_stid.sc_file->fi_lo_recalls); |
| @@ -197,7 +197,7 @@ nfsd4_layout_setlease(struct nfs4_layout_stateid *ls) · 20 unmodified lines | ||
| 197 | 197 | fl->fl_end = OFFSET_MAX; |
| 198 | 198 | fl->fl_owner = ls; |
| 199 | 199 | fl->fl_pid = current->tgid; |
| 200 | − fl->fl_file = ls->ls_file; | |
| 200 | + fl->fl_file = ls->ls_file->nf_file; | |
| 201 | 201 | |
| 202 | 202 | status = vfs_setlease(fl->fl_file, fl->fl_type, &fl, NULL); |
| 203 | 203 | if (status) { |
| @@ -236,13 +236,13 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, · 32 unmodified lines | ||
| 236 | 236 | NFSPROC4_CLNT_CB_LAYOUT); |
| 237 | 237 | |
| 238 | 238 | if (parent->sc_type == NFS4_DELEG_STID) |
| 239 | − ls->ls_file = get_file(fp->fi_deleg_file); | |
| 239 | + ls->ls_file = nfsd_file_get(fp->fi_deleg_file); | |
| 240 | 240 | else |
| 241 | 241 | ls->ls_file = find_any_file(fp); |
| 242 | 242 | BUG_ON(!ls->ls_file); |
| 243 | 243 | |
| 244 | 244 | if (nfsd4_layout_setlease(ls)) { |
| 245 | − fput(ls->ls_file); | |
| 245 | + nfsd_file_put(ls->ls_file); | |
| 246 | 246 | put_nfs4_file(fp); |
| 247 | 247 | kmem_cache_free(nfs4_layout_stateid_cache, ls); |
| 248 | 248 | return NULL; |
| @@ -626,7 +626,7 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls) · 377 unmodified lines | ||
| 626 | 626 | |
| 627 | 627 | argv[0] = (char *)nfsd_recall_failed; |
| 628 | 628 | argv[1] = addr_str; |
| 629 | − argv[2] = ls->ls_file->f_path.mnt->mnt_sb->s_id; | |
| 629 | + argv[2] = ls->ls_file->nf_file->f_path.mnt->mnt_sb->s_id; | |
| 630 | 630 | argv[3] = NULL; |
| 631 | 631 | |
| 632 | 632 | error = call_usermodehelper(nfsd_recall_failed, argv, envp, |
| @@ -568,17 +568,11 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 567 unmodified lines | ||
| 568 | 568 | |
| 569 | 569 | static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) |
| 570 | 570 | { |
| 571 | − __be32 verf[2]; | |
| 572 | − struct nfsd_net *nn = net_generic(net, nfsd_net_id); | |
| 571 | + __be32 *verf = (__be32 *)verifier->data; | |
| 573 | 572 | |
| 574 | − /* | |
| 575 | − * This is opaque to client, so no need to byte-swap. Use | |
| 576 | − * __force to keep sparse happy. y2038 time_t overflow is | |
| 577 | − * irrelevant in this usage. | |
| 578 | − */ | |
| 579 | − verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec; | |
| 580 | − verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec; | |
| 581 | − memcpy(verifier->data, verf, sizeof(verifier->data)); | |
| 573 | + BUILD_BUG_ON(2*sizeof(*verf) != sizeof(verifier->data)); | |
| 574 | + | |
| 575 | + nfsd_copy_boot_verifier(verf, net_generic(net, nfsd_net_id)); | |
| 582 | 576 | } |
| 583 | 577 | |
| 584 | 578 | static __be32 |
| @@ -761,7 +755,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 176 unmodified lines | ||
| 761 | 755 | struct nfsd4_read *read = &u->read; |
| 762 | 756 | __be32 status; |
| 763 | 757 | |
| 764 | − read->rd_filp = NULL; | |
| 758 | + read->rd_nf = NULL; | |
| 765 | 759 | if (read->rd_offset >= OFFSET_MAX) |
| 766 | 760 | return nfserr_inval; |
| 767 | 761 | |
| @@ -782,7 +776,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 14 unmodified lines | ||
| 782 | 776 | /* check stateid */ |
| 783 | 777 | status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, |
| 784 | 778 | &read->rd_stateid, RD_STATE, |
| 785 | − &read->rd_filp, &read->rd_tmp_file); | |
| 779 | + &read->rd_nf); | |
| 786 | 780 | if (status) { |
| 787 | 781 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); |
| 788 | 782 | goto out; |
| @@ -798,8 +792,8 @@ out: · 9 unmodified lines | ||
| 798 | 792 | static void |
| 799 | 793 | nfsd4_read_release(union nfsd4_op_u *u) |
| 800 | 794 | { |
| 801 | − if (u->read.rd_filp) | |
| 802 | − fput(u->read.rd_filp); | |
| 795 | + if (u->read.rd_nf) | |
| 796 | + nfsd_file_put(u->read.rd_nf); | |
| 803 | 797 | trace_nfsd_read_done(u->read.rd_rqstp, u->read.rd_fhp, |
| 804 | 798 | u->read.rd_offset, u->read.rd_length); |
| 805 | 799 | } |
| @@ -954,7 +948,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 148 unmodified lines | ||
| 954 | 948 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { |
| 955 | 949 | status = nfs4_preprocess_stateid_op(rqstp, cstate, |
| 956 | 950 | &cstate->current_fh, &setattr->sa_stateid, |
| 957 | − WR_STATE, NULL, NULL); | |
| 951 | + WR_STATE, NULL); | |
| 958 | 952 | if (status) { |
| 959 | 953 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); |
| 960 | 954 | return status; |
| @@ -993,7 +987,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 32 unmodified lines | ||
| 993 | 987 | { |
| 994 | 988 | struct nfsd4_write *write = &u->write; |
| 995 | 989 | stateid_t *stateid = &write->wr_stateid; |
| 996 | − struct file *filp = NULL; | |
| 990 | + struct nfsd_file *nf = NULL; | |
| 997 | 991 | __be32 status = nfs_ok; |
| 998 | 992 | unsigned long cnt; |
| 999 | 993 | int nvecs; |
| @@ -1005,7 +999,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 5 unmodified lines | ||
| 1005 | 999 | trace_nfsd_write_start(rqstp, &cstate->current_fh, |
| 1006 | 1000 | write->wr_offset, cnt); |
| 1007 | 1001 | status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, |
| 1008 | − stateid, WR_STATE, &filp, NULL); | |
| 1002 | + stateid, WR_STATE, &nf); | |
| 1009 | 1003 | if (status) { |
| 1010 | 1004 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); |
| 1011 | 1005 | return status; |
| @@ -1018,10 +1012,10 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 6 unmodified lines | ||
| 1018 | 1012 | &write->wr_head, write->wr_buflen); |
| 1019 | 1013 | WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); |
| 1020 | 1014 | |
| 1021 | − status = nfsd_vfs_write(rqstp, &cstate->current_fh, filp, | |
| 1015 | + status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf->nf_file, | |
| 1022 | 1016 | write->wr_offset, rqstp->rq_vec, nvecs, &cnt, |
| 1023 | 1017 | write->wr_how_written); |
| 1024 | − fput(filp); | |
| 1018 | + nfsd_file_put(nf); | |
| 1025 | 1019 | |
| 1026 | 1020 | write->wr_bytes_written = cnt; |
| 1027 | 1021 | trace_nfsd_write_done(rqstp, &cstate->current_fh, |
| @@ -1031,8 +1025,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 3 unmodified lines | ||
| 1031 | 1025 | |
| 1032 | 1026 | static __be32 |
| 1033 | 1027 | nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
| 1034 | − stateid_t *src_stateid, struct file **src, | |
| 1035 | − stateid_t *dst_stateid, struct file **dst) | |
| 1028 | + stateid_t *src_stateid, struct nfsd_file **src, | |
| 1029 | + stateid_t *dst_stateid, struct nfsd_file **dst) | |
| 1036 | 1030 | { |
| 1037 | 1031 | __be32 status; |
| 1038 | 1032 | |
| @@ -1040,22 +1034,22 @@ nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 1 unmodified line | ||
| 1040 | 1034 | return nfserr_nofilehandle; |
| 1041 | 1035 | |
| 1042 | 1036 | status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh, |
| 1043 | − src_stateid, RD_STATE, src, NULL); | |
| 1037 | + src_stateid, RD_STATE, src); | |
| 1044 | 1038 | if (status) { |
| 1045 | 1039 | dprintk("NFSD: %s: couldn't process src stateid!\n", __func__); |
| 1046 | 1040 | goto out; |
| 1047 | 1041 | } |
| 1048 | 1042 | |
| 1049 | 1043 | status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, |
| 1050 | − dst_stateid, WR_STATE, dst, NULL); | |
| 1044 | + dst_stateid, WR_STATE, dst); | |
| 1051 | 1045 | if (status) { |
| 1052 | 1046 | dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__); |
| 1053 | 1047 | goto out_put_src; |
| 1054 | 1048 | } |
| 1055 | 1049 | |
| 1056 | 1050 | /* fix up for NFS-specific error code */ |
| 1057 | − if (!S_ISREG(file_inode(*src)->i_mode) || | |
| 1058 | − !S_ISREG(file_inode(*dst)->i_mode)) { | |
| 1051 | + if (!S_ISREG(file_inode((*src)->nf_file)->i_mode) || | |
| 1052 | + !S_ISREG(file_inode((*dst)->nf_file)->i_mode)) { | |
| 1059 | 1053 | status = nfserr_wrong_type; |
| 1060 | 1054 | goto out_put_dst; |
| 1061 | 1055 | } |
| @@ -1063,9 +1057,9 @@ nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 1 unmodified line | ||
| 1063 | 1057 | out: |
| 1064 | 1058 | return status; |
| 1065 | 1059 | out_put_dst: |
| 1066 | − fput(*dst); | |
| 1060 | + nfsd_file_put(*dst); | |
| 1067 | 1061 | out_put_src: |
| 1068 | − fput(*src); | |
| 1062 | + nfsd_file_put(*src); | |
| 1069 | 1063 | goto out; |
| 1070 | 1064 | } |
| 1071 | 1065 | |
| @@ -1074,7 +1068,7 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 2 unmodified lines | ||
| 1074 | 1068 | union nfsd4_op_u *u) |
| 1075 | 1069 | { |
| 1076 | 1070 | struct nfsd4_clone *clone = &u->clone; |
| 1077 | − struct file *src, *dst; | |
| 1071 | + struct nfsd_file *src, *dst; | |
| 1078 | 1072 | __be32 status; |
| 1079 | 1073 | |
| 1080 | 1074 | status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src, |
| @@ -1082,11 +1076,11 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 1 unmodified line | ||
| 1082 | 1076 | if (status) |
| 1083 | 1077 | goto out; |
| 1084 | 1078 | |
| 1085 | − status = nfsd4_clone_file_range(src, clone->cl_src_pos, | |
| 1086 | − dst, clone->cl_dst_pos, clone->cl_count); | |
| 1079 | + status = nfsd4_clone_file_range(src->nf_file, clone->cl_src_pos, | |
| 1080 | + dst->nf_file, clone->cl_dst_pos, clone->cl_count); | |
| 1087 | 1081 | |
| 1088 | − fput(dst); | |
| 1089 | − fput(src); | |
| 1082 | + nfsd_file_put(dst); | |
| 1083 | + nfsd_file_put(src); | |
| 1090 | 1084 | out: |
| 1091 | 1085 | return status; |
| 1092 | 1086 | } |
| @@ -1176,8 +1170,9 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) · 83 unmodified lines | ||
| 1176 | 1170 | do { |
| 1177 | 1171 | if (kthread_should_stop()) |
| 1178 | 1172 | break; |
| 1179 | − bytes_copied = nfsd_copy_file_range(copy->file_src, src_pos, | |
| 1180 | − copy->file_dst, dst_pos, bytes_total); | |
| 1173 | + bytes_copied = nfsd_copy_file_range(copy->nf_src->nf_file, | |
| 1174 | + src_pos, copy->nf_dst->nf_file, dst_pos, | |
| 1175 | + bytes_total); | |
| 1181 | 1176 | if (bytes_copied <= 0) |
| 1182 | 1177 | break; |
| 1183 | 1178 | bytes_total -= bytes_copied; |
| @@ -1204,8 +1199,8 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync) · 20 unmodified lines | ||
| 1204 | 1199 | status = nfs_ok; |
| 1205 | 1200 | } |
| 1206 | 1201 | |
| 1207 | − fput(copy->file_src); | |
| 1208 | − fput(copy->file_dst); | |
| 1202 | + nfsd_file_put(copy->nf_src); | |
| 1203 | + nfsd_file_put(copy->nf_dst); | |
| 1209 | 1204 | return status; |
| 1210 | 1205 | } |
| 1211 | 1206 | |
| @@ -1218,16 +1213,16 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) · 6 unmodified lines | ||
| 1218 | 1213 | memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res)); |
| 1219 | 1214 | memcpy(&dst->fh, &src->fh, sizeof(src->fh)); |
| 1220 | 1215 | dst->cp_clp = src->cp_clp; |
| 1221 | − dst->file_dst = get_file(src->file_dst); | |
| 1222 | − dst->file_src = get_file(src->file_src); | |
| 1216 | + dst->nf_dst = nfsd_file_get(src->nf_dst); | |
| 1217 | + dst->nf_src = nfsd_file_get(src->nf_src); | |
| 1223 | 1218 | memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid)); |
| 1224 | 1219 | } |
| 1225 | 1220 | |
| 1226 | 1221 | static void cleanup_async_copy(struct nfsd4_copy *copy) |
| 1227 | 1222 | { |
| 1228 | 1223 | nfs4_free_cp_state(copy); |
| 1229 | − fput(copy->file_dst); | |
| 1230 | − fput(copy->file_src); | |
| 1224 | + nfsd_file_put(copy->nf_dst); | |
| 1225 | + nfsd_file_put(copy->nf_src); | |
| 1231 | 1226 | spin_lock(©->cp_clp->async_lock); |
| 1232 | 1227 | list_del(©->copies); |
| 1233 | 1228 | spin_unlock(©->cp_clp->async_lock); |
| @@ -1264,8 +1259,8 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 30 unmodified lines | ||
| 1264 | 1259 | struct nfsd4_copy *async_copy = NULL; |
| 1265 | 1260 | |
| 1266 | 1261 | status = nfsd4_verify_copy(rqstp, cstate, ©->cp_src_stateid, |
| 1267 | − ©->file_src, ©->cp_dst_stateid, | |
| 1268 | − ©->file_dst); | |
| 1262 | + ©->nf_src, ©->cp_dst_stateid, | |
| 1263 | + ©->nf_dst); | |
| 1269 | 1264 | if (status) |
| 1270 | 1265 | goto out; |
| 1271 | 1266 | |
| @@ -1347,21 +1342,21 @@ nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 75 unmodified lines | ||
| 1347 | 1342 | struct nfsd4_fallocate *fallocate, int flags) |
| 1348 | 1343 | { |
| 1349 | 1344 | __be32 status; |
| 1350 | − struct file *file; | |
| 1345 | + struct nfsd_file *nf; | |
| 1351 | 1346 | |
| 1352 | 1347 | status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, |
| 1353 | 1348 | &fallocate->falloc_stateid, |
| 1354 | − WR_STATE, &file, NULL); | |
| 1349 | + WR_STATE, &nf); | |
| 1355 | 1350 | if (status != nfs_ok) { |
| 1356 | 1351 | dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n"); |
| 1357 | 1352 | return status; |
| 1358 | 1353 | } |
| 1359 | 1354 | |
| 1360 | − status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, file, | |
| 1355 | + status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, nf->nf_file, | |
| 1361 | 1356 | fallocate->falloc_offset, |
| 1362 | 1357 | fallocate->falloc_length, |
| 1363 | 1358 | flags); |
| 1364 | − fput(file); | |
| 1359 | + nfsd_file_put(nf); | |
| 1365 | 1360 | return status; |
| 1366 | 1361 | } |
| 1367 | 1362 | static __be32 |
| @@ -1406,11 +1401,11 @@ nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 38 unmodified lines | ||
| 1406 | 1401 | struct nfsd4_seek *seek = &u->seek; |
| 1407 | 1402 | int whence; |
| 1408 | 1403 | __be32 status; |
| 1409 | − struct file *file; | |
| 1404 | + struct nfsd_file *nf; | |
| 1410 | 1405 | |
| 1411 | 1406 | status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, |
| 1412 | 1407 | &seek->seek_stateid, |
| 1413 | − RD_STATE, &file, NULL); | |
| 1408 | + RD_STATE, &nf); | |
| 1414 | 1409 | if (status) { |
| 1415 | 1410 | dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n"); |
| 1416 | 1411 | return status; |
| @@ -1432,14 +1427,14 @@ nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 15 unmodified lines | ||
| 1432 | 1427 | * Note: This call does change file->f_pos, but nothing in NFSD |
| 1433 | 1428 | * should ever file->f_pos. |
| 1434 | 1429 | */ |
| 1435 | − seek->seek_pos = vfs_llseek(file, seek->seek_offset, whence); | |
| 1430 | + seek->seek_pos = vfs_llseek(nf->nf_file, seek->seek_offset, whence); | |
| 1436 | 1431 | if (seek->seek_pos < 0) |
| 1437 | 1432 | status = nfserrno(seek->seek_pos); |
| 1438 | − else if (seek->seek_pos >= i_size_read(file_inode(file))) | |
| 1433 | + else if (seek->seek_pos >= i_size_read(file_inode(nf->nf_file))) | |
| 1439 | 1434 | seek->seek_eof = true; |
| 1440 | 1435 | |
| 1441 | 1436 | out: |
| 1442 | − fput(file); | |
| 1437 | + nfsd_file_put(nf); | |
| 1443 | 1438 | return status; |
| 1444 | 1439 | } |
| 1445 | 1440 | |
| @@ -59,8 +59,13 @@ struct nfsd4_client_tracking_ops { · 58 unmodified lines | ||
| 59 | 59 | void (*remove)(struct nfs4_client *); |
| 60 | 60 | int (*check)(struct nfs4_client *); |
| 61 | 61 | void (*grace_done)(struct nfsd_net *); |
| 62 | + uint8_t version; | |
| 63 | + size_t msglen; | |
| 62 | 64 | }; |
| 63 | 65 | |
| 66 | +static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops; | |
| 67 | +static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2; | |
| 68 | + | |
| 64 | 69 | /* Globals */ |
| 65 | 70 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
| 66 | 71 | |
| @@ -173,6 +178,7 @@ __nfsd4_create_reclaim_record_grace(struct nfs4_client *clp, · 106 unmodified lines | ||
| 173 | 178 | const char *dname, int len, struct nfsd_net *nn) |
| 174 | 179 | { |
| 175 | 180 | struct xdr_netobj name; |
| 181 | + struct xdr_netobj princhash = { .len = 0, .data = NULL }; | |
| 176 | 182 | struct nfs4_client_reclaim *crp; |
| 177 | 183 | |
| 178 | 184 | name.data = kmemdup(dname, len, GFP_KERNEL); |
| @@ -182,7 +188,7 @@ __nfsd4_create_reclaim_record_grace(struct nfs4_client *clp, · 3 unmodified lines | ||
| 182 | 188 | return; |
| 183 | 189 | } |
| 184 | 190 | name.len = len; |
| 185 | − crp = nfs4_client_to_reclaim(name, nn); | |
| 191 | + crp = nfs4_client_to_reclaim(name, princhash, nn); | |
| 186 | 192 | if (!crp) { |
| 187 | 193 | kfree(name.data); |
| 188 | 194 | return; |
| @@ -482,6 +488,7 @@ static int · 293 unmodified lines | ||
| 482 | 488 | load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) |
| 483 | 489 | { |
| 484 | 490 | struct xdr_netobj name; |
| 491 | + struct xdr_netobj princhash = { .len = 0, .data = NULL }; | |
| 485 | 492 | |
| 486 | 493 | if (child->d_name.len != HEXDIR_LEN - 1) { |
| 487 | 494 | printk("%s: illegal name %pd in recovery directory\n", |
| @@ -496,7 +503,7 @@ load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) · 8 unmodified lines | ||
| 496 | 503 | goto out; |
| 497 | 504 | } |
| 498 | 505 | name.len = HEXDIR_LEN; |
| 499 | − if (!nfs4_client_to_reclaim(name, nn)) | |
| 506 | + if (!nfs4_client_to_reclaim(name, princhash, nn)) | |
| 500 | 507 | kfree(name.data); |
| 501 | 508 | out: |
| 502 | 509 | return 0; |
| @@ -718,6 +725,8 @@ static const struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { · 215 unmodified lines | ||
| 718 | 725 | .remove = nfsd4_remove_clid_dir, |
| 719 | 726 | .check = nfsd4_check_legacy_client, |
| 720 | 727 | .grace_done = nfsd4_recdir_purge_old, |
| 728 | + .version = 1, | |
| 729 | + .msglen = 0, | |
| 721 | 730 | }; |
| 722 | 731 | |
| 723 | 732 | /* Globals */ |
| @@ -731,25 +740,32 @@ struct cld_net { · 7 unmodified lines | ||
| 731 | 740 | struct list_head cn_list; |
| 732 | 741 | unsigned int cn_xid; |
| 733 | 742 | bool cn_has_legacy; |
| 743 | + struct crypto_shash *cn_tfm; | |
| 734 | 744 | }; |
| 735 | 745 | |
| 736 | 746 | struct cld_upcall { |
| 737 | 747 | struct list_head cu_list; |
| 738 | 748 | struct cld_net *cu_net; |
| 739 | 749 | struct completion cu_done; |
| 740 | − struct cld_msg cu_msg; | |
| 750 | + union { | |
| 751 | + struct cld_msg_hdr cu_hdr; | |
| 752 | + struct cld_msg cu_msg; | |
| 753 | + struct cld_msg_v2 cu_msg_v2; | |
| 754 | + } cu_u; | |
| 741 | 755 | }; |
| 742 | 756 | |
| 743 | 757 | static int |
| 744 | −__cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) | |
| 758 | +__cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg) | |
| 745 | 759 | { |
| 746 | 760 | int ret; |
| 747 | 761 | struct rpc_pipe_msg msg; |
| 748 | − struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_msg); | |
| 762 | + struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_u); | |
| 763 | + struct nfsd_net *nn = net_generic(pipe->dentry->d_sb->s_fs_info, | |
| 764 | + nfsd_net_id); | |
| 749 | 765 | |
| 750 | 766 | memset(&msg, 0, sizeof(msg)); |
| 751 | 767 | msg.data = cmsg; |
| 752 | − msg.len = sizeof(*cmsg); | |
| 768 | + msg.len = nn->client_tracking_ops->msglen; | |
| 753 | 769 | |
| 754 | 770 | ret = rpc_queue_upcall(pipe, &msg); |
| 755 | 771 | if (ret < 0) { |
| @@ -765,7 +781,7 @@ out: · 9 unmodified lines | ||
| 765 | 781 | } |
| 766 | 782 | |
| 767 | 783 | static int |
| 768 | −cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) | |
| 784 | +cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg) | |
| 769 | 785 | { |
| 770 | 786 | int ret; |
| 771 | 787 | |
| @@ -781,11 +797,11 @@ cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) · 9 unmodified lines | ||
| 781 | 797 | } |
| 782 | 798 | |
| 783 | 799 | static ssize_t |
| 784 | −__cld_pipe_inprogress_downcall(const struct cld_msg __user *cmsg, | |
| 800 | +__cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, | |
| 785 | 801 | struct nfsd_net *nn) |
| 786 | 802 | { |
| 787 | − uint8_t cmd; | |
| 788 | − struct xdr_netobj name; | |
| 803 | + uint8_t cmd, princhashlen; | |
| 804 | + struct xdr_netobj name, princhash = { .len = 0, .data = NULL }; | |
| 789 | 805 | uint16_t namelen; |
| 790 | 806 | struct cld_net *cn = nn->cld_net; |
| 791 | 807 | |
| @@ -794,22 +810,48 @@ __cld_pipe_inprogress_downcall(const struct cld_msg __user *cmsg, · 2 unmodified lines | ||
| 794 | 810 | return -EFAULT; |
| 795 | 811 | } |
| 796 | 812 | if (cmd == Cld_GraceStart) { |
| 797 | − if (get_user(namelen, &cmsg->cm_u.cm_name.cn_len)) | |
| 798 | − return -EFAULT; | |
| 799 | − name.data = memdup_user(&cmsg->cm_u.cm_name.cn_id, namelen); | |
| 800 | − if (IS_ERR_OR_NULL(name.data)) | |
| 801 | − return -EFAULT; | |
| 802 | − name.len = namelen; | |
| 813 | + if (nn->client_tracking_ops->version >= 2) { | |
| 814 | + const struct cld_clntinfo __user *ci; | |
| 815 | + | |
| 816 | + ci = &cmsg->cm_u.cm_clntinfo; | |
| 817 | + if (get_user(namelen, &ci->cc_name.cn_len)) | |
| 818 | + return -EFAULT; | |
| 819 | + name.data = memdup_user(&ci->cc_name.cn_id, namelen); | |
| 820 | + if (IS_ERR_OR_NULL(name.data)) | |
| 821 | + return -EFAULT; | |
| 822 | + name.len = namelen; | |
| 823 | + get_user(princhashlen, &ci->cc_princhash.cp_len); | |
| 824 | + if (princhashlen > 0) { | |
| 825 | + princhash.data = memdup_user( | |
| 826 | + &ci->cc_princhash.cp_data, | |
| 827 | + princhashlen); | |
| 828 | + if (IS_ERR_OR_NULL(princhash.data)) | |
| 829 | + return -EFAULT; | |
| 830 | + princhash.len = princhashlen; | |
| 831 | + } else | |
| 832 | + princhash.len = 0; | |
| 833 | + } else { | |
| 834 | + const struct cld_name __user *cnm; | |
| 835 | + | |
| 836 | + cnm = &cmsg->cm_u.cm_name; | |
| 837 | + if (get_user(namelen, &cnm->cn_len)) | |
| 838 | + return -EFAULT; | |
| 839 | + name.data = memdup_user(&cnm->cn_id, namelen); | |
| 840 | + if (IS_ERR_OR_NULL(name.data)) | |
| 841 | + return -EFAULT; | |
| 842 | + name.len = namelen; | |
| 843 | + } | |
| 803 | 844 | if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) { |
| 804 | 845 | name.len = name.len - 5; |
| 805 | 846 | memmove(name.data, name.data + 5, name.len); |
| 806 | 847 | cn->cn_has_legacy = true; |
| 807 | 848 | } |
| 808 | − if (!nfs4_client_to_reclaim(name, nn)) { | |
| 849 | + if (!nfs4_client_to_reclaim(name, princhash, nn)) { | |
| 809 | 850 | kfree(name.data); |
| 851 | + kfree(princhash.data); | |
| 810 | 852 | return -EFAULT; |
| 811 | 853 | } |
| 812 | − return sizeof(*cmsg); | |
| 854 | + return nn->client_tracking_ops->msglen; | |
| 813 | 855 | } |
| 814 | 856 | return -EFAULT; |
| 815 | 857 | } |
| @@ -818,21 +860,22 @@ static ssize_t · 2 unmodified lines | ||
| 818 | 860 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
| 819 | 861 | { |
| 820 | 862 | struct cld_upcall *tmp, *cup; |
| 821 | − struct cld_msg __user *cmsg = (struct cld_msg __user *)src; | |
| 863 | + struct cld_msg_hdr __user *hdr = (struct cld_msg_hdr __user *)src; | |
| 864 | + struct cld_msg_v2 __user *cmsg = (struct cld_msg_v2 __user *)src; | |
| 822 | 865 | uint32_t xid; |
| 823 | 866 | struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info, |
| 824 | 867 | nfsd_net_id); |
| 825 | 868 | struct cld_net *cn = nn->cld_net; |
| 826 | 869 | int16_t status; |
| 827 | 870 | |
| 828 | − if (mlen != sizeof(*cmsg)) { | |
| 871 | + if (mlen != nn->client_tracking_ops->msglen) { | |
| 829 | 872 | dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen, |
| 830 | − sizeof(*cmsg)); | |
| 873 | + nn->client_tracking_ops->msglen); | |
| 831 | 874 | return -EINVAL; |
| 832 | 875 | } |
| 833 | 876 | |
| 834 | 877 | /* copy just the xid so we can try to find that */ |
| 835 | − if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) { | |
| 878 | + if (copy_from_user(&xid, &hdr->cm_xid, sizeof(xid)) != 0) { | |
| 836 | 879 | dprintk("%s: error when copying xid from userspace", __func__); |
| 837 | 880 | return -EFAULT; |
| 838 | 881 | } |
| @@ -842,7 +885,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) · 3 unmodified lines | ||
| 842 | 885 | * list (for -EINPROGRESS, we just want to make sure the xid is |
| 843 | 886 | * valid, not remove the upcall from the list) |
| 844 | 887 | */ |
| 845 | − if (get_user(status, &cmsg->cm_status)) { | |
| 888 | + if (get_user(status, &hdr->cm_status)) { | |
| 846 | 889 | dprintk("%s: error when copying status from userspace", __func__); |
| 847 | 890 | return -EFAULT; |
| 848 | 891 | } |
| @@ -851,7 +894,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) · 2 unmodified lines | ||
| 851 | 894 | cup = NULL; |
| 852 | 895 | spin_lock(&cn->cn_lock); |
| 853 | 896 | list_for_each_entry(tmp, &cn->cn_list, cu_list) { |
| 854 | − if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) { | |
| 897 | + if (get_unaligned(&tmp->cu_u.cu_hdr.cm_xid) == xid) { | |
| 855 | 898 | cup = tmp; |
| 856 | 899 | if (status != -EINPROGRESS) |
| 857 | 900 | list_del_init(&cup->cu_list); |
| @@ -869,7 +912,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) · 11 unmodified lines | ||
| 869 | 912 | if (status == -EINPROGRESS) |
| 870 | 913 | return __cld_pipe_inprogress_downcall(cmsg, nn); |
| 871 | 914 | |
| 872 | − if (copy_from_user(&cup->cu_msg, src, mlen) != 0) | |
| 915 | + if (copy_from_user(&cup->cu_u.cu_msg_v2, src, mlen) != 0) | |
| 873 | 916 | return -EFAULT; |
| 874 | 917 | |
| 875 | 918 | complete(&cup->cu_done); |
| @@ -881,7 +924,7 @@ cld_pipe_destroy_msg(struct rpc_pipe_msg *msg) · 5 unmodified lines | ||
| 881 | 924 | { |
| 882 | 925 | struct cld_msg *cmsg = msg->data; |
| 883 | 926 | struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, |
| 884 | − cu_msg); | |
| 927 | + cu_u.cu_msg); | |
| 885 | 928 | |
| 886 | 929 | /* errno >= 0 means we got a downcall */ |
| 887 | 930 | if (msg->errno >= 0) |
| @@ -1007,14 +1050,17 @@ nfsd4_remove_cld_pipe(struct net *net) · 119 unmodified lines | ||
| 1007 | 1050 | |
| 1008 | 1051 | nfsd4_cld_unregister_net(net, cn->cn_pipe); |
| 1009 | 1052 | rpc_destroy_pipe_data(cn->cn_pipe); |
| 1053 | + if (cn->cn_tfm) | |
| 1054 | + crypto_free_shash(cn->cn_tfm); | |
| 1010 | 1055 | kfree(nn->cld_net); |
| 1011 | 1056 | nn->cld_net = NULL; |
| 1012 | 1057 | } |
| 1013 | 1058 | |
| 1014 | 1059 | static struct cld_upcall * |
| 1015 | −alloc_cld_upcall(struct cld_net *cn) | |
| 1060 | +alloc_cld_upcall(struct nfsd_net *nn) | |
| 1016 | 1061 | { |
| 1017 | 1062 | struct cld_upcall *new, *tmp; |
| 1063 | + struct cld_net *cn = nn->cld_net; | |
| 1018 | 1064 | |
| 1019 | 1065 | new = kzalloc(sizeof(*new), GFP_KERNEL); |
| 1020 | 1066 | if (!new) |
| @@ -1024,20 +1070,20 @@ alloc_cld_upcall(struct cld_net *cn) · 3 unmodified lines | ||
| 1024 | 1070 | restart_search: |
| 1025 | 1071 | spin_lock(&cn->cn_lock); |
| 1026 | 1072 | list_for_each_entry(tmp, &cn->cn_list, cu_list) { |
| 1027 | − if (tmp->cu_msg.cm_xid == cn->cn_xid) { | |
| 1073 | + if (tmp->cu_u.cu_msg.cm_xid == cn->cn_xid) { | |
| 1028 | 1074 | cn->cn_xid++; |
| 1029 | 1075 | spin_unlock(&cn->cn_lock); |
| 1030 | 1076 | goto restart_search; |
| 1031 | 1077 | } |
| 1032 | 1078 | } |
| 1033 | 1079 | init_completion(&new->cu_done); |
| 1034 | − new->cu_msg.cm_vers = CLD_UPCALL_VERSION; | |
| 1035 | − put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid); | |
| 1080 | + new->cu_u.cu_msg.cm_vers = nn->client_tracking_ops->version; | |
| 1081 | + put_unaligned(cn->cn_xid++, &new->cu_u.cu_msg.cm_xid); | |
| 1036 | 1082 | new->cu_net = cn; |
| 1037 | 1083 | list_add(&new->cu_list, &cn->cn_list); |
| 1038 | 1084 | spin_unlock(&cn->cn_lock); |
| 1039 | 1085 | |
| 1040 | − dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid); | |
| 1086 | + dprintk("%s: allocated xid %u\n", __func__, new->cu_u.cu_msg.cm_xid); | |
| 1041 | 1087 | |
| 1042 | 1088 | return new; |
| 1043 | 1089 | } |
| @@ -1066,20 +1112,20 @@ nfsd4_cld_create(struct nfs4_client *clp) · 22 unmodified lines | ||
| 1066 | 1112 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
| 1067 | 1113 | return; |
| 1068 | 1114 | |
| 1069 | − cup = alloc_cld_upcall(cn); | |
| 1115 | + cup = alloc_cld_upcall(nn); | |
| 1070 | 1116 | if (!cup) { |
| 1071 | 1117 | ret = -ENOMEM; |
| 1072 | 1118 | goto out_err; |
| 1073 | 1119 | } |
| 1074 | 1120 | |
| 1075 | − cup->cu_msg.cm_cmd = Cld_Create; | |
| 1076 | − cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | |
| 1077 | − memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | |
| 1121 | + cup->cu_u.cu_msg.cm_cmd = Cld_Create; | |
| 1122 | + cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | |
| 1123 | + memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | |
| 1078 | 1124 | clp->cl_name.len); |
| 1079 | 1125 | |
| 1080 | − ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | |
| 1126 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg); | |
| 1081 | 1127 | if (!ret) { |
| 1082 | − ret = cup->cu_msg.cm_status; | |
| 1128 | + ret = cup->cu_u.cu_msg.cm_status; | |
| 1083 | 1129 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
| 1084 | 1130 | } |
| 1085 | 1131 | |
| @@ -1090,6 +1136,75 @@ out_err: · 4 unmodified lines | ||
| 1090 | 1136 | "record on stable storage: %d\n", ret); |
| 1091 | 1137 | } |
| 1092 | 1138 | |
| 1139 | +/* Ask daemon to create a new record */ | |
| 1140 | +static void | |
| 1141 | +nfsd4_cld_create_v2(struct nfs4_client *clp) | |
| 1142 | +{ | |
| 1143 | + int ret; | |
| 1144 | + struct cld_upcall *cup; | |
| 1145 | + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | |
| 1146 | + struct cld_net *cn = nn->cld_net; | |
| 1147 | + struct cld_msg_v2 *cmsg; | |
| 1148 | + struct crypto_shash *tfm = cn->cn_tfm; | |
| 1149 | + struct xdr_netobj cksum; | |
| 1150 | + char *principal = NULL; | |
| 1151 | + SHASH_DESC_ON_STACK(desc, tfm); | |
| 1152 | + | |
| 1153 | + /* Don't upcall if it's already stored */ | |
| 1154 | + if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | |
| 1155 | + return; | |
| 1156 | + | |
| 1157 | + cup = alloc_cld_upcall(nn); | |
| 1158 | + if (!cup) { | |
| 1159 | + ret = -ENOMEM; | |
| 1160 | + goto out_err; | |
| 1161 | + } | |
| 1162 | + | |
| 1163 | + cmsg = &cup->cu_u.cu_msg_v2; | |
| 1164 | + cmsg->cm_cmd = Cld_Create; | |
| 1165 | + cmsg->cm_u.cm_clntinfo.cc_name.cn_len = clp->cl_name.len; | |
| 1166 | + memcpy(cmsg->cm_u.cm_clntinfo.cc_name.cn_id, clp->cl_name.data, | |
| 1167 | + clp->cl_name.len); | |
| 1168 | + if (clp->cl_cred.cr_raw_principal) | |
| 1169 | + principal = clp->cl_cred.cr_raw_principal; | |
| 1170 | + else if (clp->cl_cred.cr_principal) | |
| 1171 | + principal = clp->cl_cred.cr_principal; | |
| 1172 | + if (principal) { | |
| 1173 | + desc->tfm = tfm; | |
| 1174 | + cksum.len = crypto_shash_digestsize(tfm); | |
| 1175 | + cksum.data = kmalloc(cksum.len, GFP_KERNEL); | |
| 1176 | + if (cksum.data == NULL) { | |
| 1177 | + ret = -ENOMEM; | |
| 1178 | + goto out; | |
| 1179 | + } | |
| 1180 | + ret = crypto_shash_digest(desc, principal, strlen(principal), | |
| 1181 | + cksum.data); | |
| 1182 | + shash_desc_zero(desc); | |
| 1183 | + if (ret) { | |
| 1184 | + kfree(cksum.data); | |
| 1185 | + goto out; | |
| 1186 | + } | |
| 1187 | + cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = cksum.len; | |
| 1188 | + memcpy(cmsg->cm_u.cm_clntinfo.cc_princhash.cp_data, | |
| 1189 | + cksum.data, cksum.len); | |
| 1190 | + kfree(cksum.data); | |
| 1191 | + } else | |
| 1192 | + cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = 0; | |
| 1193 | + | |
| 1194 | + ret = cld_pipe_upcall(cn->cn_pipe, cmsg); | |
| 1195 | + if (!ret) { | |
| 1196 | + ret = cmsg->cm_status; | |
| 1197 | + set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | |
| 1198 | + } | |
| 1199 | + | |
| 1200 | +out: | |
| 1201 | + free_cld_upcall(cup); | |
| 1202 | +out_err: | |
| 1203 | + if (ret) | |
| 1204 | + pr_err("NFSD: Unable to create client record on stable storage: %d\n", | |
| 1205 | + ret); | |
| 1206 | +} | |
| 1207 | + | |
| 1093 | 1208 | /* Ask daemon to create a new record */ |
| 1094 | 1209 | static void |
| 1095 | 1210 | nfsd4_cld_remove(struct nfs4_client *clp) |
| @@ -1103,20 +1218,20 @@ nfsd4_cld_remove(struct nfs4_client *clp) · 7 unmodified lines | ||
| 1103 | 1218 | if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
| 1104 | 1219 | return; |
| 1105 | 1220 | |
| 1106 | − cup = alloc_cld_upcall(cn); | |
| 1221 | + cup = alloc_cld_upcall(nn); | |
| 1107 | 1222 | if (!cup) { |
| 1108 | 1223 | ret = -ENOMEM; |
| 1109 | 1224 | goto out_err; |
| 1110 | 1225 | } |
| 1111 | 1226 | |
| 1112 | − cup->cu_msg.cm_cmd = Cld_Remove; | |
| 1113 | − cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | |
| 1114 | − memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | |
| 1227 | + cup->cu_u.cu_msg.cm_cmd = Cld_Remove; | |
| 1228 | + cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | |
| 1229 | + memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | |
| 1115 | 1230 | clp->cl_name.len); |
| 1116 | 1231 | |
| 1117 | − ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | |
| 1232 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg); | |
| 1118 | 1233 | if (!ret) { |
| 1119 | − ret = cup->cu_msg.cm_status; | |
| 1234 | + ret = cup->cu_u.cu_msg.cm_status; | |
| 1120 | 1235 | clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
| 1121 | 1236 | } |
| 1122 | 1237 | |
| @@ -1145,21 +1260,21 @@ nfsd4_cld_check_v0(struct nfs4_client *clp) · 22 unmodified lines | ||
| 1145 | 1260 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
| 1146 | 1261 | return 0; |
| 1147 | 1262 | |
| 1148 | − cup = alloc_cld_upcall(cn); | |
| 1263 | + cup = alloc_cld_upcall(nn); | |
| 1149 | 1264 | if (!cup) { |
| 1150 | 1265 | printk(KERN_ERR "NFSD: Unable to check client record on " |
| 1151 | 1266 | "stable storage: %d\n", -ENOMEM); |
| 1152 | 1267 | return -ENOMEM; |
| 1153 | 1268 | } |
| 1154 | 1269 | |
| 1155 | − cup->cu_msg.cm_cmd = Cld_Check; | |
| 1156 | − cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | |
| 1157 | − memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | |
| 1270 | + cup->cu_u.cu_msg.cm_cmd = Cld_Check; | |
| 1271 | + cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; | |
| 1272 | + memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, | |
| 1158 | 1273 | clp->cl_name.len); |
| 1159 | 1274 | |
| 1160 | − ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | |
| 1275 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg); | |
| 1161 | 1276 | if (!ret) { |
| 1162 | − ret = cup->cu_msg.cm_status; | |
| 1277 | + ret = cup->cu_u.cu_msg.cm_status; | |
| 1163 | 1278 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
| 1164 | 1279 | } |
| 1165 | 1280 | |
| @@ -1216,6 +1331,79 @@ found: · 50 unmodified lines | ||
| 1216 | 1331 | return 0; |
| 1217 | 1332 | } |
| 1218 | 1333 | |
| 1334 | +static int | |
| 1335 | +nfsd4_cld_check_v2(struct nfs4_client *clp) | |
| 1336 | +{ | |
| 1337 | + struct nfs4_client_reclaim *crp; | |
| 1338 | + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | |
| 1339 | + struct cld_net *cn = nn->cld_net; | |
| 1340 | + int status; | |
| 1341 | + char dname[HEXDIR_LEN]; | |
| 1342 | + struct xdr_netobj name; | |
| 1343 | + struct crypto_shash *tfm = cn->cn_tfm; | |
| 1344 | + struct xdr_netobj cksum; | |
| 1345 | + char *principal = NULL; | |
| 1346 | + SHASH_DESC_ON_STACK(desc, tfm); | |
| 1347 | + | |
| 1348 | + /* did we already find that this client is stable? */ | |
| 1349 | + if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | |
| 1350 | + return 0; | |
| 1351 | + | |
| 1352 | + /* look for it in the reclaim hashtable otherwise */ | |
| 1353 | + crp = nfsd4_find_reclaim_client(clp->cl_name, nn); | |
| 1354 | + if (crp) | |
| 1355 | + goto found; | |
| 1356 | + | |
| 1357 | + if (cn->cn_has_legacy) { | |
| 1358 | + status = nfs4_make_rec_clidname(dname, &clp->cl_name); | |
| 1359 | + if (status) | |
| 1360 | + return -ENOENT; | |
| 1361 | + | |
| 1362 | + name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL); | |
| 1363 | + if (!name.data) { | |
| 1364 | + dprintk("%s: failed to allocate memory for name.data\n", | |
| 1365 | + __func__); | |
| 1366 | + return -ENOENT; | |
| 1367 | + } | |
| 1368 | + name.len = HEXDIR_LEN; | |
| 1369 | + crp = nfsd4_find_reclaim_client(name, nn); | |
| 1370 | + kfree(name.data); | |
| 1371 | + if (crp) | |
| 1372 | + goto found; | |
| 1373 | + | |
| 1374 | + } | |
| 1375 | + return -ENOENT; | |
| 1376 | +found: | |
| 1377 | + if (crp->cr_princhash.len) { | |
| 1378 | + if (clp->cl_cred.cr_raw_principal) | |
| 1379 | + principal = clp->cl_cred.cr_raw_principal; | |
| 1380 | + else if (clp->cl_cred.cr_principal) | |
| 1381 | + principal = clp->cl_cred.cr_principal; | |
| 1382 | + if (principal == NULL) | |
| 1383 | + return -ENOENT; | |
| 1384 | + desc->tfm = tfm; | |
| 1385 | + cksum.len = crypto_shash_digestsize(tfm); | |
| 1386 | + cksum.data = kmalloc(cksum.len, GFP_KERNEL); | |
| 1387 | + if (cksum.data == NULL) | |
| 1388 | + return -ENOENT; | |
| 1389 | + status = crypto_shash_digest(desc, principal, strlen(principal), | |
| 1390 | + cksum.data); | |
| 1391 | + shash_desc_zero(desc); | |
| 1392 | + if (status) { | |
| 1393 | + kfree(cksum.data); | |
| 1394 | + return -ENOENT; | |
| 1395 | + } | |
| 1396 | + if (memcmp(crp->cr_princhash.data, cksum.data, | |
| 1397 | + crp->cr_princhash.len)) { | |
| 1398 | + kfree(cksum.data); | |
| 1399 | + return -ENOENT; | |
| 1400 | + } | |
| 1401 | + kfree(cksum.data); | |
| 1402 | + } | |
| 1403 | + crp->cr_clp = clp; | |
| 1404 | + return 0; | |
| 1405 | +} | |
| 1406 | + | |
| 1219 | 1407 | static int |
| 1220 | 1408 | nfsd4_cld_grace_start(struct nfsd_net *nn) |
| 1221 | 1409 | { |
| @@ -1223,16 +1411,16 @@ nfsd4_cld_grace_start(struct nfsd_net *nn) · 1 unmodified line | ||
| 1223 | 1411 | struct cld_upcall *cup; |
| 1224 | 1412 | struct cld_net *cn = nn->cld_net; |
| 1225 | 1413 | |
| 1226 | − cup = alloc_cld_upcall(cn); | |
| 1414 | + cup = alloc_cld_upcall(nn); | |
| 1227 | 1415 | if (!cup) { |
| 1228 | 1416 | ret = -ENOMEM; |
| 1229 | 1417 | goto out_err; |
| 1230 | 1418 | } |
| 1231 | 1419 | |
| 1232 | − cup->cu_msg.cm_cmd = Cld_GraceStart; | |
| 1233 | − ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | |
| 1420 | + cup->cu_u.cu_msg.cm_cmd = Cld_GraceStart; | |
| 1421 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg); | |
| 1234 | 1422 | if (!ret) |
| 1235 | − ret = cup->cu_msg.cm_status; | |
| 1423 | + ret = cup->cu_u.cu_msg.cm_status; | |
| 1236 | 1424 | |
| 1237 | 1425 | free_cld_upcall(cup); |
| 1238 | 1426 | out_err: |
| @@ -1250,17 +1438,17 @@ nfsd4_cld_grace_done_v0(struct nfsd_net *nn) · 11 unmodified lines | ||
| 1250 | 1438 | struct cld_upcall *cup; |
| 1251 | 1439 | struct cld_net *cn = nn->cld_net; |
| 1252 | 1440 | |
| 1253 | − cup = alloc_cld_upcall(cn); | |
| 1441 | + cup = alloc_cld_upcall(nn); | |
| 1254 | 1442 | if (!cup) { |
| 1255 | 1443 | ret = -ENOMEM; |
| 1256 | 1444 | goto out_err; |
| 1257 | 1445 | } |
| 1258 | 1446 | |
| 1259 | − cup->cu_msg.cm_cmd = Cld_GraceDone; | |
| 1260 | − cup->cu_msg.cm_u.cm_gracetime = (int64_t)nn->boot_time; | |
| 1261 | − ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | |
| 1447 | + cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone; | |
| 1448 | + cup->cu_u.cu_msg.cm_u.cm_gracetime = (int64_t)nn->boot_time; | |
| 1449 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg); | |
| 1262 | 1450 | if (!ret) |
| 1263 | − ret = cup->cu_msg.cm_status; | |
| 1451 | + ret = cup->cu_u.cu_msg.cm_status; | |
| 1264 | 1452 | |
| 1265 | 1453 | free_cld_upcall(cup); |
| 1266 | 1454 | out_err: |
| @@ -1279,16 +1467,16 @@ nfsd4_cld_grace_done(struct nfsd_net *nn) · 12 unmodified lines | ||
| 1279 | 1467 | struct cld_upcall *cup; |
| 1280 | 1468 | struct cld_net *cn = nn->cld_net; |
| 1281 | 1469 | |
| 1282 | − cup = alloc_cld_upcall(cn); | |
| 1470 | + cup = alloc_cld_upcall(nn); | |
| 1283 | 1471 | if (!cup) { |
| 1284 | 1472 | ret = -ENOMEM; |
| 1285 | 1473 | goto out_err; |
| 1286 | 1474 | } |
| 1287 | 1475 | |
| 1288 | − cup->cu_msg.cm_cmd = Cld_GraceDone; | |
| 1289 | − ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); | |
| 1476 | + cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone; | |
| 1477 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg); | |
| 1290 | 1478 | if (!ret) |
| 1291 | − ret = cup->cu_msg.cm_status; | |
| 1479 | + ret = cup->cu_u.cu_msg.cm_status; | |
| 1292 | 1480 | |
| 1293 | 1481 | free_cld_upcall(cup); |
| 1294 | 1482 | out_err: |
| @@ -1336,6 +1524,53 @@ cld_running(struct nfsd_net *nn) · 41 unmodified lines | ||
| 1336 | 1524 | return pipe->nreaders || pipe->nwriters; |
| 1337 | 1525 | } |
| 1338 | 1526 | |
| 1527 | +static int | |
| 1528 | +nfsd4_cld_get_version(struct nfsd_net *nn) | |
| 1529 | +{ | |
| 1530 | + int ret = 0; | |
| 1531 | + struct cld_upcall *cup; | |
| 1532 | + struct cld_net *cn = nn->cld_net; | |
| 1533 | + uint8_t version; | |
| 1534 | + | |
| 1535 | + cup = alloc_cld_upcall(nn); | |
| 1536 | + if (!cup) { | |
| 1537 | + ret = -ENOMEM; | |
| 1538 | + goto out_err; | |
| 1539 | + } | |
| 1540 | + cup->cu_u.cu_msg.cm_cmd = Cld_GetVersion; | |
| 1541 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg); | |
| 1542 | + if (!ret) { | |
| 1543 | + ret = cup->cu_u.cu_msg.cm_status; | |
| 1544 | + if (ret) | |
| 1545 | + goto out_free; | |
| 1546 | + version = cup->cu_u.cu_msg.cm_u.cm_version; | |
| 1547 | + dprintk("%s: userspace returned version %u\n", | |
| 1548 | + __func__, version); | |
| 1549 | + if (version < 1) | |
| 1550 | + version = 1; | |
| 1551 | + else if (version > CLD_UPCALL_VERSION) | |
| 1552 | + version = CLD_UPCALL_VERSION; | |
| 1553 | + | |
| 1554 | + switch (version) { | |
| 1555 | + case 1: | |
| 1556 | + nn->client_tracking_ops = &nfsd4_cld_tracking_ops; | |
| 1557 | + break; | |
| 1558 | + case 2: | |
| 1559 | + nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v2; | |
| 1560 | + break; | |
| 1561 | + default: | |
| 1562 | + break; | |
| 1563 | + } | |
| 1564 | + } | |
| 1565 | +out_free: | |
| 1566 | + free_cld_upcall(cup); | |
| 1567 | +out_err: | |
| 1568 | + if (ret) | |
| 1569 | + dprintk("%s: Unable to get version from userspace: %d\n", | |
| 1570 | + __func__, ret); | |
| 1571 | + return ret; | |
| 1572 | +} | |
| 1573 | + | |
| 1339 | 1574 | static int |
| 1340 | 1575 | nfsd4_cld_tracking_init(struct net *net) |
| 1341 | 1576 | { |
| @@ -1351,6 +1586,11 @@ nfsd4_cld_tracking_init(struct net *net) · 9 unmodified lines | ||
| 1351 | 1586 | status = __nfsd4_init_cld_pipe(net); |
| 1352 | 1587 | if (status) |
| 1353 | 1588 | goto err_shutdown; |
| 1589 | + nn->cld_net->cn_tfm = crypto_alloc_shash("sha256", 0, 0); | |
| 1590 | + if (IS_ERR(nn->cld_net->cn_tfm)) { | |
| 1591 | + status = PTR_ERR(nn->cld_net->cn_tfm); | |
| 1592 | + goto err_remove; | |
| 1593 | + } | |
| 1354 | 1594 | |
| 1355 | 1595 | /* |
| 1356 | 1596 | * rpc pipe upcalls take 30 seconds to time out, so we don't want to |
| @@ -1368,10 +1608,14 @@ nfsd4_cld_tracking_init(struct net *net) · 11 unmodified lines | ||
| 1368 | 1608 | goto err_remove; |
| 1369 | 1609 | } |
| 1370 | 1610 | |
| 1611 | + status = nfsd4_cld_get_version(nn); | |
| 1612 | + if (status == -EOPNOTSUPP) | |
| 1613 | + pr_warn("NFSD: nfsdcld GetVersion upcall failed. Please upgrade nfsdcld.\n"); | |
| 1614 | + | |
| 1371 | 1615 | status = nfsd4_cld_grace_start(nn); |
| 1372 | 1616 | if (status) { |
| 1373 | 1617 | if (status == -EOPNOTSUPP) |
| 1374 | − printk(KERN_WARNING "NFSD: Please upgrade nfsdcld.\n"); | |
| 1618 | + pr_warn("NFSD: nfsdcld GraceStart upcall failed. Please upgrade nfsdcld.\n"); | |
| 1375 | 1619 | nfs4_release_reclaim(nn); |
| 1376 | 1620 | goto err_remove; |
| 1377 | 1621 | } else |
| @@ -1403,6 +1647,8 @@ static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v0 = { · 25 unmodified lines | ||
| 1403 | 1647 | .remove = nfsd4_cld_remove, |
| 1404 | 1648 | .check = nfsd4_cld_check_v0, |
| 1405 | 1649 | .grace_done = nfsd4_cld_grace_done_v0, |
| 1650 | + .version = 1, | |
| 1651 | + .msglen = sizeof(struct cld_msg), | |
| 1406 | 1652 | }; |
| 1407 | 1653 | |
| 1408 | 1654 | /* For newer nfsdcld's */ |
| @@ -1413,6 +1659,20 @@ static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { · 4 unmodified lines | ||
| 1413 | 1659 | .remove = nfsd4_cld_remove, |
| 1414 | 1660 | .check = nfsd4_cld_check, |
| 1415 | 1661 | .grace_done = nfsd4_cld_grace_done, |
| 1662 | + .version = 1, | |
| 1663 | + .msglen = sizeof(struct cld_msg), | |
| 1664 | +}; | |
| 1665 | + | |
| 1666 | +/* v2 create/check ops include the principal, if available */ | |
| 1667 | +static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2 = { | |
| 1668 | + .init = nfsd4_cld_tracking_init, | |
| 1669 | + .exit = nfsd4_cld_tracking_exit, | |
| 1670 | + .create = nfsd4_cld_create_v2, | |
| 1671 | + .remove = nfsd4_cld_remove, | |
| 1672 | + .check = nfsd4_cld_check_v2, | |
| 1673 | + .grace_done = nfsd4_cld_grace_done, | |
| 1674 | + .version = 2, | |
| 1675 | + .msglen = sizeof(struct cld_msg_v2), | |
| 1416 | 1676 | }; |
| 1417 | 1677 | |
| 1418 | 1678 | /* upcall via usermodehelper */ |
| @@ -1760,6 +2020,8 @@ static const struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = { · 341 unmodified lines | ||
| 1760 | 2020 | .remove = nfsd4_umh_cltrack_remove, |
| 1761 | 2021 | .check = nfsd4_umh_cltrack_check, |
| 1762 | 2022 | .grace_done = nfsd4_umh_cltrack_grace_done, |
| 2023 | + .version = 1, | |
| 2024 | + .msglen = 0, | |
| 1763 | 2025 | }; |
| 1764 | 2026 | |
| 1765 | 2027 | int |
| @@ -50,6 +50,7 @@ · 49 unmodified lines | ||
| 50 | 50 | |
| 51 | 51 | #include "netns.h" |
| 52 | 52 | #include "pnfs.h" |
| 53 | +#include "filecache.h" | |
| 53 | 54 | |
| 54 | 55 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
| 55 | 56 | |
| @@ -429,18 +430,18 @@ put_nfs4_file(struct nfs4_file *fi) · 373 unmodified lines | ||
| 429 | 430 | } |
| 430 | 431 | } |
| 431 | 432 | |
| 432 | −static struct file * | |
| 433 | +static struct nfsd_file * | |
| 433 | 434 | __nfs4_get_fd(struct nfs4_file *f, int oflag) |
| 434 | 435 | { |
| 435 | 436 | if (f->fi_fds[oflag]) |
| 436 | − return get_file(f->fi_fds[oflag]); | |
| 437 | + return nfsd_file_get(f->fi_fds[oflag]); | |
| 437 | 438 | return NULL; |
| 438 | 439 | } |
| 439 | 440 | |
| 440 | −static struct file * | |
| 441 | +static struct nfsd_file * | |
| 441 | 442 | find_writeable_file_locked(struct nfs4_file *f) |
| 442 | 443 | { |
| 443 | − struct file *ret; | |
| 444 | + struct nfsd_file *ret; | |
| 444 | 445 | |
| 445 | 446 | lockdep_assert_held(&f->fi_lock); |
| 446 | 447 | |
| @@ -450,10 +451,10 @@ find_writeable_file_locked(struct nfs4_file *f) · 3 unmodified lines | ||
| 450 | 451 | return ret; |
| 451 | 452 | } |
| 452 | 453 | |
| 453 | −static struct file * | |
| 454 | +static struct nfsd_file * | |
| 454 | 455 | find_writeable_file(struct nfs4_file *f) |
| 455 | 456 | { |
| 456 | − struct file *ret; | |
| 457 | + struct nfsd_file *ret; | |
| 457 | 458 | |
| 458 | 459 | spin_lock(&f->fi_lock); |
| 459 | 460 | ret = find_writeable_file_locked(f); |
| @@ -462,9 +463,10 @@ find_writeable_file(struct nfs4_file *f) · 2 unmodified lines | ||
| 462 | 463 | return ret; |
| 463 | 464 | } |
| 464 | 465 | |
| 465 | −static struct file *find_readable_file_locked(struct nfs4_file *f) | |
| 466 | +static struct nfsd_file * | |
| 467 | +find_readable_file_locked(struct nfs4_file *f) | |
| 466 | 468 | { |
| 467 | − struct file *ret; | |
| 469 | + struct nfsd_file *ret; | |
| 468 | 470 | |
| 469 | 471 | lockdep_assert_held(&f->fi_lock); |
| 470 | 472 | |
| @@ -474,10 +476,10 @@ static struct file *find_readable_file_locked(struct nfs4_file *f) · 3 unmodified lines | ||
| 474 | 476 | return ret; |
| 475 | 477 | } |
| 476 | 478 | |
| 477 | −static struct file * | |
| 479 | +static struct nfsd_file * | |
| 478 | 480 | find_readable_file(struct nfs4_file *f) |
| 479 | 481 | { |
| 480 | − struct file *ret; | |
| 482 | + struct nfsd_file *ret; | |
| 481 | 483 | |
| 482 | 484 | spin_lock(&f->fi_lock); |
| 483 | 485 | ret = find_readable_file_locked(f); |
| @@ -486,10 +488,10 @@ find_readable_file(struct nfs4_file *f) · 2 unmodified lines | ||
| 486 | 488 | return ret; |
| 487 | 489 | } |
| 488 | 490 | |
| 489 | −struct file * | |
| 491 | +struct nfsd_file * | |
| 490 | 492 | find_any_file(struct nfs4_file *f) |
| 491 | 493 | { |
| 492 | − struct file *ret; | |
| 494 | + struct nfsd_file *ret; | |
| 493 | 495 | |
| 494 | 496 | spin_lock(&f->fi_lock); |
| 495 | 497 | ret = __nfs4_get_fd(f, O_RDWR); |
| @@ -590,17 +592,17 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) · 94 unmodified lines | ||
| 590 | 592 | might_lock(&fp->fi_lock); |
| 591 | 593 | |
| 592 | 594 | if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { |
| 593 | − struct file *f1 = NULL; | |
| 594 | − struct file *f2 = NULL; | |
| 595 | + struct nfsd_file *f1 = NULL; | |
| 596 | + struct nfsd_file *f2 = NULL; | |
| 595 | 597 | |
| 596 | 598 | swap(f1, fp->fi_fds[oflag]); |
| 597 | 599 | if (atomic_read(&fp->fi_access[1 - oflag]) == 0) |
| 598 | 600 | swap(f2, fp->fi_fds[O_RDWR]); |
| 599 | 601 | spin_unlock(&fp->fi_lock); |
| 600 | 602 | if (f1) |
| 601 | − fput(f1); | |
| 603 | + nfsd_file_put(f1); | |
| 602 | 604 | if (f2) |
| 603 | − fput(f2); | |
| 605 | + nfsd_file_put(f2); | |
| 604 | 606 | } |
| 605 | 607 | } |
| 606 | 608 | |
| @@ -933,25 +935,25 @@ nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) · 326 unmodified lines | ||
| 933 | 935 | |
| 934 | 936 | static void put_deleg_file(struct nfs4_file *fp) |
| 935 | 937 | { |
| 936 | − struct file *filp = NULL; | |
| 938 | + struct nfsd_file *nf = NULL; | |
| 937 | 939 | |
| 938 | 940 | spin_lock(&fp->fi_lock); |
| 939 | 941 | if (--fp->fi_delegees == 0) |
| 940 | − swap(filp, fp->fi_deleg_file); | |
| 942 | + swap(nf, fp->fi_deleg_file); | |
| 941 | 943 | spin_unlock(&fp->fi_lock); |
| 942 | 944 | |
| 943 | − if (filp) | |
| 944 | − fput(filp); | |
| 945 | + if (nf) | |
| 946 | + nfsd_file_put(nf); | |
| 945 | 947 | } |
| 946 | 948 | |
| 947 | 949 | static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) |
| 948 | 950 | { |
| 949 | 951 | struct nfs4_file *fp = dp->dl_stid.sc_file; |
| 950 | − struct file *filp = fp->fi_deleg_file; | |
| 952 | + struct nfsd_file *nf = fp->fi_deleg_file; | |
| 951 | 953 | |
| 952 | 954 | WARN_ON_ONCE(!fp->fi_delegees); |
| 953 | 955 | |
| 954 | − vfs_setlease(filp, F_UNLCK, NULL, (void **)&dp); | |
| 956 | + vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); | |
| 955 | 957 | put_deleg_file(fp); |
| 956 | 958 | } |
| 957 | 959 | |
| @@ -1289,11 +1291,14 @@ static void nfs4_free_lock_stateid(struct nfs4_stid *stid) · 331 unmodified lines | ||
| 1289 | 1291 | { |
| 1290 | 1292 | struct nfs4_ol_stateid *stp = openlockstateid(stid); |
| 1291 | 1293 | struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); |
| 1292 | − struct file *file; | |
| 1294 | + struct nfsd_file *nf; | |
| 1293 | 1295 | |
| 1294 | − file = find_any_file(stp->st_stid.sc_file); | |
| 1295 | − if (file) | |
| 1296 | − filp_close(file, (fl_owner_t)lo); | |
| 1296 | + nf = find_any_file(stp->st_stid.sc_file); | |
| 1297 | + if (nf) { | |
| 1298 | + get_file(nf->nf_file); | |
| 1299 | + filp_close(nf->nf_file, (fl_owner_t)lo); | |
| 1300 | + nfsd_file_put(nf); | |
| 1301 | + } | |
| 1297 | 1302 | nfs4_free_ol_stateid(stid); |
| 1298 | 1303 | } |
| 1299 | 1304 | |
| @@ -1563,21 +1568,39 @@ static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) · 263 unmodified lines | ||
| 1563 | 1568 | * re-negotiate active sessions and reduce their slot usage to make |
| 1564 | 1569 | * room for new connections. For now we just fail the create session. |
| 1565 | 1570 | */ |
| 1566 | −static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) | |
| 1571 | +static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) | |
| 1567 | 1572 | { |
| 1568 | 1573 | u32 slotsize = slot_bytes(ca); |
| 1569 | 1574 | u32 num = ca->maxreqs; |
| 1570 | 1575 | unsigned long avail, total_avail; |
| 1576 | + unsigned int scale_factor; | |
| 1571 | 1577 | |
| 1572 | 1578 | spin_lock(&nfsd_drc_lock); |
| 1573 | − total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; | |
| 1579 | + if (nfsd_drc_max_mem > nfsd_drc_mem_used) | |
| 1580 | + total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; | |
| 1581 | + else | |
| 1582 | + /* We have handed out more space than we chose in | |
| 1583 | + * set_max_drc() to allow. That isn't really a | |
| 1584 | + * problem as long as that doesn't make us think we | |
| 1585 | + * have lots more due to integer overflow. | |
| 1586 | + */ | |
| 1587 | + total_avail = 0; | |
| 1574 | 1588 | avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); |
| 1575 | 1589 | /* |
| 1576 | − * Never use more than a third of the remaining memory, | |
| 1577 | − * unless it's the only way to give this client a slot: | |
| 1590 | + * Never use more than a fraction of the remaining memory, | |
| 1591 | + * unless it's the only way to give this client a slot. | |
| 1592 | + * The chosen fraction is either 1/8 or 1/number of threads, | |
| 1593 | + * whichever is smaller. This ensures there are adequate | |
| 1594 | + * slots to support multiple clients per thread. | |
| 1595 | + * Give the client one slot even if that would require | |
| 1596 | + * over-allocation--it is better than failure. | |
| 1578 | 1597 | */ |
| 1579 | − avail = clamp_t(unsigned long, avail, slotsize, total_avail/3); | |
| 1598 | + scale_factor = max_t(unsigned int, 8, nn->nfsd_serv->sv_nrthreads); | |
| 1599 | + | |
| 1600 | + avail = clamp_t(unsigned long, avail, slotsize, | |
| 1601 | + total_avail/scale_factor); | |
| 1580 | 1602 | num = min_t(int, num, avail / slotsize); |
| 1603 | + num = max_t(int, num, 1); | |
| 1581 | 1604 | nfsd_drc_mem_used += num * slotsize; |
| 1582 | 1605 | spin_unlock(&nfsd_drc_lock); |
| 1583 | 1606 | |
| @@ -2323,9 +2346,9 @@ static void states_stop(struct seq_file *s, void *v) · 739 unmodified lines | ||
| 2323 | 2346 | spin_unlock(&clp->cl_lock); |
| 2324 | 2347 | } |
| 2325 | 2348 | |
| 2326 | −static void nfs4_show_superblock(struct seq_file *s, struct file *f) | |
| 2349 | +static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f) | |
| 2327 | 2350 | { |
| 2328 | − struct inode *inode = file_inode(f); | |
| 2351 | + struct inode *inode = f->nf_inode; | |
| 2329 | 2352 | |
| 2330 | 2353 | seq_printf(s, "superblock: \"%02x:%02x:%ld\"", |
| 2331 | 2354 | MAJOR(inode->i_sb->s_dev), |
| @@ -2343,7 +2366,7 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) · 11 unmodified lines | ||
| 2343 | 2366 | { |
| 2344 | 2367 | struct nfs4_ol_stateid *ols; |
| 2345 | 2368 | struct nfs4_file *nf; |
| 2346 | − struct file *file; | |
| 2369 | + struct nfsd_file *file; | |
| 2347 | 2370 | struct nfs4_stateowner *oo; |
| 2348 | 2371 | unsigned int access, deny; |
| 2349 | 2372 | |
| @@ -2370,7 +2393,7 @@ static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) · 20 unmodified lines | ||
| 2370 | 2393 | seq_printf(s, ", "); |
| 2371 | 2394 | nfs4_show_owner(s, oo); |
| 2372 | 2395 | seq_printf(s, " }\n"); |
| 2373 | − fput(file); | |
| 2396 | + nfsd_file_put(file); | |
| 2374 | 2397 | |
| 2375 | 2398 | return 0; |
| 2376 | 2399 | } |
| @@ -2379,7 +2402,7 @@ static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) · 2 unmodified lines | ||
| 2379 | 2402 | { |
| 2380 | 2403 | struct nfs4_ol_stateid *ols; |
| 2381 | 2404 | struct nfs4_file *nf; |
| 2382 | − struct file *file; | |
| 2405 | + struct nfsd_file *file; | |
| 2383 | 2406 | struct nfs4_stateowner *oo; |
| 2384 | 2407 | |
| 2385 | 2408 | ols = openlockstateid(st); |
| @@ -2401,7 +2424,7 @@ static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) · 15 unmodified lines | ||
| 2401 | 2424 | seq_printf(s, ", "); |
| 2402 | 2425 | nfs4_show_owner(s, oo); |
| 2403 | 2426 | seq_printf(s, " }\n"); |
| 2404 | − fput(file); | |
| 2427 | + nfsd_file_put(file); | |
| 2405 | 2428 | |
| 2406 | 2429 | return 0; |
| 2407 | 2430 | } |
| @@ -2410,7 +2433,7 @@ static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) · 2 unmodified lines | ||
| 2410 | 2433 | { |
| 2411 | 2434 | struct nfs4_delegation *ds; |
| 2412 | 2435 | struct nfs4_file *nf; |
| 2413 | − struct file *file; | |
| 2436 | + struct nfsd_file *file; | |
| 2414 | 2437 | |
| 2415 | 2438 | ds = delegstateid(st); |
| 2416 | 2439 | nf = st->sc_file; |
| @@ -2433,7 +2456,7 @@ static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) · 16 unmodified lines | ||
| 2433 | 2456 | static int nfs4_show_layout(struct seq_file *s, struct nfs4_stid *st) |
| 2434 | 2457 | { |
| 2435 | 2458 | struct nfs4_layout_stateid *ls; |
| 2436 | − struct file *file; | |
| 2459 | + struct nfsd_file *file; | |
| 2437 | 2460 | |
| 2438 | 2461 | ls = container_of(st, struct nfs4_layout_stateid, ls_stid); |
| 2439 | 2462 | file = ls->ls_file; |
| @@ -3169,10 +3192,10 @@ static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfs · 729 unmodified lines | ||
| 3169 | 3192 | * performance. When short on memory we therefore prefer to |
| 3170 | 3193 | * decrease number of slots instead of their size. Clients that |
| 3171 | 3194 | * request larger slots than they need will get poor results: |
| 3195 | + * Note that we always allow at least one slot, because our | |
| 3196 | + * accounting is soft and provides no guarantees either way. | |
| 3172 | 3197 | */ |
| 3173 | − ca->maxreqs = nfsd4_get_drc_mem(ca); | |
| 3174 | − if (!ca->maxreqs) | |
| 3175 | − return nfserr_jukebox; | |
| 3198 | + ca->maxreqs = nfsd4_get_drc_mem(ca, nn); | |
| 3176 | 3199 | |
| 3177 | 3200 | return nfs_ok; |
| 3178 | 3201 | } |
| @@ -4651,7 +4674,7 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, · 1472 unmodified lines | ||
| 4651 | 4674 | struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, |
| 4652 | 4675 | struct nfsd4_open *open) |
| 4653 | 4676 | { |
| 4654 | − struct file *filp = NULL; | |
| 4677 | + struct nfsd_file *nf = NULL; | |
| 4655 | 4678 | __be32 status; |
| 4656 | 4679 | int oflag = nfs4_access_to_omode(open->op_share_access); |
| 4657 | 4680 | int access = nfs4_access_to_access(open->op_share_access); |
| @@ -4687,18 +4710,18 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, · 29 unmodified lines | ||
| 4687 | 4710 | |
| 4688 | 4711 | if (!fp->fi_fds[oflag]) { |
| 4689 | 4712 | spin_unlock(&fp->fi_lock); |
| 4690 | − status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp); | |
| 4713 | + status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); | |
| 4691 | 4714 | if (status) |
| 4692 | 4715 | goto out_put_access; |
| 4693 | 4716 | spin_lock(&fp->fi_lock); |
| 4694 | 4717 | if (!fp->fi_fds[oflag]) { |
| 4695 | − fp->fi_fds[oflag] = filp; | |
| 4696 | − filp = NULL; | |
| 4718 | + fp->fi_fds[oflag] = nf; | |
| 4719 | + nf = NULL; | |
| 4697 | 4720 | } |
| 4698 | 4721 | } |
| 4699 | 4722 | spin_unlock(&fp->fi_lock); |
| 4700 | − if (filp) | |
| 4701 | − fput(filp); | |
| 4723 | + if (nf) | |
| 4724 | + nfsd_file_put(nf); | |
| 4702 | 4725 | |
| 4703 | 4726 | status = nfsd4_truncate(rqstp, cur_fh, open); |
| 4704 | 4727 | if (status) |
| @@ -4767,7 +4790,7 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, · 62 unmodified lines | ||
| 4767 | 4790 | fl->fl_end = OFFSET_MAX; |
| 4768 | 4791 | fl->fl_owner = (fl_owner_t)dp; |
| 4769 | 4792 | fl->fl_pid = current->tgid; |
| 4770 | − fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file; | |
| 4793 | + fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; | |
| 4771 | 4794 | return fl; |
| 4772 | 4795 | } |
| 4773 | 4796 | |
| @@ -4777,7 +4800,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, · 3 unmodified lines | ||
| 4777 | 4800 | { |
| 4778 | 4801 | int status = 0; |
| 4779 | 4802 | struct nfs4_delegation *dp; |
| 4780 | − struct file *filp; | |
| 4803 | + struct nfsd_file *nf; | |
| 4781 | 4804 | struct file_lock *fl; |
| 4782 | 4805 | |
| 4783 | 4806 | /* |
| @@ -4788,8 +4811,8 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, · 4 unmodified lines | ||
| 4788 | 4811 | if (fp->fi_had_conflict) |
| 4789 | 4812 | return ERR_PTR(-EAGAIN); |
| 4790 | 4813 | |
| 4791 | − filp = find_readable_file(fp); | |
| 4792 | − if (!filp) { | |
| 4814 | + nf = find_readable_file(fp); | |
| 4815 | + if (!nf) { | |
| 4793 | 4816 | /* We should always have a readable file here */ |
| 4794 | 4817 | WARN_ON_ONCE(1); |
| 4795 | 4818 | return ERR_PTR(-EBADF); |
| @@ -4799,17 +4822,17 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, · 3 unmodified lines | ||
| 4799 | 4822 | if (nfs4_delegation_exists(clp, fp)) |
| 4800 | 4823 | status = -EAGAIN; |
| 4801 | 4824 | else if (!fp->fi_deleg_file) { |
| 4802 | − fp->fi_deleg_file = filp; | |
| 4825 | + fp->fi_deleg_file = nf; | |
| 4803 | 4826 | /* increment early to prevent fi_deleg_file from being |
| 4804 | 4827 | * cleared */ |
| 4805 | 4828 | fp->fi_delegees = 1; |
| 4806 | − filp = NULL; | |
| 4829 | + nf = NULL; | |
| 4807 | 4830 | } else |
| 4808 | 4831 | fp->fi_delegees++; |
| 4809 | 4832 | spin_unlock(&fp->fi_lock); |
| 4810 | 4833 | spin_unlock(&state_lock); |
| 4811 | − if (filp) | |
| 4812 | − fput(filp); | |
| 4834 | + if (nf) | |
| 4835 | + nfsd_file_put(nf); | |
| 4813 | 4836 | if (status) |
| 4814 | 4837 | return ERR_PTR(status); |
| 4815 | 4838 | |
| @@ -4822,7 +4845,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, · 6 unmodified lines | ||
| 4822 | 4845 | if (!fl) |
| 4823 | 4846 | goto out_clnt_odstate; |
| 4824 | 4847 | |
| 4825 | − status = vfs_setlease(fp->fi_deleg_file, fl->fl_type, &fl, NULL); | |
| 4848 | + status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL); | |
| 4826 | 4849 | if (fl) |
| 4827 | 4850 | locks_free_lock(fl); |
| 4828 | 4851 | if (status) |
| @@ -4842,7 +4865,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, · 13 unmodified lines | ||
| 4842 | 4865 | |
| 4843 | 4866 | return dp; |
| 4844 | 4867 | out_unlock: |
| 4845 | − vfs_setlease(fp->fi_deleg_file, F_UNLCK, NULL, (void **)&dp); | |
| 4868 | + vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); | |
| 4846 | 4869 | out_clnt_odstate: |
| 4847 | 4870 | put_clnt_odstate(dp->dl_clnt_odstate); |
| 4848 | 4871 | nfs4_put_stid(&dp->dl_stid); |
| @@ -5513,7 +5536,7 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, · 664 unmodified lines | ||
| 5513 | 5536 | return nfs_ok; |
| 5514 | 5537 | } |
| 5515 | 5538 | |
| 5516 | −static struct file * | |
| 5539 | +static struct nfsd_file * | |
| 5517 | 5540 | nfs4_find_file(struct nfs4_stid *s, int flags) |
| 5518 | 5541 | { |
| 5519 | 5542 | if (!s) |
| @@ -5523,7 +5546,7 @@ nfs4_find_file(struct nfs4_stid *s, int flags) · 3 unmodified lines | ||
| 5523 | 5546 | case NFS4_DELEG_STID: |
| 5524 | 5547 | if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) |
| 5525 | 5548 | return NULL; |
| 5526 | − return get_file(s->sc_file->fi_deleg_file); | |
| 5549 | + return nfsd_file_get(s->sc_file->fi_deleg_file); | |
| 5527 | 5550 | case NFS4_OPEN_STID: |
| 5528 | 5551 | case NFS4_LOCK_STID: |
| 5529 | 5552 | if (flags & RD_STATE) |
| @@ -5549,32 +5572,28 @@ nfs4_check_olstateid(struct nfs4_ol_stateid *ols, int flags) · 19 unmodified lines | ||
| 5549 | 5572 | |
| 5550 | 5573 | static __be32 |
| 5551 | 5574 | nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, |
| 5552 | − struct file **filpp, bool *tmp_file, int flags) | |
| 5575 | + struct nfsd_file **nfp, int flags) | |
| 5553 | 5576 | { |
| 5554 | 5577 | int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; |
| 5555 | − struct file *file; | |
| 5578 | + struct nfsd_file *nf; | |
| 5556 | 5579 | __be32 status; |
| 5557 | 5580 | |
| 5558 | − file = nfs4_find_file(s, flags); | |
| 5559 | − if (file) { | |
| 5581 | + nf = nfs4_find_file(s, flags); | |
| 5582 | + if (nf) { | |
| 5560 | 5583 | status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, |
| 5561 | 5584 | acc | NFSD_MAY_OWNER_OVERRIDE); |
| 5562 | 5585 | if (status) { |
| 5563 | − fput(file); | |
| 5564 | − return status; | |
| 5586 | + nfsd_file_put(nf); | |
| 5587 | + goto out; | |
| 5565 | 5588 | } |
| 5566 | − | |
| 5567 | − *filpp = file; | |
| 5568 | 5589 | } else { |
| 5569 | − status = nfsd_open(rqstp, fhp, S_IFREG, acc, filpp); | |
| 5590 | + status = nfsd_file_acquire(rqstp, fhp, acc, &nf); | |
| 5570 | 5591 | if (status) |
| 5571 | 5592 | return status; |
| 5572 | − | |
| 5573 | − if (tmp_file) | |
| 5574 | − *tmp_file = true; | |
| 5575 | 5593 | } |
| 5576 | − | |
| 5577 | − return 0; | |
| 5594 | + *nfp = nf; | |
| 5595 | +out: | |
| 5596 | + return status; | |
| 5578 | 5597 | } |
| 5579 | 5598 | |
| 5580 | 5599 | /* |
| @@ -5583,7 +5602,7 @@ nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, · 2 unmodified lines | ||
| 5583 | 5602 | __be32 |
| 5584 | 5603 | nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, |
| 5585 | 5604 | struct nfsd4_compound_state *cstate, struct svc_fh *fhp, |
| 5586 | − stateid_t *stateid, int flags, struct file **filpp, bool *tmp_file) | |
| 5605 | + stateid_t *stateid, int flags, struct nfsd_file **nfp) | |
| 5587 | 5606 | { |
| 5588 | 5607 | struct inode *ino = d_inode(fhp->fh_dentry); |
| 5589 | 5608 | struct net *net = SVC_NET(rqstp); |
| @@ -5591,10 +5610,8 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, · 1 unmodified line | ||
| 5591 | 5610 | struct nfs4_stid *s = NULL; |
| 5592 | 5611 | __be32 status; |
| 5593 | 5612 | |
| 5594 | − if (filpp) | |
| 5595 | − *filpp = NULL; | |
| 5596 | − if (tmp_file) | |
| 5597 | − *tmp_file = false; | |
| 5613 | + if (nfp) | |
| 5614 | + *nfp = NULL; | |
| 5598 | 5615 | |
| 5599 | 5616 | if (grace_disallows_io(net, ino)) |
| 5600 | 5617 | return nfserr_grace; |
| @@ -5631,8 +5648,8 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, · 30 unmodified lines | ||
| 5631 | 5648 | status = nfs4_check_fh(fhp, s); |
| 5632 | 5649 | |
| 5633 | 5650 | done: |
| 5634 | − if (!status && filpp) | |
| 5635 | − status = nfs4_check_file(rqstp, fhp, s, filpp, tmp_file, flags); | |
| 5651 | + if (status == nfs_ok && nfp) | |
| 5652 | + status = nfs4_check_file(rqstp, fhp, s, nfp, flags); | |
| 5636 | 5653 | out: |
| 5637 | 5654 | if (s) |
| 5638 | 5655 | nfs4_put_stid(s); |
| @@ -6392,7 +6409,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 753 unmodified lines | ||
| 6392 | 6409 | struct nfs4_ol_stateid *lock_stp = NULL; |
| 6393 | 6410 | struct nfs4_ol_stateid *open_stp = NULL; |
| 6394 | 6411 | struct nfs4_file *fp; |
| 6395 | − struct file *filp = NULL; | |
| 6412 | + struct nfsd_file *nf = NULL; | |
| 6396 | 6413 | struct nfsd4_blocked_lock *nbl = NULL; |
| 6397 | 6414 | struct file_lock *file_lock = NULL; |
| 6398 | 6415 | struct file_lock *conflock = NULL; |
| @@ -6474,8 +6491,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 75 unmodified lines | ||
| 6474 | 6491 | /* Fallthrough */ |
| 6475 | 6492 | case NFS4_READ_LT: |
| 6476 | 6493 | spin_lock(&fp->fi_lock); |
| 6477 | − filp = find_readable_file_locked(fp); | |
| 6478 | − if (filp) | |
| 6494 | + nf = find_readable_file_locked(fp); | |
| 6495 | + if (nf) | |
| 6479 | 6496 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); |
| 6480 | 6497 | spin_unlock(&fp->fi_lock); |
| 6481 | 6498 | fl_type = F_RDLCK; |
| @@ -6486,8 +6503,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 4 unmodified lines | ||
| 6486 | 6503 | /* Fallthrough */ |
| 6487 | 6504 | case NFS4_WRITE_LT: |
| 6488 | 6505 | spin_lock(&fp->fi_lock); |
| 6489 | − filp = find_writeable_file_locked(fp); | |
| 6490 | − if (filp) | |
| 6506 | + nf = find_writeable_file_locked(fp); | |
| 6507 | + if (nf) | |
| 6491 | 6508 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); |
| 6492 | 6509 | spin_unlock(&fp->fi_lock); |
| 6493 | 6510 | fl_type = F_WRLCK; |
| @@ -6497,7 +6514,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 3 unmodified lines | ||
| 6497 | 6514 | goto out; |
| 6498 | 6515 | } |
| 6499 | 6516 | |
| 6500 | − if (!filp) { | |
| 6517 | + if (!nf) { | |
| 6501 | 6518 | status = nfserr_openmode; |
| 6502 | 6519 | goto out; |
| 6503 | 6520 | } |
| @@ -6513,7 +6530,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 9 unmodified lines | ||
| 6513 | 6530 | file_lock->fl_type = fl_type; |
| 6514 | 6531 | file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); |
| 6515 | 6532 | file_lock->fl_pid = current->tgid; |
| 6516 | − file_lock->fl_file = filp; | |
| 6533 | + file_lock->fl_file = nf->nf_file; | |
| 6517 | 6534 | file_lock->fl_flags = fl_flags; |
| 6518 | 6535 | file_lock->fl_lmops = &nfsd_posix_mng_ops; |
| 6519 | 6536 | file_lock->fl_start = lock->lk_offset; |
| @@ -6535,7 +6552,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 15 unmodified lines | ||
| 6535 | 6552 | spin_unlock(&nn->blocked_locks_lock); |
| 6536 | 6553 | } |
| 6537 | 6554 | |
| 6538 | − err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); | |
| 6555 | + err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, conflock); | |
| 6539 | 6556 | switch (err) { |
| 6540 | 6557 | case 0: /* success! */ |
| 6541 | 6558 | nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); |
| @@ -6570,8 +6587,8 @@ out: · 28 unmodified lines | ||
| 6570 | 6587 | } |
| 6571 | 6588 | free_blocked_lock(nbl); |
| 6572 | 6589 | } |
| 6573 | − if (filp) | |
| 6574 | − fput(filp); | |
| 6590 | + if (nf) | |
| 6591 | + nfsd_file_put(nf); | |
| 6575 | 6592 | if (lock_stp) { |
| 6576 | 6593 | /* Bump seqid manually if the 4.0 replay owner is openowner */ |
| 6577 | 6594 | if (cstate->replay_owner && |
| @@ -6606,11 +6623,11 @@ out: · 28 unmodified lines | ||
| 6606 | 6623 | */ |
| 6607 | 6624 | static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) |
| 6608 | 6625 | { |
| 6609 | − struct file *file; | |
| 6610 | − __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); | |
| 6626 | + struct nfsd_file *nf; | |
| 6627 | + __be32 err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); | |
| 6611 | 6628 | if (!err) { |
| 6612 | − err = nfserrno(vfs_test_lock(file, lock)); | |
| 6613 | − fput(file); | |
| 6629 | + err = nfserrno(vfs_test_lock(nf->nf_file, lock)); | |
| 6630 | + nfsd_file_put(nf); | |
| 6614 | 6631 | } |
| 6615 | 6632 | return err; |
| 6616 | 6633 | } |
| @@ -6698,7 +6715,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 81 unmodified lines | ||
| 6698 | 6715 | { |
| 6699 | 6716 | struct nfsd4_locku *locku = &u->locku; |
| 6700 | 6717 | struct nfs4_ol_stateid *stp; |
| 6701 | − struct file *filp = NULL; | |
| 6718 | + struct nfsd_file *nf = NULL; | |
| 6702 | 6719 | struct file_lock *file_lock = NULL; |
| 6703 | 6720 | __be32 status; |
| 6704 | 6721 | int err; |
| @@ -6716,8 +6733,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 11 unmodified lines | ||
| 6716 | 6733 | &stp, nn); |
| 6717 | 6734 | if (status) |
| 6718 | 6735 | goto out; |
| 6719 | − filp = find_any_file(stp->st_stid.sc_file); | |
| 6720 | − if (!filp) { | |
| 6736 | + nf = find_any_file(stp->st_stid.sc_file); | |
| 6737 | + if (!nf) { | |
| 6721 | 6738 | status = nfserr_lock_range; |
| 6722 | 6739 | goto put_stateid; |
| 6723 | 6740 | } |
| @@ -6725,13 +6742,13 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 1 unmodified line | ||
| 6725 | 6742 | if (!file_lock) { |
| 6726 | 6743 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); |
| 6727 | 6744 | status = nfserr_jukebox; |
| 6728 | − goto fput; | |
| 6745 | + goto put_file; | |
| 6729 | 6746 | } |
| 6730 | 6747 | |
| 6731 | 6748 | file_lock->fl_type = F_UNLCK; |
| 6732 | 6749 | file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); |
| 6733 | 6750 | file_lock->fl_pid = current->tgid; |
| 6734 | − file_lock->fl_file = filp; | |
| 6751 | + file_lock->fl_file = nf->nf_file; | |
| 6735 | 6752 | file_lock->fl_flags = FL_POSIX; |
| 6736 | 6753 | file_lock->fl_lmops = &nfsd_posix_mng_ops; |
| 6737 | 6754 | file_lock->fl_start = locku->lu_offset; |
| @@ -6740,14 +6757,14 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, · 2 unmodified lines | ||
| 6740 | 6757 | locku->lu_length); |
| 6741 | 6758 | nfs4_transform_lock_offset(file_lock); |
| 6742 | 6759 | |
| 6743 | − err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); | |
| 6760 | + err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, NULL); | |
| 6744 | 6761 | if (err) { |
| 6745 | 6762 | dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); |
| 6746 | 6763 | goto out_nfserr; |
| 6747 | 6764 | } |
| 6748 | 6765 | nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); |
| 6749 | −fput: | |
| 6750 | − fput(filp); | |
| 6766 | +put_file: | |
| 6767 | + nfsd_file_put(nf); | |
| 6751 | 6768 | put_stateid: |
| 6752 | 6769 | mutex_unlock(&stp->st_mutex); |
| 6753 | 6770 | nfs4_put_stid(&stp->st_stid); |
| @@ -6759,7 +6776,7 @@ out: · 5 unmodified lines | ||
| 6759 | 6776 | |
| 6760 | 6777 | out_nfserr: |
| 6761 | 6778 | status = nfserrno(err); |
| 6762 | − goto fput; | |
| 6779 | + goto put_file; | |
| 6763 | 6780 | } |
| 6764 | 6781 | |
| 6765 | 6782 | /* |
| @@ -6772,17 +6789,17 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) · 6 unmodified lines | ||
| 6772 | 6789 | { |
| 6773 | 6790 | struct file_lock *fl; |
| 6774 | 6791 | int status = false; |
| 6775 | − struct file *filp = find_any_file(fp); | |
| 6792 | + struct nfsd_file *nf = find_any_file(fp); | |
| 6776 | 6793 | struct inode *inode; |
| 6777 | 6794 | struct file_lock_context *flctx; |
| 6778 | 6795 | |
| 6779 | − if (!filp) { | |
| 6796 | + if (!nf) { | |
| 6780 | 6797 | /* Any valid lock stateid should have some sort of access */ |
| 6781 | 6798 | WARN_ON_ONCE(1); |
| 6782 | 6799 | return status; |
| 6783 | 6800 | } |
| 6784 | 6801 | |
| 6785 | − inode = locks_inode(filp); | |
| 6802 | + inode = locks_inode(nf->nf_file); | |
| 6786 | 6803 | flctx = inode->i_flctx; |
| 6787 | 6804 | |
| 6788 | 6805 | if (flctx && !list_empty_careful(&flctx->flc_posix)) { |
| @@ -6795,7 +6812,7 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) · 6 unmodified lines | ||
| 6795 | 6812 | } |
| 6796 | 6813 | spin_unlock(&flctx->flc_lock); |
| 6797 | 6814 | } |
| 6798 | − fput(filp); | |
| 6815 | + nfsd_file_put(nf); | |
| 6799 | 6816 | return status; |
| 6800 | 6817 | } |
| 6801 | 6818 | |
| @@ -6888,7 +6905,8 @@ nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) · 86 unmodified lines | ||
| 6888 | 6905 | * will be freed in nfs4_remove_reclaim_record in the normal case). |
| 6889 | 6906 | */ |
| 6890 | 6907 | struct nfs4_client_reclaim * |
| 6891 | −nfs4_client_to_reclaim(struct xdr_netobj name, struct nfsd_net *nn) | |
| 6908 | +nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, | |
| 6909 | + struct nfsd_net *nn) | |
| 6892 | 6910 | { |
| 6893 | 6911 | unsigned int strhashval; |
| 6894 | 6912 | struct nfs4_client_reclaim *crp; |
| @@ -6901,6 +6919,8 @@ nfs4_client_to_reclaim(struct xdr_netobj name, struct nfsd_net *nn) · 6 unmodified lines | ||
| 6901 | 6919 | list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); |
| 6902 | 6920 | crp->cr_name.data = name.data; |
| 6903 | 6921 | crp->cr_name.len = name.len; |
| 6922 | + crp->cr_princhash.data = princhash.data; | |
| 6923 | + crp->cr_princhash.len = princhash.len; | |
| 6904 | 6924 | crp->cr_clp = NULL; |
| 6905 | 6925 | nn->reclaim_str_hashtbl_size++; |
| 6906 | 6926 | } |
| @@ -6912,6 +6932,7 @@ nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) · 5 unmodified lines | ||
| 6912 | 6932 | { |
| 6913 | 6933 | list_del(&crp->cr_strhash); |
| 6914 | 6934 | kfree(crp->cr_name.data); |
| 6935 | + kfree(crp->cr_princhash.data); | |
| 6915 | 6936 | kfree(crp); |
| 6916 | 6937 | nn->reclaim_str_hashtbl_size--; |
| 6917 | 6938 | } |
| @@ -49,6 +49,7 @@ · 48 unmodified lines | ||
| 49 | 49 | #include "cache.h" |
| 50 | 50 | #include "netns.h" |
| 51 | 51 | #include "pnfs.h" |
| 52 | +#include "filecache.h" | |
| 52 | 53 | |
| 53 | 54 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL |
| 54 | 55 | #include <linux/security.h> |
| @@ -203,6 +204,13 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) · 148 unmodified lines | ||
| 203 | 204 | return p; |
| 204 | 205 | } |
| 205 | 206 | |
| 207 | +static unsigned int compoundargs_bytes_left(struct nfsd4_compoundargs *argp) | |
| 208 | +{ | |
| 209 | + unsigned int this = (char *)argp->end - (char *)argp->p; | |
| 210 | + | |
| 211 | + return this + argp->pagelen; | |
| 212 | +} | |
| 213 | + | |
| 206 | 214 | static int zero_clientid(clientid_t *clid) |
| 207 | 215 | { |
| 208 | 216 | return (clid->cl_boot == 0) && (clid->cl_id == 0); |
| @@ -211,10 +219,10 @@ static int zero_clientid(clientid_t *clid) · 2 unmodified lines | ||
| 211 | 219 | /** |
| 212 | 220 | * svcxdr_tmpalloc - allocate memory to be freed after compound processing |
| 213 | 221 | * @argp: NFSv4 compound argument structure |
| 214 | − * @p: pointer to be freed (with kfree()) | |
| 222 | + * @len: length of buffer to allocate | |
| 215 | 223 | * |
| 216 | − * Marks @p to be freed when processing the compound operation | |
| 217 | − * described in @argp finishes. | |
| 224 | + * Allocates a buffer of size @len to be freed when processing the compound | |
| 225 | + * operation described in @argp finishes. | |
| 218 | 226 | */ |
| 219 | 227 | static void * |
| 220 | 228 | svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len) |
| @@ -347,7 +355,12 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, · 126 unmodified lines | ||
| 347 | 355 | READ_BUF(4); len += 4; |
| 348 | 356 | nace = be32_to_cpup(p++); |
| 349 | 357 | |
| 350 | − if (nace > NFS4_ACL_MAX) | |
| 358 | + if (nace > compoundargs_bytes_left(argp)/20) | |
| 359 | + /* | |
| 360 | + * Even with 4-byte names there wouldn't be | |
| 361 | + * space for that many aces; something fishy is | |
| 362 | + * going on: | |
| 363 | + */ | |
| 351 | 364 | return nfserr_fbig; |
| 352 | 365 | |
| 353 | 366 | *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace)); |
| @@ -1418,7 +1431,6 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, · 1064 unmodified lines | ||
| 1418 | 1431 | struct nfsd4_create_session *sess) |
| 1419 | 1432 | { |
| 1420 | 1433 | DECODE_HEAD; |
| 1421 | − u32 dummy; | |
| 1422 | 1434 | |
| 1423 | 1435 | READ_BUF(16); |
| 1424 | 1436 | COPYMEM(&sess->clientid, 8); |
| @@ -1427,7 +1439,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, · 2 unmodified lines | ||
| 1427 | 1439 | |
| 1428 | 1440 | /* Fore channel attrs */ |
| 1429 | 1441 | READ_BUF(28); |
| 1430 | − dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */ | |
| 1442 | + p++; /* headerpadsz is always 0 */ | |
| 1431 | 1443 | sess->fore_channel.maxreq_sz = be32_to_cpup(p++); |
| 1432 | 1444 | sess->fore_channel.maxresp_sz = be32_to_cpup(p++); |
| 1433 | 1445 | sess->fore_channel.maxresp_cached = be32_to_cpup(p++); |
| @@ -1444,7 +1456,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, · 10 unmodified lines | ||
| 1444 | 1456 | |
| 1445 | 1457 | /* Back channel attrs */ |
| 1446 | 1458 | READ_BUF(28); |
| 1447 | − dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */ | |
| 1459 | + p++; /* headerpadsz is always 0 */ | |
| 1448 | 1460 | sess->back_channel.maxreq_sz = be32_to_cpup(p++); |
| 1449 | 1461 | sess->back_channel.maxresp_sz = be32_to_cpup(p++); |
| 1450 | 1462 | sess->back_channel.maxresp_cached = be32_to_cpup(p++); |
| @@ -1736,7 +1748,6 @@ static __be32 · 285 unmodified lines | ||
| 1736 | 1748 | nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) |
| 1737 | 1749 | { |
| 1738 | 1750 | DECODE_HEAD; |
| 1739 | − unsigned int tmp; | |
| 1740 | 1751 | |
| 1741 | 1752 | status = nfsd4_decode_stateid(argp, ©->cp_src_stateid); |
| 1742 | 1753 | if (status) |
| @@ -1751,7 +1762,7 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) · 8 unmodified lines | ||
| 1751 | 1762 | p = xdr_decode_hyper(p, ©->cp_count); |
| 1752 | 1763 | p++; /* ca_consecutive: we always do consecutive copies */ |
| 1753 | 1764 | copy->cp_synchronous = be32_to_cpup(p++); |
| 1754 | − tmp = be32_to_cpup(p); /* Source server list not supported */ | |
| 1765 | + /* tmp = be32_to_cpup(p); Source server list not supported */ | |
| 1755 | 1766 | |
| 1756 | 1767 | DECODE_TAIL; |
| 1757 | 1768 | } |
| @@ -3217,9 +3228,8 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ · 1459 unmodified lines | ||
| 3217 | 3228 | if (!p) |
| 3218 | 3229 | return nfserr_resource; |
| 3219 | 3230 | encode_cinfo(p, &create->cr_cinfo); |
| 3220 | − nfserr = nfsd4_encode_bitmap(xdr, create->cr_bmval[0], | |
| 3231 | + return nfsd4_encode_bitmap(xdr, create->cr_bmval[0], | |
| 3221 | 3232 | create->cr_bmval[1], create->cr_bmval[2]); |
| 3222 | − return 0; | |
| 3223 | 3233 | } |
| 3224 | 3234 | |
| 3225 | 3235 | static __be32 |
| @@ -3462,7 +3472,7 @@ static __be32 nfsd4_encode_splice_read( · 236 unmodified lines | ||
| 3462 | 3472 | |
| 3463 | 3473 | len = maxcount; |
| 3464 | 3474 | nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp, |
| 3465 | − file, read->rd_offset, &maxcount); | |
| 3475 | + file, read->rd_offset, &maxcount, &eof); | |
| 3466 | 3476 | read->rd_length = maxcount; |
| 3467 | 3477 | if (nfserr) { |
| 3468 | 3478 | /* |
| @@ -3474,9 +3484,6 @@ static __be32 nfsd4_encode_splice_read( · 5 unmodified lines | ||
| 3474 | 3484 | return nfserr; |
| 3475 | 3485 | } |
| 3476 | 3486 | |
| 3477 | − eof = nfsd_eof_on_read(len, maxcount, read->rd_offset, | |
| 3478 | − d_inode(read->rd_fhp->fh_dentry)->i_size); | |
| 3479 | − | |
| 3480 | 3487 | *(p++) = htonl(eof); |
| 3481 | 3488 | *(p++) = htonl(maxcount); |
| 3482 | 3489 | |
| @@ -3547,15 +3554,13 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, · 64 unmodified lines | ||
| 3547 | 3554 | |
| 3548 | 3555 | len = maxcount; |
| 3549 | 3556 | nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, |
| 3550 | − resp->rqstp->rq_vec, read->rd_vlen, &maxcount); | |
| 3557 | + resp->rqstp->rq_vec, read->rd_vlen, &maxcount, | |
| 3558 | + &eof); | |
| 3551 | 3559 | read->rd_length = maxcount; |
| 3552 | 3560 | if (nfserr) |
| 3553 | 3561 | return nfserr; |
| 3554 | 3562 | xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3)); |
| 3555 | 3563 | |
| 3556 | − eof = nfsd_eof_on_read(len, maxcount, read->rd_offset, | |
| 3557 | − d_inode(read->rd_fhp->fh_dentry)->i_size); | |
| 3558 | − | |
| 3559 | 3564 | tmp = htonl(eof); |
| 3560 | 3565 | write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4); |
| 3561 | 3566 | tmp = htonl(maxcount); |
| @@ -3574,11 +3579,14 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, · 12 unmodified lines | ||
| 3574 | 3579 | { |
| 3575 | 3580 | unsigned long maxcount; |
| 3576 | 3581 | struct xdr_stream *xdr = &resp->xdr; |
| 3577 | − struct file *file = read->rd_filp; | |
| 3582 | + struct file *file; | |
| 3578 | 3583 | int starting_len = xdr->buf->len; |
| 3579 | − struct raparms *ra = NULL; | |
| 3580 | 3584 | __be32 *p; |
| 3581 | 3585 | |
| 3586 | + if (nfserr) | |
| 3587 | + return nfserr; | |
| 3588 | + file = read->rd_nf->nf_file; | |
| 3589 | + | |
| 3582 | 3590 | p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ |
| 3583 | 3591 | if (!p) { |
| 3584 | 3592 | WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)); |
| @@ -3596,18 +3604,12 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, · 11 unmodified lines | ||
| 3596 | 3604 | (xdr->buf->buflen - xdr->buf->len)); |
| 3597 | 3605 | maxcount = min_t(unsigned long, maxcount, read->rd_length); |
| 3598 | 3606 | |
| 3599 | − if (read->rd_tmp_file) | |
| 3600 | − ra = nfsd_init_raparms(file); | |
| 3601 | − | |
| 3602 | 3607 | if (file->f_op->splice_read && |
| 3603 | 3608 | test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) |
| 3604 | 3609 | nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount); |
| 3605 | 3610 | else |
| 3606 | 3611 | nfserr = nfsd4_encode_readv(resp, read, file, maxcount); |
| 3607 | 3612 | |
| 3608 | − if (ra) | |
| 3609 | − nfsd_put_raparams(file, ra); | |
| 3610 | − | |
| 3611 | 3613 | if (nfserr) |
| 3612 | 3614 | xdr_truncate_encode(xdr, starting_len); |
| 3613 | 3615 | |
| @@ -1476,6 +1476,7 @@ static __net_init int nfsd_init_net(struct net *net) · 1475 unmodified lines | ||
| 1476 | 1476 | |
| 1477 | 1477 | atomic_set(&nn->ntf_refcnt, 0); |
| 1478 | 1478 | init_waitqueue_head(&nn->ntf_wq); |
| 1479 | + seqlock_init(&nn->boot_lock); | |
| 1479 | 1480 | |
| 1480 | 1481 | mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL); |
| 1481 | 1482 | if (IS_ERR(mnt)) { |
| @@ -172,6 +172,7 @@ nfsd_proc_read(struct svc_rqst *rqstp) · 171 unmodified lines | ||
| 172 | 172 | struct nfsd_readargs *argp = rqstp->rq_argp; |
| 173 | 173 | struct nfsd_readres *resp = rqstp->rq_resp; |
| 174 | 174 | __be32 nfserr; |
| 175 | + u32 eof; | |
| 175 | 176 | |
| 176 | 177 | dprintk("nfsd: READ %s %d bytes at %d\n", |
| 177 | 178 | SVCFH_fmt(&argp->fh), |
| @@ -195,7 +196,8 @@ nfsd_proc_read(struct svc_rqst *rqstp) · 17 unmodified lines | ||
| 195 | 196 | nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), |
| 196 | 197 | argp->offset, |
| 197 | 198 | rqstp->rq_vec, argp->vlen, |
| 198 | − &resp->count); | |
| 199 | + &resp->count, | |
| 200 | + &eof); | |
| 199 | 201 | |
| 200 | 202 | if (nfserr) return nfserr; |
| 201 | 203 | return fh_getattr(&resp->fh, &resp->stat); |
| @@ -27,6 +27,7 @@ · 26 unmodified lines | ||
| 27 | 27 | #include "cache.h" |
| 28 | 28 | #include "vfs.h" |
| 29 | 29 | #include "netns.h" |
| 30 | +#include "filecache.h" | |
| 30 | 31 | |
| 31 | 32 | #define NFSDDBG_FACILITY NFSDDBG_SVC |
| 32 | 33 | |
| @@ -313,22 +314,17 @@ static int nfsd_startup_generic(int nrservs) · 280 unmodified lines | ||
| 313 | 314 | if (nfsd_users++) |
| 314 | 315 | return 0; |
| 315 | 316 | |
| 316 | − /* | |
| 317 | − * Readahead param cache - will no-op if it already exists. | |
| 318 | − * (Note therefore results will be suboptimal if number of | |
| 319 | − * threads is modified after nfsd start.) | |
| 320 | − */ | |
| 321 | − ret = nfsd_racache_init(2*nrservs); | |
| 317 | + ret = nfsd_file_cache_init(); | |
| 322 | 318 | if (ret) |
| 323 | 319 | goto dec_users; |
| 324 | 320 | |
| 325 | 321 | ret = nfs4_state_start(); |
| 326 | 322 | if (ret) |
| 327 | − goto out_racache; | |
| 323 | + goto out_file_cache; | |
| 328 | 324 | return 0; |
| 329 | 325 | |
| 330 | −out_racache: | |
| 331 | − nfsd_racache_shutdown(); | |
| 326 | +out_file_cache: | |
| 327 | + nfsd_file_cache_shutdown(); | |
| 332 | 328 | dec_users: |
| 333 | 329 | nfsd_users--; |
| 334 | 330 | return ret; |
| @@ -340,7 +336,7 @@ static void nfsd_shutdown_generic(void) · 5 unmodified lines | ||
| 340 | 336 | return; |
| 341 | 337 | |
| 342 | 338 | nfs4_state_shutdown(); |
| 343 | − nfsd_racache_shutdown(); | |
| 339 | + nfsd_file_cache_shutdown(); | |
| 344 | 340 | } |
| 345 | 341 | |
| 346 | 342 | static bool nfsd_needs_lockd(struct nfsd_net *nn) |
| @@ -348,6 +344,35 @@ static bool nfsd_needs_lockd(struct nfsd_net *nn) · 1 unmodified line | ||
| 348 | 344 | return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST); |
| 349 | 345 | } |
| 350 | 346 | |
| 347 | +void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn) | |
| 348 | +{ | |
| 349 | + int seq = 0; | |
| 350 | + | |
| 351 | + do { | |
| 352 | + read_seqbegin_or_lock(&nn->boot_lock, &seq); | |
| 353 | + /* | |
| 354 | + * This is opaque to client, so no need to byte-swap. Use | |
| 355 | + * __force to keep sparse happy. y2038 time_t overflow is | |
| 356 | + * irrelevant in this usage | |
| 357 | + */ | |
| 358 | + verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec; | |
| 359 | + verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec; | |
| 360 | + } while (need_seqretry(&nn->boot_lock, seq)); | |
| 361 | + done_seqretry(&nn->boot_lock, seq); | |
| 362 | +} | |
| 363 | + | |
| 364 | +static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) | |
| 365 | +{ | |
| 366 | + ktime_get_real_ts64(&nn->nfssvc_boot); | |
| 367 | +} | |
| 368 | + | |
| 369 | +void nfsd_reset_boot_verifier(struct nfsd_net *nn) | |
| 370 | +{ | |
| 371 | + write_seqlock(&nn->boot_lock); | |
| 372 | + nfsd_reset_boot_verifier_locked(nn); | |
| 373 | + write_sequnlock(&nn->boot_lock); | |
| 374 | +} | |
| 375 | + | |
| 351 | 376 | static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred) |
| 352 | 377 | { |
| 353 | 378 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| @@ -391,6 +416,7 @@ static void nfsd_shutdown_net(struct net *net) · 37 unmodified lines | ||
| 391 | 416 | { |
| 392 | 417 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
| 393 | 418 | |
| 419 | + nfsd_file_cache_purge(net); | |
| 394 | 420 | nfs4_state_shutdown_net(net); |
| 395 | 421 | if (nn->lockd_up) { |
| 396 | 422 | lockd_down(net); |
| @@ -599,7 +625,7 @@ int nfsd_create_serv(struct net *net) · 202 unmodified lines | ||
| 599 | 625 | #endif |
| 600 | 626 | } |
| 601 | 627 | atomic_inc(&nn->ntf_refcnt); |
| 602 | − ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */ | |
| 628 | + nfsd_reset_boot_verifier(nn); | |
| 603 | 629 | return 0; |
| 604 | 630 | } |
| 605 | 631 | |
| @@ -378,6 +378,7 @@ struct nfs4_client_reclaim { · 377 unmodified lines | ||
| 378 | 378 | struct list_head cr_strhash; /* hash by cr_name */ |
| 379 | 379 | struct nfs4_client *cr_clp; /* pointer to associated clp */ |
| 380 | 380 | struct xdr_netobj cr_name; /* recovery dir name */ |
| 381 | + struct xdr_netobj cr_princhash; | |
| 381 | 382 | }; |
| 382 | 383 | |
| 383 | 384 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: |
| @@ -506,7 +507,7 @@ struct nfs4_file { · 122 unmodified lines | ||
| 506 | 507 | }; |
| 507 | 508 | struct list_head fi_clnt_odstate; |
| 508 | 509 | /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ |
| 509 | − struct file * fi_fds[3]; | |
| 510 | + struct nfsd_file *fi_fds[3]; | |
| 510 | 511 | /* |
| 511 | 512 | * Each open or lock stateid contributes 0-4 to the counts |
| 512 | 513 | * below depending on which bits are set in st_access_bitmap: |
| @@ -516,7 +517,7 @@ struct nfs4_file { · 3 unmodified lines | ||
| 516 | 517 | */ |
| 517 | 518 | atomic_t fi_access[2]; |
| 518 | 519 | u32 fi_share_deny; |
| 519 | − struct file *fi_deleg_file; | |
| 520 | + struct nfsd_file *fi_deleg_file; | |
| 520 | 521 | int fi_delegees; |
| 521 | 522 | struct knfsd_fh fi_fhandle; |
| 522 | 523 | bool fi_had_conflict; |
| @@ -565,7 +566,7 @@ struct nfs4_layout_stateid { · 42 unmodified lines | ||
| 565 | 566 | spinlock_t ls_lock; |
| 566 | 567 | struct list_head ls_layouts; |
| 567 | 568 | u32 ls_layout_type; |
| 568 | − struct file *ls_file; | |
| 569 | + struct nfsd_file *ls_file; | |
| 569 | 570 | struct nfsd4_callback ls_recall; |
| 570 | 571 | stateid_t ls_recall_sid; |
| 571 | 572 | bool ls_recalled; |
| @@ -616,7 +617,7 @@ struct nfsd4_copy; · 44 unmodified lines | ||
| 616 | 617 | |
| 617 | 618 | extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, |
| 618 | 619 | struct nfsd4_compound_state *cstate, struct svc_fh *fhp, |
| 619 | − stateid_t *stateid, int flags, struct file **filp, bool *tmp_file); | |
| 620 | + stateid_t *stateid, int flags, struct nfsd_file **filp); | |
| 620 | 621 | __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, |
| 621 | 622 | stateid_t *stateid, unsigned char typemask, |
| 622 | 623 | struct nfs4_stid **s, struct nfsd_net *nn); |
| @@ -645,7 +646,7 @@ extern void nfsd4_shutdown_callback(struct nfs4_client *); · 22 unmodified lines | ||
| 645 | 646 | extern void nfsd4_shutdown_copy(struct nfs4_client *clp); |
| 646 | 647 | extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp); |
| 647 | 648 | extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name, |
| 648 | − struct nfsd_net *nn); | |
| 649 | + struct xdr_netobj princhash, struct nfsd_net *nn); | |
| 649 | 650 | extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn); |
| 650 | 651 | |
| 651 | 652 | struct nfs4_file *find_file(struct knfsd_fh *fh); |
| @@ -657,7 +658,7 @@ static inline void get_nfs4_file(struct nfs4_file *fi) · 5 unmodified lines | ||
| 657 | 658 | { |
| 658 | 659 | refcount_inc(&fi->fi_ref); |
| 659 | 660 | } |
| 660 | −struct file *find_any_file(struct nfs4_file *f); | |
| 661 | +struct nfsd_file *find_any_file(struct nfs4_file *f); | |
| 661 | 662 | |
| 662 | 663 | /* grace period management */ |
| 663 | 664 | void nfsd4_end_grace(struct nfsd_net *nn); |
| @@ -126,6 +126,8 @@ DEFINE_NFSD_ERR_EVENT(read_err); · 125 unmodified lines | ||
| 126 | 126 | DEFINE_NFSD_ERR_EVENT(write_err); |
| 127 | 127 | |
| 128 | 128 | #include "state.h" |
| 129 | +#include "filecache.h" | |
| 130 | +#include "vfs.h" | |
| 129 | 131 | |
| 130 | 132 | DECLARE_EVENT_CLASS(nfsd_stateid_class, |
| 131 | 133 | TP_PROTO(stateid_t *stp), |
| @@ -164,6 +166,144 @@ DEFINE_STATEID_EVENT(layout_recall_done); · 32 unmodified lines | ||
| 164 | 166 | DEFINE_STATEID_EVENT(layout_recall_fail); |
| 165 | 167 | DEFINE_STATEID_EVENT(layout_recall_release); |
| 166 | 168 | |
| 169 | +#define show_nf_flags(val) \ | |
| 170 | + __print_flags(val, "|", \ | |
| 171 | + { 1 << NFSD_FILE_HASHED, "HASHED" }, \ | |
| 172 | + { 1 << NFSD_FILE_PENDING, "PENDING" }, \ | |
| 173 | + { 1 << NFSD_FILE_BREAK_READ, "BREAK_READ" }, \ | |
| 174 | + { 1 << NFSD_FILE_BREAK_WRITE, "BREAK_WRITE" }, \ | |
| 175 | + { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}) | |
| 176 | + | |
| 177 | +/* FIXME: This should probably be fleshed out in the future. */ | |
| 178 | +#define show_nf_may(val) \ | |
| 179 | + __print_flags(val, "|", \ | |
| 180 | + { NFSD_MAY_READ, "READ" }, \ | |
| 181 | + { NFSD_MAY_WRITE, "WRITE" }, \ | |
| 182 | + { NFSD_MAY_NOT_BREAK_LEASE, "NOT_BREAK_LEASE" }) | |
| 183 | + | |
| 184 | +DECLARE_EVENT_CLASS(nfsd_file_class, | |
| 185 | + TP_PROTO(struct nfsd_file *nf), | |
| 186 | + TP_ARGS(nf), | |
| 187 | + TP_STRUCT__entry( | |
| 188 | + __field(unsigned int, nf_hashval) | |
| 189 | + __field(void *, nf_inode) | |
| 190 | + __field(int, nf_ref) | |
| 191 | + __field(unsigned long, nf_flags) | |
| 192 | + __field(unsigned char, nf_may) | |
| 193 | + __field(struct file *, nf_file) | |
| 194 | + ), | |
| 195 | + TP_fast_assign( | |
| 196 | + __entry->nf_hashval = nf->nf_hashval; | |
| 197 | + __entry->nf_inode = nf->nf_inode; | |
| 198 | + __entry->nf_ref = atomic_read(&nf->nf_ref); | |
| 199 | + __entry->nf_flags = nf->nf_flags; | |
| 200 | + __entry->nf_may = nf->nf_may; | |
| 201 | + __entry->nf_file = nf->nf_file; | |
| 202 | + ), | |
| 203 | + TP_printk("hash=0x%x inode=0x%p ref=%d flags=%s may=%s file=%p", | |
| 204 | + __entry->nf_hashval, | |
| 205 | + __entry->nf_inode, | |
| 206 | + __entry->nf_ref, | |
| 207 | + show_nf_flags(__entry->nf_flags), | |
| 208 | + show_nf_may(__entry->nf_may), | |
| 209 | + __entry->nf_file) | |
| 210 | +) | |
| 211 | + | |
| 212 | +#define DEFINE_NFSD_FILE_EVENT(name) \ | |
| 213 | +DEFINE_EVENT(nfsd_file_class, name, \ | |
| 214 | + TP_PROTO(struct nfsd_file *nf), \ | |
| 215 | + TP_ARGS(nf)) | |
| 216 | + | |
| 217 | +DEFINE_NFSD_FILE_EVENT(nfsd_file_alloc); | |
| 218 | +DEFINE_NFSD_FILE_EVENT(nfsd_file_put_final); | |
| 219 | +DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash); | |
| 220 | +DEFINE_NFSD_FILE_EVENT(nfsd_file_put); | |
| 221 | +DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_release_locked); | |
| 222 | + | |
| 223 | +TRACE_EVENT(nfsd_file_acquire, | |
| 224 | + TP_PROTO(struct svc_rqst *rqstp, unsigned int hash, | |
| 225 | + struct inode *inode, unsigned int may_flags, | |
| 226 | + struct nfsd_file *nf, __be32 status), | |
| 227 | + | |
| 228 | + TP_ARGS(rqstp, hash, inode, may_flags, nf, status), | |
| 229 | + | |
| 230 | + TP_STRUCT__entry( | |
| 231 | + __field(__be32, xid) | |
| 232 | + __field(unsigned int, hash) | |
| 233 | + __field(void *, inode) | |
| 234 | + __field(unsigned int, may_flags) | |
| 235 | + __field(int, nf_ref) | |
| 236 | + __field(unsigned long, nf_flags) | |
| 237 | + __field(unsigned char, nf_may) | |
| 238 | + __field(struct file *, nf_file) | |
| 239 | + __field(__be32, status) | |
| 240 | + ), | |
| 241 | + | |
| 242 | + TP_fast_assign( | |
| 243 | + __entry->xid = rqstp->rq_xid; | |
| 244 | + __entry->hash = hash; | |
| 245 | + __entry->inode = inode; | |
| 246 | + __entry->may_flags = may_flags; | |
| 247 | + __entry->nf_ref = nf ? atomic_read(&nf->nf_ref) : 0; | |
| 248 | + __entry->nf_flags = nf ? nf->nf_flags : 0; | |
| 249 | + __entry->nf_may = nf ? nf->nf_may : 0; | |
| 250 | + __entry->nf_file = nf ? nf->nf_file : NULL; | |
| 251 | + __entry->status = status; | |
| 252 | + ), | |
| 253 | + | |
| 254 | + TP_printk("xid=0x%x hash=0x%x inode=0x%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=0x%p status=%u", | |
| 255 | + be32_to_cpu(__entry->xid), __entry->hash, __entry->inode, | |
| 256 | + show_nf_may(__entry->may_flags), __entry->nf_ref, | |
| 257 | + show_nf_flags(__entry->nf_flags), | |
| 258 | + show_nf_may(__entry->nf_may), __entry->nf_file, | |
| 259 | + be32_to_cpu(__entry->status)) | |
| 260 | +); | |
| 261 | + | |
| 262 | +DECLARE_EVENT_CLASS(nfsd_file_search_class, | |
| 263 | + TP_PROTO(struct inode *inode, unsigned int hash, int found), | |
| 264 | + TP_ARGS(inode, hash, found), | |
| 265 | + TP_STRUCT__entry( | |
| 266 | + __field(struct inode *, inode) | |
| 267 | + __field(unsigned int, hash) | |
| 268 | + __field(int, found) | |
| 269 | + ), | |
| 270 | + TP_fast_assign( | |
| 271 | + __entry->inode = inode; | |
| 272 | + __entry->hash = hash; | |
| 273 | + __entry->found = found; | |
| 274 | + ), | |
| 275 | + TP_printk("hash=0x%x inode=0x%p found=%d", __entry->hash, | |
| 276 | + __entry->inode, __entry->found) | |
| 277 | +); | |
| 278 | + | |
| 279 | +#define DEFINE_NFSD_FILE_SEARCH_EVENT(name) \ | |
| 280 | +DEFINE_EVENT(nfsd_file_search_class, name, \ | |
| 281 | + TP_PROTO(struct inode *inode, unsigned int hash, int found), \ | |
| 282 | + TP_ARGS(inode, hash, found)) | |
| 283 | + | |
| 284 | +DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode_sync); | |
| 285 | +DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode); | |
| 286 | +DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_is_cached); | |
| 287 | + | |
| 288 | +TRACE_EVENT(nfsd_file_fsnotify_handle_event, | |
| 289 | + TP_PROTO(struct inode *inode, u32 mask), | |
| 290 | + TP_ARGS(inode, mask), | |
| 291 | + TP_STRUCT__entry( | |
| 292 | + __field(struct inode *, inode) | |
| 293 | + __field(unsigned int, nlink) | |
| 294 | + __field(umode_t, mode) | |
| 295 | + __field(u32, mask) | |
| 296 | + ), | |
| 297 | + TP_fast_assign( | |
| 298 | + __entry->inode = inode; | |
| 299 | + __entry->nlink = inode->i_nlink; | |
| 300 | + __entry->mode = inode->i_mode; | |
| 301 | + __entry->mask = mask; | |
| 302 | + ), | |
| 303 | + TP_printk("inode=0x%p nlink=%u mode=0%ho mask=0x%x", __entry->inode, | |
| 304 | + __entry->nlink, __entry->mode, __entry->mask) | |
| 305 | +); | |
| 306 | + | |
| 167 | 307 | #endif /* _NFSD_TRACE_H */ |
| 168 | 308 | |
| 169 | 309 | #undef TRACE_INCLUDE_PATH |
| @@ -44,38 +44,11 @@ · 43 unmodified lines | ||
| 44 | 44 | |
| 45 | 45 | #include "nfsd.h" |
| 46 | 46 | #include "vfs.h" |
| 47 | +#include "filecache.h" | |
| 47 | 48 | #include "trace.h" |
| 48 | 49 | |
| 49 | 50 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP |
| 50 | 51 | |
| 51 | − | |
| 52 | −/* | |
| 53 | − * This is a cache of readahead params that help us choose the proper | |
| 54 | − * readahead strategy. Initially, we set all readahead parameters to 0 | |
| 55 | − * and let the VFS handle things. | |
| 56 | − * If you increase the number of cached files very much, you'll need to | |
| 57 | − * add a hash table here. | |
| 58 | − */ | |
| 59 | −struct raparms { | |
| 60 | − struct raparms *p_next; | |
| 61 | − unsigned int p_count; | |
| 62 | − ino_t p_ino; | |
| 63 | − dev_t p_dev; | |
| 64 | − int p_set; | |
| 65 | − struct file_ra_state p_ra; | |
| 66 | − unsigned int p_hindex; | |
| 67 | −}; | |
| 68 | − | |
| 69 | −struct raparm_hbucket { | |
| 70 | − struct raparms *pb_head; | |
| 71 | − spinlock_t pb_lock; | |
| 72 | −} ____cacheline_aligned_in_smp; | |
| 73 | − | |
| 74 | −#define RAPARM_HASH_BITS 4 | |
| 75 | −#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS) | |
| 76 | −#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) | |
| 77 | −static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; | |
| 78 | − | |
| 79 | 52 | /* |
| 80 | 53 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed |
| 81 | 54 | * a mount point. |
| @@ -699,7 +672,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor · 617 unmodified lines | ||
| 699 | 672 | } |
| 700 | 673 | #endif /* CONFIG_NFSD_V3 */ |
| 701 | 674 | |
| 702 | −static int nfsd_open_break_lease(struct inode *inode, int access) | |
| 675 | +int nfsd_open_break_lease(struct inode *inode, int access) | |
| 703 | 676 | { |
| 704 | 677 | unsigned int mode; |
| 705 | 678 | |
| @@ -715,8 +688,8 @@ static int nfsd_open_break_lease(struct inode *inode, int access) · 9 unmodified lines | ||
| 715 | 688 | * and additional flags. |
| 716 | 689 | * N.B. After this call fhp needs an fh_put |
| 717 | 690 | */ |
| 718 | −__be32 | |
| 719 | −nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |
| 691 | +static __be32 | |
| 692 | +__nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |
| 720 | 693 | int may_flags, struct file **filp) |
| 721 | 694 | { |
| 722 | 695 | struct path path; |
| @@ -726,25 +699,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, · 3 unmodified lines | ||
| 726 | 699 | __be32 err; |
| 727 | 700 | int host_err = 0; |
| 728 | 701 | |
| 729 | − validate_process_creds(); | |
| 730 | − | |
| 731 | − /* | |
| 732 | − * If we get here, then the client has already done an "open", | |
| 733 | − * and (hopefully) checked permission - so allow OWNER_OVERRIDE | |
| 734 | − * in case a chmod has now revoked permission. | |
| 735 | − * | |
| 736 | − * Arguably we should also allow the owner override for | |
| 737 | − * directories, but we never have and it doesn't seem to have | |
| 738 | − * caused anyone a problem. If we were to change this, note | |
| 739 | − * also that our filldir callbacks would need a variant of | |
| 740 | − * lookup_one_len that doesn't check permissions. | |
| 741 | − */ | |
| 742 | − if (type == S_IFREG) | |
| 743 | − may_flags |= NFSD_MAY_OWNER_OVERRIDE; | |
| 744 | − err = fh_verify(rqstp, fhp, type, may_flags); | |
| 745 | − if (err) | |
| 746 | − goto out; | |
| 747 | − | |
| 748 | 702 | path.mnt = fhp->fh_export->ex_path.mnt; |
| 749 | 703 | path.dentry = fhp->fh_dentry; |
| 750 | 704 | inode = d_inode(path.dentry); |
| @@ -798,67 +752,46 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, · 47 unmodified lines | ||
| 798 | 752 | out_nfserr: |
| 799 | 753 | err = nfserrno(host_err); |
| 800 | 754 | out: |
| 801 | − validate_process_creds(); | |
| 802 | 755 | return err; |
| 803 | 756 | } |
| 804 | 757 | |
| 805 | −struct raparms * | |
| 806 | −nfsd_init_raparms(struct file *file) | |
| 758 | +__be32 | |
| 759 | +nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |
| 760 | + int may_flags, struct file **filp) | |
| 807 | 761 | { |
| 808 | − struct inode *inode = file_inode(file); | |
| 809 | − dev_t dev = inode->i_sb->s_dev; | |
| 810 | − ino_t ino = inode->i_ino; | |
| 811 | − struct raparms *ra, **rap, **frap = NULL; | |
| 812 | − int depth = 0; | |
| 813 | − unsigned int hash; | |
| 814 | − struct raparm_hbucket *rab; | |
| 815 | − | |
| 816 | − hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK; | |
| 817 | − rab = &raparm_hash[hash]; | |
| 818 | − | |
| 819 | − spin_lock(&rab->pb_lock); | |
| 820 | − for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) { | |
| 821 | − if (ra->p_ino == ino && ra->p_dev == dev) | |
| 822 | − goto found; | |
| 823 | − depth++; | |
| 824 | − if (ra->p_count == 0) | |
| 825 | − frap = rap; | |
| 826 | − } | |
| 827 | − depth = nfsdstats.ra_size; | |
| 828 | − if (!frap) { | |
| 829 | − spin_unlock(&rab->pb_lock); | |
| 830 | − return NULL; | |
| 831 | − } | |
| 832 | − rap = frap; | |
| 833 | − ra = *frap; | |
| 834 | − ra->p_dev = dev; | |
| 835 | − ra->p_ino = ino; | |
| 836 | − ra->p_set = 0; | |
| 837 | − ra->p_hindex = hash; | |
| 838 | −found: | |
| 839 | − if (rap != &rab->pb_head) { | |
| 840 | − *rap = ra->p_next; | |
| 841 | − ra->p_next = rab->pb_head; | |
| 842 | − rab->pb_head = ra; | |
| 843 | − } | |
| 844 | − ra->p_count++; | |
| 845 | − nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; | |
| 846 | − spin_unlock(&rab->pb_lock); | |
| 762 | + __be32 err; | |
| 847 | 763 | |
| 848 | − if (ra->p_set) | |
| 849 | − file->f_ra = ra->p_ra; | |
| 850 | − return ra; | |
| 764 | + validate_process_creds(); | |
| 765 | + /* | |
| 766 | + * If we get here, then the client has already done an "open", | |
| 767 | + * and (hopefully) checked permission - so allow OWNER_OVERRIDE | |
| 768 | + * in case a chmod has now revoked permission. | |
| 769 | + * | |
| 770 | + * Arguably we should also allow the owner override for | |
| 771 | + * directories, but we never have and it doesn't seem to have | |
| 772 | + * caused anyone a problem. If we were to change this, note | |
| 773 | + * also that our filldir callbacks would need a variant of | |
| 774 | + * lookup_one_len that doesn't check permissions. | |
| 775 | + */ | |
| 776 | + if (type == S_IFREG) | |
| 777 | + may_flags |= NFSD_MAY_OWNER_OVERRIDE; | |
| 778 | + err = fh_verify(rqstp, fhp, type, may_flags); | |
| 779 | + if (!err) | |
| 780 | + err = __nfsd_open(rqstp, fhp, type, may_flags, filp); | |
| 781 | + validate_process_creds(); | |
| 782 | + return err; | |
| 851 | 783 | } |
| 852 | 784 | |
| 853 | −void nfsd_put_raparams(struct file *file, struct raparms *ra) | |
| 785 | +__be32 | |
| 786 | +nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |
| 787 | + int may_flags, struct file **filp) | |
| 854 | 788 | { |
| 855 | − struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; | |
| 789 | + __be32 err; | |
| 856 | 790 | |
| 857 | − spin_lock(&rab->pb_lock); | |
| 858 | − ra->p_ra = file->f_ra; | |
| 859 | − ra->p_set = 1; | |
| 860 | − ra->p_count--; | |
| 861 | − spin_unlock(&rab->pb_lock); | |
| 791 | + validate_process_creds(); | |
| 792 | + err = __nfsd_open(rqstp, fhp, type, may_flags, filp); | |
| 793 | + validate_process_creds(); | |
| 794 | + return err; | |
| 862 | 795 | } |
| 863 | 796 | |
| 864 | 797 | /* |
| @@ -901,12 +834,23 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe, · 36 unmodified lines | ||
| 901 | 834 | return __splice_from_pipe(pipe, sd, nfsd_splice_actor); |
| 902 | 835 | } |
| 903 | 836 | |
| 837 | +static u32 nfsd_eof_on_read(struct file *file, loff_t offset, ssize_t len, | |
| 838 | + size_t expected) | |
| 839 | +{ | |
| 840 | + if (expected != 0 && len == 0) | |
| 841 | + return 1; | |
| 842 | + if (offset+len >= i_size_read(file_inode(file))) | |
| 843 | + return 1; | |
| 844 | + return 0; | |
| 845 | +} | |
| 846 | + | |
| 904 | 847 | static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp, |
| 905 | 848 | struct file *file, loff_t offset, |
| 906 | − unsigned long *count, int host_err) | |
| 849 | + unsigned long *count, u32 *eof, ssize_t host_err) | |
| 907 | 850 | { |
| 908 | 851 | if (host_err >= 0) { |
| 909 | 852 | nfsdstats.io_read += host_err; |
| 853 | + *eof = nfsd_eof_on_read(file, offset, host_err, *count); | |
| 910 | 854 | *count = host_err; |
| 911 | 855 | fsnotify_access(file); |
| 912 | 856 | trace_nfsd_read_io_done(rqstp, fhp, offset, *count); |
| @@ -918,7 +862,8 @@ static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp, · 5 unmodified lines | ||
| 918 | 862 | } |
| 919 | 863 | |
| 920 | 864 | __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, |
| 921 | − struct file *file, loff_t offset, unsigned long *count) | |
| 865 | + struct file *file, loff_t offset, unsigned long *count, | |
| 866 | + u32 *eof) | |
| 922 | 867 | { |
| 923 | 868 | struct splice_desc sd = { |
| 924 | 869 | .len = 0, |
| @@ -926,25 +871,27 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, · 1 unmodified line | ||
| 926 | 871 | .pos = offset, |
| 927 | 872 | .u.data = rqstp, |
| 928 | 873 | }; |
| 929 | − int host_err; | |
| 874 | + ssize_t host_err; | |
| 930 | 875 | |
| 931 | 876 | trace_nfsd_read_splice(rqstp, fhp, offset, *count); |
| 932 | 877 | rqstp->rq_next_page = rqstp->rq_respages + 1; |
| 933 | 878 | host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor); |
| 934 | − return nfsd_finish_read(rqstp, fhp, file, offset, count, host_err); | |
| 879 | + return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err); | |
| 935 | 880 | } |
| 936 | 881 | |
| 937 | 882 | __be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp, |
| 938 | 883 | struct file *file, loff_t offset, |
| 939 | − struct kvec *vec, int vlen, unsigned long *count) | |
| 884 | + struct kvec *vec, int vlen, unsigned long *count, | |
| 885 | + u32 *eof) | |
| 940 | 886 | { |
| 941 | 887 | struct iov_iter iter; |
| 942 | − int host_err; | |
| 888 | + loff_t ppos = offset; | |
| 889 | + ssize_t host_err; | |
| 943 | 890 | |
| 944 | 891 | trace_nfsd_read_vector(rqstp, fhp, offset, *count); |
| 945 | 892 | iov_iter_kvec(&iter, READ, vec, vlen, *count); |
| 946 | − host_err = vfs_iter_read(file, &iter, &offset, 0); | |
| 947 | − return nfsd_finish_read(rqstp, fhp, file, offset, count, host_err); | |
| 893 | + host_err = vfs_iter_read(file, &iter, &ppos, 0); | |
| 894 | + return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err); | |
| 948 | 895 | } |
| 949 | 896 | |
| 950 | 897 | /* |
| @@ -1025,8 +972,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, · 74 unmodified lines | ||
| 1025 | 972 | nfsdstats.io_write += *cnt; |
| 1026 | 973 | fsnotify_modify(file); |
| 1027 | 974 | |
| 1028 | − if (stable && use_wgather) | |
| 975 | + if (stable && use_wgather) { | |
| 1029 | 976 | host_err = wait_for_concurrent_writes(file); |
| 977 | + if (host_err < 0) | |
| 978 | + nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp), | |
| 979 | + nfsd_net_id)); | |
| 980 | + } | |
| 1030 | 981 | |
| 1031 | 982 | out_nfserr: |
| 1032 | 983 | if (host_err >= 0) { |
| @@ -1047,27 +998,25 @@ out_nfserr: · 14 unmodified lines | ||
| 1047 | 998 | * N.B. After this call fhp needs an fh_put |
| 1048 | 999 | */ |
| 1049 | 1000 | __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, |
| 1050 | − loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | |
| 1001 | + loff_t offset, struct kvec *vec, int vlen, unsigned long *count, | |
| 1002 | + u32 *eof) | |
| 1051 | 1003 | { |
| 1004 | + struct nfsd_file *nf; | |
| 1052 | 1005 | struct file *file; |
| 1053 | − struct raparms *ra; | |
| 1054 | 1006 | __be32 err; |
| 1055 | 1007 | |
| 1056 | 1008 | trace_nfsd_read_start(rqstp, fhp, offset, *count); |
| 1057 | − err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); | |
| 1009 | + err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); | |
| 1058 | 1010 | if (err) |
| 1059 | 1011 | return err; |
| 1060 | 1012 | |
| 1061 | − ra = nfsd_init_raparms(file); | |
| 1062 | − | |
| 1013 | + file = nf->nf_file; | |
| 1063 | 1014 | if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags)) |
| 1064 | − err = nfsd_splice_read(rqstp, fhp, file, offset, count); | |
| 1015 | + err = nfsd_splice_read(rqstp, fhp, file, offset, count, eof); | |
| 1065 | 1016 | else |
| 1066 | − err = nfsd_readv(rqstp, fhp, file, offset, vec, vlen, count); | |
| 1017 | + err = nfsd_readv(rqstp, fhp, file, offset, vec, vlen, count, eof); | |
| 1067 | 1018 | |
| 1068 | − if (ra) | |
| 1069 | − nfsd_put_raparams(file, ra); | |
| 1070 | − fput(file); | |
| 1019 | + nfsd_file_put(nf); | |
| 1071 | 1020 | |
| 1072 | 1021 | trace_nfsd_read_done(rqstp, fhp, offset, *count); |
| 1073 | 1022 | |
| @@ -1083,17 +1032,18 @@ __be32 · 9 unmodified lines | ||
| 1083 | 1032 | nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, |
| 1084 | 1033 | struct kvec *vec, int vlen, unsigned long *cnt, int stable) |
| 1085 | 1034 | { |
| 1086 | − struct file *file = NULL; | |
| 1087 | − __be32 err = 0; | |
| 1035 | + struct nfsd_file *nf; | |
| 1036 | + __be32 err; | |
| 1088 | 1037 | |
| 1089 | 1038 | trace_nfsd_write_start(rqstp, fhp, offset, *cnt); |
| 1090 | 1039 | |
| 1091 | − err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); | |
| 1040 | + err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_WRITE, &nf); | |
| 1092 | 1041 | if (err) |
| 1093 | 1042 | goto out; |
| 1094 | 1043 | |
| 1095 | − err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt, stable); | |
| 1096 | − fput(file); | |
| 1044 | + err = nfsd_vfs_write(rqstp, fhp, nf->nf_file, offset, vec, | |
| 1045 | + vlen, cnt, stable); | |
| 1046 | + nfsd_file_put(nf); | |
| 1097 | 1047 | out: |
| 1098 | 1048 | trace_nfsd_write_done(rqstp, fhp, offset, *cnt); |
| 1099 | 1049 | return err; |
| @@ -1113,9 +1063,9 @@ __be32 · 13 unmodified lines | ||
| 1113 | 1063 | nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, |
| 1114 | 1064 | loff_t offset, unsigned long count) |
| 1115 | 1065 | { |
| 1116 | − struct file *file; | |
| 1117 | − loff_t end = LLONG_MAX; | |
| 1118 | − __be32 err = nfserr_inval; | |
| 1066 | + struct nfsd_file *nf; | |
| 1067 | + loff_t end = LLONG_MAX; | |
| 1068 | + __be32 err = nfserr_inval; | |
| 1119 | 1069 | |
| 1120 | 1070 | if (offset < 0) |
| 1121 | 1071 | goto out; |
| @@ -1125,20 +1075,27 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, · 3 unmodified lines | ||
| 1125 | 1075 | goto out; |
| 1126 | 1076 | } |
| 1127 | 1077 | |
| 1128 | − err = nfsd_open(rqstp, fhp, S_IFREG, | |
| 1129 | − NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &file); | |
| 1078 | + err = nfsd_file_acquire(rqstp, fhp, | |
| 1079 | + NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf); | |
| 1130 | 1080 | if (err) |
| 1131 | 1081 | goto out; |
| 1132 | 1082 | if (EX_ISSYNC(fhp->fh_export)) { |
| 1133 | − int err2 = vfs_fsync_range(file, offset, end, 0); | |
| 1083 | + int err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); | |
| 1134 | 1084 | |
| 1135 | − if (err2 != -EINVAL) | |
| 1136 | − err = nfserrno(err2); | |
| 1137 | − else | |
| 1085 | + switch (err2) { | |
| 1086 | + case 0: | |
| 1087 | + break; | |
| 1088 | + case -EINVAL: | |
| 1138 | 1089 | err = nfserr_notsupp; |
| 1090 | + break; | |
| 1091 | + default: | |
| 1092 | + err = nfserrno(err2); | |
| 1093 | + nfsd_reset_boot_verifier(net_generic(nf->nf_net, | |
| 1094 | + nfsd_net_id)); | |
| 1095 | + } | |
| 1139 | 1096 | } |
| 1140 | 1097 | |
| 1141 | − fput(file); | |
| 1098 | + nfsd_file_put(nf); | |
| 1142 | 1099 | out: |
| 1143 | 1100 | return err; |
| 1144 | 1101 | } |
| @@ -1659,6 +1616,26 @@ out_nfserr: · 514 unmodified lines | ||
| 1659 | 1616 | goto out_unlock; |
| 1660 | 1617 | } |
| 1661 | 1618 | |
| 1619 | +static void | |
| 1620 | +nfsd_close_cached_files(struct dentry *dentry) | |
| 1621 | +{ | |
| 1622 | + struct inode *inode = d_inode(dentry); | |
| 1623 | + | |
| 1624 | + if (inode && S_ISREG(inode->i_mode)) | |
| 1625 | + nfsd_file_close_inode_sync(inode); | |
| 1626 | +} | |
| 1627 | + | |
| 1628 | +static bool | |
| 1629 | +nfsd_has_cached_files(struct dentry *dentry) | |
| 1630 | +{ | |
| 1631 | + bool ret = false; | |
| 1632 | + struct inode *inode = d_inode(dentry); | |
| 1633 | + | |
| 1634 | + if (inode && S_ISREG(inode->i_mode)) | |
| 1635 | + ret = nfsd_file_is_cached(inode); | |
| 1636 | + return ret; | |
| 1637 | +} | |
| 1638 | + | |
| 1662 | 1639 | /* |
| 1663 | 1640 | * Rename a file |
| 1664 | 1641 | * N.B. After this call _both_ ffhp and tfhp need an fh_put |
| @@ -1671,6 +1648,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, · 6 unmodified lines | ||
| 1671 | 1648 | struct inode *fdir, *tdir; |
| 1672 | 1649 | __be32 err; |
| 1673 | 1650 | int host_err; |
| 1651 | + bool has_cached = false; | |
| 1674 | 1652 | |
| 1675 | 1653 | err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_REMOVE); |
| 1676 | 1654 | if (err) |
| @@ -1689,6 +1667,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, · 12 unmodified lines | ||
| 1689 | 1667 | if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen)) |
| 1690 | 1668 | goto out; |
| 1691 | 1669 | |
| 1670 | +retry: | |
| 1692 | 1671 | host_err = fh_want_write(ffhp); |
| 1693 | 1672 | if (host_err) { |
| 1694 | 1673 | err = nfserrno(host_err); |
| @@ -1728,11 +1707,16 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, · 33 unmodified lines | ||
| 1728 | 1707 | if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry) |
| 1729 | 1708 | goto out_dput_new; |
| 1730 | 1709 | |
| 1731 | − host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0); | |
| 1732 | − if (!host_err) { | |
| 1733 | − host_err = commit_metadata(tfhp); | |
| 1734 | − if (!host_err) | |
| 1735 | − host_err = commit_metadata(ffhp); | |
| 1710 | + if (nfsd_has_cached_files(ndentry)) { | |
| 1711 | + has_cached = true; | |
| 1712 | + goto out_dput_old; | |
| 1713 | + } else { | |
| 1714 | + host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0); | |
| 1715 | + if (!host_err) { | |
| 1716 | + host_err = commit_metadata(tfhp); | |
| 1717 | + if (!host_err) | |
| 1718 | + host_err = commit_metadata(ffhp); | |
| 1719 | + } | |
| 1736 | 1720 | } |
| 1737 | 1721 | out_dput_new: |
| 1738 | 1722 | dput(ndentry); |
| @@ -1745,12 +1729,26 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, · 6 unmodified lines | ||
| 1745 | 1729 | * as that would do the wrong thing if the two directories |
| 1746 | 1730 | * were the same, so again we do it by hand. |
| 1747 | 1731 | */ |
| 1748 | − fill_post_wcc(ffhp); | |
| 1749 | − fill_post_wcc(tfhp); | |
| 1732 | + if (!has_cached) { | |
| 1733 | + fill_post_wcc(ffhp); | |
| 1734 | + fill_post_wcc(tfhp); | |
| 1735 | + } | |
| 1750 | 1736 | unlock_rename(tdentry, fdentry); |
| 1751 | 1737 | ffhp->fh_locked = tfhp->fh_locked = false; |
| 1752 | 1738 | fh_drop_write(ffhp); |
| 1753 | 1739 | |
| 1740 | + /* | |
| 1741 | + * If the target dentry has cached open files, then we need to try to | |
| 1742 | + * close them prior to doing the rename. Flushing delayed fput | |
| 1743 | + * shouldn't be done with locks held however, so we delay it until this | |
| 1744 | + * point and then reattempt the whole shebang. | |
| 1745 | + */ | |
| 1746 | + if (has_cached) { | |
| 1747 | + has_cached = false; | |
| 1748 | + nfsd_close_cached_files(ndentry); | |
| 1749 | + dput(ndentry); | |
| 1750 | + goto retry; | |
| 1751 | + } | |
| 1754 | 1752 | out: |
| 1755 | 1753 | return err; |
| 1756 | 1754 | } |
| @@ -1797,10 +1795,13 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, · 40 unmodified lines | ||
| 1797 | 1795 | if (!type) |
| 1798 | 1796 | type = d_inode(rdentry)->i_mode & S_IFMT; |
| 1799 | 1797 | |
| 1800 | − if (type != S_IFDIR) | |
| 1798 | + if (type != S_IFDIR) { | |
| 1799 | + nfsd_close_cached_files(rdentry); | |
| 1801 | 1800 | host_err = vfs_unlink(dirp, rdentry, NULL); |
| 1802 | − else | |
| 1801 | + } else { | |
| 1803 | 1802 | host_err = vfs_rmdir(dirp, rdentry); |
| 1803 | + } | |
| 1804 | + | |
| 1804 | 1805 | if (!host_err) |
| 1805 | 1806 | host_err = commit_metadata(fhp); |
| 1806 | 1807 | dput(rdentry); |
| @@ -2074,63 +2075,3 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, · 267 unmodified lines | ||
| 2074 | 2075 | |
| 2075 | 2076 | return err? nfserrno(err) : 0; |
| 2076 | 2077 | } |
| 2077 | − | |
| 2078 | −void | |
| 2079 | −nfsd_racache_shutdown(void) | |
| 2080 | −{ | |
| 2081 | − struct raparms *raparm, *last_raparm; | |
| 2082 | − unsigned int i; | |
| 2083 | − | |
| 2084 | − dprintk("nfsd: freeing readahead buffers.\n"); | |
| 2085 | − | |
| 2086 | − for (i = 0; i < RAPARM_HASH_SIZE; i++) { | |
| 2087 | − raparm = raparm_hash[i].pb_head; | |
| 2088 | − while(raparm) { | |
| 2089 | − last_raparm = raparm; | |
| 2090 | − raparm = raparm->p_next; | |
| 2091 | − kfree(last_raparm); | |
| 2092 | − } | |
| 2093 | − raparm_hash[i].pb_head = NULL; | |
| 2094 | − } | |
| 2095 | −} | |
| 2096 | −/* | |
| 2097 | − * Initialize readahead param cache | |
| 2098 | − */ | |
| 2099 | −int | |
| 2100 | −nfsd_racache_init(int cache_size) | |
| 2101 | −{ | |
| 2102 | − int i; | |
| 2103 | − int j = 0; | |
| 2104 | − int nperbucket; | |
| 2105 | − struct raparms **raparm = NULL; | |
| 2106 | − | |
| 2107 | − | |
| 2108 | − if (raparm_hash[0].pb_head) | |
| 2109 | − return 0; | |
| 2110 | − nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE); | |
| 2111 | − nperbucket = max(2, nperbucket); | |
| 2112 | − cache_size = nperbucket * RAPARM_HASH_SIZE; | |
| 2113 | − | |
| 2114 | − dprintk("nfsd: allocating %d readahead buffers.\n", cache_size); | |
| 2115 | − | |
| 2116 | − for (i = 0; i < RAPARM_HASH_SIZE; i++) { | |
| 2117 | − spin_lock_init(&raparm_hash[i].pb_lock); | |
| 2118 | − | |
| 2119 | − raparm = &raparm_hash[i].pb_head; | |
| 2120 | − for (j = 0; j < nperbucket; j++) { | |
| 2121 | − *raparm = kzalloc(sizeof(struct raparms), GFP_KERNEL); | |
| 2122 | − if (!*raparm) | |
| 2123 | − goto out_nomem; | |
| 2124 | − raparm = &(*raparm)->p_next; | |
| 2125 | − } | |
| 2126 | − *raparm = NULL; | |
| 2127 | − } | |
| 2128 | − | |
| 2129 | − nfsdstats.ra_size = cache_size; | |
| 2130 | − return 0; | |
| 2131 | − | |
| 2132 | −out_nomem: | |
| 2133 | − dprintk("nfsd: kmalloc failed, freeing readahead buffers\n"); | |
| 2134 | − nfsd_racache_shutdown(); | |
| 2135 | − return -ENOMEM; | |
| 2136 | −} | |
| @@ -40,8 +40,6 @@ · 39 unmodified lines | ||
| 40 | 40 | typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned); |
| 41 | 41 | |
| 42 | 42 | /* nfsd/vfs.c */ |
| 43 | −int nfsd_racache_init(int); | |
| 44 | −void nfsd_racache_shutdown(void); | |
| 45 | 43 | int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, |
| 46 | 44 | struct svc_export **expp); |
| 47 | 45 | __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, |
| @@ -75,18 +73,23 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, · 27 unmodified lines | ||
| 75 | 73 | __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, |
| 76 | 74 | loff_t, unsigned long); |
| 77 | 75 | #endif /* CONFIG_NFSD_V3 */ |
| 76 | +int nfsd_open_break_lease(struct inode *, int); | |
| 78 | 77 | __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t, |
| 79 | 78 | int, struct file **); |
| 80 | −struct raparms; | |
| 79 | +__be32 nfsd_open_verified(struct svc_rqst *, struct svc_fh *, umode_t, | |
| 80 | + int, struct file **); | |
| 81 | 81 | __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, |
| 82 | 82 | struct file *file, loff_t offset, |
| 83 | − unsigned long *count); | |
| 83 | + unsigned long *count, | |
| 84 | + u32 *eof); | |
| 84 | 85 | __be32 nfsd_readv(struct svc_rqst *rqstp, struct svc_fh *fhp, |
| 85 | 86 | struct file *file, loff_t offset, |
| 86 | 87 | struct kvec *vec, int vlen, |
| 87 | − unsigned long *count); | |
| 88 | + unsigned long *count, | |
| 89 | + u32 *eof); | |
| 88 | 90 | __be32 nfsd_read(struct svc_rqst *, struct svc_fh *, |
| 89 | − loff_t, struct kvec *, int, unsigned long *); | |
| 91 | + loff_t, struct kvec *, int, unsigned long *, | |
| 92 | + u32 *eof); | |
| 90 | 93 | __be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t, |
| 91 | 94 | struct kvec *, int, unsigned long *, int); |
| 92 | 95 | __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, |
| @@ -115,9 +118,6 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, · 22 unmodified lines | ||
| 115 | 118 | __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, |
| 116 | 119 | struct dentry *, int); |
| 117 | 120 | |
| 118 | −struct raparms *nfsd_init_raparms(struct file *file); | |
| 119 | −void nfsd_put_raparams(struct file *file, struct raparms *ra); | |
| 120 | − | |
| 121 | 121 | static inline int fh_want_write(struct svc_fh *fh) |
| 122 | 122 | { |
| 123 | 123 | int ret; |
| @@ -152,23 +152,4 @@ static inline int nfsd_create_is_exclusive(int createmode) · 28 unmodified lines | ||
| 152 | 152 | || createmode == NFS4_CREATE_EXCLUSIVE4_1; |
| 153 | 153 | } |
| 154 | 154 | |
| 155 | −static inline bool nfsd_eof_on_read(long requested, long read, | |
| 156 | − loff_t offset, loff_t size) | |
| 157 | −{ | |
| 158 | − /* We assume a short read means eof: */ | |
| 159 | − if (requested > read) | |
| 160 | − return true; | |
| 161 | − /* | |
| 162 | − * A non-short read might also reach end of file. The spec | |
| 163 | − * still requires us to set eof in that case. | |
| 164 | − * | |
| 165 | − * Further operations may have modified the file size since | |
| 166 | − * the read, so the following check is not atomic with the read. | |
| 167 | − * We've only seen that cause a problem for a client in the case | |
| 168 | − * where the read returned a count of 0 without setting eof. | |
| 169 | − * That case was fixed by the addition of the above check. | |
| 170 | − */ | |
| 171 | − return (offset + read >= size); | |
| 172 | −} | |
| 173 | − | |
| 174 | 155 | #endif /* LINUX_NFSD_VFS_H */ |
| @@ -151,7 +151,7 @@ struct nfsd3_readres { · 150 unmodified lines | ||
| 151 | 151 | __be32 status; |
| 152 | 152 | struct svc_fh fh; |
| 153 | 153 | unsigned long count; |
| 154 | − int eof; | |
| 154 | + __u32 eof; | |
| 155 | 155 | }; |
| 156 | 156 | |
| 157 | 157 | struct nfsd3_writeres { |
| @@ -273,15 +273,14 @@ struct nfsd4_open_downgrade { · 272 unmodified lines | ||
| 273 | 273 | |
| 274 | 274 | |
| 275 | 275 | struct nfsd4_read { |
| 276 | − stateid_t rd_stateid; /* request */ | |
| 277 | − u64 rd_offset; /* request */ | |
| 278 | − u32 rd_length; /* request */ | |
| 279 | − int rd_vlen; | |
| 280 | − struct file *rd_filp; | |
| 281 | − bool rd_tmp_file; | |
| 276 | + stateid_t rd_stateid; /* request */ | |
| 277 | + u64 rd_offset; /* request */ | |
| 278 | + u32 rd_length; /* request */ | |
| 279 | + int rd_vlen; | |
| 280 | + struct nfsd_file *rd_nf; | |
| 282 | 281 | |
| 283 | − struct svc_rqst *rd_rqstp; /* response */ | |
| 284 | − struct svc_fh * rd_fhp; /* response */ | |
| 282 | + struct svc_rqst *rd_rqstp; /* response */ | |
| 283 | + struct svc_fh *rd_fhp; /* response */ | |
| 285 | 284 | }; |
| 286 | 285 | |
| 287 | 286 | struct nfsd4_readdir { |
| @@ -538,8 +537,8 @@ struct nfsd4_copy { · 250 unmodified lines | ||
| 538 | 537 | |
| 539 | 538 | struct nfs4_client *cp_clp; |
| 540 | 539 | |
| 541 | − struct file *file_src; | |
| 542 | − struct file *file_dst; | |
| 540 | + struct nfsd_file *nf_src; | |
| 541 | + struct nfsd_file *nf_dst; | |
| 543 | 542 | |
| 544 | 543 | stateid_t cp_stateid; |
| 545 | 544 | |
| @@ -54,8 +54,6 @@ static inline void fsnotify_clear_marks_by_sb(struct super_block *sb) · 53 unmodified lines | ||
| 54 | 54 | { |
| 55 | 55 | fsnotify_destroy_marks(&sb->s_fsnotify_marks); |
| 56 | 56 | } |
| 57 | −/* Wait until all marks queued for destruction are destroyed */ | |
| 58 | −extern void fsnotify_wait_marks_destroyed(void); | |
| 59 | 57 | |
| 60 | 58 | /* |
| 61 | 59 | * update the dentry->d_flags of all of inode's children to indicate if inode cares |
| @@ -108,6 +108,7 @@ void fsnotify_put_group(struct fsnotify_group *group) · 107 unmodified lines | ||
| 108 | 108 | if (refcount_dec_and_test(&group->refcnt)) |
| 109 | 109 | fsnotify_final_destroy_group(group); |
| 110 | 110 | } |
| 111 | +EXPORT_SYMBOL_GPL(fsnotify_put_group); | |
| 111 | 112 | |
| 112 | 113 | /* |
| 113 | 114 | * Create a new fsnotify_group and hold a reference for the group returned. |
| @@ -137,6 +138,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) · 23 unmodified lines | ||
| 137 | 138 | |
| 138 | 139 | return group; |
| 139 | 140 | } |
| 141 | +EXPORT_SYMBOL_GPL(fsnotify_alloc_group); | |
| 140 | 142 | |
| 141 | 143 | int fsnotify_fasync(int fd, struct file *file, int on) |
| 142 | 144 | { |
| @@ -276,6 +276,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) · 275 unmodified lines | ||
| 276 | 276 | queue_delayed_work(system_unbound_wq, &reaper_work, |
| 277 | 277 | FSNOTIFY_REAPER_DELAY); |
| 278 | 278 | } |
| 279 | +EXPORT_SYMBOL_GPL(fsnotify_put_mark); | |
| 279 | 280 | |
| 280 | 281 | /* |
| 281 | 282 | * Get mark reference when we found the mark via lockless traversal of object |
| @@ -430,6 +431,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark, · 148 unmodified lines | ||
| 430 | 431 | mutex_unlock(&group->mark_mutex); |
| 431 | 432 | fsnotify_free_mark(mark); |
| 432 | 433 | } |
| 434 | +EXPORT_SYMBOL_GPL(fsnotify_destroy_mark); | |
| 433 | 435 | |
| 434 | 436 | /* |
| 435 | 437 | * Sorting function for lists of fsnotify marks. |
| @@ -685,6 +687,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, · 249 unmodified lines | ||
| 685 | 687 | mutex_unlock(&group->mark_mutex); |
| 686 | 688 | return ret; |
| 687 | 689 | } |
| 690 | +EXPORT_SYMBOL_GPL(fsnotify_add_mark); | |
| 688 | 691 | |
| 689 | 692 | /* |
| 690 | 693 | * Given a list of marks, find the mark associated with given group. If found |
| @@ -711,6 +714,7 @@ struct fsnotify_mark *fsnotify_find_mark(fsnotify_connp_t *connp, · 20 unmodified lines | ||
| 711 | 714 | spin_unlock(&conn->lock); |
| 712 | 715 | return NULL; |
| 713 | 716 | } |
| 717 | +EXPORT_SYMBOL_GPL(fsnotify_find_mark); | |
| 714 | 718 | |
| 715 | 719 | /* Clear any marks in a group with given type mask */ |
| 716 | 720 | void fsnotify_clear_marks_by_group(struct fsnotify_group *group, |
| @@ -809,6 +813,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark, · 92 unmodified lines | ||
| 809 | 813 | mark->group = group; |
| 810 | 814 | WRITE_ONCE(mark->connector, NULL); |
| 811 | 815 | } |
| 816 | +EXPORT_SYMBOL_GPL(fsnotify_init_mark); | |
| 812 | 817 | |
| 813 | 818 | /* |
| 814 | 819 | * Destroy all marks in destroy_list, waits for SRCU period to finish before |
| @@ -837,3 +842,4 @@ void fsnotify_wait_marks_destroyed(void) · 22 unmodified lines | ||
| 837 | 842 | { |
| 838 | 843 | flush_delayed_work(&reaper_work); |
| 839 | 844 | } |
| 845 | +EXPORT_SYMBOL_GPL(fsnotify_wait_marks_destroyed); | |
| @@ -1168,6 +1168,11 @@ extern void lease_get_mtime(struct inode *, struct timespec64 *time); · 1167 unmodified lines | ||
| 1168 | 1168 | extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); |
| 1169 | 1169 | extern int vfs_setlease(struct file *, long, struct file_lock **, void **); |
| 1170 | 1170 | extern int lease_modify(struct file_lock *, int, struct list_head *); |
| 1171 | + | |
| 1172 | +struct notifier_block; | |
| 1173 | +extern int lease_register_notifier(struct notifier_block *); | |
| 1174 | +extern void lease_unregister_notifier(struct notifier_block *); | |
| 1175 | + | |
| 1171 | 1176 | struct files_struct; |
| 1172 | 1177 | extern void show_fd_locks(struct seq_file *f, |
| 1173 | 1178 | struct file *filp, struct files_struct *files); |
| @@ -475,6 +475,8 @@ extern void fsnotify_destroy_mark(struct fsnotify_mark *mark, · 474 unmodified lines | ||
| 475 | 475 | extern void fsnotify_detach_mark(struct fsnotify_mark *mark); |
| 476 | 476 | /* free mark */ |
| 477 | 477 | extern void fsnotify_free_mark(struct fsnotify_mark *mark); |
| 478 | +/* Wait until all marks queued for destruction are destroyed */ | |
| 479 | +extern void fsnotify_wait_marks_destroyed(void); | |
| 478 | 480 | /* run all the marks in a group, and clear all of the marks attached to given object type */ |
| 479 | 481 | extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group, unsigned int type); |
| 480 | 482 | /* run all the marks in a group, and clear all of the vfsmount marks */ |
| @@ -87,6 +87,7 @@ struct cache_detail { · 86 unmodified lines | ||
| 87 | 87 | int has_died); |
| 88 | 88 | |
| 89 | 89 | struct cache_head * (*alloc)(void); |
| 90 | + void (*flush)(void); | |
| 90 | 91 | int (*match)(struct cache_head *orig, struct cache_head *new); |
| 91 | 92 | void (*init)(struct cache_head *orig, struct cache_head *new); |
| 92 | 93 | void (*update)(struct cache_head *orig, struct cache_head *new); |
| @@ -107,9 +108,9 @@ struct cache_detail { · 14 unmodified lines | ||
| 107 | 108 | /* fields for communication over channel */ |
| 108 | 109 | struct list_head queue; |
| 109 | 110 | |
| 110 | − atomic_t readers; /* how many time is /chennel open */ | |
| 111 | − time_t last_close; /* if no readers, when did last close */ | |
| 112 | − time_t last_warn; /* when we last warned about no readers */ | |
| 111 | + atomic_t writers; /* how many time is /channel open */ | |
| 112 | + time_t last_close; /* if no writers, when did last close */ | |
| 113 | + time_t last_warn; /* when we last warned about no writers */ | |
| 113 | 114 | |
| 114 | 115 | union { |
| 115 | 116 | struct proc_dir_entry *procfs; |
| @@ -42,6 +42,7 @@ · 41 unmodified lines | ||
| 42 | 42 | |
| 43 | 43 | #ifndef SVC_RDMA_H |
| 44 | 44 | #define SVC_RDMA_H |
| 45 | +#include <linux/llist.h> | |
| 45 | 46 | #include <linux/sunrpc/xdr.h> |
| 46 | 47 | #include <linux/sunrpc/svcsock.h> |
| 47 | 48 | #include <linux/sunrpc/rpc_rdma.h> |
| @@ -107,8 +108,7 @@ struct svcxprt_rdma { · 59 unmodified lines | ||
| 107 | 108 | struct list_head sc_read_complete_q; |
| 108 | 109 | struct work_struct sc_work; |
| 109 | 110 | |
| 110 | − spinlock_t sc_recv_lock; | |
| 111 | − struct list_head sc_recv_ctxts; | |
| 111 | + struct llist_head sc_recv_ctxts; | |
| 112 | 112 | }; |
| 113 | 113 | /* sc_flags */ |
| 114 | 114 | #define RDMAXPRT_CONN_PENDING 3 |
| @@ -125,6 +125,7 @@ enum { · 10 unmodified lines | ||
| 125 | 125 | #define RPCSVC_MAXPAYLOAD_RDMA RPCSVC_MAXPAYLOAD |
| 126 | 126 | |
| 127 | 127 | struct svc_rdma_recv_ctxt { |
| 128 | + struct llist_node rc_node; | |
| 128 | 129 | struct list_head rc_list; |
| 129 | 130 | struct ib_recv_wr rc_recv_wr; |
| 130 | 131 | struct ib_cqe rc_cqe; |
| @@ -200,7 +201,6 @@ extern struct svc_xprt_class svc_rdma_bc_class; · 69 unmodified lines | ||
| 200 | 201 | #endif |
| 201 | 202 | |
| 202 | 203 | /* svc_rdma.c */ |
| 203 | −extern struct workqueue_struct *svc_rdma_wq; | |
| 204 | 204 | extern int svc_rdma_init(void); |
| 205 | 205 | extern void svc_rdma_cleanup(void); |
| 206 | 206 | |
| @@ -26,17 +26,22 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <linux/types.h> |
| 27 | 27 | |
| 28 | 28 | /* latest upcall version available */ |
| 29 | −#define CLD_UPCALL_VERSION 1 | |
| 29 | +#define CLD_UPCALL_VERSION 2 | |
| 30 | 30 | |
| 31 | 31 | /* defined by RFC3530 */ |
| 32 | 32 | #define NFS4_OPAQUE_LIMIT 1024 |
| 33 | 33 | |
| 34 | +#ifndef SHA256_DIGEST_SIZE | |
| 35 | +#define SHA256_DIGEST_SIZE 32 | |
| 36 | +#endif | |
| 37 | + | |
| 34 | 38 | enum cld_command { |
| 35 | 39 | Cld_Create, /* create a record for this cm_id */ |
| 36 | 40 | Cld_Remove, /* remove record of this cm_id */ |
| 37 | 41 | Cld_Check, /* is this cm_id allowed? */ |
| 38 | 42 | Cld_GraceDone, /* grace period is complete */ |
| 39 | − Cld_GraceStart, | |
| 43 | + Cld_GraceStart, /* grace start (upload client records) */ | |
| 44 | + Cld_GetVersion, /* query max supported upcall version */ | |
| 40 | 45 | }; |
| 41 | 46 | |
| 42 | 47 | /* representation of long-form NFSv4 client ID */ |
| @@ -45,6 +50,17 @@ struct cld_name { · 2 unmodified lines | ||
| 45 | 50 | unsigned char cn_id[NFS4_OPAQUE_LIMIT]; /* client-provided */ |
| 46 | 51 | } __attribute__((packed)); |
| 47 | 52 | |
| 53 | +/* sha256 hash of the kerberos principal */ | |
| 54 | +struct cld_princhash { | |
| 55 | + __u8 cp_len; /* length of cp_data */ | |
| 56 | + unsigned char cp_data[SHA256_DIGEST_SIZE]; /* hash of principal */ | |
| 57 | +} __attribute__((packed)); | |
| 58 | + | |
| 59 | +struct cld_clntinfo { | |
| 60 | + struct cld_name cc_name; | |
| 61 | + struct cld_princhash cc_princhash; | |
| 62 | +} __attribute__((packed)); | |
| 63 | + | |
| 48 | 64 | /* message struct for communication with userspace */ |
| 49 | 65 | struct cld_msg { |
| 50 | 66 | __u8 cm_vers; /* upcall version */ |
| @@ -54,7 +70,28 @@ struct cld_msg { · 3 unmodified lines | ||
| 54 | 70 | union { |
| 55 | 71 | __s64 cm_gracetime; /* grace period start time */ |
| 56 | 72 | struct cld_name cm_name; |
| 73 | + __u8 cm_version; /* for getting max version */ | |
| 74 | + } __attribute__((packed)) cm_u; | |
| 75 | +} __attribute__((packed)); | |
| 76 | + | |
| 77 | +/* version 2 message can include hash of kerberos principal */ | |
| 78 | +struct cld_msg_v2 { | |
| 79 | + __u8 cm_vers; /* upcall version */ | |
| 80 | + __u8 cm_cmd; /* upcall command */ | |
| 81 | + __s16 cm_status; /* return code */ | |
| 82 | + __u32 cm_xid; /* transaction id */ | |
| 83 | + union { | |
| 84 | + struct cld_name cm_name; | |
| 85 | + __u8 cm_version; /* for getting max version */ | |
| 86 | + struct cld_clntinfo cm_clntinfo; /* name & princ hash */ | |
| 57 | 87 | } __attribute__((packed)) cm_u; |
| 58 | 88 | } __attribute__((packed)); |
| 59 | 89 | |
| 90 | +struct cld_msg_hdr { | |
| 91 | + __u8 cm_vers; /* upcall version */ | |
| 92 | + __u8 cm_cmd; /* upcall command */ | |
| 93 | + __s16 cm_status; /* return code */ | |
| 94 | + __u32 cm_xid; /* transaction id */ | |
| 95 | +} __attribute__((packed)); | |
| 96 | + | |
| 60 | 97 | #endif /* !_NFSD_CLD_H */ |
| @@ -373,7 +373,7 @@ void sunrpc_init_cache_detail(struct cache_detail *cd) · 372 unmodified lines | ||
| 373 | 373 | spin_lock(&cache_list_lock); |
| 374 | 374 | cd->nextcheck = 0; |
| 375 | 375 | cd->entries = 0; |
| 376 | − atomic_set(&cd->readers, 0); | |
| 376 | + atomic_set(&cd->writers, 0); | |
| 377 | 377 | cd->last_close = 0; |
| 378 | 378 | cd->last_warn = -1; |
| 379 | 379 | list_add(&cd->others, &cache_list); |
| @@ -1029,11 +1029,13 @@ static int cache_open(struct inode *inode, struct file *filp, · 649 unmodified lines | ||
| 1029 | 1029 | } |
| 1030 | 1030 | rp->offset = 0; |
| 1031 | 1031 | rp->q.reader = 1; |
| 1032 | − atomic_inc(&cd->readers); | |
| 1032 | + | |
| 1033 | 1033 | spin_lock(&queue_lock); |
| 1034 | 1034 | list_add(&rp->q.list, &cd->queue); |
| 1035 | 1035 | spin_unlock(&queue_lock); |
| 1036 | 1036 | } |
| 1037 | + if (filp->f_mode & FMODE_WRITE) | |
| 1038 | + atomic_inc(&cd->writers); | |
| 1037 | 1039 | filp->private_data = rp; |
| 1038 | 1040 | return 0; |
| 1039 | 1041 | } |
| @@ -1062,8 +1064,10 @@ static int cache_release(struct inode *inode, struct file *filp, · 22 unmodified lines | ||
| 1062 | 1064 | filp->private_data = NULL; |
| 1063 | 1065 | kfree(rp); |
| 1064 | 1066 | |
| 1067 | + } | |
| 1068 | + if (filp->f_mode & FMODE_WRITE) { | |
| 1069 | + atomic_dec(&cd->writers); | |
| 1065 | 1070 | cd->last_close = seconds_since_boot(); |
| 1066 | − atomic_dec(&cd->readers); | |
| 1067 | 1071 | } |
| 1068 | 1072 | module_put(cd->owner); |
| 1069 | 1073 | return 0; |
| @@ -1171,7 +1175,7 @@ static void warn_no_listener(struct cache_detail *detail) · 101 unmodified lines | ||
| 1171 | 1175 | |
| 1172 | 1176 | static bool cache_listeners_exist(struct cache_detail *detail) |
| 1173 | 1177 | { |
| 1174 | − if (atomic_read(&detail->readers)) | |
| 1178 | + if (atomic_read(&detail->writers)) | |
| 1175 | 1179 | return true; |
| 1176 | 1180 | if (detail->last_close == 0) |
| 1177 | 1181 | /* This cache was never opened */ |
| @@ -1520,6 +1524,9 @@ static ssize_t write_flush(struct file *file, const char __user *buf, · 342 unmodified lines | ||
| 1520 | 1524 | cd->nextcheck = now; |
| 1521 | 1525 | cache_flush(); |
| 1522 | 1526 | |
| 1527 | + if (cd->flush) | |
| 1528 | + cd->flush(); | |
| 1529 | + | |
| 1523 | 1530 | *ppos += count; |
| 1524 | 1531 | return count; |
| 1525 | 1532 | } |
| @@ -1233,8 +1233,8 @@ svc_generic_init_request(struct svc_rqst *rqstp, · 1232 unmodified lines | ||
| 1233 | 1233 | |
| 1234 | 1234 | if (rqstp->rq_vers >= progp->pg_nvers ) |
| 1235 | 1235 | goto err_bad_vers; |
| 1236 | − versp = progp->pg_vers[rqstp->rq_vers]; | |
| 1237 | − if (!versp) | |
| 1236 | + versp = progp->pg_vers[rqstp->rq_vers]; | |
| 1237 | + if (!versp) | |
| 1238 | 1238 | goto err_bad_vers; |
| 1239 | 1239 | |
| 1240 | 1240 | /* |
| @@ -73,8 +73,6 @@ atomic_t rdma_stat_rq_prod; · 72 unmodified lines | ||
| 73 | 73 | atomic_t rdma_stat_sq_poll; |
| 74 | 74 | atomic_t rdma_stat_sq_prod; |
| 75 | 75 | |
| 76 | −struct workqueue_struct *svc_rdma_wq; | |
| 77 | − | |
| 78 | 76 | /* |
| 79 | 77 | * This function implements reading and resetting an atomic_t stat |
| 80 | 78 | * variable through read/write to a proc file. Any write to the file |
| @@ -230,7 +228,6 @@ static struct ctl_table svcrdma_root_table[] = { · 149 unmodified lines | ||
| 230 | 228 | void svc_rdma_cleanup(void) |
| 231 | 229 | { |
| 232 | 230 | dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n"); |
| 233 | − destroy_workqueue(svc_rdma_wq); | |
| 234 | 231 | if (svcrdma_table_header) { |
| 235 | 232 | unregister_sysctl_table(svcrdma_table_header); |
| 236 | 233 | svcrdma_table_header = NULL; |
| @@ -246,10 +243,6 @@ int svc_rdma_init(void) · 9 unmodified lines | ||
| 246 | 243 | dprintk("\tmax_bc_requests : %u\n", svcrdma_max_bc_requests); |
| 247 | 244 | dprintk("\tmax_inline : %d\n", svcrdma_max_req_size); |
| 248 | 245 | |
| 249 | − svc_rdma_wq = alloc_workqueue("svc_rdma", 0, 0); | |
| 250 | − if (!svc_rdma_wq) | |
| 251 | − return -ENOMEM; | |
| 252 | − | |
| 253 | 246 | if (!svcrdma_table_header) |
| 254 | 247 | svcrdma_table_header = |
| 255 | 248 | register_sysctl_table(svcrdma_root_table); |
| @@ -172,9 +172,10 @@ static void svc_rdma_recv_ctxt_destroy(struct svcxprt_rdma *rdma, · 171 unmodified lines | ||
| 172 | 172 | void svc_rdma_recv_ctxts_destroy(struct svcxprt_rdma *rdma) |
| 173 | 173 | { |
| 174 | 174 | struct svc_rdma_recv_ctxt *ctxt; |
| 175 | + struct llist_node *node; | |
| 175 | 176 | |
| 176 | − while ((ctxt = svc_rdma_next_recv_ctxt(&rdma->sc_recv_ctxts))) { | |
| 177 | − list_del(&ctxt->rc_list); | |
| 177 | + while ((node = llist_del_first(&rdma->sc_recv_ctxts))) { | |
| 178 | + ctxt = llist_entry(node, struct svc_rdma_recv_ctxt, rc_node); | |
| 178 | 179 | svc_rdma_recv_ctxt_destroy(rdma, ctxt); |
| 179 | 180 | } |
| 180 | 181 | } |
| @@ -183,21 +184,18 @@ static struct svc_rdma_recv_ctxt * · 2 unmodified lines | ||
| 183 | 184 | svc_rdma_recv_ctxt_get(struct svcxprt_rdma *rdma) |
| 184 | 185 | { |
| 185 | 186 | struct svc_rdma_recv_ctxt *ctxt; |
| 187 | + struct llist_node *node; | |
| 186 | 188 | |
| 187 | − spin_lock(&rdma->sc_recv_lock); | |
| 188 | − ctxt = svc_rdma_next_recv_ctxt(&rdma->sc_recv_ctxts); | |
| 189 | − if (!ctxt) | |
| 189 | + node = llist_del_first(&rdma->sc_recv_ctxts); | |
| 190 | + if (!node) | |
| 190 | 191 | goto out_empty; |
| 191 | − list_del(&ctxt->rc_list); | |
| 192 | − spin_unlock(&rdma->sc_recv_lock); | |
| 192 | + ctxt = llist_entry(node, struct svc_rdma_recv_ctxt, rc_node); | |
| 193 | 193 | |
| 194 | 194 | out: |
| 195 | 195 | ctxt->rc_page_count = 0; |
| 196 | 196 | return ctxt; |
| 197 | 197 | |
| 198 | 198 | out_empty: |
| 199 | − spin_unlock(&rdma->sc_recv_lock); | |
| 200 | − | |
| 201 | 199 | ctxt = svc_rdma_recv_ctxt_alloc(rdma); |
| 202 | 200 | if (!ctxt) |
| 203 | 201 | return NULL; |
| @@ -218,11 +216,9 @@ void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma, · 14 unmodified lines | ||
| 218 | 216 | for (i = 0; i < ctxt->rc_page_count; i++) |
| 219 | 217 | put_page(ctxt->rc_pages[i]); |
| 220 | 218 | |
| 221 | − if (!ctxt->rc_temp) { | |
| 222 | − spin_lock(&rdma->sc_recv_lock); | |
| 223 | − list_add(&ctxt->rc_list, &rdma->sc_recv_ctxts); | |
| 224 | − spin_unlock(&rdma->sc_recv_lock); | |
| 225 | − } else | |
| 219 | + if (!ctxt->rc_temp) | |
| 220 | + llist_add(&ctxt->rc_node, &rdma->sc_recv_ctxts); | |
| 221 | + else | |
| 226 | 222 | svc_rdma_recv_ctxt_destroy(rdma, ctxt); |
| 227 | 223 | } |
| 228 | 224 | |
| @@ -140,14 +140,13 @@ static struct svcxprt_rdma *svc_rdma_create_xprt(struct svc_serv *serv, · 139 unmodified lines | ||
| 140 | 140 | INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q); |
| 141 | 141 | INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q); |
| 142 | 142 | INIT_LIST_HEAD(&cma_xprt->sc_send_ctxts); |
| 143 | − INIT_LIST_HEAD(&cma_xprt->sc_recv_ctxts); | |
| 143 | + init_llist_head(&cma_xprt->sc_recv_ctxts); | |
| 144 | 144 | INIT_LIST_HEAD(&cma_xprt->sc_rw_ctxts); |
| 145 | 145 | init_waitqueue_head(&cma_xprt->sc_send_wait); |
| 146 | 146 | |
| 147 | 147 | spin_lock_init(&cma_xprt->sc_lock); |
| 148 | 148 | spin_lock_init(&cma_xprt->sc_rq_dto_lock); |
| 149 | 149 | spin_lock_init(&cma_xprt->sc_send_lock); |
| 150 | − spin_lock_init(&cma_xprt->sc_recv_lock); | |
| 151 | 150 | spin_lock_init(&cma_xprt->sc_rw_ctxt_lock); |
| 152 | 151 | |
| 153 | 152 | /* |
| @@ -630,8 +629,9 @@ static void svc_rdma_free(struct svc_xprt *xprt) · 476 unmodified lines | ||
| 630 | 629 | { |
| 631 | 630 | struct svcxprt_rdma *rdma = |
| 632 | 631 | container_of(xprt, struct svcxprt_rdma, sc_xprt); |
| 632 | + | |
| 633 | 633 | INIT_WORK(&rdma->sc_work, __svc_rdma_free); |
| 634 | − queue_work(svc_rdma_wq, &rdma->sc_work); | |
| 634 | + schedule_work(&rdma->sc_work); | |
| 635 | 635 | } |
| 636 | 636 | |
| 637 | 637 | static int svc_rdma_has_wspace(struct svc_xprt *xprt) |