diff options
-rw-r--r-- | fs/afs/afs_fs.h | 1 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 61 | ||||
-rw-r--r-- | fs/afs/internal.h | 1 | ||||
-rw-r--r-- | fs/afs/xattr.c | 52 | ||||
-rw-r--r-- | include/trace/events/afs.h | 1 |
5 files changed, 110 insertions, 6 deletions
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h index 4df1f1eec0ab..18a54ca422f8 100644 --- a/fs/afs/afs_fs.h +++ b/fs/afs/afs_fs.h @@ -20,6 +20,7 @@ enum AFS_FS_Operations { FSFETCHACL = 131, /* AFS Fetch file ACL */ FSFETCHSTATUS = 132, /* AFS Fetch file status */ FSSTOREDATA = 133, /* AFS Store file data */ + FSSTOREACL = 134, /* AFS Store file ACL */ FSSTORESTATUS = 135, /* AFS Store file status */ FSREMOVEFILE = 136, /* AFS Remove a file */ FSCREATEFILE = 137, /* AFS Create a file */ diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 283f486c59f4..7f1722b9e432 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -836,9 +836,10 @@ int afs_fs_create(struct afs_fs_cursor *fc, } /* - * deliver reply data to an FS.RemoveFile or FS.RemoveDir + * Deliver reply data to any operation that returns file status and volume + * sync. */ -static int afs_deliver_fs_remove(struct afs_call *call) +static int afs_deliver_fs_status_and_vol(struct afs_call *call) { struct afs_vnode *vnode = call->reply[0]; const __be32 *bp; @@ -868,14 +869,14 @@ static int afs_deliver_fs_remove(struct afs_call *call) static const struct afs_call_type afs_RXFSRemoveFile = { .name = "FS.RemoveFile", .op = afs_FS_RemoveFile, - .deliver = afs_deliver_fs_remove, + .deliver = afs_deliver_fs_status_and_vol, .destructor = afs_flat_call_destructor, }; static const struct afs_call_type afs_RXFSRemoveDir = { .name = "FS.RemoveDir", .op = afs_FS_RemoveDir, - .deliver = afs_deliver_fs_remove, + .deliver = afs_deliver_fs_status_and_vol, .destructor = afs_flat_call_destructor, }; @@ -2513,3 +2514,55 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) afs_make_call(&fc->ac, call, GFP_KERNEL); return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac); } + +/* + * FS.StoreACL operation type + */ +static const struct afs_call_type afs_RXFSStoreACL = { + .name = "FS.StoreACL", + .op = afs_FS_StoreACL, + .deliver = afs_deliver_fs_status_and_vol, + .destructor = afs_flat_call_destructor, +}; + +/* + * Fetch the ACL for a file. + */ +int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl) +{ + struct afs_vnode *vnode = fc->vnode; + struct afs_call *call; + struct afs_net *net = afs_v2net(vnode); + size_t size; + __be32 *bp; + + _enter(",%x,{%llx:%llu},,", + key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); + + size = round_up(acl->size, 4); + call = afs_alloc_flat_call(net, &afs_RXFSStoreACL, + 5 * 4 + size, (21 + 6) * 4); + if (!call) { + fc->ac.error = -ENOMEM; + return -ENOMEM; + } + + call->key = fc->key; + call->reply[0] = vnode; + call->reply[2] = NULL; /* volsync */ + + /* marshall the parameters */ + bp = call->request; + bp[0] = htonl(FSSTOREACL); + bp[1] = htonl(vnode->fid.vid); + bp[2] = htonl(vnode->fid.vnode); + bp[3] = htonl(vnode->fid.unique); + bp[4] = htonl(acl->size); + memcpy(&bp[5], acl->data, acl->size); + if (acl->size != size) + memset((void *)&bp[5] + acl->size, 0, size - acl->size); + + trace_afs_make_fs_call(call, &vnode->fid); + afs_make_call(&fc->ac, call, GFP_KERNEL); + return afs_wait_for_call_to_complete(call, &fc->ac); +} diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 683b802c20ea..5269824244c6 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -983,6 +983,7 @@ struct afs_acl { }; extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *); +extern int afs_fs_store_acl(struct afs_fs_cursor *, const struct afs_acl *); /* * fs_probe.c diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c index b7d3d714d8ff..31db360947a6 100644 --- a/fs/afs/xattr.c +++ b/fs/afs/xattr.c @@ -80,9 +80,57 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler, return ret; } +/* + * Set a file's AFS3 ACL. + */ +static int afs_xattr_set_acl(const struct xattr_handler *handler, + struct dentry *dentry, + struct inode *inode, const char *name, + const void *buffer, size_t size, int flags) +{ + struct afs_fs_cursor fc; + struct afs_vnode *vnode = AFS_FS_I(inode); + struct afs_acl *acl = NULL; + struct key *key; + int ret; + + if (flags == XATTR_CREATE) + return -EINVAL; + + key = afs_request_key(vnode->volume->cell); + if (IS_ERR(key)) + return PTR_ERR(key); + + acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); + if (!acl) { + key_put(key); + return -ENOMEM; + } + + acl->size = size; + memcpy(acl->data, buffer, size); + + ret = -ERESTARTSYS; + if (afs_begin_vnode_operation(&fc, vnode, key)) { + while (afs_select_fileserver(&fc)) { + fc.cb_break = afs_calc_vnode_cb_break(vnode); + afs_fs_store_acl(&fc, acl); + } + + afs_check_for_remote_deletion(&fc, fc.vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break); + ret = afs_end_vnode_operation(&fc); + } + + kfree(acl); + key_put(key); + return ret; +} + static const struct xattr_handler afs_xattr_afs_acl_handler = { - .name = "afs.acl", - .get = afs_xattr_get_acl, + .name = "afs.acl", + .get = afs_xattr_get_acl, + .set = afs_xattr_set_acl, }; /* diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 25c2e089c6ea..562f854ac4bf 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -36,6 +36,7 @@ enum afs_fs_operation { afs_FS_FetchACL = 131, /* AFS Fetch file ACL */ afs_FS_FetchStatus = 132, /* AFS Fetch file status */ afs_FS_StoreData = 133, /* AFS Store file data */ + afs_FS_StoreACL = 134, /* AFS Store file ACL */ afs_FS_StoreStatus = 135, /* AFS Store file status */ afs_FS_RemoveFile = 136, /* AFS Remove a file */ afs_FS_CreateFile = 137, /* AFS Create a file */ |