Commit 5f1ca5c6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull vfs fixes from Al Viro:
 "Assorted fixes all over the place.

  The iov_iter one is this cycle regression (splice from UDP triggering
  WARN_ON()), the rest is older"

* 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  afs: Use d_instantiate() rather than d_add() and don't d_drop()
  afs: Fix missing net error handling
  afs: Fix validation/callback interaction
  iov_iter: teach csum_and_copy_to_iter() to handle pipe-backed ones
  exportfs: do not read dentry after free
  exportfs: fix 'passing zero to ERR_PTR()' warning
  aio: fix failure to put the file pointer
  sysv: return 'err' instead of 0 in __sysv_write_inode
parents 49afe661 73116df7
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -1075,8 +1075,6 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
	if (fc->ac.error < 0)
		return;

	d_drop(new_dentry);

	inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key,
			 newfid, newstatus, newcb, fc->cbi);
	if (IS_ERR(inode)) {
@@ -1090,7 +1088,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
	vnode = AFS_FS_I(inode);
	set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
	afs_vnode_commit_status(fc, vnode, 0);
	d_add(new_dentry, inode);
	d_instantiate(new_dentry, inode);
}

/*
+24 −15
Original line number Diff line number Diff line
@@ -61,8 +61,11 @@ void afs_fileserver_probe_result(struct afs_call *call)
		afs_io_error(call, afs_io_error_fs_probe_fail);
		goto out;
	case -ECONNRESET: /* Responded, but call expired. */
	case -ERFKILL:
	case -EADDRNOTAVAIL:
	case -ENETUNREACH:
	case -EHOSTUNREACH:
	case -EHOSTDOWN:
	case -ECONNREFUSED:
	case -ETIMEDOUT:
	case -ETIME:
@@ -132,12 +135,14 @@ out:
static int afs_do_probe_fileserver(struct afs_net *net,
				   struct afs_server *server,
				   struct key *key,
				   unsigned int server_index)
				   unsigned int server_index,
				   struct afs_error *_e)
{
	struct afs_addr_cursor ac = {
		.index = 0,
	};
	int ret;
	bool in_progress = false;
	int err;

	_enter("%pU", &server->uuid);

@@ -151,15 +156,17 @@ static int afs_do_probe_fileserver(struct afs_net *net,
	server->probe.rtt = UINT_MAX;

	for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) {
		ret = afs_fs_get_capabilities(net, server, &ac, key, server_index,
		err = afs_fs_get_capabilities(net, server, &ac, key, server_index,
					      true);
		if (ret != -EINPROGRESS) {
			afs_fs_probe_done(server);
			return ret;
		}
		if (err == -EINPROGRESS)
			in_progress = true;
		else
			afs_prioritise_error(_e, err, ac.abort_code);
	}

	return 0;
	if (!in_progress)
		afs_fs_probe_done(server);
	return in_progress;
}

/*
@@ -169,21 +176,23 @@ int afs_probe_fileservers(struct afs_net *net, struct key *key,
			  struct afs_server_list *list)
{
	struct afs_server *server;
	int i, ret;
	struct afs_error e;
	bool in_progress = false;
	int i;

	e.error = 0;
	e.responded = false;
	for (i = 0; i < list->nr_servers; i++) {
		server = list->servers[i].server;
		if (test_bit(AFS_SERVER_FL_PROBED, &server->flags))
			continue;

		if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &server->flags)) {
			ret = afs_do_probe_fileserver(net, server, key, i);
			if (ret)
				return ret;
		}
		if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &server->flags) &&
		    afs_do_probe_fileserver(net, server, key, i, &e))
			in_progress = true;
	}

	return 0;
	return in_progress ? 0 : e.error;
}

/*
+12 −6
Original line number Diff line number Diff line
@@ -382,7 +382,7 @@ void afs_zap_data(struct afs_vnode *vnode)
int afs_validate(struct afs_vnode *vnode, struct key *key)
{
	time64_t now = ktime_get_real_seconds();
	bool valid = false;
	bool valid;
	int ret;

	_enter("{v={%llx:%llu} fl=%lx},%x",
@@ -402,15 +402,21 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
			vnode->cb_v_break = vnode->volume->cb_v_break;
			valid = false;
		} else if (vnode->status.type == AFS_FTYPE_DIR &&
			   test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) &&
			   vnode->cb_expires_at - 10 > now) {
			valid = true;
		} else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
			   vnode->cb_expires_at - 10 > now) {
			   (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) ||
			    vnode->cb_expires_at - 10 <= now)) {
			valid = false;
		} else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) ||
			   vnode->cb_expires_at - 10 <= now) {
			valid = false;
		} else {
			valid = true;
		}
	} else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
		valid = true;
	} else {
		vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
		vnode->cb_v_break = vnode->volume->cb_v_break;
		valid = false;
	}

	read_sequnlock_excl(&vnode->cb_lock);
+9 −0
Original line number Diff line number Diff line
@@ -695,6 +695,14 @@ struct afs_interface {
	unsigned	mtu;		/* MTU of interface */
};

/*
 * Error prioritisation and accumulation.
 */
struct afs_error {
	short	error;			/* Accumulated error */
	bool	responded;		/* T if server responded */
};

/*
 * Cursor for iterating over a server's address list.
 */
@@ -1015,6 +1023,7 @@ static inline void __afs_stat(atomic_t *s)
 * misc.c
 */
extern int afs_abort_to_error(u32);
extern void afs_prioritise_error(struct afs_error *, int, u32);

/*
 * mntpt.c
+52 −0
Original line number Diff line number Diff line
@@ -118,3 +118,55 @@ int afs_abort_to_error(u32 abort_code)
	default:		return -EREMOTEIO;
	}
}

/*
 * Select the error to report from a set of errors.
 */
void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code)
{
	switch (error) {
	case 0:
		return;
	default:
		if (e->error == -ETIMEDOUT ||
		    e->error == -ETIME)
			return;
	case -ETIMEDOUT:
	case -ETIME:
		if (e->error == -ENOMEM ||
		    e->error == -ENONET)
			return;
	case -ENOMEM:
	case -ENONET:
		if (e->error == -ERFKILL)
			return;
	case -ERFKILL:
		if (e->error == -EADDRNOTAVAIL)
			return;
	case -EADDRNOTAVAIL:
		if (e->error == -ENETUNREACH)
			return;
	case -ENETUNREACH:
		if (e->error == -EHOSTUNREACH)
			return;
	case -EHOSTUNREACH:
		if (e->error == -EHOSTDOWN)
			return;
	case -EHOSTDOWN:
		if (e->error == -ECONNREFUSED)
			return;
	case -ECONNREFUSED:
		if (e->error == -ECONNRESET)
			return;
	case -ECONNRESET: /* Responded, but call expired. */
		if (e->responded)
			return;
		e->error = error;
		return;

	case -ECONNABORTED:
		e->responded = true;
		e->error = afs_abort_to_error(abort_code);
		return;
	}
}
Loading