Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40471856 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'nfs-for-2.6.39' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* 'nfs-for-2.6.39' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (28 commits)
  Cleanup XDR parsing for LAYOUTGET, GETDEVICEINFO
  NFSv4.1 convert layoutcommit sync to boolean
  NFSv4.1 pnfs_layoutcommit_inode fixes
  NFS: Determine initial mount security
  NFS: use secinfo when crossing mountpoints
  NFS: Add secinfo procedure
  NFS: lookup supports alternate client
  NFS: convert call_sync() to a function
  NFSv4.1 remove temp code that prevented ds commits
  NFSv4.1: layoutcommit
  NFSv4.1: filelayout driver specific code for COMMIT
  NFSv4.1: remove GETATTR from ds commits
  NFSv4.1: add generic layer hooks for pnfs COMMIT
  NFSv4.1: alloc and free commit_buckets
  NFSv4.1: shift filelayout_free_lseg
  NFSv4.1: pull out code from nfs_commit_release
  NFSv4.1: pull error handling out of nfs_commit_list
  NFSv4.1: add callback to nfs4_commit_done
  NFSv4.1: rearrange nfs_commit_rpcsetup
  NFSv4.1: don't send COMMIT to ds for data sync writes
  ...
parents ae005cbe 0acd2201
Loading
Loading
Loading
Loading
+78 −11
Original line number Diff line number Diff line
@@ -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 *);
@@ -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,
};

@@ -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,
@@ -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
@@ -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;
@@ -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;
@@ -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;
		}
@@ -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);
@@ -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;

@@ -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)) {
@@ -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",
@@ -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);

@@ -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,
@@ -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);
@@ -1068,7 +1135,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
	if (fhandle == NULL || fattr == NULL)
		goto out_error;

	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
	error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr);
	if (error)
		goto out_bad;
	if (nfs_compare_fh(NFS_FH(inode), fhandle))
@@ -1224,7 +1291,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
	parent = dentry->d_parent;
	/* Protect against concurrent sillydeletes */
	nfs_block_sillyrename(parent);
	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
	error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr);
	if (error == -ENOENT)
		goto no_entry;
	if (error < 0) {
@@ -1562,7 +1629,7 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
	if (dentry->d_inode)
		goto out;
	if (fhandle->size == 0) {
		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
		error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr);
		if (error)
			goto out_error;
	}
+3 −0
Original line number Diff line number Diff line
@@ -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;
}

+4 −0
Original line number Diff line number Diff line
@@ -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");
+6 −4
Original line number Diff line number Diff line
@@ -254,7 +254,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
	struct inode *inode = ERR_PTR(-ENOENT);
	unsigned long hash;

	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0)
	nfs_attr_check_mountpoint(sb, fattr);

	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0 && (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT) == 0)
		goto out_no_inode;
	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
		goto out_no_inode;
@@ -298,8 +300,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
			if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS))
				set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
			/* Deal with crossing mountpoints */
			if ((fattr->valid & NFS_ATTR_FATTR_FSID)
					&& !nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
			if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT ||
					fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
				if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
					inode->i_op = &nfs_referral_inode_operations;
				else
@@ -639,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);
@@ -1471,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
}

+25 −2
Original line number Diff line number Diff line
@@ -39,6 +39,12 @@ static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
	return 0;
}

static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr)
{
	if (!nfs_fsid_equal(&NFS_SB(parent)->fsid, &fattr->fsid))
		fattr->valid |= NFS_ATTR_FATTR_MOUNTPOINT;
}

struct nfs_clone_mount {
	const struct super_block *sb;
	const struct dentry *dentry;
@@ -214,6 +220,7 @@ extern const u32 nfs41_maxwrite_overhead;
/* nfs4proc.c */
#ifdef CONFIG_NFS_V4
extern struct rpc_procinfo nfs4_procedures[];
void nfs_fixup_secinfo_attributes(struct nfs_fattr *, struct nfs_fh *);
#endif

extern int nfs4_init_ds_session(struct nfs_client *clp);
@@ -276,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 *);
@@ -296,12 +317,14 @@ extern int nfs4_init_client(struct nfs_client *clp,
			    rpc_authflavor_t authflavour,
			    int noresvport);
extern void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data);
extern int _nfs4_call_sync(struct nfs_server *server,
extern int _nfs4_call_sync(struct rpc_clnt *clnt,
			   struct nfs_server *server,
			   struct rpc_message *msg,
			   struct nfs4_sequence_args *args,
			   struct nfs4_sequence_res *res,
			   int cache_reply);
extern int _nfs4_call_sync_session(struct nfs_server *server,
extern int _nfs4_call_sync_session(struct rpc_clnt *clnt,
				   struct nfs_server *server,
				   struct rpc_message *msg,
				   struct nfs4_sequence_args *args,
				   struct nfs4_sequence_res *res,
Loading