Loading fs/nfs/dir.c +75 −8 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ /* #define NFS_DEBUG_VERBOSE 1 */ static int nfs_opendir(struct inode *, struct file *); static int nfs_closedir(struct inode *, struct file *); static int nfs_readdir(struct file *, void *, filldir_t); static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *); Loading @@ -64,7 +65,7 @@ const struct file_operations nfs_dir_operations = { .read = generic_read_dir, .readdir = nfs_readdir, .open = nfs_opendir, .release = nfs_release, .release = nfs_closedir, .fsync = nfs_fsync_dir, }; Loading Loading @@ -133,13 +134,35 @@ const struct inode_operations nfs4_dir_inode_operations = { #endif /* CONFIG_NFS_V4 */ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred) { struct nfs_open_dir_context *ctx; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { ctx->duped = 0; ctx->dir_cookie = 0; ctx->dup_cookie = 0; ctx->cred = get_rpccred(cred); } else ctx = ERR_PTR(-ENOMEM); return ctx; } static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) { put_rpccred(ctx->cred); kfree(ctx); } /* * Open file */ static int nfs_opendir(struct inode *inode, struct file *filp) { int res; int res = 0; struct nfs_open_dir_context *ctx; struct rpc_cred *cred; dfprintk(FILE, "NFS: open dir(%s/%s)\n", filp->f_path.dentry->d_parent->d_name.name, Loading @@ -147,8 +170,15 @@ nfs_opendir(struct inode *inode, struct file *filp) nfs_inc_stats(inode, NFSIOS_VFSOPEN); /* Call generic open code in order to cache credentials */ res = nfs_open(inode, filp); cred = rpc_lookup_cred(); if (IS_ERR(cred)) return PTR_ERR(cred); ctx = alloc_nfs_open_dir_context(cred); if (IS_ERR(ctx)) { res = PTR_ERR(ctx); goto out; } filp->private_data = ctx; if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) { /* This is a mountpoint, so d_revalidate will never * have been called, so we need to refresh the Loading @@ -156,9 +186,18 @@ nfs_opendir(struct inode *inode, struct file *filp) */ __nfs_revalidate_inode(NFS_SERVER(inode), inode); } out: put_rpccred(cred); return res; } static int nfs_closedir(struct inode *inode, struct file *filp) { put_nfs_open_dir_context(filp->private_data); return 0; } struct nfs_cache_array_entry { u64 cookie; u64 ino; Loading Loading @@ -284,19 +323,20 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri { loff_t diff = desc->file->f_pos - desc->current_index; unsigned int index; struct nfs_open_dir_context *ctx = desc->file->private_data; if (diff < 0) goto out_eof; if (diff >= array->size) { if (array->eof_index >= 0) goto out_eof; desc->current_index += array->size; return -EAGAIN; } index = (unsigned int)diff; *desc->dir_cookie = array->array[index].cookie; desc->cache_entry_index = index; ctx->duped = 0; return 0; out_eof: desc->eof = 1; Loading @@ -307,10 +347,18 @@ static int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) { int i; loff_t new_pos; int status = -EAGAIN; struct nfs_open_dir_context *ctx = desc->file->private_data; for (i = 0; i < array->size; i++) { if (array->array[i].cookie == *desc->dir_cookie) { new_pos = desc->current_index + i; if (new_pos < desc->file->f_pos) { ctx->dup_cookie = *desc->dir_cookie; ctx->duped = 1; } desc->file->f_pos = new_pos; desc->cache_entry_index = i; return 0; } Loading Loading @@ -342,6 +390,7 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) if (status == -EAGAIN) { desc->last_cookie = array->last_cookie; desc->current_index += array->size; desc->page_index++; } nfs_readdir_release_array(desc->page); Loading @@ -354,7 +403,8 @@ static int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct file *file, struct inode *inode) { struct rpc_cred *cred = nfs_file_cred(file); struct nfs_open_dir_context *ctx = file->private_data; struct rpc_cred *cred = ctx->cred; unsigned long timestamp, gencount; int error; Loading Loading @@ -693,6 +743,20 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, int i = 0; int res = 0; struct nfs_cache_array *array = NULL; struct nfs_open_dir_context *ctx = file->private_data; if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) { if (printk_ratelimit()) { pr_notice("NFS: directory %s/%s contains a readdir loop. " "Please contact your server vendor. " "Offending cookie: %llu\n", file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name, *desc->dir_cookie); } res = -ELOOP; goto out; } array = nfs_readdir_get_array(desc->page); if (IS_ERR(array)) { Loading Loading @@ -785,6 +849,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) struct inode *inode = dentry->d_inode; nfs_readdir_descriptor_t my_desc, *desc = &my_desc; struct nfs_open_dir_context *dir_ctx = filp->private_data; int res; dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", Loading @@ -801,7 +866,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) memset(desc, 0, sizeof(*desc)); desc->file = filp; desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie; desc->dir_cookie = &dir_ctx->dir_cookie; desc->decode = NFS_PROTO(inode)->decode_dirent; desc->plus = NFS_USE_READDIRPLUS(inode); Loading Loading @@ -853,6 +918,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) { struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct nfs_open_dir_context *dir_ctx = filp->private_data; dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n", dentry->d_parent->d_name.name, Loading @@ -872,7 +938,8 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) } if (offset != filp->f_pos) { filp->f_pos = offset; nfs_file_open_context(filp)->dir_cookie = 0; dir_ctx->dir_cookie = 0; dir_ctx->duped = 0; } out: mutex_unlock(&inode->i_mutex); Loading fs/nfs/file.c +3 −0 Original line number Diff line number Diff line Loading @@ -326,6 +326,9 @@ nfs_file_fsync(struct file *file, int datasync) ret = xchg(&ctx->error, 0); if (!ret && status < 0) ret = status; if (!ret && !datasync) /* application has asked for meta-data sync */ ret = pnfs_layoutcommit_inode(inode, true); return ret; } Loading fs/nfs/getroot.c +4 −0 Original line number Diff line number Diff line Loading @@ -222,6 +222,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh, goto out; } if (fattr->valid & NFS_ATTR_FATTR_FSID && !nfs_fsid_equal(&server->fsid, &fattr->fsid)) memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); inode = nfs_fhget(sb, mntfh, fattr); if (IS_ERR(inode)) { dprintk("nfs_get_root: get root inode failed\n"); Loading fs/nfs/inode.c +1 −1 Original line number Diff line number Diff line Loading @@ -641,7 +641,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cr ctx->mode = f_mode; ctx->flags = 0; ctx->error = 0; ctx->dir_cookie = 0; nfs_init_lock_context(&ctx->lock_context); ctx->lock_context.open_context = ctx; INIT_LIST_HEAD(&ctx->list); Loading Loading @@ -1473,6 +1472,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) nfsi->delegation_state = 0; init_rwsem(&nfsi->rwsem); nfsi->layout = NULL; atomic_set(&nfsi->commits_outstanding, 0); #endif } Loading fs/nfs/internal.h +14 −0 Original line number Diff line number Diff line Loading @@ -283,11 +283,25 @@ extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt, extern void nfs_read_prepare(struct rpc_task *task, void *calldata); /* write.c */ extern void nfs_commit_free(struct nfs_write_data *p); extern int nfs_initiate_write(struct nfs_write_data *data, struct rpc_clnt *clnt, const struct rpc_call_ops *call_ops, int how); extern void nfs_write_prepare(struct rpc_task *task, void *calldata); extern int nfs_initiate_commit(struct nfs_write_data *data, struct rpc_clnt *clnt, const struct rpc_call_ops *call_ops, int how); extern void nfs_init_commit(struct nfs_write_data *data, struct list_head *head, struct pnfs_layout_segment *lseg); void nfs_retry_commit(struct list_head *page_list, struct pnfs_layout_segment *lseg); void nfs_commit_clear_lock(struct nfs_inode *nfsi); void nfs_commitdata_release(void *data); void nfs_commit_release_pages(struct nfs_write_data *data); #ifdef CONFIG_MIGRATION extern int nfs_migrate_page(struct address_space *, struct page *, struct page *); Loading Loading
fs/nfs/dir.c +75 −8 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ /* #define NFS_DEBUG_VERBOSE 1 */ static int nfs_opendir(struct inode *, struct file *); static int nfs_closedir(struct inode *, struct file *); static int nfs_readdir(struct file *, void *, filldir_t); static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *); Loading @@ -64,7 +65,7 @@ const struct file_operations nfs_dir_operations = { .read = generic_read_dir, .readdir = nfs_readdir, .open = nfs_opendir, .release = nfs_release, .release = nfs_closedir, .fsync = nfs_fsync_dir, }; Loading Loading @@ -133,13 +134,35 @@ const struct inode_operations nfs4_dir_inode_operations = { #endif /* CONFIG_NFS_V4 */ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred) { struct nfs_open_dir_context *ctx; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (ctx != NULL) { ctx->duped = 0; ctx->dir_cookie = 0; ctx->dup_cookie = 0; ctx->cred = get_rpccred(cred); } else ctx = ERR_PTR(-ENOMEM); return ctx; } static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) { put_rpccred(ctx->cred); kfree(ctx); } /* * Open file */ static int nfs_opendir(struct inode *inode, struct file *filp) { int res; int res = 0; struct nfs_open_dir_context *ctx; struct rpc_cred *cred; dfprintk(FILE, "NFS: open dir(%s/%s)\n", filp->f_path.dentry->d_parent->d_name.name, Loading @@ -147,8 +170,15 @@ nfs_opendir(struct inode *inode, struct file *filp) nfs_inc_stats(inode, NFSIOS_VFSOPEN); /* Call generic open code in order to cache credentials */ res = nfs_open(inode, filp); cred = rpc_lookup_cred(); if (IS_ERR(cred)) return PTR_ERR(cred); ctx = alloc_nfs_open_dir_context(cred); if (IS_ERR(ctx)) { res = PTR_ERR(ctx); goto out; } filp->private_data = ctx; if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) { /* This is a mountpoint, so d_revalidate will never * have been called, so we need to refresh the Loading @@ -156,9 +186,18 @@ nfs_opendir(struct inode *inode, struct file *filp) */ __nfs_revalidate_inode(NFS_SERVER(inode), inode); } out: put_rpccred(cred); return res; } static int nfs_closedir(struct inode *inode, struct file *filp) { put_nfs_open_dir_context(filp->private_data); return 0; } struct nfs_cache_array_entry { u64 cookie; u64 ino; Loading Loading @@ -284,19 +323,20 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri { loff_t diff = desc->file->f_pos - desc->current_index; unsigned int index; struct nfs_open_dir_context *ctx = desc->file->private_data; if (diff < 0) goto out_eof; if (diff >= array->size) { if (array->eof_index >= 0) goto out_eof; desc->current_index += array->size; return -EAGAIN; } index = (unsigned int)diff; *desc->dir_cookie = array->array[index].cookie; desc->cache_entry_index = index; ctx->duped = 0; return 0; out_eof: desc->eof = 1; Loading @@ -307,10 +347,18 @@ static int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) { int i; loff_t new_pos; int status = -EAGAIN; struct nfs_open_dir_context *ctx = desc->file->private_data; for (i = 0; i < array->size; i++) { if (array->array[i].cookie == *desc->dir_cookie) { new_pos = desc->current_index + i; if (new_pos < desc->file->f_pos) { ctx->dup_cookie = *desc->dir_cookie; ctx->duped = 1; } desc->file->f_pos = new_pos; desc->cache_entry_index = i; return 0; } Loading Loading @@ -342,6 +390,7 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) if (status == -EAGAIN) { desc->last_cookie = array->last_cookie; desc->current_index += array->size; desc->page_index++; } nfs_readdir_release_array(desc->page); Loading @@ -354,7 +403,8 @@ static int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct file *file, struct inode *inode) { struct rpc_cred *cred = nfs_file_cred(file); struct nfs_open_dir_context *ctx = file->private_data; struct rpc_cred *cred = ctx->cred; unsigned long timestamp, gencount; int error; Loading Loading @@ -693,6 +743,20 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, int i = 0; int res = 0; struct nfs_cache_array *array = NULL; struct nfs_open_dir_context *ctx = file->private_data; if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) { if (printk_ratelimit()) { pr_notice("NFS: directory %s/%s contains a readdir loop. " "Please contact your server vendor. " "Offending cookie: %llu\n", file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name, *desc->dir_cookie); } res = -ELOOP; goto out; } array = nfs_readdir_get_array(desc->page); if (IS_ERR(array)) { Loading Loading @@ -785,6 +849,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) struct inode *inode = dentry->d_inode; nfs_readdir_descriptor_t my_desc, *desc = &my_desc; struct nfs_open_dir_context *dir_ctx = filp->private_data; int res; dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", Loading @@ -801,7 +866,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) memset(desc, 0, sizeof(*desc)); desc->file = filp; desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie; desc->dir_cookie = &dir_ctx->dir_cookie; desc->decode = NFS_PROTO(inode)->decode_dirent; desc->plus = NFS_USE_READDIRPLUS(inode); Loading Loading @@ -853,6 +918,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) { struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct nfs_open_dir_context *dir_ctx = filp->private_data; dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n", dentry->d_parent->d_name.name, Loading @@ -872,7 +938,8 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) } if (offset != filp->f_pos) { filp->f_pos = offset; nfs_file_open_context(filp)->dir_cookie = 0; dir_ctx->dir_cookie = 0; dir_ctx->duped = 0; } out: mutex_unlock(&inode->i_mutex); Loading
fs/nfs/file.c +3 −0 Original line number Diff line number Diff line Loading @@ -326,6 +326,9 @@ nfs_file_fsync(struct file *file, int datasync) ret = xchg(&ctx->error, 0); if (!ret && status < 0) ret = status; if (!ret && !datasync) /* application has asked for meta-data sync */ ret = pnfs_layoutcommit_inode(inode, true); return ret; } Loading
fs/nfs/getroot.c +4 −0 Original line number Diff line number Diff line Loading @@ -222,6 +222,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh, goto out; } if (fattr->valid & NFS_ATTR_FATTR_FSID && !nfs_fsid_equal(&server->fsid, &fattr->fsid)) memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); inode = nfs_fhget(sb, mntfh, fattr); if (IS_ERR(inode)) { dprintk("nfs_get_root: get root inode failed\n"); Loading
fs/nfs/inode.c +1 −1 Original line number Diff line number Diff line Loading @@ -641,7 +641,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cr ctx->mode = f_mode; ctx->flags = 0; ctx->error = 0; ctx->dir_cookie = 0; nfs_init_lock_context(&ctx->lock_context); ctx->lock_context.open_context = ctx; INIT_LIST_HEAD(&ctx->list); Loading Loading @@ -1473,6 +1472,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) nfsi->delegation_state = 0; init_rwsem(&nfsi->rwsem); nfsi->layout = NULL; atomic_set(&nfsi->commits_outstanding, 0); #endif } Loading
fs/nfs/internal.h +14 −0 Original line number Diff line number Diff line Loading @@ -283,11 +283,25 @@ extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt, extern void nfs_read_prepare(struct rpc_task *task, void *calldata); /* write.c */ extern void nfs_commit_free(struct nfs_write_data *p); extern int nfs_initiate_write(struct nfs_write_data *data, struct rpc_clnt *clnt, const struct rpc_call_ops *call_ops, int how); extern void nfs_write_prepare(struct rpc_task *task, void *calldata); extern int nfs_initiate_commit(struct nfs_write_data *data, struct rpc_clnt *clnt, const struct rpc_call_ops *call_ops, int how); extern void nfs_init_commit(struct nfs_write_data *data, struct list_head *head, struct pnfs_layout_segment *lseg); void nfs_retry_commit(struct list_head *page_list, struct pnfs_layout_segment *lseg); void nfs_commit_clear_lock(struct nfs_inode *nfsi); void nfs_commitdata_release(void *data); void nfs_commit_release_pages(struct nfs_write_data *data); #ifdef CONFIG_MIGRATION extern int nfs_migrate_page(struct address_space *, struct page *, struct page *); Loading