11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * File operations used by nfsd. Some of these have been ripped from 31da177e4SLinus Torvalds * other parts of the kernel because they weren't exported, others 41da177e4SLinus Torvalds * are partial duplicates with added or changed functionality. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Note that several functions dget() the dentry upon which they want 71da177e4SLinus Torvalds * to act, most notably those that create directory entries. Response 81da177e4SLinus Torvalds * dentry's are dput()'d if necessary in the release callback. 91da177e4SLinus Torvalds * So if you notice code paths that apparently fail to dput() the 101da177e4SLinus Torvalds * dentry, don't worry--they have been taken care of. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de> 131da177e4SLinus Torvalds * Zerocpy NFS support (C) 2002 Hirokazu Takahashi <taka@valinux.co.jp> 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/fs.h> 171da177e4SLinus Torvalds #include <linux/file.h> 18d6b29d7cSJens Axboe #include <linux/splice.h> 191da177e4SLinus Torvalds #include <linux/fcntl.h> 201da177e4SLinus Torvalds #include <linux/namei.h> 211da177e4SLinus Torvalds #include <linux/delay.h> 220eeca283SRobert Love #include <linux/fsnotify.h> 231da177e4SLinus Torvalds #include <linux/posix_acl_xattr.h> 241da177e4SLinus Torvalds #include <linux/xattr.h> 259a74af21SBoaz Harrosh #include <linux/jhash.h> 269a74af21SBoaz Harrosh #include <linux/ima.h> 275a0e3ad6STejun Heo #include <linux/slab.h> 289a74af21SBoaz Harrosh #include <asm/uaccess.h> 29f501912aSBen Myers #include <linux/exportfs.h> 30f501912aSBen Myers #include <linux/writeback.h> 3118032ca0SDavid Quigley #include <linux/security.h> 329a74af21SBoaz Harrosh 339a74af21SBoaz Harrosh #ifdef CONFIG_NFSD_V3 349a74af21SBoaz Harrosh #include "xdr3.h" 359a74af21SBoaz Harrosh #endif /* CONFIG_NFSD_V3 */ 369a74af21SBoaz Harrosh 375be196e5SChristoph Hellwig #ifdef CONFIG_NFSD_V4 382ca72e17SJ. Bruce Fields #include "acl.h" 392ca72e17SJ. Bruce Fields #include "idmap.h" 401da177e4SLinus Torvalds #endif /* CONFIG_NFSD_V4 */ 411da177e4SLinus Torvalds 429a74af21SBoaz Harrosh #include "nfsd.h" 439a74af21SBoaz Harrosh #include "vfs.h" 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_FILEOP 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /* 491da177e4SLinus Torvalds * This is a cache of readahead params that help us choose the proper 501da177e4SLinus Torvalds * readahead strategy. Initially, we set all readahead parameters to 0 511da177e4SLinus Torvalds * and let the VFS handle things. 521da177e4SLinus Torvalds * If you increase the number of cached files very much, you'll need to 531da177e4SLinus Torvalds * add a hash table here. 541da177e4SLinus Torvalds */ 551da177e4SLinus Torvalds struct raparms { 561da177e4SLinus Torvalds struct raparms *p_next; 571da177e4SLinus Torvalds unsigned int p_count; 581da177e4SLinus Torvalds ino_t p_ino; 591da177e4SLinus Torvalds dev_t p_dev; 601da177e4SLinus Torvalds int p_set; 611da177e4SLinus Torvalds struct file_ra_state p_ra; 62fce1456aSGreg Banks unsigned int p_hindex; 631da177e4SLinus Torvalds }; 641da177e4SLinus Torvalds 65fce1456aSGreg Banks struct raparm_hbucket { 66fce1456aSGreg Banks struct raparms *pb_head; 67fce1456aSGreg Banks spinlock_t pb_lock; 68fce1456aSGreg Banks } ____cacheline_aligned_in_smp; 69fce1456aSGreg Banks 70fce1456aSGreg Banks #define RAPARM_HASH_BITS 4 71fce1456aSGreg Banks #define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS) 72fce1456aSGreg Banks #define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) 73fce1456aSGreg Banks static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds /* 761da177e4SLinus Torvalds * Called from nfsd_lookup and encode_dirent. Check if we have crossed 771da177e4SLinus Torvalds * a mount point. 78e0bb89efSJ.Bruce Fields * Returns -EAGAIN or -ETIMEDOUT leaving *dpp and *expp unchanged, 791da177e4SLinus Torvalds * or nfs_ok having possibly changed *dpp and *expp 801da177e4SLinus Torvalds */ 811da177e4SLinus Torvalds int 821da177e4SLinus Torvalds nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, 831da177e4SLinus Torvalds struct svc_export **expp) 841da177e4SLinus Torvalds { 851da177e4SLinus Torvalds struct svc_export *exp = *expp, *exp2 = NULL; 861da177e4SLinus Torvalds struct dentry *dentry = *dpp; 8791c9fa8fSAl Viro struct path path = {.mnt = mntget(exp->ex_path.mnt), 8891c9fa8fSAl Viro .dentry = dget(dentry)}; 896264d69dSAl Viro int err = 0; 901da177e4SLinus Torvalds 917cc90cc3SAl Viro err = follow_down(&path); 92cc53ce53SDavid Howells if (err < 0) 93cc53ce53SDavid Howells goto out; 941da177e4SLinus Torvalds 9591c9fa8fSAl Viro exp2 = rqst_exp_get_by_name(rqstp, &path); 961da177e4SLinus Torvalds if (IS_ERR(exp2)) { 971da177e4SLinus Torvalds err = PTR_ERR(exp2); 983b6cee7bSJ. Bruce Fields /* 993b6cee7bSJ. Bruce Fields * We normally allow NFS clients to continue 1003b6cee7bSJ. Bruce Fields * "underneath" a mountpoint that is not exported. 1013b6cee7bSJ. Bruce Fields * The exception is V4ROOT, where no traversal is ever 1023b6cee7bSJ. Bruce Fields * allowed without an explicit export of the new 1033b6cee7bSJ. Bruce Fields * directory. 1043b6cee7bSJ. Bruce Fields */ 1053b6cee7bSJ. Bruce Fields if (err == -ENOENT && !(exp->ex_flags & NFSEXP_V4ROOT)) 1063b6cee7bSJ. Bruce Fields err = 0; 10791c9fa8fSAl Viro path_put(&path); 1081da177e4SLinus Torvalds goto out; 1091da177e4SLinus Torvalds } 1103c394ddaSSteve Dickson if (nfsd_v4client(rqstp) || 1113c394ddaSSteve Dickson (exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) { 1121da177e4SLinus Torvalds /* successfully crossed mount point */ 1131644ccc8SAl Viro /* 11491c9fa8fSAl Viro * This is subtle: path.dentry is *not* on path.mnt 11591c9fa8fSAl Viro * at this point. The only reason we are safe is that 11691c9fa8fSAl Viro * original mnt is pinned down by exp, so we should 11791c9fa8fSAl Viro * put path *before* putting exp 1181644ccc8SAl Viro */ 11991c9fa8fSAl Viro *dpp = path.dentry; 12091c9fa8fSAl Viro path.dentry = dentry; 1211644ccc8SAl Viro *expp = exp2; 12291c9fa8fSAl Viro exp2 = exp; 1231da177e4SLinus Torvalds } 12491c9fa8fSAl Viro path_put(&path); 12591c9fa8fSAl Viro exp_put(exp2); 1261da177e4SLinus Torvalds out: 1271da177e4SLinus Torvalds return err; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 130289ede45SJ. Bruce Fields static void follow_to_parent(struct path *path) 131289ede45SJ. Bruce Fields { 132289ede45SJ. Bruce Fields struct dentry *dp; 133289ede45SJ. Bruce Fields 134289ede45SJ. Bruce Fields while (path->dentry == path->mnt->mnt_root && follow_up(path)) 135289ede45SJ. Bruce Fields ; 136289ede45SJ. Bruce Fields dp = dget_parent(path->dentry); 137289ede45SJ. Bruce Fields dput(path->dentry); 138289ede45SJ. Bruce Fields path->dentry = dp; 139289ede45SJ. Bruce Fields } 140289ede45SJ. Bruce Fields 141289ede45SJ. Bruce Fields static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, struct svc_export **exp, struct dentry **dentryp) 142289ede45SJ. Bruce Fields { 143289ede45SJ. Bruce Fields struct svc_export *exp2; 144289ede45SJ. Bruce Fields struct path path = {.mnt = mntget((*exp)->ex_path.mnt), 145289ede45SJ. Bruce Fields .dentry = dget(dparent)}; 146289ede45SJ. Bruce Fields 147289ede45SJ. Bruce Fields follow_to_parent(&path); 148289ede45SJ. Bruce Fields 149289ede45SJ. Bruce Fields exp2 = rqst_exp_parent(rqstp, &path); 150289ede45SJ. Bruce Fields if (PTR_ERR(exp2) == -ENOENT) { 151289ede45SJ. Bruce Fields *dentryp = dget(dparent); 152289ede45SJ. Bruce Fields } else if (IS_ERR(exp2)) { 153289ede45SJ. Bruce Fields path_put(&path); 154289ede45SJ. Bruce Fields return PTR_ERR(exp2); 155289ede45SJ. Bruce Fields } else { 156289ede45SJ. Bruce Fields *dentryp = dget(path.dentry); 157289ede45SJ. Bruce Fields exp_put(*exp); 158289ede45SJ. Bruce Fields *exp = exp2; 159289ede45SJ. Bruce Fields } 160289ede45SJ. Bruce Fields path_put(&path); 161289ede45SJ. Bruce Fields return 0; 162289ede45SJ. Bruce Fields } 163289ede45SJ. Bruce Fields 16482ead7feSJ. Bruce Fields /* 16582ead7feSJ. Bruce Fields * For nfsd purposes, we treat V4ROOT exports as though there was an 16682ead7feSJ. Bruce Fields * export at *every* directory. 16782ead7feSJ. Bruce Fields */ 1683227fa41SJ. Bruce Fields int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp) 16982ead7feSJ. Bruce Fields { 17082ead7feSJ. Bruce Fields if (d_mountpoint(dentry)) 17182ead7feSJ. Bruce Fields return 1; 17211fcee02STrond Myklebust if (nfsd4_is_junction(dentry)) 17311fcee02STrond Myklebust return 1; 17482ead7feSJ. Bruce Fields if (!(exp->ex_flags & NFSEXP_V4ROOT)) 17582ead7feSJ. Bruce Fields return 0; 17682ead7feSJ. Bruce Fields return dentry->d_inode != NULL; 17782ead7feSJ. Bruce Fields } 17882ead7feSJ. Bruce Fields 1796264d69dSAl Viro __be32 1806c0a654dSJ. Bruce Fields nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, 1815a022fc8SChuck Lever const char *name, unsigned int len, 1826c0a654dSJ. Bruce Fields struct svc_export **exp_ret, struct dentry **dentry_ret) 1831da177e4SLinus Torvalds { 1841da177e4SLinus Torvalds struct svc_export *exp; 1851da177e4SLinus Torvalds struct dentry *dparent; 1861da177e4SLinus Torvalds struct dentry *dentry; 1876264d69dSAl Viro int host_err; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds dparent = fhp->fh_dentry; 192bf18f163SKinglong Mee exp = exp_get(fhp->fh_export); 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /* Lookup the name, but don't follow links */ 1951da177e4SLinus Torvalds if (isdotent(name, len)) { 1961da177e4SLinus Torvalds if (len==1) 1971da177e4SLinus Torvalds dentry = dget(dparent); 19854775491SJan Blunck else if (dparent != exp->ex_path.dentry) 1991da177e4SLinus Torvalds dentry = dget_parent(dparent); 200fed83811SJ. Bruce Fields else if (!EX_NOHIDE(exp) && !nfsd_v4client(rqstp)) 2011da177e4SLinus Torvalds dentry = dget(dparent); /* .. == . just like at / */ 2021da177e4SLinus Torvalds else { 2031da177e4SLinus Torvalds /* checking mountpoint crossing is very different when stepping up */ 204289ede45SJ. Bruce Fields host_err = nfsd_lookup_parent(rqstp, dparent, &exp, &dentry); 205289ede45SJ. Bruce Fields if (host_err) 2061da177e4SLinus Torvalds goto out_nfserr; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds } else { 2094335723eSJ. Bruce Fields /* 2104335723eSJ. Bruce Fields * In the nfsd4_open() case, this may be held across 2114335723eSJ. Bruce Fields * subsequent open and delegation acquisition which may 2124335723eSJ. Bruce Fields * need to take the child's i_mutex: 2134335723eSJ. Bruce Fields */ 2144335723eSJ. Bruce Fields fh_lock_nested(fhp, I_MUTEX_PARENT); 2151da177e4SLinus Torvalds dentry = lookup_one_len(name, dparent, len); 2166264d69dSAl Viro host_err = PTR_ERR(dentry); 2171da177e4SLinus Torvalds if (IS_ERR(dentry)) 2181da177e4SLinus Torvalds goto out_nfserr; 2191da177e4SLinus Torvalds /* 2201da177e4SLinus Torvalds * check if we have crossed a mount point ... 2211da177e4SLinus Torvalds */ 22282ead7feSJ. Bruce Fields if (nfsd_mountpoint(dentry, exp)) { 2236264d69dSAl Viro if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { 2241da177e4SLinus Torvalds dput(dentry); 2251da177e4SLinus Torvalds goto out_nfserr; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds } 2296c0a654dSJ. Bruce Fields *dentry_ret = dentry; 2306c0a654dSJ. Bruce Fields *exp_ret = exp; 2316c0a654dSJ. Bruce Fields return 0; 2326c0a654dSJ. Bruce Fields 2336c0a654dSJ. Bruce Fields out_nfserr: 2346c0a654dSJ. Bruce Fields exp_put(exp); 2356c0a654dSJ. Bruce Fields return nfserrno(host_err); 2366c0a654dSJ. Bruce Fields } 2376c0a654dSJ. Bruce Fields 2386c0a654dSJ. Bruce Fields /* 2396c0a654dSJ. Bruce Fields * Look up one component of a pathname. 2406c0a654dSJ. Bruce Fields * N.B. After this call _both_ fhp and resfh need an fh_put 2416c0a654dSJ. Bruce Fields * 2426c0a654dSJ. Bruce Fields * If the lookup would cross a mountpoint, and the mounted filesystem 2436c0a654dSJ. Bruce Fields * is exported to the client with NFSEXP_NOHIDE, then the lookup is 2446c0a654dSJ. Bruce Fields * accepted as it stands and the mounted directory is 2456c0a654dSJ. Bruce Fields * returned. Otherwise the covered directory is returned. 2466c0a654dSJ. Bruce Fields * NOTE: this mountpoint crossing is not supported properly by all 2476c0a654dSJ. Bruce Fields * clients and is explicitly disallowed for NFSv3 2486c0a654dSJ. Bruce Fields * NeilBrown <neilb@cse.unsw.edu.au> 2496c0a654dSJ. Bruce Fields */ 2506c0a654dSJ. Bruce Fields __be32 2516c0a654dSJ. Bruce Fields nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, 2525a022fc8SChuck Lever unsigned int len, struct svc_fh *resfh) 2536c0a654dSJ. Bruce Fields { 2546c0a654dSJ. Bruce Fields struct svc_export *exp; 2556c0a654dSJ. Bruce Fields struct dentry *dentry; 2566c0a654dSJ. Bruce Fields __be32 err; 2576c0a654dSJ. Bruce Fields 25829a78a3eSJ. Bruce Fields err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); 25929a78a3eSJ. Bruce Fields if (err) 26029a78a3eSJ. Bruce Fields return err; 2616c0a654dSJ. Bruce Fields err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry); 2626c0a654dSJ. Bruce Fields if (err) 2636c0a654dSJ. Bruce Fields return err; 26432c1eb0cSAndy Adamson err = check_nfsd_access(exp, rqstp); 26532c1eb0cSAndy Adamson if (err) 26632c1eb0cSAndy Adamson goto out; 2671da177e4SLinus Torvalds /* 2681da177e4SLinus Torvalds * Note: we compose the file handle now, but as the 2691da177e4SLinus Torvalds * dentry may be negative, it may need to be updated. 2701da177e4SLinus Torvalds */ 2711da177e4SLinus Torvalds err = fh_compose(resfh, exp, dentry, fhp); 2721da177e4SLinus Torvalds if (!err && !dentry->d_inode) 2731da177e4SLinus Torvalds err = nfserr_noent; 27432c1eb0cSAndy Adamson out: 2751da177e4SLinus Torvalds dput(dentry); 2761da177e4SLinus Torvalds exp_put(exp); 2771da177e4SLinus Torvalds return err; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 280f501912aSBen Myers /* 281f501912aSBen Myers * Commit metadata changes to stable storage. 282f501912aSBen Myers */ 283f501912aSBen Myers static int 284f501912aSBen Myers commit_metadata(struct svc_fh *fhp) 285f501912aSBen Myers { 286f501912aSBen Myers struct inode *inode = fhp->fh_dentry->d_inode; 287f501912aSBen Myers const struct export_operations *export_ops = inode->i_sb->s_export_op; 288f501912aSBen Myers 289f501912aSBen Myers if (!EX_ISSYNC(fhp->fh_export)) 290f501912aSBen Myers return 0; 291f501912aSBen Myers 292c3765016SChristoph Hellwig if (export_ops->commit_metadata) 293c3765016SChristoph Hellwig return export_ops->commit_metadata(inode); 294c3765016SChristoph Hellwig return sync_inode_metadata(inode, 1); 295f501912aSBen Myers } 2966c0a654dSJ. Bruce Fields 2971da177e4SLinus Torvalds /* 298818e5a22SChristoph Hellwig * Go over the attributes and take care of the small differences between 299818e5a22SChristoph Hellwig * NFS semantics and what Linux expects. 300818e5a22SChristoph Hellwig */ 301818e5a22SChristoph Hellwig static void 302818e5a22SChristoph Hellwig nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) 303818e5a22SChristoph Hellwig { 304818e5a22SChristoph Hellwig /* 305818e5a22SChristoph Hellwig * NFSv2 does not differentiate between "set-[ac]time-to-now" 306818e5a22SChristoph Hellwig * which only requires access, and "set-[ac]time-to-X" which 307818e5a22SChristoph Hellwig * requires ownership. 308818e5a22SChristoph Hellwig * So if it looks like it might be "set both to the same time which 309818e5a22SChristoph Hellwig * is close to now", and if inode_change_ok fails, then we 310818e5a22SChristoph Hellwig * convert to "set to now" instead of "set to explicit time" 311818e5a22SChristoph Hellwig * 312818e5a22SChristoph Hellwig * We only call inode_change_ok as the last test as technically 313818e5a22SChristoph Hellwig * it is not an interface that we should be using. 314818e5a22SChristoph Hellwig */ 315818e5a22SChristoph Hellwig #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) 316818e5a22SChristoph Hellwig #define MAX_TOUCH_TIME_ERROR (30*60) 317818e5a22SChristoph Hellwig if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && 318818e5a22SChristoph Hellwig iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { 319818e5a22SChristoph Hellwig /* 320818e5a22SChristoph Hellwig * Looks probable. 321818e5a22SChristoph Hellwig * 322818e5a22SChristoph Hellwig * Now just make sure time is in the right ballpark. 323818e5a22SChristoph Hellwig * Solaris, at least, doesn't seem to care what the time 324818e5a22SChristoph Hellwig * request is. We require it be within 30 minutes of now. 325818e5a22SChristoph Hellwig */ 326818e5a22SChristoph Hellwig time_t delta = iap->ia_atime.tv_sec - get_seconds(); 327818e5a22SChristoph Hellwig if (delta < 0) 328818e5a22SChristoph Hellwig delta = -delta; 329818e5a22SChristoph Hellwig if (delta < MAX_TOUCH_TIME_ERROR && 330818e5a22SChristoph Hellwig inode_change_ok(inode, iap) != 0) { 331818e5a22SChristoph Hellwig /* 332818e5a22SChristoph Hellwig * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. 333818e5a22SChristoph Hellwig * This will cause notify_change to set these times 334818e5a22SChristoph Hellwig * to "now" 335818e5a22SChristoph Hellwig */ 336818e5a22SChristoph Hellwig iap->ia_valid &= ~BOTH_TIME_SET; 337818e5a22SChristoph Hellwig } 338818e5a22SChristoph Hellwig } 339818e5a22SChristoph Hellwig 340818e5a22SChristoph Hellwig /* sanitize the mode change */ 341818e5a22SChristoph Hellwig if (iap->ia_valid & ATTR_MODE) { 342818e5a22SChristoph Hellwig iap->ia_mode &= S_IALLUGO; 343818e5a22SChristoph Hellwig iap->ia_mode |= (inode->i_mode & ~S_IALLUGO); 344818e5a22SChristoph Hellwig } 345818e5a22SChristoph Hellwig 346818e5a22SChristoph Hellwig /* Revoke setuid/setgid on chown */ 347818e5a22SChristoph Hellwig if (!S_ISDIR(inode->i_mode) && 348c4fa6d7cSStanislav Kholmanskikh ((iap->ia_valid & ATTR_UID) || (iap->ia_valid & ATTR_GID))) { 349818e5a22SChristoph Hellwig iap->ia_valid |= ATTR_KILL_PRIV; 350818e5a22SChristoph Hellwig if (iap->ia_valid & ATTR_MODE) { 351818e5a22SChristoph Hellwig /* we're setting mode too, just clear the s*id bits */ 352818e5a22SChristoph Hellwig iap->ia_mode &= ~S_ISUID; 353818e5a22SChristoph Hellwig if (iap->ia_mode & S_IXGRP) 354818e5a22SChristoph Hellwig iap->ia_mode &= ~S_ISGID; 355818e5a22SChristoph Hellwig } else { 356818e5a22SChristoph Hellwig /* set ATTR_KILL_* bits and let VFS handle it */ 357818e5a22SChristoph Hellwig iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); 358818e5a22SChristoph Hellwig } 359818e5a22SChristoph Hellwig } 360818e5a22SChristoph Hellwig } 361818e5a22SChristoph Hellwig 362818e5a22SChristoph Hellwig static __be32 363818e5a22SChristoph Hellwig nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, 364818e5a22SChristoph Hellwig struct iattr *iap) 365818e5a22SChristoph Hellwig { 366818e5a22SChristoph Hellwig struct inode *inode = fhp->fh_dentry->d_inode; 367818e5a22SChristoph Hellwig int host_err; 368818e5a22SChristoph Hellwig 369818e5a22SChristoph Hellwig if (iap->ia_size < inode->i_size) { 370818e5a22SChristoph Hellwig __be32 err; 371818e5a22SChristoph Hellwig 372818e5a22SChristoph Hellwig err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 373818e5a22SChristoph Hellwig NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE); 374818e5a22SChristoph Hellwig if (err) 375818e5a22SChristoph Hellwig return err; 376818e5a22SChristoph Hellwig } 377818e5a22SChristoph Hellwig 378818e5a22SChristoph Hellwig host_err = get_write_access(inode); 379818e5a22SChristoph Hellwig if (host_err) 380818e5a22SChristoph Hellwig goto out_nfserrno; 381818e5a22SChristoph Hellwig 382818e5a22SChristoph Hellwig host_err = locks_verify_truncate(inode, NULL, iap->ia_size); 383818e5a22SChristoph Hellwig if (host_err) 384818e5a22SChristoph Hellwig goto out_put_write_access; 385818e5a22SChristoph Hellwig return 0; 386818e5a22SChristoph Hellwig 387818e5a22SChristoph Hellwig out_put_write_access: 388818e5a22SChristoph Hellwig put_write_access(inode); 389818e5a22SChristoph Hellwig out_nfserrno: 390818e5a22SChristoph Hellwig return nfserrno(host_err); 391818e5a22SChristoph Hellwig } 392818e5a22SChristoph Hellwig 393818e5a22SChristoph Hellwig /* 394818e5a22SChristoph Hellwig * Set various file attributes. After this call fhp needs an fh_put. 3951da177e4SLinus Torvalds */ 3966264d69dSAl Viro __be32 3971da177e4SLinus Torvalds nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, 3981da177e4SLinus Torvalds int check_guard, time_t guardtime) 3991da177e4SLinus Torvalds { 4001da177e4SLinus Torvalds struct dentry *dentry; 4011da177e4SLinus Torvalds struct inode *inode; 4028837abcaSMiklos Szeredi int accmode = NFSD_MAY_SATTR; 403175a4eb7SAl Viro umode_t ftype = 0; 4046264d69dSAl Viro __be32 err; 4056264d69dSAl Viro int host_err; 4069f67f189SJ. Bruce Fields bool get_write_count; 4071da177e4SLinus Torvalds int size_change = 0; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) 4108837abcaSMiklos Szeredi accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; 4111da177e4SLinus Torvalds if (iap->ia_valid & ATTR_SIZE) 4121da177e4SLinus Torvalds ftype = S_IFREG; 4131da177e4SLinus Torvalds 4149f67f189SJ. Bruce Fields /* Callers that do fh_verify should do the fh_want_write: */ 4159f67f189SJ. Bruce Fields get_write_count = !fhp->fh_dentry; 4169f67f189SJ. Bruce Fields 4171da177e4SLinus Torvalds /* Get inode */ 4181da177e4SLinus Torvalds err = fh_verify(rqstp, fhp, ftype, accmode); 41915b7a1b8SNeilBrown if (err) 4201da177e4SLinus Torvalds goto out; 4219f67f189SJ. Bruce Fields if (get_write_count) { 4229f67f189SJ. Bruce Fields host_err = fh_want_write(fhp); 4239f67f189SJ. Bruce Fields if (host_err) 4249f67f189SJ. Bruce Fields return nfserrno(host_err); 4259f67f189SJ. Bruce Fields } 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds dentry = fhp->fh_dentry; 4281da177e4SLinus Torvalds inode = dentry->d_inode; 4291da177e4SLinus Torvalds 43015b7a1b8SNeilBrown /* Ignore any mode updates on symlinks */ 43115b7a1b8SNeilBrown if (S_ISLNK(inode->i_mode)) 43215b7a1b8SNeilBrown iap->ia_valid &= ~ATTR_MODE; 43315b7a1b8SNeilBrown 43415b7a1b8SNeilBrown if (!iap->ia_valid) 43515b7a1b8SNeilBrown goto out; 43615b7a1b8SNeilBrown 437818e5a22SChristoph Hellwig nfsd_sanitize_attrs(inode, iap); 4381da177e4SLinus Torvalds 4399c85fca5SChristoph Hellwig /* 440818e5a22SChristoph Hellwig * The size case is special, it changes the file in addition to the 441818e5a22SChristoph Hellwig * attributes. 4429c85fca5SChristoph Hellwig */ 4431da177e4SLinus Torvalds if (iap->ia_valid & ATTR_SIZE) { 444818e5a22SChristoph Hellwig err = nfsd_get_write_access(rqstp, fhp, iap); 4451da177e4SLinus Torvalds if (err) 4461da177e4SLinus Torvalds goto out; 4471da177e4SLinus Torvalds size_change = 1; 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds iap->ia_valid |= ATTR_CTIME; 4511da177e4SLinus Torvalds 452987da479SChristoph Hellwig if (check_guard && guardtime != inode->i_ctime.tv_sec) { 4531da177e4SLinus Torvalds err = nfserr_notsync; 454987da479SChristoph Hellwig goto out_put_write_access; 455987da479SChristoph Hellwig } 456987da479SChristoph Hellwig 457987da479SChristoph Hellwig fh_lock(fhp); 45827ac0ffeSJ. Bruce Fields host_err = notify_change(dentry, iap, NULL); 4591da177e4SLinus Torvalds fh_unlock(fhp); 4601406b916SJ. R. Okajima err = nfserrno(host_err); 461987da479SChristoph Hellwig 462987da479SChristoph Hellwig out_put_write_access: 4631da177e4SLinus Torvalds if (size_change) 4641da177e4SLinus Torvalds put_write_access(inode); 4651da177e4SLinus Torvalds if (!err) 466b160fdabSChristoph Hellwig commit_metadata(fhp); 4671da177e4SLinus Torvalds out: 4681da177e4SLinus Torvalds return err; 4691da177e4SLinus Torvalds } 4701da177e4SLinus Torvalds 4715be196e5SChristoph Hellwig #if defined(CONFIG_NFSD_V4) 4729b4146e8SChuck Lever /* 4739b4146e8SChuck Lever * NFS junction information is stored in an extended attribute. 4749b4146e8SChuck Lever */ 4759b4146e8SChuck Lever #define NFSD_JUNCTION_XATTR_NAME XATTR_TRUSTED_PREFIX "junction.nfs" 4769b4146e8SChuck Lever 4779b4146e8SChuck Lever /** 4789b4146e8SChuck Lever * nfsd4_is_junction - Test if an object could be an NFS junction 4799b4146e8SChuck Lever * 4809b4146e8SChuck Lever * @dentry: object to test 4819b4146e8SChuck Lever * 4829b4146e8SChuck Lever * Returns 1 if "dentry" appears to contain NFS junction information. 4839b4146e8SChuck Lever * Otherwise 0 is returned. 4849b4146e8SChuck Lever */ 48511fcee02STrond Myklebust int nfsd4_is_junction(struct dentry *dentry) 48611fcee02STrond Myklebust { 48711fcee02STrond Myklebust struct inode *inode = dentry->d_inode; 48811fcee02STrond Myklebust 48911fcee02STrond Myklebust if (inode == NULL) 49011fcee02STrond Myklebust return 0; 49111fcee02STrond Myklebust if (inode->i_mode & S_IXUGO) 49211fcee02STrond Myklebust return 0; 49311fcee02STrond Myklebust if (!(inode->i_mode & S_ISVTX)) 49411fcee02STrond Myklebust return 0; 4959b4146e8SChuck Lever if (vfs_getxattr(dentry, NFSD_JUNCTION_XATTR_NAME, NULL, 0) <= 0) 49611fcee02STrond Myklebust return 0; 49711fcee02STrond Myklebust return 1; 49811fcee02STrond Myklebust } 49918032ca0SDavid Quigley #ifdef CONFIG_NFSD_V4_SECURITY_LABEL 50018032ca0SDavid Quigley __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, 50118032ca0SDavid Quigley struct xdr_netobj *label) 50218032ca0SDavid Quigley { 50318032ca0SDavid Quigley __be32 error; 50418032ca0SDavid Quigley int host_error; 50518032ca0SDavid Quigley struct dentry *dentry; 50618032ca0SDavid Quigley 50718032ca0SDavid Quigley error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); 50818032ca0SDavid Quigley if (error) 50918032ca0SDavid Quigley return error; 51018032ca0SDavid Quigley 51118032ca0SDavid Quigley dentry = fhp->fh_dentry; 51218032ca0SDavid Quigley 51318032ca0SDavid Quigley mutex_lock(&dentry->d_inode->i_mutex); 51418032ca0SDavid Quigley host_error = security_inode_setsecctx(dentry, label->data, label->len); 51518032ca0SDavid Quigley mutex_unlock(&dentry->d_inode->i_mutex); 51618032ca0SDavid Quigley return nfserrno(host_error); 51718032ca0SDavid Quigley } 51818032ca0SDavid Quigley #else 51918032ca0SDavid Quigley __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, 52018032ca0SDavid Quigley struct xdr_netobj *label) 52118032ca0SDavid Quigley { 52218032ca0SDavid Quigley return nfserr_notsupp; 52318032ca0SDavid Quigley } 52418032ca0SDavid Quigley #endif 52518032ca0SDavid Quigley 5266a85d6c7SJ. Bruce Fields #endif /* defined(CONFIG_NFSD_V4) */ 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds #ifdef CONFIG_NFSD_V3 5291da177e4SLinus Torvalds /* 5301da177e4SLinus Torvalds * Check server access rights to a file system object 5311da177e4SLinus Torvalds */ 5321da177e4SLinus Torvalds struct accessmap { 5331da177e4SLinus Torvalds u32 access; 5341da177e4SLinus Torvalds int how; 5351da177e4SLinus Torvalds }; 5361da177e4SLinus Torvalds static struct accessmap nfs3_regaccess[] = { 5378837abcaSMiklos Szeredi { NFS3_ACCESS_READ, NFSD_MAY_READ }, 5388837abcaSMiklos Szeredi { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC }, 5398837abcaSMiklos Szeredi { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_TRUNC }, 5408837abcaSMiklos Szeredi { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE }, 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds { 0, 0 } 5431da177e4SLinus Torvalds }; 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds static struct accessmap nfs3_diraccess[] = { 5468837abcaSMiklos Szeredi { NFS3_ACCESS_READ, NFSD_MAY_READ }, 5478837abcaSMiklos Szeredi { NFS3_ACCESS_LOOKUP, NFSD_MAY_EXEC }, 5488837abcaSMiklos Szeredi { NFS3_ACCESS_MODIFY, NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC}, 5498837abcaSMiklos Szeredi { NFS3_ACCESS_EXTEND, NFSD_MAY_EXEC|NFSD_MAY_WRITE }, 5508837abcaSMiklos Szeredi { NFS3_ACCESS_DELETE, NFSD_MAY_REMOVE }, 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds { 0, 0 } 5531da177e4SLinus Torvalds }; 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds static struct accessmap nfs3_anyaccess[] = { 5561da177e4SLinus Torvalds /* Some clients - Solaris 2.6 at least, make an access call 5571da177e4SLinus Torvalds * to the server to check for access for things like /dev/null 5581da177e4SLinus Torvalds * (which really, the server doesn't care about). So 5591da177e4SLinus Torvalds * We provide simple access checking for them, looking 5601da177e4SLinus Torvalds * mainly at mode bits, and we make sure to ignore read-only 5611da177e4SLinus Torvalds * filesystem checks 5621da177e4SLinus Torvalds */ 5638837abcaSMiklos Szeredi { NFS3_ACCESS_READ, NFSD_MAY_READ }, 5648837abcaSMiklos Szeredi { NFS3_ACCESS_EXECUTE, NFSD_MAY_EXEC }, 5658837abcaSMiklos Szeredi { NFS3_ACCESS_MODIFY, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS }, 5668837abcaSMiklos Szeredi { NFS3_ACCESS_EXTEND, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS }, 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds { 0, 0 } 5691da177e4SLinus Torvalds }; 5701da177e4SLinus Torvalds 5716264d69dSAl Viro __be32 5721da177e4SLinus Torvalds nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported) 5731da177e4SLinus Torvalds { 5741da177e4SLinus Torvalds struct accessmap *map; 5751da177e4SLinus Torvalds struct svc_export *export; 5761da177e4SLinus Torvalds struct dentry *dentry; 5771da177e4SLinus Torvalds u32 query, result = 0, sresult = 0; 5786264d69dSAl Viro __be32 error; 5791da177e4SLinus Torvalds 5808837abcaSMiklos Szeredi error = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); 5811da177e4SLinus Torvalds if (error) 5821da177e4SLinus Torvalds goto out; 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds export = fhp->fh_export; 5851da177e4SLinus Torvalds dentry = fhp->fh_dentry; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds if (S_ISREG(dentry->d_inode->i_mode)) 5881da177e4SLinus Torvalds map = nfs3_regaccess; 5891da177e4SLinus Torvalds else if (S_ISDIR(dentry->d_inode->i_mode)) 5901da177e4SLinus Torvalds map = nfs3_diraccess; 5911da177e4SLinus Torvalds else 5921da177e4SLinus Torvalds map = nfs3_anyaccess; 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds query = *access; 5961da177e4SLinus Torvalds for (; map->access; map++) { 5971da177e4SLinus Torvalds if (map->access & query) { 5986264d69dSAl Viro __be32 err2; 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds sresult |= map->access; 6011da177e4SLinus Torvalds 6020ec757dfSJ. Bruce Fields err2 = nfsd_permission(rqstp, export, dentry, map->how); 6031da177e4SLinus Torvalds switch (err2) { 6041da177e4SLinus Torvalds case nfs_ok: 6051da177e4SLinus Torvalds result |= map->access; 6061da177e4SLinus Torvalds break; 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds /* the following error codes just mean the access was not allowed, 6091da177e4SLinus Torvalds * rather than an error occurred */ 6101da177e4SLinus Torvalds case nfserr_rofs: 6111da177e4SLinus Torvalds case nfserr_acces: 6121da177e4SLinus Torvalds case nfserr_perm: 6131da177e4SLinus Torvalds /* simply don't "or" in the access bit. */ 6141da177e4SLinus Torvalds break; 6151da177e4SLinus Torvalds default: 6161da177e4SLinus Torvalds error = err2; 6171da177e4SLinus Torvalds goto out; 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds } 6201da177e4SLinus Torvalds } 6211da177e4SLinus Torvalds *access = result; 6221da177e4SLinus Torvalds if (supported) 6231da177e4SLinus Torvalds *supported = sresult; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds out: 6261da177e4SLinus Torvalds return error; 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds #endif /* CONFIG_NFSD_V3 */ 6291da177e4SLinus Torvalds 630105f4622SJ. Bruce Fields static int nfsd_open_break_lease(struct inode *inode, int access) 631105f4622SJ. Bruce Fields { 632105f4622SJ. Bruce Fields unsigned int mode; 6331da177e4SLinus Torvalds 634105f4622SJ. Bruce Fields if (access & NFSD_MAY_NOT_BREAK_LEASE) 635105f4622SJ. Bruce Fields return 0; 636105f4622SJ. Bruce Fields mode = (access & NFSD_MAY_WRITE) ? O_WRONLY : O_RDONLY; 637105f4622SJ. Bruce Fields return break_lease(inode, mode | O_NONBLOCK); 638105f4622SJ. Bruce Fields } 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds /* 6411da177e4SLinus Torvalds * Open an existing file or directory. 642999448a8SBernd Schubert * The may_flags argument indicates the type of open (read/write/lock) 643999448a8SBernd Schubert * and additional flags. 6441da177e4SLinus Torvalds * N.B. After this call fhp needs an fh_put 6451da177e4SLinus Torvalds */ 6466264d69dSAl Viro __be32 647175a4eb7SAl Viro nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, 648999448a8SBernd Schubert int may_flags, struct file **filp) 6491da177e4SLinus Torvalds { 650765927b2SAl Viro struct path path; 6511da177e4SLinus Torvalds struct inode *inode; 6526264d69dSAl Viro int flags = O_RDONLY|O_LARGEFILE; 6536264d69dSAl Viro __be32 err; 65491885258SJeff Layton int host_err = 0; 6551da177e4SLinus Torvalds 656e0e81739SDavid Howells validate_process_creds(); 657e0e81739SDavid Howells 6581da177e4SLinus Torvalds /* 6591da177e4SLinus Torvalds * If we get here, then the client has already done an "open", 6601da177e4SLinus Torvalds * and (hopefully) checked permission - so allow OWNER_OVERRIDE 6611da177e4SLinus Torvalds * in case a chmod has now revoked permission. 662d91d0b56SJ. Bruce Fields * 663d91d0b56SJ. Bruce Fields * Arguably we should also allow the owner override for 664d91d0b56SJ. Bruce Fields * directories, but we never have and it doesn't seem to have 665d91d0b56SJ. Bruce Fields * caused anyone a problem. If we were to change this, note 666d91d0b56SJ. Bruce Fields * also that our filldir callbacks would need a variant of 667d91d0b56SJ. Bruce Fields * lookup_one_len that doesn't check permissions. 6681da177e4SLinus Torvalds */ 669d91d0b56SJ. Bruce Fields if (type == S_IFREG) 670d91d0b56SJ. Bruce Fields may_flags |= NFSD_MAY_OWNER_OVERRIDE; 671d91d0b56SJ. Bruce Fields err = fh_verify(rqstp, fhp, type, may_flags); 6721da177e4SLinus Torvalds if (err) 6731da177e4SLinus Torvalds goto out; 6741da177e4SLinus Torvalds 675765927b2SAl Viro path.mnt = fhp->fh_export->ex_path.mnt; 676765927b2SAl Viro path.dentry = fhp->fh_dentry; 677765927b2SAl Viro inode = path.dentry->d_inode; 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds /* Disallow write access to files with the append-only bit set 6801da177e4SLinus Torvalds * or any access when mandatory locking enabled 6811da177e4SLinus Torvalds */ 6821da177e4SLinus Torvalds err = nfserr_perm; 683999448a8SBernd Schubert if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE)) 6841da177e4SLinus Torvalds goto out; 6855e7fc436SJ. Bruce Fields /* 6865e7fc436SJ. Bruce Fields * We must ignore files (but only files) which might have mandatory 6875e7fc436SJ. Bruce Fields * locks on them because there is no way to know if the accesser has 6885e7fc436SJ. Bruce Fields * the lock. 6895e7fc436SJ. Bruce Fields */ 6905e7fc436SJ. Bruce Fields if (S_ISREG((inode)->i_mode) && mandatory_lock(inode)) 6911da177e4SLinus Torvalds goto out; 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds if (!inode->i_fop) 6941da177e4SLinus Torvalds goto out; 6951da177e4SLinus Torvalds 696999448a8SBernd Schubert host_err = nfsd_open_break_lease(inode, may_flags); 6976264d69dSAl Viro if (host_err) /* NOMEM or WOULDBLOCK */ 6981da177e4SLinus Torvalds goto out_nfserr; 6991da177e4SLinus Torvalds 700999448a8SBernd Schubert if (may_flags & NFSD_MAY_WRITE) { 701999448a8SBernd Schubert if (may_flags & NFSD_MAY_READ) 7029ecb6a08SJ. Bruce Fields flags = O_RDWR|O_LARGEFILE; 7039ecb6a08SJ. Bruce Fields else 7041da177e4SLinus Torvalds flags = O_WRONLY|O_LARGEFILE; 7051da177e4SLinus Torvalds } 706765927b2SAl Viro *filp = dentry_open(&path, flags, current_cred()); 707e4daf1ffSHarshula Jayasuriya if (IS_ERR(*filp)) { 7086264d69dSAl Viro host_err = PTR_ERR(*filp); 709e4daf1ffSHarshula Jayasuriya *filp = NULL; 710e4daf1ffSHarshula Jayasuriya } else { 711999448a8SBernd Schubert host_err = ima_file_check(*filp, may_flags); 712999448a8SBernd Schubert 71306effdbbSBernd Schubert if (may_flags & NFSD_MAY_64BIT_COOKIE) 71406effdbbSBernd Schubert (*filp)->f_mode |= FMODE_64BITHASH; 715aeaa5ccdSChuck Ebbert else 71606effdbbSBernd Schubert (*filp)->f_mode |= FMODE_32BITHASH; 71706effdbbSBernd Schubert } 71806effdbbSBernd Schubert 7191da177e4SLinus Torvalds out_nfserr: 7206264d69dSAl Viro err = nfserrno(host_err); 7211da177e4SLinus Torvalds out: 722e0e81739SDavid Howells validate_process_creds(); 7231da177e4SLinus Torvalds return err; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds /* 7271da177e4SLinus Torvalds * Close a file. 7281da177e4SLinus Torvalds */ 7291da177e4SLinus Torvalds void 7301da177e4SLinus Torvalds nfsd_close(struct file *filp) 7311da177e4SLinus Torvalds { 7321da177e4SLinus Torvalds fput(filp); 7331da177e4SLinus Torvalds } 7341da177e4SLinus Torvalds 7359a8d248eSJ. Bruce Fields /* 7361da177e4SLinus Torvalds * Obtain the readahead parameters for the file 7371da177e4SLinus Torvalds * specified by (dev, ino). 7381da177e4SLinus Torvalds */ 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds static inline struct raparms * 7411da177e4SLinus Torvalds nfsd_get_raparms(dev_t dev, ino_t ino) 7421da177e4SLinus Torvalds { 7431da177e4SLinus Torvalds struct raparms *ra, **rap, **frap = NULL; 7441da177e4SLinus Torvalds int depth = 0; 745fce1456aSGreg Banks unsigned int hash; 746fce1456aSGreg Banks struct raparm_hbucket *rab; 7471da177e4SLinus Torvalds 748fce1456aSGreg Banks hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK; 749fce1456aSGreg Banks rab = &raparm_hash[hash]; 750fce1456aSGreg Banks 751fce1456aSGreg Banks spin_lock(&rab->pb_lock); 752fce1456aSGreg Banks for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) { 7531da177e4SLinus Torvalds if (ra->p_ino == ino && ra->p_dev == dev) 7541da177e4SLinus Torvalds goto found; 7551da177e4SLinus Torvalds depth++; 7561da177e4SLinus Torvalds if (ra->p_count == 0) 7571da177e4SLinus Torvalds frap = rap; 7581da177e4SLinus Torvalds } 7593aa6e0aaSKonstantin Khorenko depth = nfsdstats.ra_size; 7601da177e4SLinus Torvalds if (!frap) { 761fce1456aSGreg Banks spin_unlock(&rab->pb_lock); 7621da177e4SLinus Torvalds return NULL; 7631da177e4SLinus Torvalds } 7641da177e4SLinus Torvalds rap = frap; 7651da177e4SLinus Torvalds ra = *frap; 7661da177e4SLinus Torvalds ra->p_dev = dev; 7671da177e4SLinus Torvalds ra->p_ino = ino; 7681da177e4SLinus Torvalds ra->p_set = 0; 769fce1456aSGreg Banks ra->p_hindex = hash; 7701da177e4SLinus Torvalds found: 771fce1456aSGreg Banks if (rap != &rab->pb_head) { 7721da177e4SLinus Torvalds *rap = ra->p_next; 773fce1456aSGreg Banks ra->p_next = rab->pb_head; 774fce1456aSGreg Banks rab->pb_head = ra; 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds ra->p_count++; 7771da177e4SLinus Torvalds nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; 778fce1456aSGreg Banks spin_unlock(&rab->pb_lock); 7791da177e4SLinus Torvalds return ra; 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds /* 783cf8208d0SJens Axboe * Grab and keep cached pages associated with a file in the svc_rqst 784cf8208d0SJens Axboe * so that they can be passed to the network sendmsg/sendpage routines 785cf8208d0SJens Axboe * directly. They will be released after the sending has completed. 7861da177e4SLinus Torvalds */ 7871da177e4SLinus Torvalds static int 788cf8208d0SJens Axboe nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, 789cf8208d0SJens Axboe struct splice_desc *sd) 7901da177e4SLinus Torvalds { 791cf8208d0SJens Axboe struct svc_rqst *rqstp = sd->u.data; 792afc59400SJ. Bruce Fields struct page **pp = rqstp->rq_next_page; 793cf8208d0SJens Axboe struct page *page = buf->page; 794cf8208d0SJens Axboe size_t size; 795cf8208d0SJens Axboe 796cf8208d0SJens Axboe size = sd->len; 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds if (rqstp->rq_res.page_len == 0) { 7991da177e4SLinus Torvalds get_page(page); 800afc59400SJ. Bruce Fields put_page(*rqstp->rq_next_page); 801afc59400SJ. Bruce Fields *(rqstp->rq_next_page++) = page; 802cf8208d0SJens Axboe rqstp->rq_res.page_base = buf->offset; 8031da177e4SLinus Torvalds rqstp->rq_res.page_len = size; 80444524359SNeilBrown } else if (page != pp[-1]) { 8051da177e4SLinus Torvalds get_page(page); 806afc59400SJ. Bruce Fields if (*rqstp->rq_next_page) 807afc59400SJ. Bruce Fields put_page(*rqstp->rq_next_page); 808afc59400SJ. Bruce Fields *(rqstp->rq_next_page++) = page; 8091da177e4SLinus Torvalds rqstp->rq_res.page_len += size; 81044524359SNeilBrown } else 8111da177e4SLinus Torvalds rqstp->rq_res.page_len += size; 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds return size; 8141da177e4SLinus Torvalds } 8151da177e4SLinus Torvalds 816cf8208d0SJens Axboe static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe, 817cf8208d0SJens Axboe struct splice_desc *sd) 818cf8208d0SJens Axboe { 819cf8208d0SJens Axboe return __splice_from_pipe(pipe, sd, nfsd_splice_actor); 820cf8208d0SJens Axboe } 821cf8208d0SJens Axboe 822e2afc819SJeff Layton static __be32 823e2afc819SJeff Layton nfsd_finish_read(struct file *file, unsigned long *count, int host_err) 8241da177e4SLinus Torvalds { 825dc97618dSJ. Bruce Fields if (host_err >= 0) { 826dc97618dSJ. Bruce Fields nfsdstats.io_read += host_err; 827dc97618dSJ. Bruce Fields *count = host_err; 828dc97618dSJ. Bruce Fields fsnotify_access(file); 829dc97618dSJ. Bruce Fields return 0; 830dc97618dSJ. Bruce Fields } else 831dc97618dSJ. Bruce Fields return nfserrno(host_err); 832dc97618dSJ. Bruce Fields } 8331da177e4SLinus Torvalds 834e2afc819SJeff Layton __be32 nfsd_splice_read(struct svc_rqst *rqstp, 835dc97618dSJ. Bruce Fields struct file *file, loff_t offset, unsigned long *count) 836dc97618dSJ. Bruce Fields { 837cf8208d0SJens Axboe struct splice_desc sd = { 838cf8208d0SJens Axboe .len = 0, 839cf8208d0SJens Axboe .total_len = *count, 840cf8208d0SJens Axboe .pos = offset, 841cf8208d0SJens Axboe .u.data = rqstp, 842cf8208d0SJens Axboe }; 843dc97618dSJ. Bruce Fields int host_err; 844cf8208d0SJens Axboe 845afc59400SJ. Bruce Fields rqstp->rq_next_page = rqstp->rq_respages + 1; 846cf8208d0SJens Axboe host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor); 847dc97618dSJ. Bruce Fields return nfsd_finish_read(file, count, host_err); 848dc97618dSJ. Bruce Fields } 849dc97618dSJ. Bruce Fields 850e2afc819SJeff Layton __be32 nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen, 851dc97618dSJ. Bruce Fields unsigned long *count) 852dc97618dSJ. Bruce Fields { 853dc97618dSJ. Bruce Fields mm_segment_t oldfs; 854dc97618dSJ. Bruce Fields int host_err; 855dc97618dSJ. Bruce Fields 8561da177e4SLinus Torvalds oldfs = get_fs(); 8571da177e4SLinus Torvalds set_fs(KERNEL_DS); 8586264d69dSAl Viro host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset); 8591da177e4SLinus Torvalds set_fs(oldfs); 860dc97618dSJ. Bruce Fields return nfsd_finish_read(file, count, host_err); 8611da177e4SLinus Torvalds } 8621da177e4SLinus Torvalds 863dc97618dSJ. Bruce Fields static __be32 864dc97618dSJ. Bruce Fields nfsd_vfs_read(struct svc_rqst *rqstp, struct file *file, 865dc97618dSJ. Bruce Fields loff_t offset, struct kvec *vec, int vlen, unsigned long *count) 866dc97618dSJ. Bruce Fields { 867dc97618dSJ. Bruce Fields if (file->f_op->splice_read && rqstp->rq_splice_ok) 868dc97618dSJ. Bruce Fields return nfsd_splice_read(rqstp, file, offset, count); 869dc97618dSJ. Bruce Fields else 870dc97618dSJ. Bruce Fields return nfsd_readv(file, offset, vec, vlen, count); 8711da177e4SLinus Torvalds } 8721da177e4SLinus Torvalds 873d911df7bSJ. Bruce Fields /* 874d911df7bSJ. Bruce Fields * Gathered writes: If another process is currently writing to the file, 875d911df7bSJ. Bruce Fields * there's a high chance this is another nfsd (triggered by a bulk write 876d911df7bSJ. Bruce Fields * from a client's biod). Rather than syncing the file with each write 877d911df7bSJ. Bruce Fields * request, we sleep for 10 msec. 878d911df7bSJ. Bruce Fields * 879d911df7bSJ. Bruce Fields * I don't know if this roughly approximates C. Juszak's idea of 880d911df7bSJ. Bruce Fields * gathered writes, but it's a nice and simple solution (IMHO), and it 881d911df7bSJ. Bruce Fields * seems to work:-) 882d911df7bSJ. Bruce Fields * 883d911df7bSJ. Bruce Fields * Note: we do this only in the NFSv2 case, since v3 and higher have a 884d911df7bSJ. Bruce Fields * better tool (separate unstable writes and commits) for solving this 885d911df7bSJ. Bruce Fields * problem. 886d911df7bSJ. Bruce Fields */ 887d911df7bSJ. Bruce Fields static int wait_for_concurrent_writes(struct file *file) 888d911df7bSJ. Bruce Fields { 889496ad9aaSAl Viro struct inode *inode = file_inode(file); 890d911df7bSJ. Bruce Fields static ino_t last_ino; 891d911df7bSJ. Bruce Fields static dev_t last_dev; 892d911df7bSJ. Bruce Fields int err = 0; 893d911df7bSJ. Bruce Fields 894d911df7bSJ. Bruce Fields if (atomic_read(&inode->i_writecount) > 1 895d911df7bSJ. Bruce Fields || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { 896d911df7bSJ. Bruce Fields dprintk("nfsd: write defer %d\n", task_pid_nr(current)); 897d911df7bSJ. Bruce Fields msleep(10); 898d911df7bSJ. Bruce Fields dprintk("nfsd: write resume %d\n", task_pid_nr(current)); 899d911df7bSJ. Bruce Fields } 900d911df7bSJ. Bruce Fields 901d911df7bSJ. Bruce Fields if (inode->i_state & I_DIRTY) { 902d911df7bSJ. Bruce Fields dprintk("nfsd: write sync %d\n", task_pid_nr(current)); 9038018ab05SChristoph Hellwig err = vfs_fsync(file, 0); 904d911df7bSJ. Bruce Fields } 905d911df7bSJ. Bruce Fields last_ino = inode->i_ino; 906d911df7bSJ. Bruce Fields last_dev = inode->i_sb->s_dev; 907d911df7bSJ. Bruce Fields return err; 908d911df7bSJ. Bruce Fields } 909d911df7bSJ. Bruce Fields 9106264d69dSAl Viro static __be32 9111da177e4SLinus Torvalds nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, 9121da177e4SLinus Torvalds loff_t offset, struct kvec *vec, int vlen, 91331dec253SDavid Shaw unsigned long *cnt, int *stablep) 9141da177e4SLinus Torvalds { 9151da177e4SLinus Torvalds struct svc_export *exp; 9161da177e4SLinus Torvalds struct dentry *dentry; 9171da177e4SLinus Torvalds struct inode *inode; 9181da177e4SLinus Torvalds mm_segment_t oldfs; 9196264d69dSAl Viro __be32 err = 0; 9206264d69dSAl Viro int host_err; 9211da177e4SLinus Torvalds int stable = *stablep; 92248e03bc5STrond Myklebust int use_wgather; 923e49dbbf3SKent Overstreet loff_t pos = offset; 9248658452eSNeilBrown unsigned int pflags = current->flags; 9258658452eSNeilBrown 9268658452eSNeilBrown if (rqstp->rq_local) 9278658452eSNeilBrown /* 9288658452eSNeilBrown * We want less throttling in balance_dirty_pages() 9298658452eSNeilBrown * and shrink_inactive_list() so that nfs to 9308658452eSNeilBrown * localhost doesn't cause nfsd to lock up due to all 9318658452eSNeilBrown * the client's dirty pages or its congested queue. 9328658452eSNeilBrown */ 9338658452eSNeilBrown current->flags |= PF_LESS_THROTTLE; 9341da177e4SLinus Torvalds 9357eaa36e2SJosef "Jeff" Sipek dentry = file->f_path.dentry; 9361da177e4SLinus Torvalds inode = dentry->d_inode; 9371da177e4SLinus Torvalds exp = fhp->fh_export; 9381da177e4SLinus Torvalds 93948e03bc5STrond Myklebust use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds if (!EX_ISSYNC(exp)) 9421da177e4SLinus Torvalds stable = 0; 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds /* Write the data. */ 9451da177e4SLinus Torvalds oldfs = get_fs(); set_fs(KERNEL_DS); 946e49dbbf3SKent Overstreet host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &pos); 9471da177e4SLinus Torvalds set_fs(oldfs); 948e4636d53SJ. Bruce Fields if (host_err < 0) 949e4636d53SJ. Bruce Fields goto out_nfserr; 950a0d24b29SWei Yongjun *cnt = host_err; 95131dec253SDavid Shaw nfsdstats.io_write += host_err; 9522a12a9d7SEric Paris fsnotify_modify(file); 9531da177e4SLinus Torvalds 954face1502SJ. Bruce Fields if (stable) { 955face1502SJ. Bruce Fields if (use_wgather) 956d911df7bSJ. Bruce Fields host_err = wait_for_concurrent_writes(file); 957face1502SJ. Bruce Fields else 958face1502SJ. Bruce Fields host_err = vfs_fsync_range(file, offset, offset+*cnt, 0); 959face1502SJ. Bruce Fields } 9601da177e4SLinus Torvalds 961e4636d53SJ. Bruce Fields out_nfserr: 9626264d69dSAl Viro dprintk("nfsd: write complete host_err=%d\n", host_err); 963a0d24b29SWei Yongjun if (host_err >= 0) 9641da177e4SLinus Torvalds err = 0; 965a0d24b29SWei Yongjun else 9666264d69dSAl Viro err = nfserrno(host_err); 9678658452eSNeilBrown if (rqstp->rq_local) 9688658452eSNeilBrown tsk_restore_flags(current, pflags, PF_LESS_THROTTLE); 9691da177e4SLinus Torvalds return err; 9701da177e4SLinus Torvalds } 9711da177e4SLinus Torvalds 972dc97618dSJ. Bruce Fields __be32 nfsd_get_tmp_read_open(struct svc_rqst *rqstp, struct svc_fh *fhp, 973dc97618dSJ. Bruce Fields struct file **file, struct raparms **ra) 974fa0a2126SJ. Bruce Fields { 975fa0a2126SJ. Bruce Fields struct inode *inode; 976fa0a2126SJ. Bruce Fields __be32 err; 977fa0a2126SJ. Bruce Fields 978dc97618dSJ. Bruce Fields err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, file); 979fa0a2126SJ. Bruce Fields if (err) 980fa0a2126SJ. Bruce Fields return err; 981fa0a2126SJ. Bruce Fields 982dc97618dSJ. Bruce Fields inode = file_inode(*file); 983fa0a2126SJ. Bruce Fields 984fa0a2126SJ. Bruce Fields /* Get readahead parameters */ 985dc97618dSJ. Bruce Fields *ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino); 986fa0a2126SJ. Bruce Fields 987dc97618dSJ. Bruce Fields if (*ra && (*ra)->p_set) 988dc97618dSJ. Bruce Fields (*file)->f_ra = (*ra)->p_ra; 989dc97618dSJ. Bruce Fields return nfs_ok; 990dc97618dSJ. Bruce Fields } 991fa0a2126SJ. Bruce Fields 992dc97618dSJ. Bruce Fields void nfsd_put_tmp_read_open(struct file *file, struct raparms *ra) 993dc97618dSJ. Bruce Fields { 994fa0a2126SJ. Bruce Fields /* Write back readahead params */ 995fa0a2126SJ. Bruce Fields if (ra) { 996fa0a2126SJ. Bruce Fields struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; 997fa0a2126SJ. Bruce Fields spin_lock(&rab->pb_lock); 998fa0a2126SJ. Bruce Fields ra->p_ra = file->f_ra; 999fa0a2126SJ. Bruce Fields ra->p_set = 1; 1000fa0a2126SJ. Bruce Fields ra->p_count--; 1001fa0a2126SJ. Bruce Fields spin_unlock(&rab->pb_lock); 1002fa0a2126SJ. Bruce Fields } 1003fa0a2126SJ. Bruce Fields nfsd_close(file); 1004dc97618dSJ. Bruce Fields } 1005dc97618dSJ. Bruce Fields 1006dc97618dSJ. Bruce Fields /* 1007dc97618dSJ. Bruce Fields * Read data from a file. count must contain the requested read count 1008dc97618dSJ. Bruce Fields * on entry. On return, *count contains the number of bytes actually read. 1009dc97618dSJ. Bruce Fields * N.B. After this call fhp needs an fh_put 1010dc97618dSJ. Bruce Fields */ 1011dc97618dSJ. Bruce Fields __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, 1012dc97618dSJ. Bruce Fields loff_t offset, struct kvec *vec, int vlen, unsigned long *count) 1013dc97618dSJ. Bruce Fields { 1014dc97618dSJ. Bruce Fields struct file *file; 1015dc97618dSJ. Bruce Fields struct raparms *ra; 1016dc97618dSJ. Bruce Fields __be32 err; 1017dc97618dSJ. Bruce Fields 1018dc97618dSJ. Bruce Fields err = nfsd_get_tmp_read_open(rqstp, fhp, &file, &ra); 1019dc97618dSJ. Bruce Fields if (err) 1020dc97618dSJ. Bruce Fields return err; 1021dc97618dSJ. Bruce Fields 1022dc97618dSJ. Bruce Fields err = nfsd_vfs_read(rqstp, file, offset, vec, vlen, count); 1023dc97618dSJ. Bruce Fields 1024dc97618dSJ. Bruce Fields nfsd_put_tmp_read_open(file, ra); 1025dc97618dSJ. Bruce Fields 1026fa0a2126SJ. Bruce Fields return err; 1027fa0a2126SJ. Bruce Fields } 1028fa0a2126SJ. Bruce Fields 10291da177e4SLinus Torvalds /* 10301da177e4SLinus Torvalds * Write data to a file. 10311da177e4SLinus Torvalds * The stable flag requests synchronous writes. 10321da177e4SLinus Torvalds * N.B. After this call fhp needs an fh_put 10331da177e4SLinus Torvalds */ 10346264d69dSAl Viro __be32 10351da177e4SLinus Torvalds nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, 103631dec253SDavid Shaw loff_t offset, struct kvec *vec, int vlen, unsigned long *cnt, 10371da177e4SLinus Torvalds int *stablep) 10381da177e4SLinus Torvalds { 10396264d69dSAl Viro __be32 err = 0; 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds if (file) { 10420ec757dfSJ. Bruce Fields err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 10438837abcaSMiklos Szeredi NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE); 10441da177e4SLinus Torvalds if (err) 10451da177e4SLinus Torvalds goto out; 10461da177e4SLinus Torvalds err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, cnt, 10471da177e4SLinus Torvalds stablep); 10481da177e4SLinus Torvalds } else { 10498837abcaSMiklos Szeredi err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); 10501da177e4SLinus Torvalds if (err) 10511da177e4SLinus Torvalds goto out; 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds if (cnt) 10541da177e4SLinus Torvalds err = nfsd_vfs_write(rqstp, fhp, file, offset, vec, vlen, 10551da177e4SLinus Torvalds cnt, stablep); 10561da177e4SLinus Torvalds nfsd_close(file); 10571da177e4SLinus Torvalds } 10581da177e4SLinus Torvalds out: 10591da177e4SLinus Torvalds return err; 10601da177e4SLinus Torvalds } 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds #ifdef CONFIG_NFSD_V3 10631da177e4SLinus Torvalds /* 10641da177e4SLinus Torvalds * Commit all pending writes to stable storage. 1065aa696a6fSTrond Myklebust * 1066aa696a6fSTrond Myklebust * Note: we only guarantee that data that lies within the range specified 1067aa696a6fSTrond Myklebust * by the 'offset' and 'count' parameters will be synced. 10681da177e4SLinus Torvalds * 10691da177e4SLinus Torvalds * Unfortunately we cannot lock the file to make sure we return full WCC 10701da177e4SLinus Torvalds * data to the client, as locking happens lower down in the filesystem. 10711da177e4SLinus Torvalds */ 10726264d69dSAl Viro __be32 10731da177e4SLinus Torvalds nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, 10741da177e4SLinus Torvalds loff_t offset, unsigned long count) 10751da177e4SLinus Torvalds { 10761da177e4SLinus Torvalds struct file *file; 1077aa696a6fSTrond Myklebust loff_t end = LLONG_MAX; 1078aa696a6fSTrond Myklebust __be32 err = nfserr_inval; 10791da177e4SLinus Torvalds 1080aa696a6fSTrond Myklebust if (offset < 0) 1081aa696a6fSTrond Myklebust goto out; 1082aa696a6fSTrond Myklebust if (count != 0) { 1083aa696a6fSTrond Myklebust end = offset + (loff_t)count - 1; 1084aa696a6fSTrond Myklebust if (end < offset) 1085aa696a6fSTrond Myklebust goto out; 1086aa696a6fSTrond Myklebust } 10871da177e4SLinus Torvalds 108891885258SJeff Layton err = nfsd_open(rqstp, fhp, S_IFREG, 108991885258SJeff Layton NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &file); 10908837abcaSMiklos Szeredi if (err) 1091aa696a6fSTrond Myklebust goto out; 10921da177e4SLinus Torvalds if (EX_ISSYNC(fhp->fh_export)) { 10938018ab05SChristoph Hellwig int err2 = vfs_fsync_range(file, offset, end, 0); 1094aa696a6fSTrond Myklebust 1095aa696a6fSTrond Myklebust if (err2 != -EINVAL) 1096aa696a6fSTrond Myklebust err = nfserrno(err2); 1097aa696a6fSTrond Myklebust else 10981da177e4SLinus Torvalds err = nfserr_notsupp; 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds 11011da177e4SLinus Torvalds nfsd_close(file); 1102aa696a6fSTrond Myklebust out: 11031da177e4SLinus Torvalds return err; 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds #endif /* CONFIG_NFSD_V3 */ 11061da177e4SLinus Torvalds 1107f2b0dee2SAdrian Bunk static __be32 11085c002b3bSJ. Bruce Fields nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, 11095c002b3bSJ. Bruce Fields struct iattr *iap) 11105c002b3bSJ. Bruce Fields { 11115c002b3bSJ. Bruce Fields /* 11125c002b3bSJ. Bruce Fields * Mode has already been set earlier in create: 11135c002b3bSJ. Bruce Fields */ 11145c002b3bSJ. Bruce Fields iap->ia_valid &= ~ATTR_MODE; 11155c002b3bSJ. Bruce Fields /* 11165c002b3bSJ. Bruce Fields * Setting uid/gid works only for root. Irix appears to 11175c002b3bSJ. Bruce Fields * send along the gid on create when it tries to implement 11185c002b3bSJ. Bruce Fields * setgid directories via NFS: 11195c002b3bSJ. Bruce Fields */ 11206fab8779SEric W. Biederman if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) 11215c002b3bSJ. Bruce Fields iap->ia_valid &= ~(ATTR_UID|ATTR_GID); 11225c002b3bSJ. Bruce Fields if (iap->ia_valid) 11235c002b3bSJ. Bruce Fields return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); 11245c002b3bSJ. Bruce Fields return 0; 11255c002b3bSJ. Bruce Fields } 11265c002b3bSJ. Bruce Fields 11274ac35c2fSwengang wang /* HPUX client sometimes creates a file in mode 000, and sets size to 0. 11284ac35c2fSwengang wang * setting size to 0 may fail for some specific file systems by the permission 11294ac35c2fSwengang wang * checking which requires WRITE permission but the mode is 000. 11304ac35c2fSwengang wang * we ignore the resizing(to 0) on the just new created file, since the size is 11314ac35c2fSwengang wang * 0 after file created. 11324ac35c2fSwengang wang * 11334ac35c2fSwengang wang * call this only after vfs_create() is called. 11344ac35c2fSwengang wang * */ 11354ac35c2fSwengang wang static void 11364ac35c2fSwengang wang nfsd_check_ignore_resizing(struct iattr *iap) 11374ac35c2fSwengang wang { 11384ac35c2fSwengang wang if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) 11394ac35c2fSwengang wang iap->ia_valid &= ~ATTR_SIZE; 11404ac35c2fSwengang wang } 11414ac35c2fSwengang wang 11421da177e4SLinus Torvalds /* 11431da177e4SLinus Torvalds * Create a file (regular, directory, device, fifo); UNIX sockets 11441da177e4SLinus Torvalds * not yet implemented. 11451da177e4SLinus Torvalds * If the response fh has been verified, the parent directory should 11461da177e4SLinus Torvalds * already be locked. Note that the parent directory is left locked. 11471da177e4SLinus Torvalds * 11481da177e4SLinus Torvalds * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp 11491da177e4SLinus Torvalds */ 11506264d69dSAl Viro __be32 11511da177e4SLinus Torvalds nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, 11521da177e4SLinus Torvalds char *fname, int flen, struct iattr *iap, 11531da177e4SLinus Torvalds int type, dev_t rdev, struct svc_fh *resfhp) 11541da177e4SLinus Torvalds { 11551da177e4SLinus Torvalds struct dentry *dentry, *dchild = NULL; 11561da177e4SLinus Torvalds struct inode *dirp; 11576264d69dSAl Viro __be32 err; 11585c002b3bSJ. Bruce Fields __be32 err2; 11596264d69dSAl Viro int host_err; 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds err = nfserr_perm; 11621da177e4SLinus Torvalds if (!flen) 11631da177e4SLinus Torvalds goto out; 11641da177e4SLinus Torvalds err = nfserr_exist; 11651da177e4SLinus Torvalds if (isdotent(fname, flen)) 11661da177e4SLinus Torvalds goto out; 11671da177e4SLinus Torvalds 11688837abcaSMiklos Szeredi err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); 11691da177e4SLinus Torvalds if (err) 11701da177e4SLinus Torvalds goto out; 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds dentry = fhp->fh_dentry; 11731da177e4SLinus Torvalds dirp = dentry->d_inode; 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds err = nfserr_notdir; 1176acfa4380SAl Viro if (!dirp->i_op->lookup) 11771da177e4SLinus Torvalds goto out; 11781da177e4SLinus Torvalds /* 11791da177e4SLinus Torvalds * Check whether the response file handle has been verified yet. 11801da177e4SLinus Torvalds * If it has, the parent directory should already be locked. 11811da177e4SLinus Torvalds */ 11821da177e4SLinus Torvalds if (!resfhp->fh_dentry) { 11834a55c101SJan Kara host_err = fh_want_write(fhp); 11844a55c101SJan Kara if (host_err) 11854a55c101SJan Kara goto out_nfserr; 11864a55c101SJan Kara 11871da177e4SLinus Torvalds /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ 118812fd3520SPeter Zijlstra fh_lock_nested(fhp, I_MUTEX_PARENT); 11891da177e4SLinus Torvalds dchild = lookup_one_len(fname, dentry, flen); 11906264d69dSAl Viro host_err = PTR_ERR(dchild); 11911da177e4SLinus Torvalds if (IS_ERR(dchild)) 11921da177e4SLinus Torvalds goto out_nfserr; 11931da177e4SLinus Torvalds err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); 11941da177e4SLinus Torvalds if (err) 11951da177e4SLinus Torvalds goto out; 11961da177e4SLinus Torvalds } else { 11971da177e4SLinus Torvalds /* called from nfsd_proc_create */ 11981da177e4SLinus Torvalds dchild = dget(resfhp->fh_dentry); 11991da177e4SLinus Torvalds if (!fhp->fh_locked) { 12001da177e4SLinus Torvalds /* not actually possible */ 12011da177e4SLinus Torvalds printk(KERN_ERR 1202a6a9f18fSAl Viro "nfsd_create: parent %pd2 not locked!\n", 1203a6a9f18fSAl Viro dentry); 1204d75f2b9fSAl Viro err = nfserr_io; 12051da177e4SLinus Torvalds goto out; 12061da177e4SLinus Torvalds } 12071da177e4SLinus Torvalds } 12081da177e4SLinus Torvalds /* 12091da177e4SLinus Torvalds * Make sure the child dentry is still negative ... 12101da177e4SLinus Torvalds */ 12111da177e4SLinus Torvalds err = nfserr_exist; 12121da177e4SLinus Torvalds if (dchild->d_inode) { 1213a6a9f18fSAl Viro dprintk("nfsd_create: dentry %pd/%pd not negative!\n", 1214a6a9f18fSAl Viro dentry, dchild); 12151da177e4SLinus Torvalds goto out; 12161da177e4SLinus Torvalds } 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds if (!(iap->ia_valid & ATTR_MODE)) 12191da177e4SLinus Torvalds iap->ia_mode = 0; 12201da177e4SLinus Torvalds iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type; 12211da177e4SLinus Torvalds 122207cad1d2SMiklos Szeredi err = nfserr_inval; 122307cad1d2SMiklos Szeredi if (!S_ISREG(type) && !S_ISDIR(type) && !special_file(type)) { 122407cad1d2SMiklos Szeredi printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n", 122507cad1d2SMiklos Szeredi type); 122607cad1d2SMiklos Szeredi goto out; 122707cad1d2SMiklos Szeredi } 122807cad1d2SMiklos Szeredi 12291da177e4SLinus Torvalds /* 12301da177e4SLinus Torvalds * Get the dir op function pointer. 12311da177e4SLinus Torvalds */ 1232088406bcSJ. Bruce Fields err = 0; 12334a55c101SJan Kara host_err = 0; 12341da177e4SLinus Torvalds switch (type) { 12351da177e4SLinus Torvalds case S_IFREG: 1236312b63fbSAl Viro host_err = vfs_create(dirp, dchild, iap->ia_mode, true); 12374ac35c2fSwengang wang if (!host_err) 12384ac35c2fSwengang wang nfsd_check_ignore_resizing(iap); 12391da177e4SLinus Torvalds break; 12401da177e4SLinus Torvalds case S_IFDIR: 12416264d69dSAl Viro host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); 12421da177e4SLinus Torvalds break; 12431da177e4SLinus Torvalds case S_IFCHR: 12441da177e4SLinus Torvalds case S_IFBLK: 12451da177e4SLinus Torvalds case S_IFIFO: 12461da177e4SLinus Torvalds case S_IFSOCK: 12476264d69dSAl Viro host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); 12481da177e4SLinus Torvalds break; 1249463c3197SDave Hansen } 12504a55c101SJan Kara if (host_err < 0) 1251463c3197SDave Hansen goto out_nfserr; 12521da177e4SLinus Torvalds 1253f501912aSBen Myers err = nfsd_create_setattr(rqstp, resfhp, iap); 12541da177e4SLinus Torvalds 1255f501912aSBen Myers /* 1256f501912aSBen Myers * nfsd_setattr already committed the child. Transactional filesystems 1257f501912aSBen Myers * had a chance to commit changes for both parent and child 1258f501912aSBen Myers * simultaneously making the following commit_metadata a noop. 1259f501912aSBen Myers */ 1260f501912aSBen Myers err2 = nfserrno(commit_metadata(fhp)); 1261f193fbabSYAMAMOTO Takashi if (err2) 1262f193fbabSYAMAMOTO Takashi err = err2; 12631da177e4SLinus Torvalds /* 12641da177e4SLinus Torvalds * Update the file handle to get the new inode info. 12651da177e4SLinus Torvalds */ 12661da177e4SLinus Torvalds if (!err) 12671da177e4SLinus Torvalds err = fh_update(resfhp); 12681da177e4SLinus Torvalds out: 12691da177e4SLinus Torvalds if (dchild && !IS_ERR(dchild)) 12701da177e4SLinus Torvalds dput(dchild); 12711da177e4SLinus Torvalds return err; 12721da177e4SLinus Torvalds 12731da177e4SLinus Torvalds out_nfserr: 12746264d69dSAl Viro err = nfserrno(host_err); 12751da177e4SLinus Torvalds goto out; 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds #ifdef CONFIG_NFSD_V3 1279ac6721a1SMi Jinlong 1280ac6721a1SMi Jinlong static inline int nfsd_create_is_exclusive(int createmode) 1281ac6721a1SMi Jinlong { 1282ac6721a1SMi Jinlong return createmode == NFS3_CREATE_EXCLUSIVE 1283ac6721a1SMi Jinlong || createmode == NFS4_CREATE_EXCLUSIVE4_1; 1284ac6721a1SMi Jinlong } 1285ac6721a1SMi Jinlong 12861da177e4SLinus Torvalds /* 1287ac6721a1SMi Jinlong * NFSv3 and NFSv4 version of nfsd_create 12881da177e4SLinus Torvalds */ 12896264d69dSAl Viro __be32 1290ac6721a1SMi Jinlong do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, 12911da177e4SLinus Torvalds char *fname, int flen, struct iattr *iap, 12921da177e4SLinus Torvalds struct svc_fh *resfhp, int createmode, u32 *verifier, 1293856121b2SJ. Bruce Fields bool *truncp, bool *created) 12941da177e4SLinus Torvalds { 12951da177e4SLinus Torvalds struct dentry *dentry, *dchild = NULL; 12961da177e4SLinus Torvalds struct inode *dirp; 12976264d69dSAl Viro __be32 err; 12986264d69dSAl Viro int host_err; 12991da177e4SLinus Torvalds __u32 v_mtime=0, v_atime=0; 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds err = nfserr_perm; 13021da177e4SLinus Torvalds if (!flen) 13031da177e4SLinus Torvalds goto out; 13041da177e4SLinus Torvalds err = nfserr_exist; 13051da177e4SLinus Torvalds if (isdotent(fname, flen)) 13061da177e4SLinus Torvalds goto out; 13071da177e4SLinus Torvalds if (!(iap->ia_valid & ATTR_MODE)) 13081da177e4SLinus Torvalds iap->ia_mode = 0; 13091574dff8SSachin Prabhu err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); 13101da177e4SLinus Torvalds if (err) 13111da177e4SLinus Torvalds goto out; 13121da177e4SLinus Torvalds 13131da177e4SLinus Torvalds dentry = fhp->fh_dentry; 13141da177e4SLinus Torvalds dirp = dentry->d_inode; 13151da177e4SLinus Torvalds 13161da177e4SLinus Torvalds /* Get all the sanity checks out of the way before 13171da177e4SLinus Torvalds * we lock the parent. */ 13181da177e4SLinus Torvalds err = nfserr_notdir; 1319acfa4380SAl Viro if (!dirp->i_op->lookup) 13201da177e4SLinus Torvalds goto out; 13214a55c101SJan Kara 13224a55c101SJan Kara host_err = fh_want_write(fhp); 13234a55c101SJan Kara if (host_err) 13244a55c101SJan Kara goto out_nfserr; 13254a55c101SJan Kara 132612fd3520SPeter Zijlstra fh_lock_nested(fhp, I_MUTEX_PARENT); 13271da177e4SLinus Torvalds 13281da177e4SLinus Torvalds /* 13291da177e4SLinus Torvalds * Compose the response file handle. 13301da177e4SLinus Torvalds */ 13311da177e4SLinus Torvalds dchild = lookup_one_len(fname, dentry, flen); 13326264d69dSAl Viro host_err = PTR_ERR(dchild); 13331da177e4SLinus Torvalds if (IS_ERR(dchild)) 13341da177e4SLinus Torvalds goto out_nfserr; 13351da177e4SLinus Torvalds 13361574dff8SSachin Prabhu /* If file doesn't exist, check for permissions to create one */ 13371574dff8SSachin Prabhu if (!dchild->d_inode) { 13381574dff8SSachin Prabhu err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); 13391574dff8SSachin Prabhu if (err) 13401574dff8SSachin Prabhu goto out; 13411574dff8SSachin Prabhu } 13421574dff8SSachin Prabhu 13431da177e4SLinus Torvalds err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); 13441da177e4SLinus Torvalds if (err) 13451da177e4SLinus Torvalds goto out; 13461da177e4SLinus Torvalds 1347ac6721a1SMi Jinlong if (nfsd_create_is_exclusive(createmode)) { 1348c397852cSPeter Staubach /* solaris7 gets confused (bugid 4218508) if these have 1349749997e5SJeff Layton * the high bit set, so just clear the high bits. If this is 1350749997e5SJeff Layton * ever changed to use different attrs for storing the 1351749997e5SJeff Layton * verifier, then do_open_lookup() will also need to be fixed 1352749997e5SJeff Layton * accordingly. 13531da177e4SLinus Torvalds */ 13541da177e4SLinus Torvalds v_mtime = verifier[0]&0x7fffffff; 13551da177e4SLinus Torvalds v_atime = verifier[1]&0x7fffffff; 13561da177e4SLinus Torvalds } 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds if (dchild->d_inode) { 13591da177e4SLinus Torvalds err = 0; 13601da177e4SLinus Torvalds 13611da177e4SLinus Torvalds switch (createmode) { 13621da177e4SLinus Torvalds case NFS3_CREATE_UNCHECKED: 13631da177e4SLinus Torvalds if (! S_ISREG(dchild->d_inode->i_mode)) 13649dc4e6c4SJ. Bruce Fields goto out; 13651da177e4SLinus Torvalds else if (truncp) { 13661da177e4SLinus Torvalds /* in nfsv4, we need to treat this case a little 13671da177e4SLinus Torvalds * differently. we don't want to truncate the 13681da177e4SLinus Torvalds * file now; this would be wrong if the OPEN 13691da177e4SLinus Torvalds * fails for some other reason. furthermore, 13701da177e4SLinus Torvalds * if the size is nonzero, we should ignore it 13711da177e4SLinus Torvalds * according to spec! 13721da177e4SLinus Torvalds */ 13731da177e4SLinus Torvalds *truncp = (iap->ia_valid & ATTR_SIZE) && !iap->ia_size; 13741da177e4SLinus Torvalds } 13751da177e4SLinus Torvalds else { 13761da177e4SLinus Torvalds iap->ia_valid &= ATTR_SIZE; 13771da177e4SLinus Torvalds goto set_attr; 13781da177e4SLinus Torvalds } 13791da177e4SLinus Torvalds break; 13801da177e4SLinus Torvalds case NFS3_CREATE_EXCLUSIVE: 13811da177e4SLinus Torvalds if ( dchild->d_inode->i_mtime.tv_sec == v_mtime 13821da177e4SLinus Torvalds && dchild->d_inode->i_atime.tv_sec == v_atime 13837007c90fSNeil Brown && dchild->d_inode->i_size == 0 ) { 13847007c90fSNeil Brown if (created) 13857007c90fSNeil Brown *created = 1; 13861da177e4SLinus Torvalds break; 13877007c90fSNeil Brown } 1388ac6721a1SMi Jinlong case NFS4_CREATE_EXCLUSIVE4_1: 1389ac6721a1SMi Jinlong if ( dchild->d_inode->i_mtime.tv_sec == v_mtime 1390ac6721a1SMi Jinlong && dchild->d_inode->i_atime.tv_sec == v_atime 13917007c90fSNeil Brown && dchild->d_inode->i_size == 0 ) { 13927007c90fSNeil Brown if (created) 13937007c90fSNeil Brown *created = 1; 1394ac6721a1SMi Jinlong goto set_attr; 13957007c90fSNeil Brown } 13961da177e4SLinus Torvalds /* fallthru */ 13971da177e4SLinus Torvalds case NFS3_CREATE_GUARDED: 13981da177e4SLinus Torvalds err = nfserr_exist; 13991da177e4SLinus Torvalds } 1400bad0dcffSAl Viro fh_drop_write(fhp); 14011da177e4SLinus Torvalds goto out; 14021da177e4SLinus Torvalds } 14031da177e4SLinus Torvalds 1404312b63fbSAl Viro host_err = vfs_create(dirp, dchild, iap->ia_mode, true); 1405463c3197SDave Hansen if (host_err < 0) { 1406bad0dcffSAl Viro fh_drop_write(fhp); 14071da177e4SLinus Torvalds goto out_nfserr; 1408463c3197SDave Hansen } 140981ac95c5SJ. Bruce Fields if (created) 141081ac95c5SJ. Bruce Fields *created = 1; 14111da177e4SLinus Torvalds 14124ac35c2fSwengang wang nfsd_check_ignore_resizing(iap); 14134ac35c2fSwengang wang 1414ac6721a1SMi Jinlong if (nfsd_create_is_exclusive(createmode)) { 1415c397852cSPeter Staubach /* Cram the verifier into atime/mtime */ 14161da177e4SLinus Torvalds iap->ia_valid = ATTR_MTIME|ATTR_ATIME 1417c397852cSPeter Staubach | ATTR_MTIME_SET|ATTR_ATIME_SET; 14181da177e4SLinus Torvalds /* XXX someone who knows this better please fix it for nsec */ 14191da177e4SLinus Torvalds iap->ia_mtime.tv_sec = v_mtime; 14201da177e4SLinus Torvalds iap->ia_atime.tv_sec = v_atime; 14211da177e4SLinus Torvalds iap->ia_mtime.tv_nsec = 0; 14221da177e4SLinus Torvalds iap->ia_atime.tv_nsec = 0; 14231da177e4SLinus Torvalds } 14241da177e4SLinus Torvalds 14251da177e4SLinus Torvalds set_attr: 1426f501912aSBen Myers err = nfsd_create_setattr(rqstp, resfhp, iap); 1427f501912aSBen Myers 1428f501912aSBen Myers /* 1429f501912aSBen Myers * nfsd_setattr already committed the child (and possibly also the parent). 1430f501912aSBen Myers */ 1431f501912aSBen Myers if (!err) 1432f501912aSBen Myers err = nfserrno(commit_metadata(fhp)); 1433f193fbabSYAMAMOTO Takashi 1434f193fbabSYAMAMOTO Takashi /* 1435f193fbabSYAMAMOTO Takashi * Update the filehandle to get the new inode info. 1436f193fbabSYAMAMOTO Takashi */ 1437f193fbabSYAMAMOTO Takashi if (!err) 1438f193fbabSYAMAMOTO Takashi err = fh_update(resfhp); 14391da177e4SLinus Torvalds 14401da177e4SLinus Torvalds out: 14411da177e4SLinus Torvalds fh_unlock(fhp); 14421da177e4SLinus Torvalds if (dchild && !IS_ERR(dchild)) 14431da177e4SLinus Torvalds dput(dchild); 14444a55c101SJan Kara fh_drop_write(fhp); 14451da177e4SLinus Torvalds return err; 14461da177e4SLinus Torvalds 14471da177e4SLinus Torvalds out_nfserr: 14486264d69dSAl Viro err = nfserrno(host_err); 14491da177e4SLinus Torvalds goto out; 14501da177e4SLinus Torvalds } 14511da177e4SLinus Torvalds #endif /* CONFIG_NFSD_V3 */ 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds /* 14541da177e4SLinus Torvalds * Read a symlink. On entry, *lenp must contain the maximum path length that 14551da177e4SLinus Torvalds * fits into the buffer. On return, it contains the true length. 14561da177e4SLinus Torvalds * N.B. After this call fhp needs an fh_put 14571da177e4SLinus Torvalds */ 14586264d69dSAl Viro __be32 14591da177e4SLinus Torvalds nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) 14601da177e4SLinus Torvalds { 14611da177e4SLinus Torvalds struct inode *inode; 14621da177e4SLinus Torvalds mm_segment_t oldfs; 14636264d69dSAl Viro __be32 err; 14646264d69dSAl Viro int host_err; 146568ac1234SAl Viro struct path path; 14661da177e4SLinus Torvalds 14678837abcaSMiklos Szeredi err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP); 14681da177e4SLinus Torvalds if (err) 14691da177e4SLinus Torvalds goto out; 14701da177e4SLinus Torvalds 147168ac1234SAl Viro path.mnt = fhp->fh_export->ex_path.mnt; 147268ac1234SAl Viro path.dentry = fhp->fh_dentry; 147368ac1234SAl Viro inode = path.dentry->d_inode; 14741da177e4SLinus Torvalds 14751da177e4SLinus Torvalds err = nfserr_inval; 1476acfa4380SAl Viro if (!inode->i_op->readlink) 14771da177e4SLinus Torvalds goto out; 14781da177e4SLinus Torvalds 147968ac1234SAl Viro touch_atime(&path); 14801da177e4SLinus Torvalds /* N.B. Why does this call need a get_fs()?? 14811da177e4SLinus Torvalds * Remove the set_fs and watch the fireworks:-) --okir 14821da177e4SLinus Torvalds */ 14831da177e4SLinus Torvalds 14841da177e4SLinus Torvalds oldfs = get_fs(); set_fs(KERNEL_DS); 1485fac7a17bSJ. Bruce Fields host_err = inode->i_op->readlink(path.dentry, (char __user *)buf, *lenp); 14861da177e4SLinus Torvalds set_fs(oldfs); 14871da177e4SLinus Torvalds 14886264d69dSAl Viro if (host_err < 0) 14891da177e4SLinus Torvalds goto out_nfserr; 14906264d69dSAl Viro *lenp = host_err; 14911da177e4SLinus Torvalds err = 0; 14921da177e4SLinus Torvalds out: 14931da177e4SLinus Torvalds return err; 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds out_nfserr: 14966264d69dSAl Viro err = nfserrno(host_err); 14971da177e4SLinus Torvalds goto out; 14981da177e4SLinus Torvalds } 14991da177e4SLinus Torvalds 15001da177e4SLinus Torvalds /* 15011da177e4SLinus Torvalds * Create a symlink and look up its inode 15021da177e4SLinus Torvalds * N.B. After this call _both_ fhp and resfhp need an fh_put 15031da177e4SLinus Torvalds */ 15046264d69dSAl Viro __be32 15051da177e4SLinus Torvalds nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, 15061da177e4SLinus Torvalds char *fname, int flen, 1507*52ee0433SJ. Bruce Fields char *path, 15081da177e4SLinus Torvalds struct svc_fh *resfhp, 15091da177e4SLinus Torvalds struct iattr *iap) 15101da177e4SLinus Torvalds { 15111da177e4SLinus Torvalds struct dentry *dentry, *dnew; 15126264d69dSAl Viro __be32 err, cerr; 15136264d69dSAl Viro int host_err; 15141da177e4SLinus Torvalds 15151da177e4SLinus Torvalds err = nfserr_noent; 1516*52ee0433SJ. Bruce Fields if (!flen || path[0] == '\0') 15171da177e4SLinus Torvalds goto out; 15181da177e4SLinus Torvalds err = nfserr_exist; 15191da177e4SLinus Torvalds if (isdotent(fname, flen)) 15201da177e4SLinus Torvalds goto out; 15211da177e4SLinus Torvalds 15228837abcaSMiklos Szeredi err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); 15231da177e4SLinus Torvalds if (err) 15241da177e4SLinus Torvalds goto out; 15254a55c101SJan Kara 15264a55c101SJan Kara host_err = fh_want_write(fhp); 15274a55c101SJan Kara if (host_err) 15284a55c101SJan Kara goto out_nfserr; 15294a55c101SJan Kara 15301da177e4SLinus Torvalds fh_lock(fhp); 15311da177e4SLinus Torvalds dentry = fhp->fh_dentry; 15321da177e4SLinus Torvalds dnew = lookup_one_len(fname, dentry, flen); 15336264d69dSAl Viro host_err = PTR_ERR(dnew); 15341da177e4SLinus Torvalds if (IS_ERR(dnew)) 15351da177e4SLinus Torvalds goto out_nfserr; 15361da177e4SLinus Torvalds 1537db2e747bSMiklos Szeredi host_err = vfs_symlink(dentry->d_inode, dnew, path); 15386264d69dSAl Viro err = nfserrno(host_err); 1539f501912aSBen Myers if (!err) 1540f501912aSBen Myers err = nfserrno(commit_metadata(fhp)); 15411da177e4SLinus Torvalds fh_unlock(fhp); 15421da177e4SLinus Torvalds 1543bad0dcffSAl Viro fh_drop_write(fhp); 154475c3f29dSDave Hansen 15451da177e4SLinus Torvalds cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); 15461da177e4SLinus Torvalds dput(dnew); 15471da177e4SLinus Torvalds if (err==0) err = cerr; 15481da177e4SLinus Torvalds out: 15491da177e4SLinus Torvalds return err; 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds out_nfserr: 15526264d69dSAl Viro err = nfserrno(host_err); 15531da177e4SLinus Torvalds goto out; 15541da177e4SLinus Torvalds } 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds /* 15571da177e4SLinus Torvalds * Create a hardlink 15581da177e4SLinus Torvalds * N.B. After this call _both_ ffhp and tfhp need an fh_put 15591da177e4SLinus Torvalds */ 15606264d69dSAl Viro __be32 15611da177e4SLinus Torvalds nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, 15621da177e4SLinus Torvalds char *name, int len, struct svc_fh *tfhp) 15631da177e4SLinus Torvalds { 15641da177e4SLinus Torvalds struct dentry *ddir, *dnew, *dold; 156555b13354SJ. Bruce Fields struct inode *dirp; 15666264d69dSAl Viro __be32 err; 15676264d69dSAl Viro int host_err; 15681da177e4SLinus Torvalds 15698837abcaSMiklos Szeredi err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE); 15701da177e4SLinus Torvalds if (err) 15711da177e4SLinus Torvalds goto out; 15727d818a7bSJ. Bruce Fields err = fh_verify(rqstp, tfhp, 0, NFSD_MAY_NOP); 15731da177e4SLinus Torvalds if (err) 15741da177e4SLinus Torvalds goto out; 15757d818a7bSJ. Bruce Fields err = nfserr_isdir; 15767d818a7bSJ. Bruce Fields if (S_ISDIR(tfhp->fh_dentry->d_inode->i_mode)) 15777d818a7bSJ. Bruce Fields goto out; 15781da177e4SLinus Torvalds err = nfserr_perm; 15791da177e4SLinus Torvalds if (!len) 15801da177e4SLinus Torvalds goto out; 15811da177e4SLinus Torvalds err = nfserr_exist; 15821da177e4SLinus Torvalds if (isdotent(name, len)) 15831da177e4SLinus Torvalds goto out; 15841da177e4SLinus Torvalds 15854a55c101SJan Kara host_err = fh_want_write(tfhp); 15864a55c101SJan Kara if (host_err) { 15874a55c101SJan Kara err = nfserrno(host_err); 15884a55c101SJan Kara goto out; 15894a55c101SJan Kara } 15904a55c101SJan Kara 159112fd3520SPeter Zijlstra fh_lock_nested(ffhp, I_MUTEX_PARENT); 15921da177e4SLinus Torvalds ddir = ffhp->fh_dentry; 15931da177e4SLinus Torvalds dirp = ddir->d_inode; 15941da177e4SLinus Torvalds 15951da177e4SLinus Torvalds dnew = lookup_one_len(name, ddir, len); 15966264d69dSAl Viro host_err = PTR_ERR(dnew); 15971da177e4SLinus Torvalds if (IS_ERR(dnew)) 15981da177e4SLinus Torvalds goto out_nfserr; 15991da177e4SLinus Torvalds 16001da177e4SLinus Torvalds dold = tfhp->fh_dentry; 16011da177e4SLinus Torvalds 16024795bb37SJ. Bruce Fields err = nfserr_noent; 16034795bb37SJ. Bruce Fields if (!dold->d_inode) 16044a55c101SJan Kara goto out_dput; 1605146a8595SJ. Bruce Fields host_err = vfs_link(dold, dirp, dnew, NULL); 16066264d69dSAl Viro if (!host_err) { 1607f501912aSBen Myers err = nfserrno(commit_metadata(ffhp)); 1608f501912aSBen Myers if (!err) 1609f501912aSBen Myers err = nfserrno(commit_metadata(tfhp)); 16101da177e4SLinus Torvalds } else { 16116264d69dSAl Viro if (host_err == -EXDEV && rqstp->rq_vers == 2) 16121da177e4SLinus Torvalds err = nfserr_acces; 16131da177e4SLinus Torvalds else 16146264d69dSAl Viro err = nfserrno(host_err); 16151da177e4SLinus Torvalds } 161675c3f29dSDave Hansen out_dput: 16171da177e4SLinus Torvalds dput(dnew); 1618270d56e5SDavid M. Richter out_unlock: 1619270d56e5SDavid M. Richter fh_unlock(ffhp); 16204a55c101SJan Kara fh_drop_write(tfhp); 16211da177e4SLinus Torvalds out: 16221da177e4SLinus Torvalds return err; 16231da177e4SLinus Torvalds 16241da177e4SLinus Torvalds out_nfserr: 16256264d69dSAl Viro err = nfserrno(host_err); 1626270d56e5SDavid M. Richter goto out_unlock; 16271da177e4SLinus Torvalds } 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds /* 16301da177e4SLinus Torvalds * Rename a file 16311da177e4SLinus Torvalds * N.B. After this call _both_ ffhp and tfhp need an fh_put 16321da177e4SLinus Torvalds */ 16336264d69dSAl Viro __be32 16341da177e4SLinus Torvalds nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, 16351da177e4SLinus Torvalds struct svc_fh *tfhp, char *tname, int tlen) 16361da177e4SLinus Torvalds { 16371da177e4SLinus Torvalds struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap; 16381da177e4SLinus Torvalds struct inode *fdir, *tdir; 16396264d69dSAl Viro __be32 err; 16406264d69dSAl Viro int host_err; 16411da177e4SLinus Torvalds 16428837abcaSMiklos Szeredi err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_REMOVE); 16431da177e4SLinus Torvalds if (err) 16441da177e4SLinus Torvalds goto out; 16458837abcaSMiklos Szeredi err = fh_verify(rqstp, tfhp, S_IFDIR, NFSD_MAY_CREATE); 16461da177e4SLinus Torvalds if (err) 16471da177e4SLinus Torvalds goto out; 16481da177e4SLinus Torvalds 16491da177e4SLinus Torvalds fdentry = ffhp->fh_dentry; 16501da177e4SLinus Torvalds fdir = fdentry->d_inode; 16511da177e4SLinus Torvalds 16521da177e4SLinus Torvalds tdentry = tfhp->fh_dentry; 16531da177e4SLinus Torvalds tdir = tdentry->d_inode; 16541da177e4SLinus Torvalds 16551da177e4SLinus Torvalds err = nfserr_perm; 16561da177e4SLinus Torvalds if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen)) 16571da177e4SLinus Torvalds goto out; 16581da177e4SLinus Torvalds 16594a55c101SJan Kara host_err = fh_want_write(ffhp); 16604a55c101SJan Kara if (host_err) { 16614a55c101SJan Kara err = nfserrno(host_err); 16624a55c101SJan Kara goto out; 16634a55c101SJan Kara } 16644a55c101SJan Kara 16651da177e4SLinus Torvalds /* cannot use fh_lock as we need deadlock protective ordering 16661da177e4SLinus Torvalds * so do it by hand */ 16671da177e4SLinus Torvalds trap = lock_rename(tdentry, fdentry); 16681da177e4SLinus Torvalds ffhp->fh_locked = tfhp->fh_locked = 1; 16691da177e4SLinus Torvalds fill_pre_wcc(ffhp); 16701da177e4SLinus Torvalds fill_pre_wcc(tfhp); 16711da177e4SLinus Torvalds 16721da177e4SLinus Torvalds odentry = lookup_one_len(fname, fdentry, flen); 16736264d69dSAl Viro host_err = PTR_ERR(odentry); 16741da177e4SLinus Torvalds if (IS_ERR(odentry)) 16751da177e4SLinus Torvalds goto out_nfserr; 16761da177e4SLinus Torvalds 16776264d69dSAl Viro host_err = -ENOENT; 16781da177e4SLinus Torvalds if (!odentry->d_inode) 16791da177e4SLinus Torvalds goto out_dput_old; 16806264d69dSAl Viro host_err = -EINVAL; 16811da177e4SLinus Torvalds if (odentry == trap) 16821da177e4SLinus Torvalds goto out_dput_old; 16831da177e4SLinus Torvalds 16841da177e4SLinus Torvalds ndentry = lookup_one_len(tname, tdentry, tlen); 16856264d69dSAl Viro host_err = PTR_ERR(ndentry); 16861da177e4SLinus Torvalds if (IS_ERR(ndentry)) 16871da177e4SLinus Torvalds goto out_dput_old; 16886264d69dSAl Viro host_err = -ENOTEMPTY; 16891da177e4SLinus Torvalds if (ndentry == trap) 16901da177e4SLinus Torvalds goto out_dput_new; 16911da177e4SLinus Torvalds 16929079b1ebSDave Hansen host_err = -EXDEV; 16939079b1ebSDave Hansen if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) 16949079b1ebSDave Hansen goto out_dput_new; 1695aa387d6cSJ. Bruce Fields if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry) 1696aa387d6cSJ. Bruce Fields goto out_dput_new; 16979079b1ebSDave Hansen 1698520c8b16SMiklos Szeredi host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0); 1699f501912aSBen Myers if (!host_err) { 1700f501912aSBen Myers host_err = commit_metadata(tfhp); 17016264d69dSAl Viro if (!host_err) 1702f501912aSBen Myers host_err = commit_metadata(ffhp); 17031da177e4SLinus Torvalds } 17041da177e4SLinus Torvalds out_dput_new: 17051da177e4SLinus Torvalds dput(ndentry); 17061da177e4SLinus Torvalds out_dput_old: 17071da177e4SLinus Torvalds dput(odentry); 17081da177e4SLinus Torvalds out_nfserr: 17096264d69dSAl Viro err = nfserrno(host_err); 1710fbb74a34SJ. Bruce Fields /* 1711fbb74a34SJ. Bruce Fields * We cannot rely on fh_unlock on the two filehandles, 17121da177e4SLinus Torvalds * as that would do the wrong thing if the two directories 1713fbb74a34SJ. Bruce Fields * were the same, so again we do it by hand. 17141da177e4SLinus Torvalds */ 17151da177e4SLinus Torvalds fill_post_wcc(ffhp); 17161da177e4SLinus Torvalds fill_post_wcc(tfhp); 17171da177e4SLinus Torvalds unlock_rename(tdentry, fdentry); 17181da177e4SLinus Torvalds ffhp->fh_locked = tfhp->fh_locked = 0; 17194a55c101SJan Kara fh_drop_write(ffhp); 17201da177e4SLinus Torvalds 17211da177e4SLinus Torvalds out: 17221da177e4SLinus Torvalds return err; 17231da177e4SLinus Torvalds } 17241da177e4SLinus Torvalds 17251da177e4SLinus Torvalds /* 17261da177e4SLinus Torvalds * Unlink a file or directory 17271da177e4SLinus Torvalds * N.B. After this call fhp needs an fh_put 17281da177e4SLinus Torvalds */ 17296264d69dSAl Viro __be32 17301da177e4SLinus Torvalds nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, 17311da177e4SLinus Torvalds char *fname, int flen) 17321da177e4SLinus Torvalds { 17331da177e4SLinus Torvalds struct dentry *dentry, *rdentry; 17341da177e4SLinus Torvalds struct inode *dirp; 17356264d69dSAl Viro __be32 err; 17366264d69dSAl Viro int host_err; 17371da177e4SLinus Torvalds 17381da177e4SLinus Torvalds err = nfserr_acces; 17391da177e4SLinus Torvalds if (!flen || isdotent(fname, flen)) 17401da177e4SLinus Torvalds goto out; 17418837abcaSMiklos Szeredi err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_REMOVE); 17421da177e4SLinus Torvalds if (err) 17431da177e4SLinus Torvalds goto out; 17441da177e4SLinus Torvalds 17454a55c101SJan Kara host_err = fh_want_write(fhp); 17464a55c101SJan Kara if (host_err) 17474a55c101SJan Kara goto out_nfserr; 17484a55c101SJan Kara 174912fd3520SPeter Zijlstra fh_lock_nested(fhp, I_MUTEX_PARENT); 17501da177e4SLinus Torvalds dentry = fhp->fh_dentry; 17511da177e4SLinus Torvalds dirp = dentry->d_inode; 17521da177e4SLinus Torvalds 17531da177e4SLinus Torvalds rdentry = lookup_one_len(fname, dentry, flen); 17546264d69dSAl Viro host_err = PTR_ERR(rdentry); 17551da177e4SLinus Torvalds if (IS_ERR(rdentry)) 17561da177e4SLinus Torvalds goto out_nfserr; 17571da177e4SLinus Torvalds 17581da177e4SLinus Torvalds if (!rdentry->d_inode) { 17591da177e4SLinus Torvalds dput(rdentry); 17601da177e4SLinus Torvalds err = nfserr_noent; 17611da177e4SLinus Torvalds goto out; 17621da177e4SLinus Torvalds } 17631da177e4SLinus Torvalds 17641da177e4SLinus Torvalds if (!type) 17651da177e4SLinus Torvalds type = rdentry->d_inode->i_mode & S_IFMT; 17661da177e4SLinus Torvalds 17679ce137eeSJ. Bruce Fields if (type != S_IFDIR) 1768b21996e3SJ. Bruce Fields host_err = vfs_unlink(dirp, rdentry, NULL); 17699ce137eeSJ. Bruce Fields else 17706264d69dSAl Viro host_err = vfs_rmdir(dirp, rdentry); 1771541ce98cSJ. Bruce Fields if (!host_err) 1772541ce98cSJ. Bruce Fields host_err = commit_metadata(fhp); 17731da177e4SLinus Torvalds dput(rdentry); 17741da177e4SLinus Torvalds 17751da177e4SLinus Torvalds out_nfserr: 17766264d69dSAl Viro err = nfserrno(host_err); 1777f193fbabSYAMAMOTO Takashi out: 1778f193fbabSYAMAMOTO Takashi return err; 17791da177e4SLinus Torvalds } 17801da177e4SLinus Torvalds 17811da177e4SLinus Torvalds /* 178214f7dd63SDavid Woodhouse * We do this buffering because we must not call back into the file 178314f7dd63SDavid Woodhouse * system's ->lookup() method from the filldir callback. That may well 178414f7dd63SDavid Woodhouse * deadlock a number of file systems. 178514f7dd63SDavid Woodhouse * 178614f7dd63SDavid Woodhouse * This is based heavily on the implementation of same in XFS. 178714f7dd63SDavid Woodhouse */ 178814f7dd63SDavid Woodhouse struct buffered_dirent { 178914f7dd63SDavid Woodhouse u64 ino; 179014f7dd63SDavid Woodhouse loff_t offset; 179114f7dd63SDavid Woodhouse int namlen; 179214f7dd63SDavid Woodhouse unsigned int d_type; 179314f7dd63SDavid Woodhouse char name[]; 179414f7dd63SDavid Woodhouse }; 179514f7dd63SDavid Woodhouse 179614f7dd63SDavid Woodhouse struct readdir_data { 17975c0ba4e0SAl Viro struct dir_context ctx; 179814f7dd63SDavid Woodhouse char *dirent; 179914f7dd63SDavid Woodhouse size_t used; 180053c9c5c0SAl Viro int full; 180114f7dd63SDavid Woodhouse }; 180214f7dd63SDavid Woodhouse 180314f7dd63SDavid Woodhouse static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen, 180414f7dd63SDavid Woodhouse loff_t offset, u64 ino, unsigned int d_type) 180514f7dd63SDavid Woodhouse { 180614f7dd63SDavid Woodhouse struct readdir_data *buf = __buf; 180714f7dd63SDavid Woodhouse struct buffered_dirent *de = (void *)(buf->dirent + buf->used); 180814f7dd63SDavid Woodhouse unsigned int reclen; 180914f7dd63SDavid Woodhouse 181014f7dd63SDavid Woodhouse reclen = ALIGN(sizeof(struct buffered_dirent) + namlen, sizeof(u64)); 181153c9c5c0SAl Viro if (buf->used + reclen > PAGE_SIZE) { 181253c9c5c0SAl Viro buf->full = 1; 181314f7dd63SDavid Woodhouse return -EINVAL; 181453c9c5c0SAl Viro } 181514f7dd63SDavid Woodhouse 181614f7dd63SDavid Woodhouse de->namlen = namlen; 181714f7dd63SDavid Woodhouse de->offset = offset; 181814f7dd63SDavid Woodhouse de->ino = ino; 181914f7dd63SDavid Woodhouse de->d_type = d_type; 182014f7dd63SDavid Woodhouse memcpy(de->name, name, namlen); 182114f7dd63SDavid Woodhouse buf->used += reclen; 182214f7dd63SDavid Woodhouse 182314f7dd63SDavid Woodhouse return 0; 182414f7dd63SDavid Woodhouse } 182514f7dd63SDavid Woodhouse 18262f9092e1SDavid Woodhouse static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func, 18272628b766SDavid Woodhouse struct readdir_cd *cdp, loff_t *offsetp) 18282628b766SDavid Woodhouse { 182914f7dd63SDavid Woodhouse struct buffered_dirent *de; 18302628b766SDavid Woodhouse int host_err; 183114f7dd63SDavid Woodhouse int size; 183214f7dd63SDavid Woodhouse loff_t offset; 1833ac6614b7SAl Viro struct readdir_data buf = { 1834ac6614b7SAl Viro .ctx.actor = nfsd_buffered_filldir, 1835ac6614b7SAl Viro .dirent = (void *)__get_free_page(GFP_KERNEL) 1836ac6614b7SAl Viro }; 18372628b766SDavid Woodhouse 183814f7dd63SDavid Woodhouse if (!buf.dirent) 18392f9092e1SDavid Woodhouse return nfserrno(-ENOMEM); 184014f7dd63SDavid Woodhouse 184114f7dd63SDavid Woodhouse offset = *offsetp; 18422628b766SDavid Woodhouse 184314f7dd63SDavid Woodhouse while (1) { 1844496ad9aaSAl Viro struct inode *dir_inode = file_inode(file); 184514f7dd63SDavid Woodhouse unsigned int reclen; 184614f7dd63SDavid Woodhouse 1847b726e923SDoug Nazar cdp->err = nfserr_eof; /* will be cleared on successful read */ 184814f7dd63SDavid Woodhouse buf.used = 0; 184953c9c5c0SAl Viro buf.full = 0; 185014f7dd63SDavid Woodhouse 18515c0ba4e0SAl Viro host_err = iterate_dir(file, &buf.ctx); 185253c9c5c0SAl Viro if (buf.full) 185353c9c5c0SAl Viro host_err = 0; 185453c9c5c0SAl Viro 185553c9c5c0SAl Viro if (host_err < 0) 185614f7dd63SDavid Woodhouse break; 185714f7dd63SDavid Woodhouse 185814f7dd63SDavid Woodhouse size = buf.used; 185914f7dd63SDavid Woodhouse 186014f7dd63SDavid Woodhouse if (!size) 186114f7dd63SDavid Woodhouse break; 186214f7dd63SDavid Woodhouse 18632f9092e1SDavid Woodhouse /* 18642f9092e1SDavid Woodhouse * Various filldir functions may end up calling back into 18652f9092e1SDavid Woodhouse * lookup_one_len() and the file system's ->lookup() method. 18662f9092e1SDavid Woodhouse * These expect i_mutex to be held, as it would within readdir. 18672f9092e1SDavid Woodhouse */ 18682f9092e1SDavid Woodhouse host_err = mutex_lock_killable(&dir_inode->i_mutex); 18692f9092e1SDavid Woodhouse if (host_err) 18702f9092e1SDavid Woodhouse break; 18712f9092e1SDavid Woodhouse 187214f7dd63SDavid Woodhouse de = (struct buffered_dirent *)buf.dirent; 187314f7dd63SDavid Woodhouse while (size > 0) { 187414f7dd63SDavid Woodhouse offset = de->offset; 187514f7dd63SDavid Woodhouse 187614f7dd63SDavid Woodhouse if (func(cdp, de->name, de->namlen, de->offset, 187714f7dd63SDavid Woodhouse de->ino, de->d_type)) 18782f9092e1SDavid Woodhouse break; 187914f7dd63SDavid Woodhouse 188014f7dd63SDavid Woodhouse if (cdp->err != nfs_ok) 18812f9092e1SDavid Woodhouse break; 188214f7dd63SDavid Woodhouse 188314f7dd63SDavid Woodhouse reclen = ALIGN(sizeof(*de) + de->namlen, 188414f7dd63SDavid Woodhouse sizeof(u64)); 188514f7dd63SDavid Woodhouse size -= reclen; 188614f7dd63SDavid Woodhouse de = (struct buffered_dirent *)((char *)de + reclen); 188714f7dd63SDavid Woodhouse } 18882f9092e1SDavid Woodhouse mutex_unlock(&dir_inode->i_mutex); 18892f9092e1SDavid Woodhouse if (size > 0) /* We bailed out early */ 18902f9092e1SDavid Woodhouse break; 18912f9092e1SDavid Woodhouse 1892c002a6c7SDavid Woodhouse offset = vfs_llseek(file, 0, SEEK_CUR); 189314f7dd63SDavid Woodhouse } 189414f7dd63SDavid Woodhouse 189514f7dd63SDavid Woodhouse free_page((unsigned long)(buf.dirent)); 18962628b766SDavid Woodhouse 18972628b766SDavid Woodhouse if (host_err) 18982628b766SDavid Woodhouse return nfserrno(host_err); 189914f7dd63SDavid Woodhouse 190014f7dd63SDavid Woodhouse *offsetp = offset; 19012628b766SDavid Woodhouse return cdp->err; 19022628b766SDavid Woodhouse } 19032628b766SDavid Woodhouse 19041da177e4SLinus Torvalds /* 19051da177e4SLinus Torvalds * Read entries from a directory. 19061da177e4SLinus Torvalds * The NFSv3/4 verifier we ignore for now. 19071da177e4SLinus Torvalds */ 19086264d69dSAl Viro __be32 19091da177e4SLinus Torvalds nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, 1910a0ad13efSNeilBrown struct readdir_cd *cdp, filldir_t func) 19111da177e4SLinus Torvalds { 19126264d69dSAl Viro __be32 err; 19131da177e4SLinus Torvalds struct file *file; 19141da177e4SLinus Torvalds loff_t offset = *offsetp; 191506effdbbSBernd Schubert int may_flags = NFSD_MAY_READ; 19161da177e4SLinus Torvalds 191706effdbbSBernd Schubert /* NFSv2 only supports 32 bit cookies */ 191806effdbbSBernd Schubert if (rqstp->rq_vers > 2) 191906effdbbSBernd Schubert may_flags |= NFSD_MAY_64BIT_COOKIE; 192006effdbbSBernd Schubert 192106effdbbSBernd Schubert err = nfsd_open(rqstp, fhp, S_IFDIR, may_flags, &file); 19221da177e4SLinus Torvalds if (err) 19231da177e4SLinus Torvalds goto out; 19241da177e4SLinus Torvalds 1925b108fe6bSJeff Layton offset = vfs_llseek(file, offset, SEEK_SET); 19261da177e4SLinus Torvalds if (offset < 0) { 19271da177e4SLinus Torvalds err = nfserrno((int)offset); 19281da177e4SLinus Torvalds goto out_close; 19291da177e4SLinus Torvalds } 19301da177e4SLinus Torvalds 193114f7dd63SDavid Woodhouse err = nfsd_buffered_readdir(file, func, cdp, offsetp); 19321da177e4SLinus Torvalds 19331da177e4SLinus Torvalds if (err == nfserr_eof || err == nfserr_toosmall) 19341da177e4SLinus Torvalds err = nfs_ok; /* can still be found in ->err */ 19351da177e4SLinus Torvalds out_close: 19361da177e4SLinus Torvalds nfsd_close(file); 19371da177e4SLinus Torvalds out: 19381da177e4SLinus Torvalds return err; 19391da177e4SLinus Torvalds } 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds /* 19421da177e4SLinus Torvalds * Get file system stats 19431da177e4SLinus Torvalds * N.B. After this call fhp needs an fh_put 19441da177e4SLinus Torvalds */ 19456264d69dSAl Viro __be32 194604716e66SJ. Bruce Fields nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access) 19471da177e4SLinus Torvalds { 1948f6360efbSTakashi Iwai __be32 err; 1949f6360efbSTakashi Iwai 1950f6360efbSTakashi Iwai err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access); 1951f6360efbSTakashi Iwai if (!err) { 1952ebabe9a9SChristoph Hellwig struct path path = { 1953ebabe9a9SChristoph Hellwig .mnt = fhp->fh_export->ex_path.mnt, 1954ebabe9a9SChristoph Hellwig .dentry = fhp->fh_dentry, 1955ebabe9a9SChristoph Hellwig }; 1956f6360efbSTakashi Iwai if (vfs_statfs(&path, stat)) 19571da177e4SLinus Torvalds err = nfserr_io; 1958f6360efbSTakashi Iwai } 19591da177e4SLinus Torvalds return err; 19601da177e4SLinus Torvalds } 19611da177e4SLinus Torvalds 1962c7d51402SJ. Bruce Fields static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp) 1963e22841c6SJ. Bruce Fields { 1964c7d51402SJ. Bruce Fields return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY; 1965e22841c6SJ. Bruce Fields } 1966e22841c6SJ. Bruce Fields 19671da177e4SLinus Torvalds /* 19681da177e4SLinus Torvalds * Check for a user's access permissions to this inode. 19691da177e4SLinus Torvalds */ 19706264d69dSAl Viro __be32 19710ec757dfSJ. Bruce Fields nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, 19720ec757dfSJ. Bruce Fields struct dentry *dentry, int acc) 19731da177e4SLinus Torvalds { 19741da177e4SLinus Torvalds struct inode *inode = dentry->d_inode; 19751da177e4SLinus Torvalds int err; 19761da177e4SLinus Torvalds 1977aea93397SJ. Bruce Fields if ((acc & NFSD_MAY_MASK) == NFSD_MAY_NOP) 19781da177e4SLinus Torvalds return 0; 19791da177e4SLinus Torvalds #if 0 19801da177e4SLinus Torvalds dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n", 19811da177e4SLinus Torvalds acc, 19828837abcaSMiklos Szeredi (acc & NFSD_MAY_READ)? " read" : "", 19838837abcaSMiklos Szeredi (acc & NFSD_MAY_WRITE)? " write" : "", 19848837abcaSMiklos Szeredi (acc & NFSD_MAY_EXEC)? " exec" : "", 19858837abcaSMiklos Szeredi (acc & NFSD_MAY_SATTR)? " sattr" : "", 19868837abcaSMiklos Szeredi (acc & NFSD_MAY_TRUNC)? " trunc" : "", 19878837abcaSMiklos Szeredi (acc & NFSD_MAY_LOCK)? " lock" : "", 19888837abcaSMiklos Szeredi (acc & NFSD_MAY_OWNER_OVERRIDE)? " owneroverride" : "", 19891da177e4SLinus Torvalds inode->i_mode, 19901da177e4SLinus Torvalds IS_IMMUTABLE(inode)? " immut" : "", 19911da177e4SLinus Torvalds IS_APPEND(inode)? " append" : "", 19922c463e95SDave Hansen __mnt_is_readonly(exp->ex_path.mnt)? " ro" : ""); 19931da177e4SLinus Torvalds dprintk(" owner %d/%d user %d/%d\n", 19945cc0a840SDavid Howells inode->i_uid, inode->i_gid, current_fsuid(), current_fsgid()); 19951da177e4SLinus Torvalds #endif 19961da177e4SLinus Torvalds 19971da177e4SLinus Torvalds /* Normally we reject any write/sattr etc access on a read-only file 19981da177e4SLinus Torvalds * system. But if it is IRIX doing check on write-access for a 19991da177e4SLinus Torvalds * device special file, we ignore rofs. 20001da177e4SLinus Torvalds */ 20018837abcaSMiklos Szeredi if (!(acc & NFSD_MAY_LOCAL_ACCESS)) 20028837abcaSMiklos Szeredi if (acc & (NFSD_MAY_WRITE | NFSD_MAY_SATTR | NFSD_MAY_TRUNC)) { 20032c463e95SDave Hansen if (exp_rdonly(rqstp, exp) || 20042c463e95SDave Hansen __mnt_is_readonly(exp->ex_path.mnt)) 20051da177e4SLinus Torvalds return nfserr_rofs; 20068837abcaSMiklos Szeredi if (/* (acc & NFSD_MAY_WRITE) && */ IS_IMMUTABLE(inode)) 20071da177e4SLinus Torvalds return nfserr_perm; 20081da177e4SLinus Torvalds } 20098837abcaSMiklos Szeredi if ((acc & NFSD_MAY_TRUNC) && IS_APPEND(inode)) 20101da177e4SLinus Torvalds return nfserr_perm; 20111da177e4SLinus Torvalds 20128837abcaSMiklos Szeredi if (acc & NFSD_MAY_LOCK) { 20131da177e4SLinus Torvalds /* If we cannot rely on authentication in NLM requests, 20141da177e4SLinus Torvalds * just allow locks, otherwise require read permission, or 20151da177e4SLinus Torvalds * ownership 20161da177e4SLinus Torvalds */ 20171da177e4SLinus Torvalds if (exp->ex_flags & NFSEXP_NOAUTHNLM) 20181da177e4SLinus Torvalds return 0; 20191da177e4SLinus Torvalds else 20208837abcaSMiklos Szeredi acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE; 20211da177e4SLinus Torvalds } 20221da177e4SLinus Torvalds /* 20231da177e4SLinus Torvalds * The file owner always gets access permission for accesses that 20241da177e4SLinus Torvalds * would normally be checked at open time. This is to make 20251da177e4SLinus Torvalds * file access work even when the client has done a fchmod(fd, 0). 20261da177e4SLinus Torvalds * 20271da177e4SLinus Torvalds * However, `cp foo bar' should fail nevertheless when bar is 20281da177e4SLinus Torvalds * readonly. A sensible way to do this might be to reject all 20291da177e4SLinus Torvalds * attempts to truncate a read-only file, because a creat() call 20301da177e4SLinus Torvalds * always implies file truncation. 20311da177e4SLinus Torvalds * ... but this isn't really fair. A process may reasonably call 20321da177e4SLinus Torvalds * ftruncate on an open file descriptor on a file with perm 000. 20331da177e4SLinus Torvalds * We must trust the client to do permission checking - using "ACCESS" 20341da177e4SLinus Torvalds * with NFSv3. 20351da177e4SLinus Torvalds */ 20368837abcaSMiklos Szeredi if ((acc & NFSD_MAY_OWNER_OVERRIDE) && 20376fab8779SEric W. Biederman uid_eq(inode->i_uid, current_fsuid())) 20381da177e4SLinus Torvalds return 0; 20391da177e4SLinus Torvalds 20408837abcaSMiklos Szeredi /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ 2041f419a2e3SAl Viro err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); 20421da177e4SLinus Torvalds 20431da177e4SLinus Torvalds /* Allow read access to binaries even when mode 111 */ 20441da177e4SLinus Torvalds if (err == -EACCES && S_ISREG(inode->i_mode) && 2045a043226bSJ. Bruce Fields (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) || 2046a043226bSJ. Bruce Fields acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC))) 2047f419a2e3SAl Viro err = inode_permission(inode, MAY_EXEC); 20481da177e4SLinus Torvalds 20491da177e4SLinus Torvalds return err? nfserrno(err) : 0; 20501da177e4SLinus Torvalds } 20511da177e4SLinus Torvalds 20521da177e4SLinus Torvalds void 20531da177e4SLinus Torvalds nfsd_racache_shutdown(void) 20541da177e4SLinus Torvalds { 205554a66e54SJeff Layton struct raparms *raparm, *last_raparm; 205654a66e54SJeff Layton unsigned int i; 205754a66e54SJeff Layton 20581da177e4SLinus Torvalds dprintk("nfsd: freeing readahead buffers.\n"); 205954a66e54SJeff Layton 206054a66e54SJeff Layton for (i = 0; i < RAPARM_HASH_SIZE; i++) { 206154a66e54SJeff Layton raparm = raparm_hash[i].pb_head; 206254a66e54SJeff Layton while(raparm) { 206354a66e54SJeff Layton last_raparm = raparm; 206454a66e54SJeff Layton raparm = raparm->p_next; 206554a66e54SJeff Layton kfree(last_raparm); 206654a66e54SJeff Layton } 206754a66e54SJeff Layton raparm_hash[i].pb_head = NULL; 206854a66e54SJeff Layton } 20691da177e4SLinus Torvalds } 20701da177e4SLinus Torvalds /* 20711da177e4SLinus Torvalds * Initialize readahead param cache 20721da177e4SLinus Torvalds */ 20731da177e4SLinus Torvalds int 20741da177e4SLinus Torvalds nfsd_racache_init(int cache_size) 20751da177e4SLinus Torvalds { 20761da177e4SLinus Torvalds int i; 2077fce1456aSGreg Banks int j = 0; 2078fce1456aSGreg Banks int nperbucket; 207954a66e54SJeff Layton struct raparms **raparm = NULL; 20801da177e4SLinus Torvalds 2081fce1456aSGreg Banks 208254a66e54SJeff Layton if (raparm_hash[0].pb_head) 20831da177e4SLinus Torvalds return 0; 208454a66e54SJeff Layton nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE); 20853c7aa15dSKinglong Mee nperbucket = max(2, nperbucket); 208654a66e54SJeff Layton cache_size = nperbucket * RAPARM_HASH_SIZE; 20874b3bb06bSYan Burman 20884b3bb06bSYan Burman dprintk("nfsd: allocating %d readahead buffers.\n", cache_size); 208954a66e54SJeff Layton 2090fce1456aSGreg Banks for (i = 0; i < RAPARM_HASH_SIZE; i++) { 2091fce1456aSGreg Banks spin_lock_init(&raparm_hash[i].pb_lock); 209254a66e54SJeff Layton 209354a66e54SJeff Layton raparm = &raparm_hash[i].pb_head; 209454a66e54SJeff Layton for (j = 0; j < nperbucket; j++) { 209554a66e54SJeff Layton *raparm = kzalloc(sizeof(struct raparms), GFP_KERNEL); 209654a66e54SJeff Layton if (!*raparm) 209754a66e54SJeff Layton goto out_nomem; 209854a66e54SJeff Layton raparm = &(*raparm)->p_next; 2099fce1456aSGreg Banks } 210054a66e54SJeff Layton *raparm = NULL; 21011da177e4SLinus Torvalds } 21024b3bb06bSYan Burman 21031da177e4SLinus Torvalds nfsdstats.ra_size = cache_size; 21041da177e4SLinus Torvalds return 0; 210554a66e54SJeff Layton 210654a66e54SJeff Layton out_nomem: 210754a66e54SJeff Layton dprintk("nfsd: kmalloc failed, freeing readahead buffers\n"); 210854a66e54SJeff Layton nfsd_racache_shutdown(); 210954a66e54SJeff Layton return -ENOMEM; 21101da177e4SLinus Torvalds } 2111