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

Commit 45222b9e authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

AFS: implement statfs



Implement the statfs() op for AFS.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0f300ca9
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

#define AFS_MAXCELLNAME	64		/* maximum length of a cell name */
#define AFS_MAXVOLNAME	64		/* maximum length of a volume name */
#define AFSNAMEMAX	256		/* maximum length of a filename plus NUL */
#define AFSPATHMAX	1024		/* maximum length of a pathname plus NUL */
#define AFSOPAQUEMAX	1024		/* maximum length of an opaque field */

typedef unsigned			afs_volid_t;
typedef unsigned			afs_vnodeid_t;
@@ -143,4 +146,24 @@ struct afs_volsync {
	time_t			creation;	/* volume creation time */
};

/*
 * AFS volume status record
 */
struct afs_volume_status {
	u32			vid;		/* volume ID */
	u32			parent_id;	/* parent volume ID */
	u8			online;		/* true if volume currently online and available */
	u8			in_service;	/* true if volume currently in service */
	u8			blessed;	/* same as in_service */
	u8			needs_salvage;	/* true if consistency checking required */
	u32			type;		/* volume type (afs_voltype_t) */
	u32			min_quota;	/* minimum space set aside (blocks) */
	u32			max_quota;	/* maximum space this volume may occupy (blocks) */
	u32			blocks_in_use;	/* space this volume currently occupies (blocks) */
	u32			part_blocks_avail; /* space available in volume's partition */
	u32			part_max_blocks; /* size of volume's partition */
};

#define AFS_BLOCK_SIZE	1024

#endif /* AFS_H */
+2 −1
Original line number Diff line number Diff line
@@ -28,7 +28,8 @@ enum AFS_FS_Operations {
	FSMAKEDIR		= 141,	/* AFS Create a directory */
	FSREMOVEDIR		= 142,	/* AFS Remove a directory */
	FSGIVEUPCALLBACKS	= 147,	/* AFS Discard callback promises */
	FSGETVOLUMEINFO		= 148,	/* AFS Get root volume information */
	FSGETVOLUMEINFO		= 148,	/* AFS Get information about a volume */
	FSGETVOLUMESTATUS	= 149,	/* AFS Get volume status information */
	FSGETROOTVOLUME		= 151,	/* AFS Get root volume name */
	FSLOOKUP		= 161,	/* AFS lookup file in directory */
	FSFETCHDATA64		= 65537, /* AFS Fetch file data */
+9 −9
Original line number Diff line number Diff line
@@ -497,7 +497,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,

	ASSERTCMP(dentry->d_inode, ==, NULL);

	if (dentry->d_name.len > 255) {
	if (dentry->d_name.len >= AFSNAMEMAX) {
		_leave(" = -ENAMETOOLONG");
		return ERR_PTR(-ENAMETOOLONG);
	}
@@ -736,7 +736,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);

	ret = -ENAMETOOLONG;
	if (dentry->d_name.len > 255)
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

	key = afs_request_key(dvnode->volume->cell);
@@ -801,7 +801,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);

	ret = -ENAMETOOLONG;
	if (dentry->d_name.len > 255)
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

	key = afs_request_key(dvnode->volume->cell);
@@ -847,7 +847,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);

	ret = -ENAMETOOLONG;
	if (dentry->d_name.len > 255)
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

	key = afs_request_key(dvnode->volume->cell);
@@ -921,7 +921,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, int mode,
	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);

	ret = -ENAMETOOLONG;
	if (dentry->d_name.len > 255)
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

	key = afs_request_key(dvnode->volume->cell);
@@ -990,7 +990,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
	       dentry->d_name.name);

	ret = -ENAMETOOLONG;
	if (dentry->d_name.len > 255)
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

	key = afs_request_key(dvnode->volume->cell);
@@ -1038,11 +1038,11 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
	       content);

	ret = -ENAMETOOLONG;
	if (dentry->d_name.len > 255)
	if (dentry->d_name.len >= AFSNAMEMAX)
		goto error;

	ret = -EINVAL;
	if (strlen(content) > 1023)
	if (strlen(content) >= AFSPATHMAX)
		goto error;

	key = afs_request_key(dvnode->volume->cell);
