···12681268 depends on INET12691269 select LOCKD12701270 select SUNRPC12711271+ select NFS_ACL_SUPPORT if NFS_V3_ACL12711272 help12721273 If you are connected to some other (usually local) Unix computer12731274 (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing···13101309 3 of the NFS protocol.1311131013121311 If unsure, say Y.13121312+13131313+config NFS_V3_ACL13141314+ bool "Provide client support for the NFSv3 ACL protocol extension"13151315+ depends on NFS_V313161316+ help13171317+ Implement the NFSv3 ACL protocol extension for manipulating POSIX13181318+ Access Control Lists. The server should also be compiled with13191319+ the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option.13201320+13211321+ If unsure, say N.1313132213141323config NFS_V413151324 bool "Provide NFSv4 client support (EXPERIMENTAL)"···13641353 select LOCKD13651354 select SUNRPC13661355 select EXPORTFS13561356+ select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL13671357 help13681358 If you want your Linux box to act as an NFS *server*, so that other13691359 computers on your local network which support NFS can access certain···13881376 To compile the NFS server support as a module, choose M here: the13891377 module will be called nfsd. If unsure, say N.1390137813791379+config NFSD_V2_ACL13801380+ bool13811381+ depends on NFSD13821382+13911383config NFSD_V313921384 bool "Provide NFSv3 server support"13931385 depends on NFSD13941386 help13951387 If you would like to include the NFSv3 server as well as the NFSv213961388 server, say Y here. If unsure, say Y.13891389+13901390+config NFSD_V3_ACL13911391+ bool "Provide server support for the NFSv3 ACL protocol extension"13921392+ depends on NFSD_V313931393+ select NFSD_V2_ACL13941394+ help13951395+ Implement the NFSv3 ACL protocol extension for manipulating POSIX13961396+ Access Control Lists on exported file systems. NFS clients should13971397+ be compiled with the NFSv3 ACL protocol extension; see the13981398+ CONFIG_NFS_V3_ACL option. If unsure, say N.1397139913981400config NFSD_V413991401 bool "Provide NFSv4 server support (EXPERIMENTAL)"···1452142614531427config EXPORTFS14541428 tristate14291429+14301430+config NFS_ACL_SUPPORT14311431+ tristate14321432+ select FS_POSIX_ACL14331433+14341434+config NFS_COMMON14351435+ bool14361436+ depends on NFSD || NFS_FS14371437+ default y1455143814561439config SUNRPC14571440 tristate
···3131 * This is the representation of a blocked client lock.3232 */3333struct nlm_wait {3434- struct nlm_wait * b_next; /* linked list */3434+ struct list_head b_list; /* linked list */3535 wait_queue_head_t b_wait; /* where to wait on */3636 struct nlm_host * b_host;3737 struct file_lock * b_lock; /* local file lock */···3939 u32 b_status; /* grant callback status */4040};41414242-static struct nlm_wait * nlm_blocked;4242+static LIST_HEAD(nlm_blocked);4343+4444+/*4545+ * Queue up a lock for blocking so that the GRANTED request can see it4646+ */4747+int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl)4848+{4949+ struct nlm_wait *block;5050+5151+ BUG_ON(req->a_block != NULL);5252+ block = kmalloc(sizeof(*block), GFP_KERNEL);5353+ if (block == NULL)5454+ return -ENOMEM;5555+ block->b_host = host;5656+ block->b_lock = fl;5757+ init_waitqueue_head(&block->b_wait);5858+ block->b_status = NLM_LCK_BLOCKED;5959+6060+ list_add(&block->b_list, &nlm_blocked);6161+ req->a_block = block;6262+6363+ return 0;6464+}6565+6666+void nlmclnt_finish_block(struct nlm_rqst *req)6767+{6868+ struct nlm_wait *block = req->a_block;6969+7070+ if (block == NULL)7171+ return;7272+ req->a_block = NULL;7373+ list_del(&block->b_list);7474+ kfree(block);7575+}43764477/*4578 * Block on a lock4679 */4747-int4848-nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp)8080+long nlmclnt_block(struct nlm_rqst *req, long timeout)4981{5050- struct nlm_wait block, **head;5151- int err;5252- u32 pstate;8282+ struct nlm_wait *block = req->a_block;8383+ long ret;53845454- block.b_host = host;5555- block.b_lock = fl;5656- init_waitqueue_head(&block.b_wait);5757- block.b_status = NLM_LCK_BLOCKED;5858- block.b_next = nlm_blocked;5959- nlm_blocked = █6060-6161- /* Remember pseudo nsm state */6262- pstate = host->h_state;8585+ /* A borken server might ask us to block even if we didn't8686+ * request it. Just say no!8787+ */8888+ if (!req->a_args.block)8989+ return -EAGAIN;63906491 /* Go to sleep waiting for GRANT callback. Some servers seem6592 * to lose callbacks, however, so we're going to poll from···9669 * a 1 minute timeout would do. See the comment before9770 * nlmclnt_lock for an explanation.9871 */9999- sleep_on_timeout(&block.b_wait, 30*HZ);7272+ ret = wait_event_interruptible_timeout(block->b_wait,7373+ block->b_status != NLM_LCK_BLOCKED,7474+ timeout);10075101101- for (head = &nlm_blocked; *head; head = &(*head)->b_next) {102102- if (*head == &block) {103103- *head = block.b_next;104104- break;105105- }7676+ if (block->b_status != NLM_LCK_BLOCKED) {7777+ req->a_res.status = block->b_status;7878+ block->b_status = NLM_LCK_BLOCKED;10679 }10780108108- if (!signalled()) {109109- *statp = block.b_status;110110- return 0;111111- }112112-113113- /* Okay, we were interrupted. Cancel the pending request114114- * unless the server has rebooted.115115- */116116- if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0)117117- printk(KERN_NOTICE118118- "lockd: CANCEL call failed (errno %d)\n", -err);119119-120120- return -ERESTARTSYS;8181+ return ret;12182}1228312384/*···115100nlmclnt_grant(struct nlm_lock *lock)116101{117102 struct nlm_wait *block;103103+ u32 res = nlm_lck_denied;118104119105 /*120106 * Look up blocked request based on arguments. 121107 * Warning: must not use cookie to match it!122108 */123123- for (block = nlm_blocked; block; block = block->b_next) {124124- if (nlm_compare_locks(block->b_lock, &lock->fl))125125- break;109109+ list_for_each_entry(block, &nlm_blocked, b_list) {110110+ if (nlm_compare_locks(block->b_lock, &lock->fl)) {111111+ /* Alright, we found a lock. Set the return status112112+ * and wake up the caller113113+ */114114+ block->b_status = NLM_LCK_GRANTED;115115+ wake_up(&block->b_wait);116116+ res = nlm_granted;117117+ }126118 }127127-128128- /* Ooops, no blocked request found. */129129- if (block == NULL)130130- return nlm_lck_denied;131131-132132- /* Alright, we found the lock. Set the return status and133133- * wake up the caller.134134- */135135- block->b_status = NLM_LCK_GRANTED;136136- wake_up(&block->b_wait);137137-138138- return nlm_granted;119119+ return res;139120}140121141122/*···241230 host->h_reclaiming = 0;242231243232 /* Now, wake up all processes that sleep on a blocked lock */244244- for (block = nlm_blocked; block; block = block->b_next) {233233+ list_for_each_entry(block, &nlm_blocked, b_list) {245234 if (block->b_host == host) {246235 block->b_status = NLM_LCK_DENIED_GRACE_PERIOD;247236 wake_up(&block->b_wait);
+32-8
fs/lockd/clntproc.c
···21212222#define NLMDBG_FACILITY NLMDBG_CLIENT2323#define NLMCLNT_GRACE_WAIT (5*HZ)2424+#define NLMCLNT_POLL_TIMEOUT (30*HZ)24252526static int nlmclnt_test(struct nlm_rqst *, struct file_lock *);2627static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *);···554553{555554 struct nlm_host *host = req->a_host;556555 struct nlm_res *resp = &req->a_res;557557- int status;556556+ long timeout;557557+ int status;558558559559 if (!host->h_monitored && nsm_monitor(host) < 0) {560560 printk(KERN_NOTICE "lockd: failed to monitor %s\n",···564562 goto out;565563 }566564567567- do {568568- if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) {569569- if (resp->status != NLM_LCK_BLOCKED)570570- break;571571- status = nlmclnt_block(host, fl, &resp->status);572572- }565565+ if (req->a_args.block) {566566+ status = nlmclnt_prepare_block(req, host, fl);573567 if (status < 0)574568 goto out;575575- } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block);569569+ }570570+ for(;;) {571571+ status = nlmclnt_call(req, NLMPROC_LOCK);572572+ if (status < 0)573573+ goto out_unblock;574574+ if (resp->status != NLM_LCK_BLOCKED)575575+ break;576576+ /* Wait on an NLM blocking lock */577577+ timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT);578578+ /* Did a reclaimer thread notify us of a server reboot? */579579+ if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD)580580+ continue;581581+ if (resp->status != NLM_LCK_BLOCKED)582582+ break;583583+ if (timeout >= 0)584584+ continue;585585+ /* We were interrupted. Send a CANCEL request to the server586586+ * and exit587587+ */588588+ status = (int)timeout;589589+ goto out_unblock;590590+ }576591577592 if (resp->status == NLM_LCK_GRANTED) {578593 fl->fl_u.nfs_fl.state = host->h_state;···598579 do_vfs_lock(fl);599580 }600581 status = nlm_stat_to_errno(resp->status);582582+out_unblock:583583+ nlmclnt_finish_block(req);584584+ /* Cancel the blocked request if it is still pending */585585+ if (resp->status == NLM_LCK_BLOCKED)586586+ nlmclnt_cancel(host, fl);601587out:602588 nlmclnt_release_lockargs(req);603589 return status;
+3-5
fs/lockd/host.c
···189189 goto forgetit;190190191191 xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);192192+ xprt->nocong = 1; /* No congestion control for NLM */193193+ xprt->resvport = 1; /* NLM requires a reserved port */192194193195 /* Existing NLM servers accept AUTH_UNIX only */194196 clnt = rpc_create_client(xprt, host->h_name, &nlm_program,195197 host->h_version, RPC_AUTH_UNIX);196196- if (IS_ERR(clnt)) {197197- xprt_destroy(xprt);198198+ if (IS_ERR(clnt))198199 goto forgetit;199199- }200200 clnt->cl_autobind = 1; /* turn on pmap queries */201201- xprt->nocong = 1; /* No congestion control for NLM */202202- xprt->resvport = 1; /* NLM requires a reserved port */203201204202 host->h_rpcclnt = clnt;205203 }
+3-4
fs/lockd/mon.c
···115115 xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL);116116 if (IS_ERR(xprt))117117 return (struct rpc_clnt *)xprt;118118+ xprt->resvport = 1; /* NSM requires a reserved port */118119119120 clnt = rpc_create_client(xprt, "localhost",120121 &nsm_program, SM_VERSION,121122 RPC_AUTH_NULL);122123 if (IS_ERR(clnt))123123- goto out_destroy;124124+ goto out_err;124125 clnt->cl_softrtry = 1;125126 clnt->cl_chatty = 1;126127 clnt->cl_oneshot = 1;127127- xprt->resvport = 1; /* NSM requires a reserved port */128128 return clnt;129129130130-out_destroy:131131- xprt_destroy(xprt);130130+out_err:132131 return clnt;133132}134133
+6
fs/locks.c
···1548154815491549 if (filp->f_op && filp->f_op->lock) {15501550 error = filp->f_op->lock(filp, F_GETLK, &file_lock);15511551+ if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)15521552+ file_lock.fl_ops->fl_release_private(&file_lock);15511553 if (error < 0)15521554 goto out;15531555 else···1692169016931691 if (filp->f_op && filp->f_op->lock) {16941692 error = filp->f_op->lock(filp, F_GETLK, &file_lock);16931693+ if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)16941694+ file_lock.fl_ops->fl_release_private(&file_lock);16951695 if (error < 0)16961696 goto out;16971697 else···18771873 .fl_end = OFFSET_MAX,18781874 };18791875 filp->f_op->flock(filp, F_SETLKW, &fl);18761876+ if (fl.fl_ops && fl.fl_ops->fl_release_private)18771877+ fl.fl_ops->fl_release_private(&fl);18801878 }1881187918821880 lock_kernel();
···3232#include <linux/smp_lock.h>3333#include <linux/namei.h>34343535+#include "nfs4_fs.h"3536#include "delegation.h"36373738#define NFS_PARANOIA 1···5150static int nfs_rename(struct inode *, struct dentry *,5251 struct inode *, struct dentry *);5352static int nfs_fsync_dir(struct file *, struct dentry *, int);5353+static loff_t nfs_llseek_dir(struct file *, loff_t, int);54545555struct file_operations nfs_dir_operations = {5656+ .llseek = nfs_llseek_dir,5657 .read = generic_read_dir,5758 .readdir = nfs_readdir,5859 .open = nfs_opendir,···7774 .setattr = nfs_setattr,7875};79767777+#ifdef CONFIG_NFS_V37878+struct inode_operations nfs3_dir_inode_operations = {7979+ .create = nfs_create,8080+ .lookup = nfs_lookup,8181+ .link = nfs_link,8282+ .unlink = nfs_unlink,8383+ .symlink = nfs_symlink,8484+ .mkdir = nfs_mkdir,8585+ .rmdir = nfs_rmdir,8686+ .mknod = nfs_mknod,8787+ .rename = nfs_rename,8888+ .permission = nfs_permission,8989+ .getattr = nfs_getattr,9090+ .setattr = nfs_setattr,9191+ .listxattr = nfs3_listxattr,9292+ .getxattr = nfs3_getxattr,9393+ .setxattr = nfs3_setxattr,9494+ .removexattr = nfs3_removexattr,9595+};9696+#endif /* CONFIG_NFS_V3 */9797+8098#ifdef CONFIG_NFS_V4819982100static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);···11490 .permission = nfs_permission,11591 .getattr = nfs_getattr,11692 .setattr = nfs_setattr,9393+ .getxattr = nfs4_getxattr,9494+ .setxattr = nfs4_setxattr,9595+ .listxattr = nfs4_listxattr,11796};1189711998#endif /* CONFIG_NFS_V4 */···143116 struct page *page;144117 unsigned long page_index;145118 u32 *ptr;146146- u64 target;119119+ u64 *dir_cookie;120120+ loff_t current_index;147121 struct nfs_entry *entry;148122 decode_dirent_t decode;149123 int plus;···192164 NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;193165 /* Ensure consistent page alignment of the data.194166 * Note: assumes we have exclusive access to this mapping either195195- * throught inode->i_sem or some other mechanism.167167+ * through inode->i_sem or some other mechanism.196168 */197197- if (page->index == 0) {198198- invalidate_inode_pages(inode->i_mapping);199199- NFS_I(inode)->readdir_timestamp = timestamp;200200- }169169+ if (page->index == 0)170170+ invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1);201171 unlock_page(page);202172 return 0;203173 error:···228202229203/*230204 * Given a pointer to a buffer that has already been filled by a call231231- * to readdir, find the next entry.205205+ * to readdir, find the next entry with cookie '*desc->dir_cookie'.232206 *233207 * If the end of the buffer has been reached, return -EAGAIN, if not,234208 * return the offset within the buffer of the next entry to be235209 * read.236210 */237211static inline238238-int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page)212212+int find_dirent(nfs_readdir_descriptor_t *desc)239213{240214 struct nfs_entry *entry = desc->entry;241215 int loop_count = 0,242216 status;243217244218 while((status = dir_decode(desc)) == 0) {245245- dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie);246246- if (entry->prev_cookie == desc->target)219219+ dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie);220220+ if (entry->prev_cookie == *desc->dir_cookie)247221 break;248222 if (loop_count++ > 200) {249223 loop_count = 0;···255229}256230257231/*258258- * Find the given page, and call find_dirent() in order to try to259259- * return the next entry.232232+ * Given a pointer to a buffer that has already been filled by a call233233+ * to readdir, find the entry at offset 'desc->file->f_pos'.234234+ *235235+ * If the end of the buffer has been reached, return -EAGAIN, if not,236236+ * return the offset within the buffer of the next entry to be237237+ * read.238238+ */239239+static inline240240+int find_dirent_index(nfs_readdir_descriptor_t *desc)241241+{242242+ struct nfs_entry *entry = desc->entry;243243+ int loop_count = 0,244244+ status;245245+246246+ for(;;) {247247+ status = dir_decode(desc);248248+ if (status)249249+ break;250250+251251+ dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index);252252+253253+ if (desc->file->f_pos == desc->current_index) {254254+ *desc->dir_cookie = entry->cookie;255255+ break;256256+ }257257+ desc->current_index++;258258+ if (loop_count++ > 200) {259259+ loop_count = 0;260260+ schedule();261261+ }262262+ }263263+ dfprintk(VFS, "NFS: find_dirent_index() returns %d\n", status);264264+ return status;265265+}266266+267267+/*268268+ * Find the given page, and call find_dirent() or find_dirent_index in269269+ * order to try to return the next entry.260270 */261271static inline262272int find_dirent_page(nfs_readdir_descriptor_t *desc)···315253 /* NOTE: Someone else may have changed the READDIRPLUS flag */316254 desc->page = page;317255 desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */318318- status = find_dirent(desc, page);256256+ if (*desc->dir_cookie != 0)257257+ status = find_dirent(desc);258258+ else259259+ status = find_dirent_index(desc);319260 if (status < 0)320261 dir_page_release(desc);321262 out:···333268 * Recurse through the page cache pages, and return a334269 * filled nfs_entry structure of the next directory entry if possible.335270 *336336- * The target for the search is 'desc->target'.271271+ * The target for the search is '*desc->dir_cookie' if non-0,272272+ * 'desc->file->f_pos' otherwise337273 */338274static inline339275int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)···342276 int loop_count = 0;343277 int res;344278345345- dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target);279279+ /* Always search-by-index from the beginning of the cache */280280+ if (*desc->dir_cookie == 0) {281281+ dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos);282282+ desc->page_index = 0;283283+ desc->entry->cookie = desc->entry->prev_cookie = 0;284284+ desc->entry->eof = 0;285285+ desc->current_index = 0;286286+ } else287287+ dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie);288288+346289 for (;;) {347290 res = find_dirent_page(desc);348291 if (res != -EAGAIN)···388313 int loop_count = 0,389314 res;390315391391- dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target);316316+ dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)entry->cookie);392317393318 for(;;) {394319 unsigned d_type = DT_UNKNOWN;···408333 }409334410335 res = filldir(dirent, entry->name, entry->len, 411411- entry->prev_cookie, fileid, d_type);336336+ file->f_pos, fileid, d_type);412337 if (res < 0)413338 break;414414- file->f_pos = desc->target = entry->cookie;339339+ file->f_pos++;340340+ *desc->dir_cookie = entry->cookie;415341 if (dir_decode(desc) != 0) {416342 desc->page_index ++;417343 break;···425349 dir_page_release(desc);426350 if (dentry != NULL)427351 dput(dentry);428428- dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res);352352+ dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res);429353 return res;430354}431355···451375 struct page *page = NULL;452376 int status;453377454454- dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target);378378+ dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie);455379456380 page = alloc_page(GFP_HIGHUSER);457381 if (!page) {458382 status = -ENOMEM;459383 goto out;460384 }461461- desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target,385385+ desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie,462386 page,463387 NFS_SERVER(inode)->dtsize,464388 desc->plus);···467391 desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */468392 if (desc->error >= 0) {469393 if ((status = dir_decode(desc)) == 0)470470- desc->entry->prev_cookie = desc->target;394394+ desc->entry->prev_cookie = *desc->dir_cookie;471395 } else472396 status = -EIO;473397 if (status < 0)···488412 goto out;489413}490414491491-/* The file offset position is now represented as a true offset into the492492- * page cache as is the case in most of the other filesystems.415415+/* The file offset position represents the dirent entry number. A416416+ last cookie cache takes care of the common case of reading the417417+ whole directory.493418 */494419static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)495420{···512435 }513436514437 /*515515- * filp->f_pos points to the file offset in the page cache.516516- * but if the cache has meanwhile been zapped, we need to517517- * read from the last dirent to revalidate f_pos518518- * itself.438438+ * filp->f_pos points to the dirent entry number.439439+ * *desc->dir_cookie has the cookie for the next entry. We have440440+ * to either find the entry with the appropriate number or441441+ * revalidate the cookie.519442 */520443 memset(desc, 0, sizeof(*desc));521444522445 desc->file = filp;523523- desc->target = filp->f_pos;446446+ desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie;524447 desc->decode = NFS_PROTO(inode)->decode_dirent;525448 desc->plus = NFS_USE_READDIRPLUS(inode);526449···532455533456 while(!desc->entry->eof) {534457 res = readdir_search_pagecache(desc);458458+535459 if (res == -EBADCOOKIE) {536460 /* This means either end of directory */537537- if (desc->entry->cookie != desc->target) {461461+ if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) {538462 /* Or that the server has 'lost' a cookie */539463 res = uncached_readdir(desc, dirent, filldir);540464 if (res >= 0)···566488 if (res < 0)567489 return res;568490 return 0;491491+}492492+493493+loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)494494+{495495+ down(&filp->f_dentry->d_inode->i_sem);496496+ switch (origin) {497497+ case 1:498498+ offset += filp->f_pos;499499+ case 0:500500+ if (offset >= 0)501501+ break;502502+ default:503503+ offset = -EINVAL;504504+ goto out;505505+ }506506+ if (offset != filp->f_pos) {507507+ filp->f_pos = offset;508508+ ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0;509509+ }510510+out:511511+ up(&filp->f_dentry->d_inode->i_sem);512512+ return offset;569513}570514571515/*
+1-1
fs/nfs/direct.c
···517517 result = tot_bytes;518518519519out:520520- nfs_end_data_update_defer(inode);520520+ nfs_end_data_update(inode);521521 nfs_writedata_free(wdata);522522 return result;523523
+41-7
fs/nfs/file.c
···7171 .setattr = nfs_setattr,7272};73737474+#ifdef CONFIG_NFS_V37575+struct inode_operations nfs3_file_inode_operations = {7676+ .permission = nfs_permission,7777+ .getattr = nfs_getattr,7878+ .setattr = nfs_setattr,7979+ .listxattr = nfs3_listxattr,8080+ .getxattr = nfs3_getxattr,8181+ .setxattr = nfs3_setxattr,8282+ .removexattr = nfs3_removexattr,8383+};8484+#endif /* CONFIG_NFS_v3 */8585+7486/* Hack for future NFS swap support */7587#ifndef IS_SWAPFILE7688# define IS_SWAPFILE(inode) (0)···128116}129117130118/**119119+ * nfs_revalidate_file - Revalidate the page cache & related metadata120120+ * @inode - pointer to inode struct121121+ * @file - pointer to file122122+ */123123+static int nfs_revalidate_file(struct inode *inode, struct file *filp)124124+{125125+ int retval = 0;126126+127127+ if ((NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode))128128+ retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode);129129+ nfs_revalidate_mapping(inode, filp->f_mapping);130130+ return 0;131131+}132132+133133+/**131134 * nfs_revalidate_size - Revalidate the file size132135 * @inode - pointer to inode struct133136 * @file - pointer to struct file···164137 goto force_reval;165138 if (nfsi->npages != 0)166139 return 0;167167- return nfs_revalidate_inode(server, inode);140140+ if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode))141141+ return 0;168142force_reval:169143 return __nfs_revalidate_inode(server, inode);170144}···226198 dentry->d_parent->d_name.name, dentry->d_name.name,227199 (unsigned long) count, (unsigned long) pos);228200229229- result = nfs_revalidate_inode(NFS_SERVER(inode), inode);201201+ result = nfs_revalidate_file(inode, iocb->ki_filp);230202 if (!result)231203 result = generic_file_aio_read(iocb, buf, count, pos);232204 return result;···244216 dentry->d_parent->d_name.name, dentry->d_name.name,245217 (unsigned long) count, (unsigned long long) *ppos);246218247247- res = nfs_revalidate_inode(NFS_SERVER(inode), inode);219219+ res = nfs_revalidate_file(inode, filp);248220 if (!res)249221 res = generic_file_sendfile(filp, ppos, count, actor, target);250222 return res;···260232 dfprintk(VFS, "nfs: mmap(%s/%s)\n",261233 dentry->d_parent->d_name.name, dentry->d_name.name);262234263263- status = nfs_revalidate_inode(NFS_SERVER(inode), inode);235235+ status = nfs_revalidate_file(inode, file);264236 if (!status)265237 status = generic_file_mmap(file, vma);266238 return status;···349321 result = -EBUSY;350322 if (IS_SWAPFILE(inode))351323 goto out_swapfile;352352- result = nfs_revalidate_inode(NFS_SERVER(inode), inode);353353- if (result)354354- goto out;324324+ /*325325+ * O_APPEND implies that we must revalidate the file length.326326+ */327327+ if (iocb->ki_filp->f_flags & O_APPEND) {328328+ result = nfs_revalidate_file_size(inode, iocb->ki_filp);329329+ if (result)330330+ goto out;331331+ }332332+ nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);355333356334 result = count;357335 if (!count)
···11+/*22+ * linux/fs/nfs/nfs4_fs.h33+ *44+ * Copyright (C) 2005 Trond Myklebust55+ *66+ * NFSv4-specific filesystem definitions and declarations77+ */88+99+#ifndef __LINUX_FS_NFS_NFS4_FS_H1010+#define __LINUX_FS_NFS_NFS4_FS_H1111+1212+#ifdef CONFIG_NFS_V41313+1414+struct idmap;1515+1616+/*1717+ * In a seqid-mutating op, this macro controls which error return1818+ * values trigger incrementation of the seqid.1919+ *2020+ * from rfc 3010:2121+ * The client MUST monotonically increment the sequence number for the2222+ * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE2323+ * operations. This is true even in the event that the previous2424+ * operation that used the sequence number received an error. The only2525+ * exception to this rule is if the previous operation received one of2626+ * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID,2727+ * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR,2828+ * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE.2929+ *3030+ */3131+#define seqid_mutating_err(err) \3232+(((err) != NFSERR_STALE_CLIENTID) && \3333+ ((err) != NFSERR_STALE_STATEID) && \3434+ ((err) != NFSERR_BAD_STATEID) && \3535+ ((err) != NFSERR_BAD_SEQID) && \3636+ ((err) != NFSERR_BAD_XDR) && \3737+ ((err) != NFSERR_RESOURCE) && \3838+ ((err) != NFSERR_NOFILEHANDLE))3939+4040+enum nfs4_client_state {4141+ NFS4CLNT_OK = 0,4242+};4343+4444+/*4545+ * The nfs4_client identifies our client state to the server.4646+ */4747+struct nfs4_client {4848+ struct list_head cl_servers; /* Global list of servers */4949+ struct in_addr cl_addr; /* Server identifier */5050+ u64 cl_clientid; /* constant */5151+ nfs4_verifier cl_confirm;5252+ unsigned long cl_state;5353+5454+ u32 cl_lockowner_id;5555+5656+ /*5757+ * The following rwsem ensures exclusive access to the server5858+ * while we recover the state following a lease expiration.5959+ */6060+ struct rw_semaphore cl_sem;6161+6262+ struct list_head cl_delegations;6363+ struct list_head cl_state_owners;6464+ struct list_head cl_unused;6565+ int cl_nunused;6666+ spinlock_t cl_lock;6767+ atomic_t cl_count;6868+6969+ struct rpc_clnt * cl_rpcclient;7070+ struct rpc_cred * cl_cred;7171+7272+ struct list_head cl_superblocks; /* List of nfs_server structs */7373+7474+ unsigned long cl_lease_time;7575+ unsigned long cl_last_renewal;7676+ struct work_struct cl_renewd;7777+ struct work_struct cl_recoverd;7878+7979+ wait_queue_head_t cl_waitq;8080+ struct rpc_wait_queue cl_rpcwaitq;8181+8282+ /* used for the setclientid verifier */8383+ struct timespec cl_boot_time;8484+8585+ /* idmapper */8686+ struct idmap * cl_idmap;8787+8888+ /* Our own IP address, as a null-terminated string.8989+ * This is used to generate the clientid, and the callback address.9090+ */9191+ char cl_ipaddr[16];9292+ unsigned char cl_id_uniquifier;9393+};9494+9595+/*9696+ * NFS4 state_owners and lock_owners are simply labels for ordered9797+ * sequences of RPC calls. Their sole purpose is to provide once-only9898+ * semantics by allowing the server to identify replayed requests.9999+ *100100+ * The ->so_sema is held during all state_owner seqid-mutating operations:101101+ * OPEN, OPEN_DOWNGRADE, and CLOSE. Its purpose is to properly serialize102102+ * so_seqid.103103+ */104104+struct nfs4_state_owner {105105+ struct list_head so_list; /* per-clientid list of state_owners */106106+ struct nfs4_client *so_client;107107+ u32 so_id; /* 32-bit identifier, unique */108108+ struct semaphore so_sema;109109+ u32 so_seqid; /* protected by so_sema */110110+ atomic_t so_count;111111+112112+ struct rpc_cred *so_cred; /* Associated cred */113113+ struct list_head so_states;114114+ struct list_head so_delegations;115115+};116116+117117+/*118118+ * struct nfs4_state maintains the client-side state for a given119119+ * (state_owner,inode) tuple (OPEN) or state_owner (LOCK).120120+ *121121+ * OPEN:122122+ * In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server,123123+ * we need to know how many files are open for reading or writing on a124124+ * given inode. This information too is stored here.125125+ *126126+ * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN)127127+ */128128+129129+struct nfs4_lock_state {130130+ struct list_head ls_locks; /* Other lock stateids */131131+ struct nfs4_state * ls_state; /* Pointer to open state */132132+ fl_owner_t ls_owner; /* POSIX lock owner */133133+#define NFS_LOCK_INITIALIZED 1134134+ int ls_flags;135135+ u32 ls_seqid;136136+ u32 ls_id;137137+ nfs4_stateid ls_stateid;138138+ atomic_t ls_count;139139+};140140+141141+/* bits for nfs4_state->flags */142142+enum {143143+ LK_STATE_IN_USE,144144+ NFS_DELEGATED_STATE,145145+};146146+147147+struct nfs4_state {148148+ struct list_head open_states; /* List of states for the same state_owner */149149+ struct list_head inode_states; /* List of states for the same inode */150150+ struct list_head lock_states; /* List of subservient lock stateids */151151+152152+ struct nfs4_state_owner *owner; /* Pointer to the open owner */153153+ struct inode *inode; /* Pointer to the inode */154154+155155+ unsigned long flags; /* Do we hold any locks? */156156+ struct semaphore lock_sema; /* Serializes file locking operations */157157+ spinlock_t state_lock; /* Protects the lock_states list */158158+159159+ nfs4_stateid stateid;160160+161161+ unsigned int nreaders;162162+ unsigned int nwriters;163163+ int state; /* State on the server (R,W, or RW) */164164+ atomic_t count;165165+};166166+167167+168168+struct nfs4_exception {169169+ long timeout;170170+ int retry;171171+};172172+173173+struct nfs4_state_recovery_ops {174174+ int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *);175175+ int (*recover_lock)(struct nfs4_state *, struct file_lock *);176176+};177177+178178+extern struct dentry_operations nfs4_dentry_operations;179179+extern struct inode_operations nfs4_dir_inode_operations;180180+181181+/* inode.c */182182+extern ssize_t nfs4_getxattr(struct dentry *, const char *, void *, size_t);183183+extern int nfs4_setxattr(struct dentry *, const char *, const void *, size_t, int);184184+extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t);185185+186186+187187+/* nfs4proc.c */188188+extern int nfs4_map_errors(int err);189189+extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);190190+extern int nfs4_proc_setclientid_confirm(struct nfs4_client *);191191+extern int nfs4_proc_async_renew(struct nfs4_client *);192192+extern int nfs4_proc_renew(struct nfs4_client *);193193+extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode);194194+extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);195195+extern int nfs4_open_revalidate(struct inode *, struct dentry *, int);196196+197197+extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;198198+extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;199199+200200+extern const u32 nfs4_fattr_bitmap[2];201201+extern const u32 nfs4_statfs_bitmap[2];202202+extern const u32 nfs4_pathconf_bitmap[2];203203+extern const u32 nfs4_fsinfo_bitmap[2];204204+205205+/* nfs4renewd.c */206206+extern void nfs4_schedule_state_renewal(struct nfs4_client *);207207+extern void nfs4_renewd_prepare_shutdown(struct nfs_server *);208208+extern void nfs4_kill_renewd(struct nfs4_client *);209209+extern void nfs4_renew_state(void *);210210+211211+/* nfs4state.c */212212+extern void init_nfsv4_state(struct nfs_server *);213213+extern void destroy_nfsv4_state(struct nfs_server *);214214+extern struct nfs4_client *nfs4_get_client(struct in_addr *);215215+extern void nfs4_put_client(struct nfs4_client *clp);216216+extern int nfs4_init_client(struct nfs4_client *clp);217217+extern struct nfs4_client *nfs4_find_client(struct in_addr *);218218+extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);219219+220220+extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);221221+extern void nfs4_put_state_owner(struct nfs4_state_owner *);222222+extern void nfs4_drop_state_owner(struct nfs4_state_owner *);223223+extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);224224+extern void nfs4_put_open_state(struct nfs4_state *);225225+extern void nfs4_close_state(struct nfs4_state *, mode_t);226226+extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode);227227+extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp);228228+extern void nfs4_schedule_state_recovery(struct nfs4_client *);229229+extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);230230+extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls);231231+extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);232232+233233+extern const nfs4_stateid zero_stateid;234234+235235+/* nfs4xdr.c */236236+extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus);237237+extern struct rpc_procinfo nfs4_procedures[];238238+239239+struct nfs4_mount_data;240240+241241+/* callback_xdr.c */242242+extern struct svc_version nfs4_callback_version1;243243+244244+#else245245+246246+#define init_nfsv4_state(server) do { } while (0)247247+#define destroy_nfsv4_state(server) do { } while (0)248248+#define nfs4_put_state_owner(inode, owner) do { } while (0)249249+#define nfs4_put_open_state(state) do { } while (0)250250+#define nfs4_close_state(a, b) do { } while (0)251251+252252+#endif /* CONFIG_NFS_V4 */253253+#endif /* __LINUX_FS_NFS_NFS4_FS.H */
+339-90
fs/nfs/nfs4proc.c
···4848#include <linux/smp_lock.h>4949#include <linux/namei.h>50505151+#include "nfs4_fs.h"5152#include "delegation.h"52535354#define NFSDBG_FACILITY NFSDBG_PROC···6261static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception);6362extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);6463extern struct rpc_procinfo nfs4_procedures[];6565-6666-extern nfs4_stateid zero_stateid;67646865/* Prevent leaks of NFSv4 errors into userland */6966int nfs4_map_errors(int err)···103104 | FATTR4_WORD1_SPACE_TOTAL104105};105106106106-u32 nfs4_pathconf_bitmap[2] = {107107+const u32 nfs4_pathconf_bitmap[2] = {107108 FATTR4_WORD0_MAXLINK108109 | FATTR4_WORD0_MAXNAME,109110 0···123124124125 BUG_ON(readdir->count < 80);125126 if (cookie > 2) {126126- readdir->cookie = (cookie > 2) ? cookie : 0;127127+ readdir->cookie = cookie;127128 memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));128129 return;129130 }···269270 int err;270271 do {271272 err = _nfs4_open_reclaim(sp, state);272272- switch (err) {273273- case 0:274274- case -NFS4ERR_STALE_CLIENTID:275275- case -NFS4ERR_STALE_STATEID:276276- case -NFS4ERR_EXPIRED:277277- return err;278278- }279279- err = nfs4_handle_exception(server, err, &exception);273273+ if (err != -NFS4ERR_DELAY)274274+ break;275275+ nfs4_handle_exception(server, err, &exception);280276 } while (exception.retry);281277 return err;282278}···503509 goto out_nodeleg;504510}505511512512+static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)513513+{514514+ struct nfs_server *server = NFS_SERVER(dentry->d_inode);515515+ struct nfs4_exception exception = { };516516+ int err;517517+518518+ do {519519+ err = _nfs4_open_expired(sp, state, dentry);520520+ if (err == -NFS4ERR_DELAY)521521+ nfs4_handle_exception(server, err, &exception);522522+ } while (exception.retry);523523+ return err;524524+}525525+506526static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)507527{508528 struct nfs_inode *nfsi = NFS_I(state->inode);···529521 continue;530522 get_nfs_open_context(ctx);531523 spin_unlock(&state->inode->i_lock);532532- status = _nfs4_open_expired(sp, state, ctx->dentry);524524+ status = nfs4_do_open_expired(sp, state, ctx->dentry);533525 put_nfs_open_context(ctx);534526 return status;535527 }···756748757749 fattr->valid = 0;758750759759- if (state != NULL)751751+ if (state != NULL) {760752 msg.rpc_cred = state->owner->so_cred;761761- if (sattr->ia_valid & ATTR_SIZE)762762- nfs4_copy_stateid(&arg.stateid, state, NULL);763763- else753753+ nfs4_copy_stateid(&arg.stateid, state, current->files);754754+ } else764755 memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));765756766757 return rpc_call_sync(server->client, &msg, 0);···11231116nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,11241117 struct iattr *sattr)11251118{11261126- struct inode * inode = dentry->d_inode;11271127- int size_change = sattr->ia_valid & ATTR_SIZE;11281128- struct nfs4_state *state = NULL;11291129- int need_iput = 0;11191119+ struct rpc_cred *cred;11201120+ struct inode *inode = dentry->d_inode;11211121+ struct nfs4_state *state;11301122 int status;1131112311321124 fattr->valid = 0;1133112511341134- if (size_change) {11351135- struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);11361136- if (IS_ERR(cred))11371137- return PTR_ERR(cred);11261126+ cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);11271127+ if (IS_ERR(cred))11281128+ return PTR_ERR(cred);11291129+ /* Search for an existing WRITE delegation first */11301130+ state = nfs4_open_delegated(inode, FMODE_WRITE, cred);11311131+ if (!IS_ERR(state)) {11321132+ /* NB: nfs4_open_delegated() bumps the inode->i_count */11331133+ iput(inode);11341134+ } else {11351135+ /* Search for an existing open(O_WRITE) stateid */11381136 state = nfs4_find_state(inode, cred, FMODE_WRITE);11391139- if (state == NULL) {11401140- state = nfs4_open_delegated(dentry->d_inode,11411141- FMODE_WRITE, cred);11421142- if (IS_ERR(state))11431143- state = nfs4_do_open(dentry->d_parent->d_inode,11441144- dentry, FMODE_WRITE,11451145- NULL, cred);11461146- need_iput = 1;11471147- }11481148- put_rpccred(cred);11491149- if (IS_ERR(state))11501150- return PTR_ERR(state);11511151-11521152- if (state->inode != inode) {11531153- printk(KERN_WARNING "nfs: raced in setattr (%p != %p), returning -EIO\n", inode, state->inode);11541154- status = -EIO;11551155- goto out;11561156- }11571137 }11381138+11581139 status = nfs4_do_setattr(NFS_SERVER(inode), fattr,11591140 NFS_FH(inode), sattr, state);11601160-out:11611161- if (state) {11621162- inode = state->inode;11411141+ if (state != NULL)11631142 nfs4_close_state(state, FMODE_WRITE);11641164- if (need_iput)11651165- iput(inode);11661166- }11431143+ put_rpccred(cred);11671144 return status;11681145}11691146···17221731 };17231732 int status;1724173317341734+ dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __FUNCTION__,17351735+ dentry->d_parent->d_name.name,17361736+ dentry->d_name.name,17371737+ (unsigned long long)cookie);17251738 lock_kernel();17261739 nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);17271740 res.pgbase = args.pgbase;···17331738 if (status == 0)17341739 memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);17351740 unlock_kernel();17411741+ dprintk("%s: returns %d\n", __FUNCTION__, status);17361742 return status;17371743}17381744···21592163 return 0;21602164}2161216521662166+static inline int nfs4_server_supports_acls(struct nfs_server *server)21672167+{21682168+ return (server->caps & NFS_CAP_ACLS)21692169+ && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)21702170+ && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);21712171+}21722172+21732173+/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that21742174+ * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on21752175+ * the stack.21762176+ */21772177+#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)21782178+21792179+static void buf_to_pages(const void *buf, size_t buflen,21802180+ struct page **pages, unsigned int *pgbase)21812181+{21822182+ const void *p = buf;21832183+21842184+ *pgbase = offset_in_page(buf);21852185+ p -= *pgbase;21862186+ while (p < buf + buflen) {21872187+ *(pages++) = virt_to_page(p);21882188+ p += PAGE_CACHE_SIZE;21892189+ }21902190+}21912191+21922192+struct nfs4_cached_acl {21932193+ int cached;21942194+ size_t len;21952195+ char data[0];21962196+};21972197+21982198+static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl)21992199+{22002200+ struct nfs_inode *nfsi = NFS_I(inode);22012201+22022202+ spin_lock(&inode->i_lock);22032203+ kfree(nfsi->nfs4_acl);22042204+ nfsi->nfs4_acl = acl;22052205+ spin_unlock(&inode->i_lock);22062206+}22072207+22082208+static void nfs4_zap_acl_attr(struct inode *inode)22092209+{22102210+ nfs4_set_cached_acl(inode, NULL);22112211+}22122212+22132213+static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen)22142214+{22152215+ struct nfs_inode *nfsi = NFS_I(inode);22162216+ struct nfs4_cached_acl *acl;22172217+ int ret = -ENOENT;22182218+22192219+ spin_lock(&inode->i_lock);22202220+ acl = nfsi->nfs4_acl;22212221+ if (acl == NULL)22222222+ goto out;22232223+ if (buf == NULL) /* user is just asking for length */22242224+ goto out_len;22252225+ if (acl->cached == 0)22262226+ goto out;22272227+ ret = -ERANGE; /* see getxattr(2) man page */22282228+ if (acl->len > buflen)22292229+ goto out;22302230+ memcpy(buf, acl->data, acl->len);22312231+out_len:22322232+ ret = acl->len;22332233+out:22342234+ spin_unlock(&inode->i_lock);22352235+ return ret;22362236+}22372237+22382238+static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len)22392239+{22402240+ struct nfs4_cached_acl *acl;22412241+22422242+ if (buf && acl_len <= PAGE_SIZE) {22432243+ acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);22442244+ if (acl == NULL)22452245+ goto out;22462246+ acl->cached = 1;22472247+ memcpy(acl->data, buf, acl_len);22482248+ } else {22492249+ acl = kmalloc(sizeof(*acl), GFP_KERNEL);22502250+ if (acl == NULL)22512251+ goto out;22522252+ acl->cached = 0;22532253+ }22542254+ acl->len = acl_len;22552255+out:22562256+ nfs4_set_cached_acl(inode, acl);22572257+}22582258+22592259+static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)22602260+{22612261+ struct page *pages[NFS4ACL_MAXPAGES];22622262+ struct nfs_getaclargs args = {22632263+ .fh = NFS_FH(inode),22642264+ .acl_pages = pages,22652265+ .acl_len = buflen,22662266+ };22672267+ size_t resp_len = buflen;22682268+ void *resp_buf;22692269+ struct rpc_message msg = {22702270+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],22712271+ .rpc_argp = &args,22722272+ .rpc_resp = &resp_len,22732273+ };22742274+ struct page *localpage = NULL;22752275+ int ret;22762276+22772277+ if (buflen < PAGE_SIZE) {22782278+ /* As long as we're doing a round trip to the server anyway,22792279+ * let's be prepared for a page of acl data. */22802280+ localpage = alloc_page(GFP_KERNEL);22812281+ resp_buf = page_address(localpage);22822282+ if (localpage == NULL)22832283+ return -ENOMEM;22842284+ args.acl_pages[0] = localpage;22852285+ args.acl_pgbase = 0;22862286+ args.acl_len = PAGE_SIZE;22872287+ } else {22882288+ resp_buf = buf;22892289+ buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase);22902290+ }22912291+ ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);22922292+ if (ret)22932293+ goto out_free;22942294+ if (resp_len > args.acl_len)22952295+ nfs4_write_cached_acl(inode, NULL, resp_len);22962296+ else22972297+ nfs4_write_cached_acl(inode, resp_buf, resp_len);22982298+ if (buf) {22992299+ ret = -ERANGE;23002300+ if (resp_len > buflen)23012301+ goto out_free;23022302+ if (localpage)23032303+ memcpy(buf, resp_buf, resp_len);23042304+ }23052305+ ret = resp_len;23062306+out_free:23072307+ if (localpage)23082308+ __free_page(localpage);23092309+ return ret;23102310+}23112311+23122312+static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)23132313+{23142314+ struct nfs_server *server = NFS_SERVER(inode);23152315+ int ret;23162316+23172317+ if (!nfs4_server_supports_acls(server))23182318+ return -EOPNOTSUPP;23192319+ ret = nfs_revalidate_inode(server, inode);23202320+ if (ret < 0)23212321+ return ret;23222322+ ret = nfs4_read_cached_acl(inode, buf, buflen);23232323+ if (ret != -ENOENT)23242324+ return ret;23252325+ return nfs4_get_acl_uncached(inode, buf, buflen);23262326+}23272327+23282328+static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)23292329+{23302330+ struct nfs_server *server = NFS_SERVER(inode);23312331+ struct page *pages[NFS4ACL_MAXPAGES];23322332+ struct nfs_setaclargs arg = {23332333+ .fh = NFS_FH(inode),23342334+ .acl_pages = pages,23352335+ .acl_len = buflen,23362336+ };23372337+ struct rpc_message msg = {23382338+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL],23392339+ .rpc_argp = &arg,23402340+ .rpc_resp = NULL,23412341+ };23422342+ int ret;23432343+23442344+ if (!nfs4_server_supports_acls(server))23452345+ return -EOPNOTSUPP;23462346+ buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);23472347+ ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);23482348+ if (ret == 0)23492349+ nfs4_write_cached_acl(inode, buf, buflen);23502350+ return ret;23512351+}23522352+21622353static int21632354nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server)21642355{···26312448 down_read(&clp->cl_sem);26322449 nlo.clientid = clp->cl_clientid;26332450 down(&state->lock_sema);26342634- lsp = nfs4_find_lock_state(state, request->fl_owner);26352635- if (lsp)26362636- nlo.id = lsp->ls_id; 26372637- else {26382638- spin_lock(&clp->cl_lock);26392639- nlo.id = nfs4_alloc_lockowner_id(clp);26402640- spin_unlock(&clp->cl_lock);26412641- }24512451+ status = nfs4_set_lock_state(state, request);24522452+ if (status != 0)24532453+ goto out;24542454+ lsp = request->fl_u.nfs4_fl.owner;24552455+ nlo.id = lsp->ls_id; 26422456 arg.u.lockt = &nlo;26432457 status = rpc_call_sync(server->client, &msg, 0);26442458 if (!status) {···26562476 request->fl_pid = 0;26572477 status = 0;26582478 }26592659- if (lsp)26602660- nfs4_put_lock_state(lsp);24792479+out:26612480 up(&state->lock_sema);26622481 up_read(&clp->cl_sem);26632482 return status;···27162537 };27172538 struct nfs4_lock_state *lsp;27182539 struct nfs_locku_opargs luargs;27192719- int status = 0;25402540+ int status;2720254127212542 down_read(&clp->cl_sem);27222543 down(&state->lock_sema);27232723- lsp = nfs4_find_lock_state(state, request->fl_owner);27242724- if (!lsp)25442544+ status = nfs4_set_lock_state(state, request);25452545+ if (status != 0)27252546 goto out;25472547+ lsp = request->fl_u.nfs4_fl.owner;27262548 /* We might have lost the locks! */27272727- if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {27282728- luargs.seqid = lsp->ls_seqid;27292729- memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid));27302730- arg.u.locku = &luargs;27312731- status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);27322732- nfs4_increment_lock_seqid(status, lsp);27332733- }25492549+ if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0)25502550+ goto out;25512551+ luargs.seqid = lsp->ls_seqid;25522552+ memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid));25532553+ arg.u.locku = &luargs;25542554+ status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);25552555+ nfs4_increment_lock_seqid(status, lsp);2734255627352735- if (status == 0) {25572557+ if (status == 0)27362558 memcpy(&lsp->ls_stateid, &res.u.stateid, 27372559 sizeof(lsp->ls_stateid));27382738- nfs4_notify_unlck(state, request, lsp);27392739- }27402740- nfs4_put_lock_state(lsp);27412560out:27422561 up(&state->lock_sema);27432562 if (status == 0)···27612584{27622585 struct inode *inode = state->inode;27632586 struct nfs_server *server = NFS_SERVER(inode);27642764- struct nfs4_lock_state *lsp;25872587+ struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner;27652588 struct nfs_lockargs arg = {27662589 .fh = NFS_FH(inode),27672590 .type = nfs4_lck_type(cmd, request),···27832606 };27842607 int status;2785260827862786- lsp = nfs4_get_lock_state(state, request->fl_owner);27872787- if (lsp == NULL)27882788- return -ENOMEM;27892609 if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) {27902610 struct nfs4_state_owner *owner = state->owner;27912611 struct nfs_open_to_lock otl = {···28042630 * seqid mutating errors */28052631 nfs4_increment_seqid(status, owner);28062632 up(&owner->so_sema);26332633+ if (status == 0) {26342634+ lsp->ls_flags |= NFS_LOCK_INITIALIZED;26352635+ lsp->ls_seqid++;26362636+ }28072637 } else {28082638 struct nfs_exist_lock el = {28092639 .seqid = lsp->ls_seqid,28102640 };28112641 memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid));28122642 largs.u.exist_lock = ⪙28132813- largs.new_lock_owner = 0;28142643 arg.u.lock = &largs;28152644 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);26452645+ /* increment seqid on success, and * seqid mutating errors*/26462646+ nfs4_increment_lock_seqid(status, lsp);28162647 }28172817- /* increment seqid on success, and * seqid mutating errors*/28182818- nfs4_increment_lock_seqid(status, lsp);28192648 /* save the returned stateid. */28202820- if (status == 0) {26492649+ if (status == 0)28212650 memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid));28222822- lsp->ls_flags |= NFS_LOCK_INITIALIZED;28232823- if (!reclaim)28242824- nfs4_notify_setlk(state, request, lsp);28252825- } else if (status == -NFS4ERR_DENIED)26512651+ else if (status == -NFS4ERR_DENIED)28262652 status = -EAGAIN;28272827- nfs4_put_lock_state(lsp);28282653 return status;28292654}2830265528312656static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)28322657{28332833- return _nfs4_do_setlk(state, F_SETLK, request, 1);26582658+ struct nfs_server *server = NFS_SERVER(state->inode);26592659+ struct nfs4_exception exception = { };26602660+ int err;26612661+26622662+ do {26632663+ err = _nfs4_do_setlk(state, F_SETLK, request, 1);26642664+ if (err != -NFS4ERR_DELAY)26652665+ break;26662666+ nfs4_handle_exception(server, err, &exception);26672667+ } while (exception.retry);26682668+ return err;28342669}2835267028362671static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)28372672{28382838- return _nfs4_do_setlk(state, F_SETLK, request, 0);26732673+ struct nfs_server *server = NFS_SERVER(state->inode);26742674+ struct nfs4_exception exception = { };26752675+ int err;26762676+26772677+ do {26782678+ err = _nfs4_do_setlk(state, F_SETLK, request, 0);26792679+ if (err != -NFS4ERR_DELAY)26802680+ break;26812681+ nfs4_handle_exception(server, err, &exception);26822682+ } while (exception.retry);26832683+ return err;28392684}2840268528412686static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)···2864267128652672 down_read(&clp->cl_sem);28662673 down(&state->lock_sema);28672867- status = _nfs4_do_setlk(state, cmd, request, 0);26742674+ status = nfs4_set_lock_state(state, request);26752675+ if (status == 0)26762676+ status = _nfs4_do_setlk(state, cmd, request, 0);28682677 up(&state->lock_sema);28692678 if (status == 0) {28702679 /* Note: we always want to sleep here! */···29242729 if (signalled())29252730 break;29262731 } while(status < 0);29272927-29282732 return status;27332733+}27342734+27352735+27362736+#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"27372737+27382738+int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,27392739+ size_t buflen, int flags)27402740+{27412741+ struct inode *inode = dentry->d_inode;27422742+27432743+ if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)27442744+ return -EOPNOTSUPP;27452745+27462746+ if (!S_ISREG(inode->i_mode) &&27472747+ (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))27482748+ return -EPERM;27492749+27502750+ return nfs4_proc_set_acl(inode, buf, buflen);27512751+}27522752+27532753+/* The getxattr man page suggests returning -ENODATA for unknown attributes,27542754+ * and that's what we'll do for e.g. user attributes that haven't been set.27552755+ * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported27562756+ * attributes in kernel-managed attribute namespaces. */27572757+ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf,27582758+ size_t buflen)27592759+{27602760+ struct inode *inode = dentry->d_inode;27612761+27622762+ if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)27632763+ return -EOPNOTSUPP;27642764+27652765+ return nfs4_proc_get_acl(inode, buf, buflen);27662766+}27672767+27682768+ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)27692769+{27702770+ size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;27712771+27722772+ if (buf && buflen < len)27732773+ return -ERANGE;27742774+ if (buf)27752775+ memcpy(buf, XATTR_NAME_NFSV4_ACL, len);27762776+ return len;29292777}2930277829312779struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {···29812743 .recover_lock = nfs4_lock_expired,29822744};2983274527462746+static struct inode_operations nfs4_file_inode_operations = {27472747+ .permission = nfs_permission,27482748+ .getattr = nfs_getattr,27492749+ .setattr = nfs_setattr,27502750+ .getxattr = nfs4_getxattr,27512751+ .setxattr = nfs4_setxattr,27522752+ .listxattr = nfs4_listxattr,27532753+};27542754+29842755struct nfs_rpc_ops nfs_v4_clientops = {29852756 .version = 4, /* protocol version */29862757 .dentry_ops = &nfs4_dentry_operations,29872758 .dir_inode_ops = &nfs4_dir_inode_operations,27592759+ .file_inode_ops = &nfs4_file_inode_operations,29882760 .getroot = nfs4_proc_get_root,29892761 .getattr = nfs4_proc_getattr,29902762 .setattr = nfs4_proc_setattr,···30252777 .file_open = nfs4_proc_file_open,30262778 .file_release = nfs4_proc_file_release,30272779 .lock = nfs4_proc_lock,27802780+ .clear_acl_cache = nfs4_zap_acl_attr,30282781};3029278230302783/*
···107107 smp_mb__before_clear_bit();108108 clear_bit(PG_BUSY, &req->wb_flags);109109 smp_mb__after_clear_bit();110110- wake_up_all(&req->wb_context->waitq);110110+ wake_up_bit(&req->wb_flags, PG_BUSY);111111 nfs_release_request(req);112112+}113113+114114+/**115115+ * nfs_set_page_writeback_locked - Lock a request for writeback116116+ * @req:117117+ */118118+int nfs_set_page_writeback_locked(struct nfs_page *req)119119+{120120+ struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);121121+122122+ if (!nfs_lock_request(req))123123+ return 0;124124+ radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK);125125+ return 1;126126+}127127+128128+/**129129+ * nfs_clear_page_writeback - Unlock request and wake up sleepers130130+ */131131+void nfs_clear_page_writeback(struct nfs_page *req)132132+{133133+ struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);134134+135135+ spin_lock(&nfsi->req_lock);136136+ radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK);137137+ spin_unlock(&nfsi->req_lock);138138+ nfs_unlock_request(req);112139}113140114141/**···177150 nfs_page_free(req);178151}179152180180-/**181181- * nfs_list_add_request - Insert a request into a sorted list182182- * @req: request183183- * @head: head of list into which to insert the request.184184- *185185- * Note that the wb_list is sorted by page index in order to facilitate186186- * coalescing of requests.187187- * We use an insertion sort that is optimized for the case of appended188188- * writes.189189- */190190-void191191-nfs_list_add_request(struct nfs_page *req, struct list_head *head)153153+static int nfs_wait_bit_interruptible(void *word)192154{193193- struct list_head *pos;155155+ int ret = 0;194156195195-#ifdef NFS_PARANOIA196196- if (!list_empty(&req->wb_list)) {197197- printk(KERN_ERR "NFS: Add to list failed!\n");198198- BUG();199199- }200200-#endif201201- list_for_each_prev(pos, head) {202202- struct nfs_page *p = nfs_list_entry(pos);203203- if (p->wb_index < req->wb_index)204204- break;205205- }206206- list_add(&req->wb_list, pos);207207- req->wb_list_head = head;157157+ if (signal_pending(current))158158+ ret = -ERESTARTSYS;159159+ else160160+ schedule();161161+ return ret;208162}209163210164/**···198190int199191nfs_wait_on_request(struct nfs_page *req)200192{201201- struct inode *inode = req->wb_context->dentry->d_inode;202202- struct rpc_clnt *clnt = NFS_CLIENT(inode);193193+ struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode);194194+ sigset_t oldmask;195195+ int ret = 0;203196204204- if (!NFS_WBACK_BUSY(req))205205- return 0;206206- return nfs_wait_event(clnt, req->wb_context->waitq, !NFS_WBACK_BUSY(req));197197+ if (!test_bit(PG_BUSY, &req->wb_flags))198198+ goto out;199199+ /*200200+ * Note: the call to rpc_clnt_sigmask() suffices to ensure that we201201+ * are not interrupted if intr flag is not set202202+ */203203+ rpc_clnt_sigmask(clnt, &oldmask);204204+ ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY,205205+ nfs_wait_bit_interruptible, TASK_INTERRUPTIBLE);206206+ rpc_clnt_sigunmask(clnt, &oldmask);207207+out:208208+ return ret;207209}208210209211/**···261243 return npages;262244}263245246246+#define NFS_SCAN_MAXENTRIES 16247247+/**248248+ * nfs_scan_lock_dirty - Scan the radix tree for dirty requests249249+ * @nfsi: NFS inode250250+ * @dst: Destination list251251+ * @idx_start: lower bound of page->index to scan252252+ * @npages: idx_start + npages sets the upper bound to scan.253253+ *254254+ * Moves elements from one of the inode request lists.255255+ * If the number of requests is set to 0, the entire address_space256256+ * starting at index idx_start, is scanned.257257+ * The requests are *not* checked to ensure that they form a contiguous set.258258+ * You must be holding the inode's req_lock when calling this function259259+ */260260+int261261+nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst,262262+ unsigned long idx_start, unsigned int npages)263263+{264264+ struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];265265+ struct nfs_page *req;266266+ unsigned long idx_end;267267+ int found, i;268268+ int res;269269+270270+ res = 0;271271+ if (npages == 0)272272+ idx_end = ~0;273273+ else274274+ idx_end = idx_start + npages - 1;275275+276276+ for (;;) {277277+ found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,278278+ (void **)&pgvec[0], idx_start, NFS_SCAN_MAXENTRIES,279279+ NFS_PAGE_TAG_DIRTY);280280+ if (found <= 0)281281+ break;282282+ for (i = 0; i < found; i++) {283283+ req = pgvec[i];284284+ if (req->wb_index > idx_end)285285+ goto out;286286+287287+ idx_start = req->wb_index + 1;288288+289289+ if (nfs_set_page_writeback_locked(req)) {290290+ radix_tree_tag_clear(&nfsi->nfs_page_tree,291291+ req->wb_index, NFS_PAGE_TAG_DIRTY);292292+ nfs_list_remove_request(req);293293+ nfs_list_add_request(req, dst);294294+ res++;295295+ }296296+ }297297+ }298298+out:299299+ return res;300300+}301301+264302/**265303 * nfs_scan_list - Scan a list for matching requests266304 * @head: One of the NFS inode request lists···354280 if (req->wb_index > idx_end)355281 break;356282357357- if (!nfs_lock_request(req))283283+ if (!nfs_set_page_writeback_locked(req))358284 continue;359285 nfs_list_remove_request(req);360286 nfs_list_add_request(req, dst);
···220220 ClearPageError(page);221221222222io_error:223223- nfs_end_data_update_defer(inode);223223+ nfs_end_data_update(inode);224224 nfs_writedata_free(wdata);225225 return written ? written : result;226226}···352352 if (err < 0)353353 goto out;354354 }355355- err = nfs_commit_inode(inode, 0, 0, wb_priority(wbc));355355+ err = nfs_commit_inode(inode, wb_priority(wbc));356356 if (err > 0) {357357 wbc->nr_to_write -= err;358358 err = 0;···401401 nfsi->npages--;402402 if (!nfsi->npages) {403403 spin_unlock(&nfsi->req_lock);404404- nfs_end_data_update_defer(inode);404404+ nfs_end_data_update(inode);405405 iput(inode);406406 } else407407 spin_unlock(&nfsi->req_lock);···446446 struct nfs_inode *nfsi = NFS_I(inode);447447448448 spin_lock(&nfsi->req_lock);449449+ radix_tree_tag_set(&nfsi->nfs_page_tree,450450+ req->wb_index, NFS_PAGE_TAG_DIRTY);449451 nfs_list_add_request(req, &nfsi->dirty);450452 nfsi->ndirty++;451453 spin_unlock(&nfsi->req_lock);···505503506504 spin_lock(&nfsi->req_lock);507505 next = idx_start;508508- while (radix_tree_gang_lookup(&nfsi->nfs_page_tree, (void **)&req, next, 1)) {506506+ while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) {509507 if (req->wb_index > idx_end)510508 break;511509512510 next = req->wb_index + 1;513513- if (!NFS_WBACK_BUSY(req))514514- continue;511511+ BUG_ON(!NFS_WBACK_BUSY(req));515512516513 atomic_inc(&req->wb_count);517514 spin_unlock(&nfsi->req_lock);···539538nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)540539{541540 struct nfs_inode *nfsi = NFS_I(inode);542542- int res;543543- res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages);544544- nfsi->ndirty -= res;545545- sub_page_state(nr_dirty,res);546546- if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty))547547- printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");541541+ int res = 0;542542+543543+ if (nfsi->ndirty != 0) {544544+ res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages);545545+ nfsi->ndirty -= res;546546+ sub_page_state(nr_dirty,res);547547+ if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty))548548+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");549549+ }548550 return res;549551}550552···566562nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)567563{568564 struct nfs_inode *nfsi = NFS_I(inode);569569- int res;570570- res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);571571- nfsi->ncommit -= res;572572- if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))573573- printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");565565+ int res = 0;566566+567567+ if (nfsi->ncommit != 0) {568568+ res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);569569+ nfsi->ncommit -= res;570570+ if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))571571+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");572572+ }574573 return res;575574}576575#endif···757750 * is entirely in cache, it may be more efficient to avoid758751 * fragmenting write requests.759752 */760760- if (PageUptodate(page) && inode->i_flock == NULL) {753753+ if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) {761754 loff_t end_offs = i_size_read(inode) - 1;762755 unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT;763756···828821#else829822 nfs_inode_remove_request(req);830823#endif831831- nfs_unlock_request(req);824824+ nfs_clear_page_writeback(req);832825}833826834827static inline int flush_task_priority(int how)···959952 nfs_writedata_free(data);960953 }961954 nfs_mark_request_dirty(req);962962- nfs_unlock_request(req);955955+ nfs_clear_page_writeback(req);963956 return -ENOMEM;964957}965958···10091002 struct nfs_page *req = nfs_list_entry(head->next);10101003 nfs_list_remove_request(req);10111004 nfs_mark_request_dirty(req);10121012- nfs_unlock_request(req);10051005+ nfs_clear_page_writeback(req);10131006 }10141007 return -ENOMEM;10151008}···10361029 req = nfs_list_entry(head->next);10371030 nfs_list_remove_request(req);10381031 nfs_mark_request_dirty(req);10391039- nfs_unlock_request(req);10321032+ nfs_clear_page_writeback(req);10401033 }10411034 return error;10421035}···11281121 nfs_inode_remove_request(req);11291122#endif11301123 next:11311131- nfs_unlock_request(req);11241124+ nfs_clear_page_writeback(req);11321125 }11331126}11341127···12171210 struct nfs_write_data *data, int how)12181211{12191212 struct rpc_task *task = &data->task;12201220- struct nfs_page *first, *last;12131213+ struct nfs_page *first;12211214 struct inode *inode;12221222- loff_t start, end, len;1223121512241216 /* Set up the RPC argument and reply structs12251217 * NB: take care not to mess about with data->commit et al. */1226121812271219 list_splice_init(head, &data->pages);12281220 first = nfs_list_entry(data->pages.next);12291229- last = nfs_list_entry(data->pages.prev);12301221 inode = first->wb_context->dentry->d_inode;12311231-12321232- /*12331233- * Determine the offset range of requests in the COMMIT call.12341234- * We rely on the fact that data->pages is an ordered list...12351235- */12361236- start = req_offset(first);12371237- end = req_offset(last) + last->wb_bytes;12381238- len = end - start;12391239- /* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */12401240- if (end >= i_size_read(inode) || len < 0 || len > (~((u32)0) >> 1))12411241- len = 0;1242122212431223 data->inode = inode;12441224 data->cred = first->wb_context->cred;1245122512461226 data->args.fh = NFS_FH(data->inode);12471247- data->args.offset = start;12481248- data->args.count = len;12491249- data->res.count = len;12271227+ /* Note: we always request a commit of the entire inode */12281228+ data->args.offset = 0;12291229+ data->args.count = 0;12301230+ data->res.count = 0;12501231 data->res.fattr = &data->fattr;12511232 data->res.verf = &data->verf;12521233···12731278 req = nfs_list_entry(head->next);12741279 nfs_list_remove_request(req);12751280 nfs_mark_request_commit(req);12761276- nfs_unlock_request(req);12811281+ nfs_clear_page_writeback(req);12771282 }12781283 return -ENOMEM;12791284}···13191324 dprintk(" mismatch\n");13201325 nfs_mark_request_dirty(req);13211326 next:13221322- nfs_unlock_request(req);13271327+ nfs_clear_page_writeback(req);13231328 res++;13241329 }13251330 sub_page_state(nr_unstable,res);···13371342 spin_lock(&nfsi->req_lock);13381343 res = nfs_scan_dirty(inode, &head, idx_start, npages);13391344 spin_unlock(&nfsi->req_lock);13401340- if (res)13411341- error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how);13451345+ if (res) {13461346+ struct nfs_server *server = NFS_SERVER(inode);13471347+13481348+ /* For single writes, FLUSH_STABLE is more efficient */13491349+ if (res == nfsi->npages && nfsi->npages <= server->wpages) {13501350+ if (res > 1 || nfs_list_entry(head.next)->wb_bytes <= server->wsize)13511351+ how |= FLUSH_STABLE;13521352+ }13531353+ error = nfs_flush_list(&head, server->wpages, how);13541354+ }13421355 if (error < 0)13431356 return error;13441357 return res;13451358}1346135913471360#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)13481348-int nfs_commit_inode(struct inode *inode, unsigned long idx_start,13491349- unsigned int npages, int how)13611361+int nfs_commit_inode(struct inode *inode, int how)13501362{13511363 struct nfs_inode *nfsi = NFS_I(inode);13521364 LIST_HEAD(head);···13611359 error = 0;1362136013631361 spin_lock(&nfsi->req_lock);13641364- res = nfs_scan_commit(inode, &head, idx_start, npages);13621362+ res = nfs_scan_commit(inode, &head, 0, 0);13631363+ spin_unlock(&nfsi->req_lock);13651364 if (res) {13661366- res += nfs_scan_commit(inode, &head, 0, 0);13671367- spin_unlock(&nfsi->req_lock);13681365 error = nfs_commit_list(&head, how);13691369- } else13701370- spin_unlock(&nfsi->req_lock);13711371- if (error < 0)13721372- return error;13661366+ if (error < 0)13671367+ return error;13681368+ }13731369 return res;13741370}13751371#endif···13891389 error = nfs_flush_inode(inode, idx_start, npages, how);13901390#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)13911391 if (error == 0)13921392- error = nfs_commit_inode(inode, idx_start, npages, how);13921392+ error = nfs_commit_inode(inode, how);13931393#endif13941394 } while (error > 0);13951395 return error;
+7
fs/nfs_common/Makefile
···11+#22+# Makefile for Linux filesystem routines that are shared by client and server.33+#44+55+obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o66+77+nfs_acl-objs := nfsacl.o
+257
fs/nfs_common/nfsacl.c
···11+/*22+ * fs/nfs_common/nfsacl.c33+ *44+ * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>55+ */66+77+/*88+ * The Solaris nfsacl protocol represents some ACLs slightly differently99+ * than POSIX 1003.1e draft 17 does (and we do):1010+ *1111+ * - Minimal ACLs always have an ACL_MASK entry, so they have1212+ * four instead of three entries.1313+ * - The ACL_MASK entry in such minimal ACLs always has the same1414+ * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs1515+ * the ACL_MASK and ACL_GROUP_OBJ entries may differ.)1616+ * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ1717+ * entries contain the identifiers of the owner and owning group.1818+ * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID).1919+ * - ACL entries in the kernel are kept sorted in ascending order2020+ * of (e_tag, e_id). Solaris ACLs are unsorted.2121+ */2222+2323+#include <linux/module.h>2424+#include <linux/fs.h>2525+#include <linux/sunrpc/xdr.h>2626+#include <linux/nfsacl.h>2727+#include <linux/nfs3.h>2828+#include <linux/sort.h>2929+3030+MODULE_LICENSE("GPL");3131+3232+EXPORT_SYMBOL(nfsacl_encode);3333+EXPORT_SYMBOL(nfsacl_decode);3434+3535+struct nfsacl_encode_desc {3636+ struct xdr_array2_desc desc;3737+ unsigned int count;3838+ struct posix_acl *acl;3939+ int typeflag;4040+ uid_t uid;4141+ gid_t gid;4242+};4343+4444+static int4545+xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)4646+{4747+ struct nfsacl_encode_desc *nfsacl_desc =4848+ (struct nfsacl_encode_desc *) desc;4949+ u32 *p = (u32 *) elem;5050+5151+ if (nfsacl_desc->count < nfsacl_desc->acl->a_count) {5252+ struct posix_acl_entry *entry =5353+ &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];5454+5555+ *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag);5656+ switch(entry->e_tag) {5757+ case ACL_USER_OBJ:5858+ *p++ = htonl(nfsacl_desc->uid);5959+ break;6060+ case ACL_GROUP_OBJ:6161+ *p++ = htonl(nfsacl_desc->gid);6262+ break;6363+ case ACL_USER:6464+ case ACL_GROUP:6565+ *p++ = htonl(entry->e_id);6666+ break;6767+ default: /* Solaris depends on that! */6868+ *p++ = 0;6969+ break;7070+ }7171+ *p++ = htonl(entry->e_perm & S_IRWXO);7272+ } else {7373+ const struct posix_acl_entry *pa, *pe;7474+ int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE;7575+7676+ FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) {7777+ if (pa->e_tag == ACL_GROUP_OBJ) {7878+ group_obj_perm = pa->e_perm & S_IRWXO;7979+ break;8080+ }8181+ }8282+ /* fake up ACL_MASK entry */8383+ *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag);8484+ *p++ = htonl(0);8585+ *p++ = htonl(group_obj_perm);8686+ }8787+8888+ return 0;8989+}9090+9191+unsigned int9292+nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,9393+ struct posix_acl *acl, int encode_entries, int typeflag)9494+{9595+ int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;9696+ struct nfsacl_encode_desc nfsacl_desc = {9797+ .desc = {9898+ .elem_size = 12,9999+ .array_len = encode_entries ? entries : 0,100100+ .xcode = xdr_nfsace_encode,101101+ },102102+ .acl = acl,103103+ .typeflag = typeflag,104104+ .uid = inode->i_uid,105105+ .gid = inode->i_gid,106106+ };107107+ int err;108108+109109+ if (entries > NFS_ACL_MAX_ENTRIES ||110110+ xdr_encode_word(buf, base, entries))111111+ return -EINVAL;112112+ err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);113113+ if (!err)114114+ err = 8 + nfsacl_desc.desc.elem_size *115115+ nfsacl_desc.desc.array_len;116116+ return err;117117+}118118+119119+struct nfsacl_decode_desc {120120+ struct xdr_array2_desc desc;121121+ unsigned int count;122122+ struct posix_acl *acl;123123+};124124+125125+static int126126+xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem)127127+{128128+ struct nfsacl_decode_desc *nfsacl_desc =129129+ (struct nfsacl_decode_desc *) desc;130130+ u32 *p = (u32 *) elem;131131+ struct posix_acl_entry *entry;132132+133133+ if (!nfsacl_desc->acl) {134134+ if (desc->array_len > NFS_ACL_MAX_ENTRIES)135135+ return -EINVAL;136136+ nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL);137137+ if (!nfsacl_desc->acl)138138+ return -ENOMEM;139139+ nfsacl_desc->count = 0;140140+ }141141+142142+ entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];143143+ entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT;144144+ entry->e_id = ntohl(*p++);145145+ entry->e_perm = ntohl(*p++);146146+147147+ switch(entry->e_tag) {148148+ case ACL_USER_OBJ:149149+ case ACL_USER:150150+ case ACL_GROUP_OBJ:151151+ case ACL_GROUP:152152+ case ACL_OTHER:153153+ if (entry->e_perm & ~S_IRWXO)154154+ return -EINVAL;155155+ break;156156+ case ACL_MASK:157157+ /* Solaris sometimes sets additonal bits in the mask */158158+ entry->e_perm &= S_IRWXO;159159+ break;160160+ default:161161+ return -EINVAL;162162+ }163163+164164+ return 0;165165+}166166+167167+static int168168+cmp_acl_entry(const void *x, const void *y)169169+{170170+ const struct posix_acl_entry *a = x, *b = y;171171+172172+ if (a->e_tag != b->e_tag)173173+ return a->e_tag - b->e_tag;174174+ else if (a->e_id > b->e_id)175175+ return 1;176176+ else if (a->e_id < b->e_id)177177+ return -1;178178+ else179179+ return 0;180180+}181181+182182+/*183183+ * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL.184184+ */185185+static int186186+posix_acl_from_nfsacl(struct posix_acl *acl)187187+{188188+ struct posix_acl_entry *pa, *pe,189189+ *group_obj = NULL, *mask = NULL;190190+191191+ if (!acl)192192+ return 0;193193+194194+ sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry),195195+ cmp_acl_entry, NULL);196196+197197+ /* Clear undefined identifier fields and find the ACL_GROUP_OBJ198198+ and ACL_MASK entries. */199199+ FOREACH_ACL_ENTRY(pa, acl, pe) {200200+ switch(pa->e_tag) {201201+ case ACL_USER_OBJ:202202+ pa->e_id = ACL_UNDEFINED_ID;203203+ break;204204+ case ACL_GROUP_OBJ:205205+ pa->e_id = ACL_UNDEFINED_ID;206206+ group_obj = pa;207207+ break;208208+ case ACL_MASK:209209+ mask = pa;210210+ /* fall through */211211+ case ACL_OTHER:212212+ pa->e_id = ACL_UNDEFINED_ID;213213+ break;214214+ }215215+ }216216+ if (acl->a_count == 4 && group_obj && mask &&217217+ mask->e_perm == group_obj->e_perm) {218218+ /* remove bogus ACL_MASK entry */219219+ memmove(mask, mask+1, (3 - (mask - acl->a_entries)) *220220+ sizeof(struct posix_acl_entry));221221+ acl->a_count = 3;222222+ }223223+ return 0;224224+}225225+226226+unsigned int227227+nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,228228+ struct posix_acl **pacl)229229+{230230+ struct nfsacl_decode_desc nfsacl_desc = {231231+ .desc = {232232+ .elem_size = 12,233233+ .xcode = pacl ? xdr_nfsace_decode : NULL,234234+ },235235+ };236236+ u32 entries;237237+ int err;238238+239239+ if (xdr_decode_word(buf, base, &entries) ||240240+ entries > NFS_ACL_MAX_ENTRIES)241241+ return -EINVAL;242242+ err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc);243243+ if (err)244244+ return err;245245+ if (pacl) {246246+ if (entries != nfsacl_desc.desc.array_len ||247247+ posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) {248248+ posix_acl_release(nfsacl_desc.acl);249249+ return -EINVAL;250250+ }251251+ *pacl = nfsacl_desc.acl;252252+ }253253+ if (aclcnt)254254+ *aclcnt = entries;255255+ return 8 + nfsacl_desc.desc.elem_size *256256+ nfsacl_desc.desc.array_len;257257+}
···3131struct rpc_wait {3232 struct list_head list; /* wait queue links */3333 struct list_head links; /* Links to related tasks */3434- wait_queue_head_t waitq; /* sync: sleep on this q */3534 struct rpc_wait_queue * rpc_waitq; /* RPC wait queue we're on */3635};3736
+13-1
include/linux/sunrpc/svc.h
···185185 return vec->iov_len <= PAGE_SIZE;186186}187187188188+static inline struct page *189189+svc_take_res_page(struct svc_rqst *rqstp)190190+{191191+ if (rqstp->rq_arghi <= rqstp->rq_argused)192192+ return NULL;193193+ rqstp->rq_arghi--;194194+ rqstp->rq_respages[rqstp->rq_resused] =195195+ rqstp->rq_argpages[rqstp->rq_arghi];196196+ return rqstp->rq_respages[rqstp->rq_resused++];197197+}198198+188199static inline int svc_take_page(struct svc_rqst *rqstp)189200{190201 if (rqstp->rq_arghi <= rqstp->rq_argused)···251240};252241253242/*254254- * RPC program243243+ * List of RPC programs on the same transport endpoint255244 */256245struct svc_program {246246+ struct svc_program * pg_next; /* other programs (same xprt) */257247 u32 pg_prog; /* program number */258248 unsigned int pg_lovers; /* lowest version */259249 unsigned int pg_hivers; /* lowest version */
+19-2
include/linux/sunrpc/xdr.h
···146146extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *);147147extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int);148148extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int);149149-extern int read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len);149149+extern int read_bytes_from_xdr_buf(struct xdr_buf *, int, void *, int);150150+extern int write_bytes_to_xdr_buf(struct xdr_buf *, int, void *, int);150151151152/*152153 * Helper structure for copying from an sk_buff.···161160162161typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len);163162164164-extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,163163+extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,165164 skb_reader_t *, skb_read_actor_t);166165167166struct socket;168167struct sockaddr;169168extern int xdr_sendpages(struct socket *, struct sockaddr *, int,170169 struct xdr_buf *, unsigned int, int);170170+171171+extern int xdr_encode_word(struct xdr_buf *, int, u32);172172+extern int xdr_decode_word(struct xdr_buf *, int, u32 *);173173+174174+struct xdr_array2_desc;175175+typedef int (*xdr_xcode_elem_t)(struct xdr_array2_desc *desc, void *elem);176176+struct xdr_array2_desc {177177+ unsigned int elem_size;178178+ unsigned int array_len;179179+ xdr_xcode_elem_t xcode;180180+};181181+182182+extern int xdr_decode_array2(struct xdr_buf *buf, unsigned int base,183183+ struct xdr_array2_desc *desc);184184+extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base,185185+ struct xdr_array2_desc *desc);171186172187/*173188 * Provide some simple tools for XDR buffer overflow-checking etc.
+3-3
net/sunrpc/auth.c
···6666 u32 flavor = pseudoflavor_to_flavor(pseudoflavor);67676868 if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor]))6969- return NULL;6969+ return ERR_PTR(-EINVAL);7070 auth = ops->create(clnt, pseudoflavor);7171- if (!auth)7272- return NULL;7171+ if (IS_ERR(auth))7272+ return auth;7373 if (clnt->cl_auth)7474 rpcauth_destroy(clnt->cl_auth);7575 clnt->cl_auth = auth;
+11-7
net/sunrpc/auth_gss/auth_gss.c
···660660{661661 struct gss_auth *gss_auth;662662 struct rpc_auth * auth;663663+ int err = -ENOMEM; /* XXX? */663664664665 dprintk("RPC: creating GSS authenticator for client %p\n",clnt);665666666667 if (!try_module_get(THIS_MODULE))667667- return NULL;668668+ return ERR_PTR(err);668669 if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL)))669670 goto out_dec;670671 gss_auth->client = clnt;672672+ err = -EINVAL;671673 gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);672674 if (!gss_auth->mech) {673675 printk(KERN_WARNING "%s: Pseudoflavor %d not found!",···677675 goto err_free;678676 }679677 gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);680680- /* FIXME: Will go away once privacy support is merged in */681681- if (gss_auth->service == RPC_GSS_SVC_PRIVACY)682682- gss_auth->service = RPC_GSS_SVC_INTEGRITY;678678+ if (gss_auth->service == 0)679679+ goto err_put_mech;683680 INIT_LIST_HEAD(&gss_auth->upcalls);684681 spin_lock_init(&gss_auth->lock);685682 auth = &gss_auth->rpc_auth;···688687 auth->au_flavor = flavor;689688 atomic_set(&auth->au_count, 1);690689691691- if (rpcauth_init_credcache(auth, GSS_CRED_EXPIRE) < 0)690690+ err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE);691691+ if (err)692692 goto err_put_mech;693693694694 snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s",695695 clnt->cl_pathname,696696 gss_auth->mech->gm_name);697697 gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);698698- if (IS_ERR(gss_auth->dentry))698698+ if (IS_ERR(gss_auth->dentry)) {699699+ err = PTR_ERR(gss_auth->dentry);699700 goto err_put_mech;701701+ }700702701703 return auth;702704err_put_mech:···708704 kfree(gss_auth);709705out_dec:710706 module_put(THIS_MODULE);711711- return NULL;707707+ return ERR_PTR(err);712708}713709714710static void
+157-48
net/sunrpc/clnt.c
···9797 * made to sleep too long.9898 */9999struct rpc_clnt *100100-rpc_create_client(struct rpc_xprt *xprt, char *servname,100100+rpc_new_client(struct rpc_xprt *xprt, char *servname,101101 struct rpc_program *program, u32 vers,102102 rpc_authflavor_t flavor)103103{104104 struct rpc_version *version;105105 struct rpc_clnt *clnt = NULL;106106+ struct rpc_auth *auth;106107 int err;107108 int len;108109···158157 if (err < 0)159158 goto out_no_path;160159161161- err = -ENOMEM;162162- if (!rpcauth_create(flavor, clnt)) {160160+ auth = rpcauth_create(flavor, clnt);161161+ if (IS_ERR(auth)) {163162 printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",164163 flavor);164164+ err = PTR_ERR(auth);165165 goto out_no_auth;166166 }167167···180178 kfree(clnt->cl_server);181179 kfree(clnt);182180out_err:181181+ xprt_destroy(xprt);182182+ return ERR_PTR(err);183183+}184184+185185+/**186186+ * Create an RPC client187187+ * @xprt - pointer to xprt struct188188+ * @servname - name of server189189+ * @info - rpc_program190190+ * @version - rpc_program version191191+ * @authflavor - rpc_auth flavour to use192192+ *193193+ * Creates an RPC client structure, then pings the server in order to194194+ * determine if it is up, and if it supports this program and version.195195+ *196196+ * This function should never be called by asynchronous tasks such as197197+ * the portmapper.198198+ */199199+struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,200200+ struct rpc_program *info, u32 version, rpc_authflavor_t authflavor)201201+{202202+ struct rpc_clnt *clnt;203203+ int err;204204+205205+ clnt = rpc_new_client(xprt, servname, info, version, authflavor);206206+ if (IS_ERR(clnt))207207+ return clnt;208208+ err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);209209+ if (err == 0)210210+ return clnt;211211+ rpc_shutdown_client(clnt);183212 return ERR_PTR(err);184213}185214···241208 rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);242209 if (new->cl_auth)243210 atomic_inc(&new->cl_auth->au_count);211211+ new->cl_pmap = &new->cl_pmap_default;212212+ rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");244213 return new;245214out_no_clnt:246215 printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);···331296 rpc_destroy_client(clnt);332297}333298299299+/**300300+ * rpc_bind_new_program - bind a new RPC program to an existing client301301+ * @old - old rpc_client302302+ * @program - rpc program to set303303+ * @vers - rpc program version304304+ *305305+ * Clones the rpc client and sets up a new RPC program. This is mainly306306+ * of use for enabling different RPC programs to share the same transport.307307+ * The Sun NFSv2/v3 ACL protocol can do this.308308+ */309309+struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,310310+ struct rpc_program *program,311311+ int vers)312312+{313313+ struct rpc_clnt *clnt;314314+ struct rpc_version *version;315315+ int err;316316+317317+ BUG_ON(vers >= program->nrvers || !program->version[vers]);318318+ version = program->version[vers];319319+ clnt = rpc_clone_client(old);320320+ if (IS_ERR(clnt))321321+ goto out;322322+ clnt->cl_procinfo = version->procs;323323+ clnt->cl_maxproc = version->nrprocs;324324+ clnt->cl_protname = program->name;325325+ clnt->cl_prog = program->number;326326+ clnt->cl_vers = version->number;327327+ clnt->cl_stats = program->stats;328328+ err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);329329+ if (err != 0) {330330+ rpc_shutdown_client(clnt);331331+ clnt = ERR_PTR(err);332332+ }333333+out: 334334+ return clnt;335335+}336336+334337/*335338 * Default callback for async RPC calls336339 */···378305}379306380307/*381381- * Export the signal mask handling for aysnchronous code that308308+ * Export the signal mask handling for synchronous code that382309 * sleeps on RPC calls383310 */311311+#define RPC_INTR_SIGNALS (sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGKILL))384312313313+static void rpc_save_sigmask(sigset_t *oldset, int intr)314314+{315315+ unsigned long sigallow = 0;316316+ sigset_t sigmask;317317+318318+ /* Block all signals except those listed in sigallow */319319+ if (intr)320320+ sigallow |= RPC_INTR_SIGNALS;321321+ siginitsetinv(&sigmask, sigallow);322322+ sigprocmask(SIG_BLOCK, &sigmask, oldset);323323+}324324+325325+static inline void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset)326326+{327327+ rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task));328328+}329329+330330+static inline void rpc_restore_sigmask(sigset_t *oldset)331331+{332332+ sigprocmask(SIG_SETMASK, oldset, NULL);333333+}334334+385335void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset)386336{387387- unsigned long sigallow = sigmask(SIGKILL);388388- unsigned long irqflags;389389-390390- /* Turn off various signals */391391- if (clnt->cl_intr) {392392- struct k_sigaction *action = current->sighand->action;393393- if (action[SIGINT-1].sa.sa_handler == SIG_DFL)394394- sigallow |= sigmask(SIGINT);395395- if (action[SIGQUIT-1].sa.sa_handler == SIG_DFL)396396- sigallow |= sigmask(SIGQUIT);397397- }398398- spin_lock_irqsave(¤t->sighand->siglock, irqflags);399399- *oldset = current->blocked;400400- siginitsetinv(¤t->blocked, sigallow & ~oldset->sig[0]);401401- recalc_sigpending();402402- spin_unlock_irqrestore(¤t->sighand->siglock, irqflags);337337+ rpc_save_sigmask(oldset, clnt->cl_intr);403338}404339405340void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)406341{407407- unsigned long irqflags;408408-409409- spin_lock_irqsave(¤t->sighand->siglock, irqflags);410410- current->blocked = *oldset;411411- recalc_sigpending();412412- spin_unlock_irqrestore(¤t->sighand->siglock, irqflags);342342+ rpc_restore_sigmask(oldset);413343}414344415345/*···430354431355 BUG_ON(flags & RPC_TASK_ASYNC);432356433433- rpc_clnt_sigmask(clnt, &oldset); 434434-435357 status = -ENOMEM;436358 task = rpc_new_task(clnt, NULL, flags);437359 if (task == NULL)438360 goto out;439361362362+ /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */363363+ rpc_task_sigmask(task, &oldset);364364+440365 rpc_call_setup(task, msg, 0);441366442367 /* Set up the call info struct and execute the task */443443- if (task->tk_status == 0)368368+ if (task->tk_status == 0) {444369 status = rpc_execute(task);445445- else {370370+ } else {446371 status = task->tk_status;447372 rpc_release_task(task);448373 }449374375375+ rpc_restore_sigmask(&oldset);450376out:451451- rpc_clnt_sigunmask(clnt, &oldset); 452452-453377 return status;454378}455379···470394471395 flags |= RPC_TASK_ASYNC;472396473473- rpc_clnt_sigmask(clnt, &oldset); 474474-475397 /* Create/initialize a new RPC task */476398 if (!callback)477399 callback = rpc_default_callback;···477403 if (!(task = rpc_new_task(clnt, callback, flags)))478404 goto out;479405 task->tk_calldata = data;406406+407407+ /* Mask signals on GSS_AUTH upcalls */408408+ rpc_task_sigmask(task, &oldset); 480409481410 rpc_call_setup(task, msg, 0);482411···490413 else491414 rpc_release_task(task);492415416416+ rpc_restore_sigmask(&oldset); 493417out:494494- rpc_clnt_sigunmask(clnt, &oldset); 495495-496418 return status;497419}498420···669593 return;670594 printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); 671595672672- if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) {596596+ if (RPC_IS_ASYNC(task) || !signalled()) {673597 xprt_release(task);674598 task->tk_action = call_reserve;675599 rpc_delay(task, HZ>>4);···1033957 *p++ = htonl(clnt->cl_prog); /* program number */1034958 *p++ = htonl(clnt->cl_vers); /* program version */1035959 *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */10361036- return rpcauth_marshcred(task, p);960960+ p = rpcauth_marshcred(task, p);961961+ req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p);962962+ return p;1037963}10389641039965/*···1064986 case RPC_AUTH_ERROR:1065987 break;1066988 case RPC_MISMATCH:10671067- printk(KERN_WARNING "%s: RPC call version mismatch!\n", __FUNCTION__);10681068- goto out_eio;989989+ dprintk("%s: RPC call version mismatch!\n", __FUNCTION__);990990+ error = -EPROTONOSUPPORT;991991+ goto out_err;1069992 default:10701070- printk(KERN_WARNING "%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n);993993+ dprintk("%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n);1071994 goto out_eio;1072995 }1073996 if (--len < 0)···11191040 case RPC_SUCCESS:11201041 return p;11211042 case RPC_PROG_UNAVAIL:11221122- printk(KERN_WARNING "RPC: call_verify: program %u is unsupported by server %s\n",10431043+ dprintk("RPC: call_verify: program %u is unsupported by server %s\n",11231044 (unsigned int)task->tk_client->cl_prog,11241045 task->tk_client->cl_server);11251125- goto out_eio;10461046+ error = -EPFNOSUPPORT;10471047+ goto out_err;11261048 case RPC_PROG_MISMATCH:11271127- printk(KERN_WARNING "RPC: call_verify: program %u, version %u unsupported by server %s\n",10491049+ dprintk("RPC: call_verify: program %u, version %u unsupported by server %s\n",11281050 (unsigned int)task->tk_client->cl_prog,11291051 (unsigned int)task->tk_client->cl_vers,11301052 task->tk_client->cl_server);11311131- goto out_eio;10531053+ error = -EPROTONOSUPPORT;10541054+ goto out_err;11321055 case RPC_PROC_UNAVAIL:11331133- printk(KERN_WARNING "RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n",10561056+ dprintk("RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n",11341057 task->tk_msg.rpc_proc,11351058 task->tk_client->cl_prog,11361059 task->tk_client->cl_vers,11371060 task->tk_client->cl_server);11381138- goto out_eio;10611061+ error = -EOPNOTSUPP;10621062+ goto out_err;11391063 case RPC_GARBAGE_ARGS:11401064 dprintk("RPC: %4d %s: server saw garbage\n", task->tk_pid, __FUNCTION__);11411065 break; /* retry */···11511069 task->tk_client->cl_stats->rpcgarbage++;11521070 if (task->tk_garb_retry) {11531071 task->tk_garb_retry--;11541154- dprintk(KERN_WARNING "RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid);10721072+ dprintk("RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid);11551073 task->tk_action = call_bind;11561074 return NULL;11571075 }···11641082out_overflow:11651083 printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__);11661084 goto out_retry;10851085+}10861086+10871087+static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj)10881088+{10891089+ return 0;10901090+}10911091+10921092+static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj)10931093+{10941094+ return 0;10951095+}10961096+10971097+static struct rpc_procinfo rpcproc_null = {10981098+ .p_encode = rpcproc_encode_null,10991099+ .p_decode = rpcproc_decode_null,11001100+};11011101+11021102+int rpc_ping(struct rpc_clnt *clnt, int flags)11031103+{11041104+ struct rpc_message msg = {11051105+ .rpc_proc = &rpcproc_null,11061106+ };11071107+ int err;11081108+ msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0);11091109+ err = rpc_call_sync(clnt, &msg, flags);11101110+ put_rpccred(msg.rpc_cred);11111111+ return err;11671112}
···290290 return;291291 }292292 } else293293- wake_up(&task->u.tk_wait.waitq);293293+ wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED);294294}295295296296/*···555555}556556557557/*558558+ * Helper that calls task->tk_exit if it exists and then returns559559+ * true if we should exit __rpc_execute.560560+ */561561+static inline int __rpc_do_exit(struct rpc_task *task)562562+{563563+ if (task->tk_exit != NULL) {564564+ lock_kernel();565565+ task->tk_exit(task);566566+ unlock_kernel();567567+ /* If tk_action is non-null, we should restart the call */568568+ if (task->tk_action != NULL) {569569+ if (!RPC_ASSASSINATED(task)) {570570+ /* Release RPC slot and buffer memory */571571+ xprt_release(task);572572+ rpc_free(task);573573+ return 0;574574+ }575575+ printk(KERN_ERR "RPC: dead task tried to walk away.\n");576576+ }577577+ }578578+ return 1;579579+}580580+581581+static int rpc_wait_bit_interruptible(void *word)582582+{583583+ if (signal_pending(current))584584+ return -ERESTARTSYS;585585+ schedule();586586+ return 0;587587+}588588+589589+/*558590 * This is the RPC `scheduler' (or rather, the finite state machine).559591 */560592static int __rpc_execute(struct rpc_task *task)···598566599567 BUG_ON(RPC_IS_QUEUED(task));600568601601- restarted:602602- while (1) {569569+ for (;;) {603570 /*604571 * Garbage collection of pending timers...605572 */···631600 * by someone else.632601 */633602 if (!RPC_IS_QUEUED(task)) {634634- if (!task->tk_action)603603+ if (task->tk_action != NULL) {604604+ lock_kernel();605605+ task->tk_action(task);606606+ unlock_kernel();607607+ } else if (__rpc_do_exit(task))635608 break;636636- lock_kernel();637637- task->tk_action(task);638638- unlock_kernel();639609 }640610641611 /*···656624657625 /* sync task: sleep here */658626 dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid);659659- if (RPC_TASK_UNINTERRUPTIBLE(task)) {660660- __wait_event(task->u.tk_wait.waitq, !RPC_IS_QUEUED(task));661661- } else {662662- __wait_event_interruptible(task->u.tk_wait.waitq, !RPC_IS_QUEUED(task), status);627627+ /* Note: Caller should be using rpc_clnt_sigmask() */628628+ status = out_of_line_wait_on_bit(&task->tk_runstate,629629+ RPC_TASK_QUEUED, rpc_wait_bit_interruptible,630630+ TASK_INTERRUPTIBLE);631631+ if (status == -ERESTARTSYS) {663632 /*664633 * When a sync task receives a signal, it exits with665634 * -ERESTARTSYS. In order to catch any callbacks that666635 * clean up after sleeping on some queue, we don't667636 * break the loop here, but go around once more.668637 */669669- if (status == -ERESTARTSYS) {670670- dprintk("RPC: %4d got signal\n", task->tk_pid);671671- task->tk_flags |= RPC_TASK_KILLED;672672- rpc_exit(task, -ERESTARTSYS);673673- rpc_wake_up_task(task);674674- }638638+ dprintk("RPC: %4d got signal\n", task->tk_pid);639639+ task->tk_flags |= RPC_TASK_KILLED;640640+ rpc_exit(task, -ERESTARTSYS);641641+ rpc_wake_up_task(task);675642 }676643 rpc_set_running(task);677644 dprintk("RPC: %4d sync task resuming\n", task->tk_pid);678678- }679679-680680- if (task->tk_exit) {681681- lock_kernel();682682- task->tk_exit(task);683683- unlock_kernel();684684- /* If tk_action is non-null, the user wants us to restart */685685- if (task->tk_action) {686686- if (!RPC_ASSASSINATED(task)) {687687- /* Release RPC slot and buffer memory */688688- if (task->tk_rqstp)689689- xprt_release(task);690690- rpc_free(task);691691- goto restarted;692692- }693693- printk(KERN_ERR "RPC: dead task tries to walk away.\n");694694- }695645 }696646697647 dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status);···773759774760 /* Initialize workqueue for async tasks */775761 task->tk_workqueue = rpciod_workqueue;776776- if (!RPC_IS_ASYNC(task))777777- init_waitqueue_head(&task->u.tk_wait.waitq);778762779763 if (clnt) {780764 atomic_inc(&clnt->cl_users);
+5-1
net/sunrpc/sunrpc_syms.c
···4242/* RPC client functions */4343EXPORT_SYMBOL(rpc_create_client);4444EXPORT_SYMBOL(rpc_clone_client);4545+EXPORT_SYMBOL(rpc_bind_new_program);4546EXPORT_SYMBOL(rpc_destroy_client);4647EXPORT_SYMBOL(rpc_shutdown_client);4748EXPORT_SYMBOL(rpc_release_client);···62616362/* Client transport */6463EXPORT_SYMBOL(xprt_create_proto);6565-EXPORT_SYMBOL(xprt_destroy);6664EXPORT_SYMBOL(xprt_set_timeout);6765EXPORT_SYMBOL(xprt_udp_slot_table_entries);6866EXPORT_SYMBOL(xprt_tcp_slot_table_entries);···129129EXPORT_SYMBOL(xdr_encode_pages);130130EXPORT_SYMBOL(xdr_inline_pages);131131EXPORT_SYMBOL(xdr_shift_buf);132132+EXPORT_SYMBOL(xdr_encode_word);133133+EXPORT_SYMBOL(xdr_decode_word);134134+EXPORT_SYMBOL(xdr_encode_array2);135135+EXPORT_SYMBOL(xdr_decode_array2);132136EXPORT_SYMBOL(xdr_buf_from_iov);133137EXPORT_SYMBOL(xdr_buf_subsegment);134138EXPORT_SYMBOL(xdr_buf_read_netobj);
+19-17
net/sunrpc/svc.c
···3535 if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))3636 return NULL;3737 memset(serv, 0, sizeof(*serv));3838+ serv->sv_name = prog->pg_name;3839 serv->sv_program = prog;3940 serv->sv_nrthreads = 1;4041 serv->sv_stats = prog->pg_stats;4142 serv->sv_bufsz = bufsize? bufsize : 4096;4242- prog->pg_lovers = prog->pg_nvers-1;4343 xdrsize = 0;4444- for (vers=0; vers<prog->pg_nvers ; vers++)4545- if (prog->pg_vers[vers]) {4646- prog->pg_hivers = vers;4747- if (prog->pg_lovers > vers)4848- prog->pg_lovers = vers;4949- if (prog->pg_vers[vers]->vs_xdrsize > xdrsize)5050- xdrsize = prog->pg_vers[vers]->vs_xdrsize;5151- }4444+ while (prog) {4545+ prog->pg_lovers = prog->pg_nvers-1;4646+ for (vers=0; vers<prog->pg_nvers ; vers++)4747+ if (prog->pg_vers[vers]) {4848+ prog->pg_hivers = vers;4949+ if (prog->pg_lovers > vers)5050+ prog->pg_lovers = vers;5151+ if (prog->pg_vers[vers]->vs_xdrsize > xdrsize)5252+ xdrsize = prog->pg_vers[vers]->vs_xdrsize;5353+ }5454+ prog = prog->pg_next;5555+ }5256 serv->sv_xdrsize = xdrsize;5357 INIT_LIST_HEAD(&serv->sv_threads);5458 INIT_LIST_HEAD(&serv->sv_sockets);5559 INIT_LIST_HEAD(&serv->sv_tempsocks);5660 INIT_LIST_HEAD(&serv->sv_permsocks);5761 spin_lock_init(&serv->sv_lock);5858-5959- serv->sv_name = prog->pg_name;60626163 /* Remove any stale portmap registrations */6264 svc_register(serv, 0, 0);···283281 rqstp->rq_res.len = 0;284282 rqstp->rq_res.page_base = 0;285283 rqstp->rq_res.page_len = 0;284284+ rqstp->rq_res.buflen = PAGE_SIZE;286285 rqstp->rq_res.tail[0].iov_len = 0;287286 /* tcp needs a space for the record length... */288287 if (rqstp->rq_prot == IPPROTO_TCP)···341338 goto sendit;342339 }343340344344- if (prog != progp->pg_prog)341341+ for (progp = serv->sv_program; progp; progp = progp->pg_next)342342+ if (prog == progp->pg_prog)343343+ break;344344+ if (progp == NULL)345345 goto err_bad_prog;346346347347 if (vers >= progp->pg_nvers ||···457451 goto sendit;458452459453err_bad_prog:460460-#ifdef RPC_PARANOIA461461- if (prog != 100227 || progp->pg_prog != 100003)462462- printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);463463- /* else it is just a Solaris client seeing if ACLs are supported */464464-#endif454454+ dprintk("svc: unknown program %d\n", prog);465455 serv->sv_stats->rpcbadfmt++;466456 svc_putu32(resv, rpc_prog_unavail);467457 goto sendit;
+288-10
net/sunrpc/xdr.c
···176176 xdr->buflen += len;177177}178178179179-void179179+ssize_t180180xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,181181 skb_reader_t *desc,182182 skb_read_actor_t copy_actor)183183{184184 struct page **ppage = xdr->pages;185185 unsigned int len, pglen = xdr->page_len;186186+ ssize_t copied = 0;186187 int ret;187188188189 len = xdr->head[0].iov_len;189190 if (base < len) {190191 len -= base;191192 ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);193193+ copied += ret;192194 if (ret != len || !desc->count)193193- return;195195+ goto out;194196 base = 0;195197 } else196198 base -= len;···212210 do {213211 char *kaddr;214212213213+ /* ACL likes to be lazy in allocating pages - ACLs214214+ * are small by default but can get huge. */215215+ if (unlikely(*ppage == NULL)) {216216+ *ppage = alloc_page(GFP_ATOMIC);217217+ if (unlikely(*ppage == NULL)) {218218+ if (copied == 0)219219+ copied = -ENOMEM;220220+ goto out;221221+ }222222+ }223223+215224 len = PAGE_CACHE_SIZE;216225 kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA);217226 if (base) {···238225 }239226 flush_dcache_page(*ppage);240227 kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);228228+ copied += ret;241229 if (ret != len || !desc->count)242242- return;230230+ goto out;243231 ppage++;244232 } while ((pglen -= len) != 0);245233copy_tail:246234 len = xdr->tail[0].iov_len;247235 if (base < len)248248- copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base);236236+ copied += copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base);237237+out:238238+ return copied;249239}250240251241···632616void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)633617{634618 struct kvec *iov = buf->head;619619+ int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;635620621621+ BUG_ON(scratch_len < 0);636622 xdr->buf = buf;637623 xdr->iov = iov;638638- xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);639639- buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base;640640- xdr->p = p;624624+ xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len);625625+ xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len);626626+ BUG_ON(iov->iov_len > scratch_len);627627+628628+ if (p != xdr->p && p != NULL) {629629+ size_t len;630630+631631+ BUG_ON(p < xdr->p || p > xdr->end);632632+ len = (char *)p - (char *)xdr->p;633633+ xdr->p = p;634634+ buf->len += len;635635+ iov->iov_len += len;636636+ }641637}642638EXPORT_SYMBOL(xdr_init_encode);643639···887859 return status;888860}889861890890-static int891891-read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)862862+/* obj is assumed to point to allocated memory of size at least len: */863863+int864864+write_bytes_to_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len)865865+{866866+ struct xdr_buf subbuf;867867+ int this_len;868868+ int status;869869+870870+ status = xdr_buf_subsegment(buf, &subbuf, base, len);871871+ if (status)872872+ goto out;873873+ this_len = min(len, (int)subbuf.head[0].iov_len);874874+ memcpy(subbuf.head[0].iov_base, obj, this_len);875875+ len -= this_len;876876+ obj += this_len;877877+ this_len = min(len, (int)subbuf.page_len);878878+ if (this_len)879879+ _copy_to_pages(subbuf.pages, subbuf.page_base, obj, this_len);880880+ len -= this_len;881881+ obj += this_len;882882+ this_len = min(len, (int)subbuf.tail[0].iov_len);883883+ memcpy(subbuf.tail[0].iov_base, obj, this_len);884884+out:885885+ return status;886886+}887887+888888+int889889+xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj)892890{893891 u32 raw;894892 int status;···924870 return status;925871 *obj = ntohl(raw);926872 return 0;873873+}874874+875875+int876876+xdr_encode_word(struct xdr_buf *buf, int base, u32 obj)877877+{878878+ u32 raw = htonl(obj);879879+880880+ return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));927881}928882929883/* If the netobj starting offset bytes from the start of xdr_buf is contained···944882 u32 tail_offset = buf->head[0].iov_len + buf->page_len;945883 u32 obj_end_offset;946884947947- if (read_u32_from_xdr_buf(buf, offset, &obj->len))885885+ if (xdr_decode_word(buf, offset, &obj->len))948886 goto out;949887 obj_end_offset = offset + 4 + obj->len;950888···976914 return 0;977915out:978916 return -1;917917+}918918+919919+/* Returns 0 on success, or else a negative error code. */920920+static int921921+xdr_xcode_array2(struct xdr_buf *buf, unsigned int base,922922+ struct xdr_array2_desc *desc, int encode)923923+{924924+ char *elem = NULL, *c;925925+ unsigned int copied = 0, todo, avail_here;926926+ struct page **ppages = NULL;927927+ int err;928928+929929+ if (encode) {930930+ if (xdr_encode_word(buf, base, desc->array_len) != 0)931931+ return -EINVAL;932932+ } else {933933+ if (xdr_decode_word(buf, base, &desc->array_len) != 0 ||934934+ (unsigned long) base + 4 + desc->array_len *935935+ desc->elem_size > buf->len)936936+ return -EINVAL;937937+ }938938+ base += 4;939939+940940+ if (!desc->xcode)941941+ return 0;942942+943943+ todo = desc->array_len * desc->elem_size;944944+945945+ /* process head */946946+ if (todo && base < buf->head->iov_len) {947947+ c = buf->head->iov_base + base;948948+ avail_here = min_t(unsigned int, todo,949949+ buf->head->iov_len - base);950950+ todo -= avail_here;951951+952952+ while (avail_here >= desc->elem_size) {953953+ err = desc->xcode(desc, c);954954+ if (err)955955+ goto out;956956+ c += desc->elem_size;957957+ avail_here -= desc->elem_size;958958+ }959959+ if (avail_here) {960960+ if (!elem) {961961+ elem = kmalloc(desc->elem_size, GFP_KERNEL);962962+ err = -ENOMEM;963963+ if (!elem)964964+ goto out;965965+ }966966+ if (encode) {967967+ err = desc->xcode(desc, elem);968968+ if (err)969969+ goto out;970970+ memcpy(c, elem, avail_here);971971+ } else972972+ memcpy(elem, c, avail_here);973973+ copied = avail_here;974974+ }975975+ base = buf->head->iov_len; /* align to start of pages */976976+ }977977+978978+ /* process pages array */979979+ base -= buf->head->iov_len;980980+ if (todo && base < buf->page_len) {981981+ unsigned int avail_page;982982+983983+ avail_here = min(todo, buf->page_len - base);984984+ todo -= avail_here;985985+986986+ base += buf->page_base;987987+ ppages = buf->pages + (base >> PAGE_CACHE_SHIFT);988988+ base &= ~PAGE_CACHE_MASK;989989+ avail_page = min_t(unsigned int, PAGE_CACHE_SIZE - base,990990+ avail_here);991991+ c = kmap(*ppages) + base;992992+993993+ while (avail_here) {994994+ avail_here -= avail_page;995995+ if (copied || avail_page < desc->elem_size) {996996+ unsigned int l = min(avail_page,997997+ desc->elem_size - copied);998998+ if (!elem) {999999+ elem = kmalloc(desc->elem_size,10001000+ GFP_KERNEL);10011001+ err = -ENOMEM;10021002+ if (!elem)10031003+ goto out;10041004+ }10051005+ if (encode) {10061006+ if (!copied) {10071007+ err = desc->xcode(desc, elem);10081008+ if (err)10091009+ goto out;10101010+ }10111011+ memcpy(c, elem + copied, l);10121012+ copied += l;10131013+ if (copied == desc->elem_size)10141014+ copied = 0;10151015+ } else {10161016+ memcpy(elem + copied, c, l);10171017+ copied += l;10181018+ if (copied == desc->elem_size) {10191019+ err = desc->xcode(desc, elem);10201020+ if (err)10211021+ goto out;10221022+ copied = 0;10231023+ }10241024+ }10251025+ avail_page -= l;10261026+ c += l;10271027+ }10281028+ while (avail_page >= desc->elem_size) {10291029+ err = desc->xcode(desc, c);10301030+ if (err)10311031+ goto out;10321032+ c += desc->elem_size;10331033+ avail_page -= desc->elem_size;10341034+ }10351035+ if (avail_page) {10361036+ unsigned int l = min(avail_page,10371037+ desc->elem_size - copied);10381038+ if (!elem) {10391039+ elem = kmalloc(desc->elem_size,10401040+ GFP_KERNEL);10411041+ err = -ENOMEM;10421042+ if (!elem)10431043+ goto out;10441044+ }10451045+ if (encode) {10461046+ if (!copied) {10471047+ err = desc->xcode(desc, elem);10481048+ if (err)10491049+ goto out;10501050+ }10511051+ memcpy(c, elem + copied, l);10521052+ copied += l;10531053+ if (copied == desc->elem_size)10541054+ copied = 0;10551055+ } else {10561056+ memcpy(elem + copied, c, l);10571057+ copied += l;10581058+ if (copied == desc->elem_size) {10591059+ err = desc->xcode(desc, elem);10601060+ if (err)10611061+ goto out;10621062+ copied = 0;10631063+ }10641064+ }10651065+ }10661066+ if (avail_here) {10671067+ kunmap(*ppages);10681068+ ppages++;10691069+ c = kmap(*ppages);10701070+ }10711071+10721072+ avail_page = min(avail_here,10731073+ (unsigned int) PAGE_CACHE_SIZE);10741074+ }10751075+ base = buf->page_len; /* align to start of tail */10761076+ }10771077+10781078+ /* process tail */10791079+ base -= buf->page_len;10801080+ if (todo) {10811081+ c = buf->tail->iov_base + base;10821082+ if (copied) {10831083+ unsigned int l = desc->elem_size - copied;10841084+10851085+ if (encode)10861086+ memcpy(c, elem + copied, l);10871087+ else {10881088+ memcpy(elem + copied, c, l);10891089+ err = desc->xcode(desc, elem);10901090+ if (err)10911091+ goto out;10921092+ }10931093+ todo -= l;10941094+ c += l;10951095+ }10961096+ while (todo) {10971097+ err = desc->xcode(desc, c);10981098+ if (err)10991099+ goto out;11001100+ c += desc->elem_size;11011101+ todo -= desc->elem_size;11021102+ }11031103+ }11041104+ err = 0;11051105+11061106+out:11071107+ if (elem)11081108+ kfree(elem);11091109+ if (ppages)11101110+ kunmap(*ppages);11111111+ return err;11121112+}11131113+11141114+int11151115+xdr_decode_array2(struct xdr_buf *buf, unsigned int base,11161116+ struct xdr_array2_desc *desc)11171117+{11181118+ if (base >= buf->len)11191119+ return -EINVAL;11201120+11211121+ return xdr_xcode_array2(buf, base, desc, 0);11221122+}11231123+11241124+int11251125+xdr_encode_array2(struct xdr_buf *buf, unsigned int base,11261126+ struct xdr_array2_desc *desc)11271127+{11281128+ if ((unsigned long) base + 4 + desc->array_len * desc->elem_size >11291129+ buf->head->iov_len + buf->page_len + buf->tail->iov_len)11301130+ return -EINVAL;11311131+11321132+ return xdr_xcode_array2(buf, base, desc, 1);9791133}
+57-14
net/sunrpc/xprt.c
···569569 if (xprt->sock != NULL)570570 schedule_delayed_work(&xprt->sock_connect,571571 RPC_REESTABLISH_TIMEOUT);572572- else572572+ else {573573 schedule_work(&xprt->sock_connect);574574+ if (!RPC_IS_ASYNC(task))575575+ flush_scheduled_work();576576+ }574577 }575578 return;576579 out_write:···728725 goto no_checksum;729726730727 desc.csum = csum_partial(skb->data, desc.offset, skb->csum);731731- xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits);728728+ if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits) < 0)729729+ return -1;732730 if (desc.offset != skb->len) {733731 unsigned int csum2;734732 csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0);···741737 return -1;742738 return 0;743739no_checksum:744744- xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits);740740+ if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0)741741+ return -1;745742 if (desc.count)746743 return -1;747744 return 0;···826821{827822 if (len > desc->count)828823 len = desc->count;829829- if (skb_copy_bits(desc->skb, desc->offset, p, len))824824+ if (skb_copy_bits(desc->skb, desc->offset, p, len)) {825825+ dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n",826826+ len, desc->count);830827 return 0;828828+ }831829 desc->offset += len;832830 desc->count -= len;831831+ dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n",832832+ len, desc->count);833833 return len;834834}835835···873863static void874864tcp_check_recm(struct rpc_xprt *xprt)875865{866866+ dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n",867867+ xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags);876868 if (xprt->tcp_offset == xprt->tcp_reclen) {877869 xprt->tcp_flags |= XPRT_COPY_RECM;878870 xprt->tcp_offset = 0;···919907 struct rpc_rqst *req;920908 struct xdr_buf *rcvbuf;921909 size_t len;910910+ ssize_t r;922911923912 /* Find and lock the request corresponding to this xid */924913 spin_lock(&xprt->sock_lock);···940927 len = xprt->tcp_reclen - xprt->tcp_offset;941928 memcpy(&my_desc, desc, sizeof(my_desc));942929 my_desc.count = len;943943- xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,930930+ r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,944931 &my_desc, tcp_copy_data);945945- desc->count -= len;946946- desc->offset += len;932932+ desc->count -= r;933933+ desc->offset += r;947934 } else948948- xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,935935+ r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,949936 desc, tcp_copy_data);950950- xprt->tcp_copied += len;951951- xprt->tcp_offset += len;937937+938938+ if (r > 0) {939939+ xprt->tcp_copied += r;940940+ xprt->tcp_offset += r;941941+ }942942+ if (r != len) {943943+ /* Error when copying to the receive buffer,944944+ * usually because we weren't able to allocate945945+ * additional buffer pages. All we can do now946946+ * is turn off XPRT_COPY_DATA, so the request947947+ * will not receive any additional updates,948948+ * and time out.949949+ * Any remaining data from this record will950950+ * be discarded.951951+ */952952+ xprt->tcp_flags &= ~XPRT_COPY_DATA;953953+ dprintk("RPC: XID %08x truncated request\n",954954+ ntohl(xprt->tcp_xid));955955+ dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n",956956+ xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen);957957+ goto out;958958+ }959959+960960+ dprintk("RPC: XID %08x read %u bytes\n",961961+ ntohl(xprt->tcp_xid), r);962962+ dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n",963963+ xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen);952964953965 if (xprt->tcp_copied == req->rq_private_buf.buflen)954966 xprt->tcp_flags &= ~XPRT_COPY_DATA;···982944 xprt->tcp_flags &= ~XPRT_COPY_DATA;983945 }984946947947+out:985948 if (!(xprt->tcp_flags & XPRT_COPY_DATA)) {986949 dprintk("RPC: %4d received reply complete\n",987950 req->rq_task->tk_pid);···1006967 desc->count -= len;1007968 desc->offset += len;1008969 xprt->tcp_offset += len;970970+ dprintk("RPC: discarded %u bytes\n", len);1009971 tcp_check_recm(xprt);1010972}1011973···11041064 case TCP_SYN_RECV:11051065 break;11061066 default:11071107- if (xprt_test_and_clear_connected(xprt))11081108- rpc_wake_up_status(&xprt->pending, -ENOTCONN);10671067+ xprt_disconnect(xprt);11091068 break;11101069 }11111070 out:···12421203 list_add_tail(&req->rq_list, &xprt->recv);12431204 spin_unlock_bh(&xprt->sock_lock);12441205 xprt_reset_majortimeo(req);12061206+ /* Turn off autodisconnect */12071207+ del_singleshot_timer_sync(&xprt->timer);12451208 }12461209 } else if (!req->rq_bytes_sent)12471210 return;···13741333 spin_lock(&xprt->xprt_lock);13751334 do_xprt_reserve(task);13761335 spin_unlock(&xprt->xprt_lock);13771377- if (task->tk_rqstp)13781378- del_timer_sync(&xprt->timer);13791336 }13801337}13811338···16881649 rpc_wake_up(&xprt->backlog);16891650 wake_up(&xprt->cong_wait);16901651 del_timer_sync(&xprt->timer);16521652+16531653+ /* synchronously wait for connect worker to finish */16541654+ cancel_delayed_work(&xprt->sock_connect);16551655+ flush_scheduled_work();16911656}1692165716931658/*