@@ -1112,7 +1112,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
	       new_dentry->d_name.name);

	ret = -ENAMETOOLONG;
	if (new_dentry->d_name.len > 255)
	if (new_dentry->d_name.len >= AFSNAMEMAX)
		goto error;

	key = afs_request_key(orig_dvnode->volume->cell);
+298 −0
Original line number Diff line number Diff line
@@ -201,6 +201,29 @@ static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
	*_bp = bp;
}

/*
 * decode an AFSFetchVolumeStatus block
 */
static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
					    struct afs_volume_status *vs)
{
	const __be32 *bp = *_bp;

	vs->vid			= ntohl(*bp++);
	vs->parent_id		= ntohl(*bp++);
	vs->online		= ntohl(*bp++);
	vs->in_service		= ntohl(*bp++);
	vs->blessed		= ntohl(*bp++);
	vs->needs_salvage	= ntohl(*bp++);
	vs->type		= ntohl(*bp++);
	vs->min_quota		= ntohl(*bp++);
	vs->max_quota		= ntohl(*bp++);
	vs->blocks_in_use	= ntohl(*bp++);
	vs->part_blocks_avail	= ntohl(*bp++);
	vs->part_max_blocks	= ntohl(*bp++);
	*_bp = bp;
}

/*
 * deliver reply data to an FS.FetchStatus
 */
@@ -1450,3 +1473,278 @@ int afs_fs_setattr(struct afs_server *server, struct key *key,

	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
}

/*
 * deliver reply data to an FS.GetVolumeStatus
 */
static int afs_deliver_fs_get_volume_status(struct afs_call *call,
					    struct sk_buff *skb, bool last)
{
	const __be32 *bp;
	char *p;
	int ret;

	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);

	switch (call->unmarshall) {
	case 0:
		call->offset = 0;
		call->unmarshall++;

		/* extract the returned status record */
	case 1:
		_debug("extract status");
		ret = afs_extract_data(call, skb, last, call->buffer,
				       12 * 4);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
		default:	return ret;
		}

		bp = call->buffer;
		xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
		call->offset = 0;
		call->unmarshall++;

		/* extract the volume name length */
	case 2:
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
		default:	return ret;
		}

		call->count = ntohl(call->tmp);
		_debug("volname length: %u", call->count);
		if (call->count >= AFSNAMEMAX)
			return -EBADMSG;
		call->offset = 0;
		call->unmarshall++;

		/* extract the volume name */
	case 3:
		_debug("extract volname");
		if (call->count > 0) {
			ret = afs_extract_data(call, skb, last, call->reply3,
					       call->count);
			switch (ret) {
			case 0:		break;
			case -EAGAIN:	return 0;
			default:	return ret;
			}
		}

		p = call->reply3;
		p[call->count] = 0;
		_debug("volname '%s'", p);

		call->offset = 0;
		call->unmarshall++;

		/* extract the volume name padding */
		if ((call->count & 3) == 0) {
			call->unmarshall++;
			goto no_volname_padding;
		}
		call->count = 4 - (call->count & 3);

	case 4:
		ret = afs_extract_data(call, skb, last, call->buffer,
				       call->count);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
		default:	return ret;
		}

		call->offset = 0;
		call->unmarshall++;
	no_volname_padding:

		/* extract the offline message length */
	case 5:
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
		default:	return ret;
		}

		call->count = ntohl(call->tmp);
		_debug("offline msg length: %u", call->count);
		if (call->count >= AFSNAMEMAX)
			return -EBADMSG;
		call->offset = 0;
		call->unmarshall++;

		/* extract the offline message */
	case 6:
		_debug("extract offline");
		if (call->count > 0) {
			ret = afs_extract_data(call, skb, last, call->reply3,
					       call->count);
			switch (ret) {
			case 0:		break;
			case -EAGAIN:	return 0;
			default:	return ret;
			}
		}

		p = call->reply3;
		p[call->count] = 0;
		_debug("offline '%s'", p);

		call->offset = 0;
		call->unmarshall++;

		/* extract the offline message padding */
		if ((call->count & 3) == 0) {
			call->unmarshall++;
			goto no_offline_padding;
		}
		call->count = 4 - (call->count & 3);

	case 7:
		ret = afs_extract_data(call, skb, last, call->buffer,
				       call->count);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
		default:	return ret;
		}

		call->offset = 0;
		call->unmarshall++;
	no_offline_padding:

		/* extract the message of the day length */
	case 8:
		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
		default:	return ret;
		}

		call->count = ntohl(call->tmp);
		_debug("motd length: %u", call->count);
		if (call->count >= AFSNAMEMAX)
			return -EBADMSG;
		call->offset = 0;
		call->unmarshall++;

		/* extract the message of the day */
	case 9:
		_debug("extract motd");
		if (call->count > 0) {
			ret = afs_extract_data(call, skb, last, call->reply3,
					       call->count);
			switch (ret) {
			case 0:		break;
			case -EAGAIN:	return 0;
			default:	return ret;
			}
		}

		p = call->reply3;
		p[call->count] = 0;
		_debug("motd '%s'", p);

		call->offset = 0;
		call->unmarshall++;

		/* extract the message of the day padding */
		if ((call->count & 3) == 0) {
			call->unmarshall++;
			goto no_motd_padding;
		}
		call->count = 4 - (call->count & 3);

	case 10:
		ret = afs_extract_data(call, skb, last, call->buffer,
				       call->count);
		switch (ret) {
		case 0:		break;
		case -EAGAIN:	return 0;
		default:	return ret;
		}

		call->offset = 0;
		call->unmarshall++;
	no_motd_padding:

	case 11:
		_debug("trailer %d", skb->len);
		if (skb->len != 0)
			return -EBADMSG;
		break;
	}

	if (!last)
		return 0;

	_leave(" = 0 [done]");
	return 0;
}

/*
 * destroy an FS.GetVolumeStatus call
 */
static void afs_get_volume_status_call_destructor(struct afs_call *call)
{
	kfree(call->reply3);
	call->reply3 = NULL;
	afs_flat_call_destructor(call);
}

/*
 * FS.GetVolumeStatus operation type
 */
static const struct afs_call_type afs_RXFSGetVolumeStatus = {
	.name		= "FS.GetVolumeStatus",
	.deliver	= afs_deliver_fs_get_volume_status,
	.abort_to_error	= afs_abort_to_error,
	.destructor	= afs_get_volume_status_call_destructor,
};

/*
 * fetch the status of a volume
 */
int afs_fs_get_volume_status(struct afs_server *server,
			     struct key *key,
			     struct afs_vnode *vnode,
			     struct afs_volume_status *vs,
			     const struct afs_wait_mode *wait_mode)
{
	struct afs_call *call;
	__be32 *bp;
	void *tmpbuf;

	_enter("");

	tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
	if (!tmpbuf)
		return -ENOMEM;

	call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
	if (!call) {
		kfree(tmpbuf);
		return -ENOMEM;
	}

	call->key = key;
	call->reply = vnode;
	call->reply2 = vs;
	call->reply3 = tmpbuf;
	call->service_id = FS_SERVICE;
	call->port = htons(AFS_FS_PORT);

	/* marshall the parameters */
	bp = call->request;
	bp[0] = htonl(FSGETVOLUMESTATUS);
	bp[1] = htonl(vnode->fid.vid);

	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
}
+6 −0
Original line number Diff line number Diff line
@@ -506,6 +506,10 @@ extern int afs_fs_store_data(struct afs_server *, struct afs_writeback *,
extern int afs_fs_setattr(struct afs_server *, struct key *,
			  struct afs_vnode *, struct iattr *,
			  const struct afs_wait_mode *);
extern int afs_fs_get_volume_status(struct afs_server *, struct key *,
				    struct afs_vnode *,
				    struct afs_volume_status *,
				    const struct afs_wait_mode *);

/*
 * inode.c
@@ -672,6 +676,8 @@ extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *,
extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t,
				unsigned, unsigned);
extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *);
extern int afs_vnode_get_volume_status(struct afs_vnode *, struct key *,
				       struct afs_volume_status *);

/*
 * volume.c
Loading