diff options
| -rw-r--r-- | fs/afs/Makefile | 1 | ||||
| -rw-r--r-- | fs/afs/afs.h | 27 | ||||
| -rw-r--r-- | fs/afs/callback.c | 5 | ||||
| -rw-r--r-- | fs/afs/cell.c | 98 | ||||
| -rw-r--r-- | fs/afs/cmservice.c | 3 | ||||
| -rw-r--r-- | fs/afs/dir.c | 51 | ||||
| -rw-r--r-- | fs/afs/file.c | 60 | ||||
| -rw-r--r-- | fs/afs/fsclient.c | 9 | ||||
| -rw-r--r-- | fs/afs/inode.c | 21 | ||||
| -rw-r--r-- | fs/afs/internal.h | 106 | ||||
| -rw-r--r-- | fs/afs/mntpt.c | 12 | ||||
| -rw-r--r-- | fs/afs/rxrpc.c | 137 | ||||
| -rw-r--r-- | fs/afs/security.c | 345 | ||||
| -rw-r--r-- | fs/afs/super.c | 142 | ||||
| -rw-r--r-- | fs/afs/vlclient.c | 6 | ||||
| -rw-r--r-- | fs/afs/vlocation.c | 26 | ||||
| -rw-r--r-- | fs/afs/vnode.c | 25 | ||||
| -rw-r--r-- | fs/afs/volume.c | 109 |
18 files changed, 945 insertions, 238 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile index 66bdc219ccde..cca198b2caed 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile | |||
| @@ -15,6 +15,7 @@ kafs-objs := \ | |||
| 15 | mntpt.o \ | 15 | mntpt.o \ |
| 16 | proc.o \ | 16 | proc.o \ |
| 17 | rxrpc.o \ | 17 | rxrpc.o \ |
| 18 | security.o \ | ||
| 18 | server.o \ | 19 | server.o \ |
| 19 | super.o \ | 20 | super.o \ |
| 20 | vlclient.o \ | 21 | vlclient.o \ |
diff --git a/fs/afs/afs.h b/fs/afs/afs.h index b9d2d2ceaf43..d959092aaf4b 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h | |||
| @@ -14,6 +14,9 @@ | |||
| 14 | 14 | ||
| 15 | #include <linux/in.h> | 15 | #include <linux/in.h> |
| 16 | 16 | ||
| 17 | #define AFS_MAXCELLNAME 64 /* maximum length of a cell name */ | ||
| 18 | #define AFS_MAXVOLNAME 64 /* maximum length of a volume name */ | ||
| 19 | |||
| 17 | typedef unsigned afs_volid_t; | 20 | typedef unsigned afs_volid_t; |
| 18 | typedef unsigned afs_vnodeid_t; | 21 | typedef unsigned afs_vnodeid_t; |
| 19 | typedef unsigned long long afs_dataversion_t; | 22 | typedef unsigned long long afs_dataversion_t; |
| @@ -75,6 +78,26 @@ struct afs_volume_info { | |||
| 75 | }; | 78 | }; |
| 76 | 79 | ||
| 77 | /* | 80 | /* |
| 81 | * AFS security ACE access mask | ||
| 82 | */ | ||
| 83 | typedef u32 afs_access_t; | ||
| 84 | #define AFS_ACE_READ 0x00000001U /* - permission to read a file/dir */ | ||
| 85 | #define AFS_ACE_WRITE 0x00000002U /* - permission to write/chmod a file */ | ||
| 86 | #define AFS_ACE_INSERT 0x00000004U /* - permission to create dirent in a dir */ | ||
| 87 | #define AFS_ACE_LOOKUP 0x00000008U /* - permission to lookup a file/dir in a dir */ | ||
| 88 | #define AFS_ACE_DELETE 0x00000010U /* - permission to delete a dirent from a dir */ | ||
| 89 | #define AFS_ACE_LOCK 0x00000020U /* - permission to lock a file */ | ||
| 90 | #define AFS_ACE_ADMINISTER 0x00000040U /* - permission to change ACL */ | ||
| 91 | #define AFS_ACE_USER_A 0x01000000U /* - 'A' user-defined permission */ | ||
| 92 | #define AFS_ACE_USER_B 0x02000000U /* - 'B' user-defined permission */ | ||
| 93 | #define AFS_ACE_USER_C 0x04000000U /* - 'C' user-defined permission */ | ||
| 94 | #define AFS_ACE_USER_D 0x08000000U /* - 'D' user-defined permission */ | ||
| 95 | #define AFS_ACE_USER_E 0x10000000U /* - 'E' user-defined permission */ | ||
| 96 | #define AFS_ACE_USER_F 0x20000000U /* - 'F' user-defined permission */ | ||
| 97 | #define AFS_ACE_USER_G 0x40000000U /* - 'G' user-defined permission */ | ||
| 98 | #define AFS_ACE_USER_H 0x80000000U /* - 'H' user-defined permission */ | ||
| 99 | |||
| 100 | /* | ||
| 78 | * AFS file status information | 101 | * AFS file status information |
| 79 | */ | 102 | */ |
| 80 | struct afs_file_status { | 103 | struct afs_file_status { |
| @@ -87,8 +110,8 @@ struct afs_file_status { | |||
| 87 | afs_dataversion_t data_version; /* current data version */ | 110 | afs_dataversion_t data_version; /* current data version */ |
| 88 | unsigned author; /* author ID */ | 111 | unsigned author; /* author ID */ |
| 89 | unsigned owner; /* owner ID */ | 112 | unsigned owner; /* owner ID */ |
| 90 | unsigned caller_access; /* access rights for authenticated caller */ | 113 | afs_access_t caller_access; /* access rights for authenticated caller */ |
| 91 | unsigned anon_access; /* access rights for unauthenticated caller */ | 114 | afs_access_t anon_access; /* access rights for unauthenticated caller */ |
| 92 | umode_t mode; /* UNIX mode */ | 115 | umode_t mode; /* UNIX mode */ |
| 93 | struct afs_fid parent; /* parent file ID */ | 116 | struct afs_fid parent; /* parent file ID */ |
| 94 | time_t mtime_client; /* last time client changed data */ | 117 | time_t mtime_client; /* last time client changed data */ |
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 611215547142..e674bebbb8b1 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
| @@ -72,7 +72,10 @@ void afs_broken_callback_work(struct work_struct *work) | |||
| 72 | return; /* someone else is dealing with it */ | 72 | return; /* someone else is dealing with it */ |
| 73 | 73 | ||
| 74 | if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { | 74 | if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { |
| 75 | if (afs_vnode_fetch_status(vnode) < 0) | 75 | if (S_ISDIR(vnode->vfs_inode.i_mode)) |
| 76 | afs_clear_permits(vnode); | ||
| 77 | |||
| 78 | if (afs_vnode_fetch_status(vnode, NULL, NULL) < 0) | ||
| 76 | goto out; | 79 | goto out; |
| 77 | 80 | ||
| 78 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) | 81 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 733c60246ab0..9b1311a1df51 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
| @@ -11,6 +11,9 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 14 | #include <linux/key.h> | ||
| 15 | #include <linux/ctype.h> | ||
| 16 | #include <keys/rxrpc-type.h> | ||
| 14 | #include "internal.h" | 17 | #include "internal.h" |
| 15 | 18 | ||
| 16 | DECLARE_RWSEM(afs_proc_cells_sem); | 19 | DECLARE_RWSEM(afs_proc_cells_sem); |
| @@ -23,45 +26,43 @@ static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq); | |||
| 23 | static struct afs_cell *afs_cell_root; | 26 | static struct afs_cell *afs_cell_root; |
| 24 | 27 | ||
| 25 | /* | 28 | /* |
| 26 | * create a cell record | 29 | * allocate a cell record and fill in its name, VL server address list and |
| 27 | * - "name" is the name of the cell | 30 | * allocate an anonymous key |
| 28 | * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format | ||
| 29 | */ | 31 | */ |
| 30 | struct afs_cell *afs_cell_create(const char *name, char *vllist) | 32 | static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) |
| 31 | { | 33 | { |
| 32 | struct afs_cell *cell; | 34 | struct afs_cell *cell; |
| 33 | char *next; | 35 | size_t namelen; |
| 36 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; | ||
| 34 | int ret; | 37 | int ret; |
| 35 | 38 | ||
| 36 | _enter("%s,%s", name, vllist); | 39 | _enter("%s,%s", name, vllist); |
| 37 | 40 | ||
| 38 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ | 41 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ |
| 39 | 42 | ||
| 43 | namelen = strlen(name); | ||
| 44 | if (namelen > AFS_MAXCELLNAME) | ||
| 45 | return ERR_PTR(-ENAMETOOLONG); | ||
| 46 | |||
| 40 | /* allocate and initialise a cell record */ | 47 | /* allocate and initialise a cell record */ |
| 41 | cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL); | 48 | cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL); |
| 42 | if (!cell) { | 49 | if (!cell) { |
| 43 | _leave(" = -ENOMEM"); | 50 | _leave(" = -ENOMEM"); |
| 44 | return ERR_PTR(-ENOMEM); | 51 | return ERR_PTR(-ENOMEM); |
| 45 | } | 52 | } |
| 46 | 53 | ||
| 47 | down_write(&afs_cells_sem); | 54 | memcpy(cell->name, name, namelen); |
| 55 | cell->name[namelen] = 0; | ||
| 48 | 56 | ||
| 49 | memset(cell, 0, sizeof(struct afs_cell)); | ||
| 50 | atomic_set(&cell->usage, 1); | 57 | atomic_set(&cell->usage, 1); |
| 51 | |||
| 52 | INIT_LIST_HEAD(&cell->link); | 58 | INIT_LIST_HEAD(&cell->link); |
| 53 | |||
| 54 | rwlock_init(&cell->servers_lock); | 59 | rwlock_init(&cell->servers_lock); |
| 55 | INIT_LIST_HEAD(&cell->servers); | 60 | INIT_LIST_HEAD(&cell->servers); |
| 56 | |||
| 57 | init_rwsem(&cell->vl_sem); | 61 | init_rwsem(&cell->vl_sem); |
| 58 | INIT_LIST_HEAD(&cell->vl_list); | 62 | INIT_LIST_HEAD(&cell->vl_list); |
| 59 | spin_lock_init(&cell->vl_lock); | 63 | spin_lock_init(&cell->vl_lock); |
| 60 | 64 | ||
| 61 | strcpy(cell->name, name); | ||
| 62 | |||
| 63 | /* fill in the VL server list from the rest of the string */ | 65 | /* fill in the VL server list from the rest of the string */ |
| 64 | ret = -EINVAL; | ||
| 65 | do { | 66 | do { |
| 66 | unsigned a, b, c, d; | 67 | unsigned a, b, c, d; |
| 67 | 68 | ||
| @@ -70,18 +71,73 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist) | |||
| 70 | *next++ = 0; | 71 | *next++ = 0; |
| 71 | 72 | ||
| 72 | if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) | 73 | if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) |
| 73 | goto badaddr; | 74 | goto bad_address; |
| 74 | 75 | ||
| 75 | if (a > 255 || b > 255 || c > 255 || d > 255) | 76 | if (a > 255 || b > 255 || c > 255 || d > 255) |
| 76 | goto badaddr; | 77 | goto bad_address; |
| 77 | 78 | ||
| 78 | cell->vl_addrs[cell->vl_naddrs++].s_addr = | 79 | cell->vl_addrs[cell->vl_naddrs++].s_addr = |
| 79 | htonl((a << 24) | (b << 16) | (c << 8) | d); | 80 | htonl((a << 24) | (b << 16) | (c << 8) | d); |
| 80 | 81 | ||
| 81 | if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS) | 82 | } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next)); |
| 82 | break; | 83 | |
| 84 | /* create a key to represent an anonymous user */ | ||
| 85 | memcpy(keyname, "afs@", 4); | ||
| 86 | dp = keyname + 4; | ||
| 87 | cp = cell->name; | ||
| 88 | do { | ||
| 89 | *dp++ = toupper(*cp); | ||
| 90 | } while (*cp++); | ||
| 91 | cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current, | ||
| 92 | KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA); | ||
| 93 | if (IS_ERR(cell->anonymous_key)) { | ||
| 94 | _debug("no key"); | ||
| 95 | ret = PTR_ERR(cell->anonymous_key); | ||
| 96 | goto error; | ||
| 97 | } | ||
| 98 | |||
| 99 | ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0, | ||
| 100 | NULL, NULL); | ||
| 101 | if (ret < 0) { | ||
| 102 | _debug("instantiate failed"); | ||
| 103 | goto error; | ||
| 104 | } | ||
| 105 | |||
| 106 | _debug("anon key %p{%x}", | ||
| 107 | cell->anonymous_key, key_serial(cell->anonymous_key)); | ||
| 108 | |||
| 109 | _leave(" = %p", cell); | ||
| 110 | return cell; | ||
| 111 | |||
| 112 | bad_address: | ||
| 113 | printk(KERN_ERR "kAFS: bad VL server IP address\n"); | ||
| 114 | ret = -EINVAL; | ||
| 115 | error: | ||
| 116 | key_put(cell->anonymous_key); | ||
| 117 | kfree(cell); | ||
| 118 | _leave(" = %d", ret); | ||
| 119 | return ERR_PTR(ret); | ||
| 120 | } | ||
| 83 | 121 | ||
| 84 | } while ((vllist = next)); | 122 | /* |
| 123 | * create a cell record | ||
| 124 | * - "name" is the name of the cell | ||
| 125 | * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format | ||
| 126 | */ | ||
| 127 | struct afs_cell *afs_cell_create(const char *name, char *vllist) | ||
| 128 | { | ||
| 129 | struct afs_cell *cell; | ||
| 130 | int ret; | ||
| 131 | |||
| 132 | _enter("%s,%s", name, vllist); | ||
| 133 | |||
| 134 | cell = afs_cell_alloc(name, vllist); | ||
| 135 | if (IS_ERR(cell)) { | ||
| 136 | _leave(" = %ld", PTR_ERR(cell)); | ||
| 137 | return cell; | ||
| 138 | } | ||
| 139 | |||
| 140 | down_write(&afs_cells_sem); | ||
| 85 | 141 | ||
| 86 | /* add a proc directory for this cell */ | 142 | /* add a proc directory for this cell */ |
| 87 | ret = afs_proc_cell_setup(cell); | 143 | ret = afs_proc_cell_setup(cell); |
| @@ -109,10 +165,9 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist) | |||
| 109 | _leave(" = %p", cell); | 165 | _leave(" = %p", cell); |
| 110 | return cell; | 166 | return cell; |
| 111 | 167 | ||
| 112 | badaddr: | ||
| 113 | printk(KERN_ERR "kAFS: bad VL server IP address\n"); | ||
| 114 | error: | 168 | error: |
| 115 | up_write(&afs_cells_sem); | 169 | up_write(&afs_cells_sem); |
| 170 | key_put(cell->anonymous_key); | ||
| 116 | kfree(cell); | 171 | kfree(cell); |
| 117 | _leave(" = %d", ret); | 172 | _leave(" = %d", ret); |
| 118 | return ERR_PTR(ret); | 173 | return ERR_PTR(ret); |
| @@ -301,6 +356,7 @@ static void afs_cell_destroy(struct afs_cell *cell) | |||
| 301 | cachefs_relinquish_cookie(cell->cache, 0); | 356 | cachefs_relinquish_cookie(cell->cache, 0); |
| 302 | #endif | 357 | #endif |
| 303 | 358 | ||
| 359 | key_put(cell->anonymous_key); | ||
| 304 | kfree(cell); | 360 | kfree(cell); |
| 305 | 361 | ||
| 306 | _leave(" [destroyed]"); | 362 | _leave(" [destroyed]"); |
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index c7141175391b..c3ec57a237bf 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
| @@ -28,6 +28,7 @@ static void afs_cm_destructor(struct afs_call *); | |||
| 28 | * CB.CallBack operation type | 28 | * CB.CallBack operation type |
| 29 | */ | 29 | */ |
| 30 | static const struct afs_call_type afs_SRXCBCallBack = { | 30 | static const struct afs_call_type afs_SRXCBCallBack = { |
| 31 | .name = "CB.CallBack", | ||
| 31 | .deliver = afs_deliver_cb_callback, | 32 | .deliver = afs_deliver_cb_callback, |
| 32 | .abort_to_error = afs_abort_to_error, | 33 | .abort_to_error = afs_abort_to_error, |
| 33 | .destructor = afs_cm_destructor, | 34 | .destructor = afs_cm_destructor, |
| @@ -37,6 +38,7 @@ static const struct afs_call_type afs_SRXCBCallBack = { | |||
| 37 | * CB.InitCallBackState operation type | 38 | * CB.InitCallBackState operation type |
| 38 | */ | 39 | */ |
| 39 | static const struct afs_call_type afs_SRXCBInitCallBackState = { | 40 | static const struct afs_call_type afs_SRXCBInitCallBackState = { |
| 41 | .name = "CB.InitCallBackState", | ||
| 40 | .deliver = afs_deliver_cb_init_call_back_state, | 42 | .deliver = afs_deliver_cb_init_call_back_state, |
| 41 | .abort_to_error = afs_abort_to_error, | 43 | .abort_to_error = afs_abort_to_error, |
| 42 | .destructor = afs_cm_destructor, | 44 | .destructor = afs_cm_destructor, |
| @@ -46,6 +48,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState = { | |||
| 46 | * CB.Probe operation type | 48 | * CB.Probe operation type |
| 47 | */ | 49 | */ |
| 48 | static const struct afs_call_type afs_SRXCBProbe = { | 50 | static const struct afs_call_type afs_SRXCBProbe = { |
| 51 | .name = "CB.Probe", | ||
| 49 | .deliver = afs_deliver_cb_probe, | 52 | .deliver = afs_deliver_cb_probe, |
| 50 | .abort_to_error = afs_abort_to_error, | 53 | .abort_to_error = afs_abort_to_error, |
| 51 | .destructor = afs_cm_destructor, | 54 | .destructor = afs_cm_destructor, |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index d7697f6f3b7f..87368417e4d3 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
| 17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
| 18 | #include <linux/ctype.h> | ||
| 18 | #include "internal.h" | 19 | #include "internal.h" |
| 19 | 20 | ||
| 20 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | 21 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, |
| @@ -28,11 +29,13 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
| 28 | 29 | ||
| 29 | const struct file_operations afs_dir_file_operations = { | 30 | const struct file_operations afs_dir_file_operations = { |
| 30 | .open = afs_dir_open, | 31 | .open = afs_dir_open, |
| 32 | .release = afs_release, | ||
| 31 | .readdir = afs_dir_readdir, | 33 | .readdir = afs_dir_readdir, |
| 32 | }; | 34 | }; |
| 33 | 35 | ||
| 34 | const struct inode_operations afs_dir_inode_operations = { | 36 | const struct inode_operations afs_dir_inode_operations = { |
| 35 | .lookup = afs_dir_lookup, | 37 | .lookup = afs_dir_lookup, |
| 38 | .permission = afs_permission, | ||
| 36 | .getattr = afs_inode_getattr, | 39 | .getattr = afs_inode_getattr, |
| 37 | #if 0 /* TODO */ | 40 | #if 0 /* TODO */ |
| 38 | .create = afs_dir_create, | 41 | .create = afs_dir_create, |
| @@ -169,13 +172,17 @@ static inline void afs_dir_put_page(struct page *page) | |||
| 169 | /* | 172 | /* |
| 170 | * get a page into the pagecache | 173 | * get a page into the pagecache |
| 171 | */ | 174 | */ |
| 172 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) | 175 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index, |
| 176 | struct key *key) | ||
| 173 | { | 177 | { |
| 174 | struct page *page; | 178 | struct page *page; |
| 179 | struct file file = { | ||
| 180 | .private_data = key, | ||
| 181 | }; | ||
| 175 | 182 | ||
| 176 | _enter("{%lu},%lu", dir->i_ino, index); | 183 | _enter("{%lu},%lu", dir->i_ino, index); |
| 177 | 184 | ||
| 178 | page = read_mapping_page(dir->i_mapping, index, NULL); | 185 | page = read_mapping_page(dir->i_mapping, index, &file); |
| 179 | if (!IS_ERR(page)) { | 186 | if (!IS_ERR(page)) { |
| 180 | wait_on_page_locked(page); | 187 | wait_on_page_locked(page); |
| 181 | kmap(page); | 188 | kmap(page); |
| @@ -207,8 +214,7 @@ static int afs_dir_open(struct inode *inode, struct file *file) | |||
| 207 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) | 214 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) |
| 208 | return -ENOENT; | 215 | return -ENOENT; |
| 209 | 216 | ||
| 210 | _leave(" = 0"); | 217 | return afs_open(inode, file); |
| 211 | return 0; | ||
| 212 | } | 218 | } |
| 213 | 219 | ||
| 214 | /* | 220 | /* |
| @@ -311,7 +317,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
| 311 | * iterate through the data blob that lists the contents of an AFS directory | 317 | * iterate through the data blob that lists the contents of an AFS directory |
| 312 | */ | 318 | */ |
| 313 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | 319 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, |
| 314 | filldir_t filldir) | 320 | filldir_t filldir, struct key *key) |
| 315 | { | 321 | { |
| 316 | union afs_dir_block *dblock; | 322 | union afs_dir_block *dblock; |
| 317 | struct afs_dir_page *dbuf; | 323 | struct afs_dir_page *dbuf; |
| @@ -336,7 +342,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | |||
| 336 | blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); | 342 | blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); |
| 337 | 343 | ||
| 338 | /* fetch the appropriate page from the directory */ | 344 | /* fetch the appropriate page from the directory */ |
| 339 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE); | 345 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key); |
| 340 | if (IS_ERR(page)) { | 346 | if (IS_ERR(page)) { |
| 341 | ret = PTR_ERR(page); | 347 | ret = PTR_ERR(page); |
| 342 | break; | 348 | break; |
| @@ -381,9 +387,11 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir) | |||
| 381 | _enter("{%Ld,{%lu}}", | 387 | _enter("{%Ld,{%lu}}", |
| 382 | file->f_pos, file->f_path.dentry->d_inode->i_ino); | 388 | file->f_pos, file->f_path.dentry->d_inode->i_ino); |
| 383 | 389 | ||
| 390 | ASSERT(file->private_data != NULL); | ||
| 391 | |||
| 384 | fpos = file->f_pos; | 392 | fpos = file->f_pos; |
| 385 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, | 393 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, |
| 386 | cookie, filldir); | 394 | cookie, filldir, file->private_data); |
| 387 | file->f_pos = fpos; | 395 | file->f_pos = fpos; |
| 388 | 396 | ||
| 389 | _leave(" = %d", ret); | 397 | _leave(" = %d", ret); |
| @@ -424,7 +432,7 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
| 424 | * do a lookup in a directory | 432 | * do a lookup in a directory |
| 425 | */ | 433 | */ |
| 426 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | 434 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, |
| 427 | struct afs_fid *fid) | 435 | struct afs_fid *fid, struct key *key) |
| 428 | { | 436 | { |
| 429 | struct afs_dir_lookup_cookie cookie; | 437 | struct afs_dir_lookup_cookie cookie; |
| 430 | struct afs_super_info *as; | 438 | struct afs_super_info *as; |
| @@ -442,7 +450,8 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
| 442 | cookie.found = 0; | 450 | cookie.found = 0; |
| 443 | 451 | ||
| 444 | fpos = 0; | 452 | fpos = 0; |
| 445 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir); | 453 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir, |
| 454 | key); | ||
| 446 | if (ret < 0) { | 455 | if (ret < 0) { |
| 447 | _leave(" = %d [iter]", ret); | 456 | _leave(" = %d [iter]", ret); |
| 448 | return ret; | 457 | return ret; |
| @@ -468,6 +477,7 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | |||
| 468 | struct afs_vnode *vnode; | 477 | struct afs_vnode *vnode; |
| 469 | struct afs_fid fid; | 478 | struct afs_fid fid; |
| 470 | struct inode *inode; | 479 | struct inode *inode; |
| 480 | struct key *key; | ||
| 471 | int ret; | 481 | int ret; |
| 472 | 482 | ||
| 473 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); | 483 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); |
| @@ -483,14 +493,22 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | |||
| 483 | return ERR_PTR(-ESTALE); | 493 | return ERR_PTR(-ESTALE); |
| 484 | } | 494 | } |
| 485 | 495 | ||
| 486 | ret = afs_do_lookup(dir, dentry, &fid); | 496 | key = afs_request_key(vnode->volume->cell); |
| 497 | if (IS_ERR(key)) { | ||
| 498 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
| 499 | return ERR_PTR(PTR_ERR(key)); | ||
| 500 | } | ||
| 501 | |||
| 502 | ret = afs_do_lookup(dir, dentry, &fid, key); | ||
| 487 | if (ret < 0) { | 503 | if (ret < 0) { |
| 504 | key_put(key); | ||
| 488 | _leave(" = %d [do]", ret); | 505 | _leave(" = %d [do]", ret); |
| 489 | return ERR_PTR(ret); | 506 | return ERR_PTR(ret); |
| 490 | } | 507 | } |
| 491 | 508 | ||
| 492 | /* instantiate the dentry */ | 509 | /* instantiate the dentry */ |
| 493 | inode = afs_iget(dir->i_sb, &fid); | 510 | inode = afs_iget(dir->i_sb, key, &fid); |
| 511 | key_put(key); | ||
| 494 | if (IS_ERR(inode)) { | 512 | if (IS_ERR(inode)) { |
| 495 | _leave(" = %ld", PTR_ERR(inode)); | 513 | _leave(" = %ld", PTR_ERR(inode)); |
| 496 | return ERR_PTR(PTR_ERR(inode)); | 514 | return ERR_PTR(PTR_ERR(inode)); |
| @@ -559,6 +577,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 559 | struct afs_fid fid; | 577 | struct afs_fid fid; |
| 560 | struct dentry *parent; | 578 | struct dentry *parent; |
| 561 | struct inode *inode, *dir; | 579 | struct inode *inode, *dir; |
| 580 | struct key *key; | ||
| 562 | int ret; | 581 | int ret; |
| 563 | 582 | ||
| 564 | vnode = AFS_FS_I(dentry->d_inode); | 583 | vnode = AFS_FS_I(dentry->d_inode); |
| @@ -566,6 +585,10 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 566 | _enter("{sb=%p n=%s fl=%lx},", | 585 | _enter("{sb=%p n=%s fl=%lx},", |
| 567 | dentry->d_sb, dentry->d_name.name, vnode->flags); | 586 | dentry->d_sb, dentry->d_name.name, vnode->flags); |
| 568 | 587 | ||
| 588 | key = afs_request_key(vnode->volume->cell); | ||
| 589 | if (IS_ERR(key)) | ||
| 590 | key = NULL; | ||
| 591 | |||
| 569 | /* lock down the parent dentry so we can peer at it */ | 592 | /* lock down the parent dentry so we can peer at it */ |
| 570 | parent = dget_parent(dentry); | 593 | parent = dget_parent(dentry); |
| 571 | 594 | ||
| @@ -595,7 +618,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 595 | _debug("dir modified"); | 618 | _debug("dir modified"); |
| 596 | 619 | ||
| 597 | /* search the directory for this vnode */ | 620 | /* search the directory for this vnode */ |
| 598 | ret = afs_do_lookup(dir, dentry, &fid); | 621 | ret = afs_do_lookup(dir, dentry, &fid, key); |
| 599 | if (ret == -ENOENT) { | 622 | if (ret == -ENOENT) { |
| 600 | _debug("%s: dirent not found", dentry->d_name.name); | 623 | _debug("%s: dirent not found", dentry->d_name.name); |
| 601 | goto not_found; | 624 | goto not_found; |
| @@ -637,7 +660,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 637 | test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { | 660 | test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { |
| 638 | _debug("%s: changed", dentry->d_name.name); | 661 | _debug("%s: changed", dentry->d_name.name); |
| 639 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | 662 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
| 640 | if (afs_vnode_fetch_status(vnode) < 0) { | 663 | if (afs_vnode_fetch_status(vnode, NULL, key) < 0) { |
| 641 | mutex_unlock(&vnode->cb_broken_lock); | 664 | mutex_unlock(&vnode->cb_broken_lock); |
| 642 | goto out_bad; | 665 | goto out_bad; |
| 643 | } | 666 | } |
| @@ -667,6 +690,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 667 | 690 | ||
| 668 | out_valid: | 691 | out_valid: |
| 669 | dput(parent); | 692 | dput(parent); |
| 693 | key_put(key); | ||
| 670 | _leave(" = 1 [valid]"); | 694 | _leave(" = 1 [valid]"); |
| 671 | return 1; | 695 | return 1; |
| 672 | 696 | ||
| @@ -688,6 +712,7 @@ out_bad: | |||
| 688 | shrink_dcache_parent(dentry); | 712 | shrink_dcache_parent(dentry); |
| 689 | d_drop(dentry); | 713 | d_drop(dentry); |
| 690 | dput(parent); | 714 | dput(parent); |
| 715 | key_put(key); | ||
| 691 | 716 | ||
| 692 | _leave(" = 0 [bad]"); | 717 | _leave(" = 0 [bad]"); |
| 693 | return 0; | 718 | return 0; |
diff --git a/fs/afs/file.c b/fs/afs/file.c index 6990327e75dd..101bbb8c0d8b 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
| @@ -17,17 +17,23 @@ | |||
| 17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
| 18 | #include "internal.h" | 18 | #include "internal.h" |
| 19 | 19 | ||
| 20 | #if 0 | ||
| 21 | static int afs_file_open(struct inode *inode, struct file *file); | ||
| 22 | static int afs_file_release(struct inode *inode, struct file *file); | ||
| 23 | #endif | ||
| 24 | |||
| 25 | static int afs_file_readpage(struct file *file, struct page *page); | 20 | static int afs_file_readpage(struct file *file, struct page *page); |
| 26 | static void afs_file_invalidatepage(struct page *page, unsigned long offset); | 21 | static void afs_file_invalidatepage(struct page *page, unsigned long offset); |
| 27 | static int afs_file_releasepage(struct page *page, gfp_t gfp_flags); | 22 | static int afs_file_releasepage(struct page *page, gfp_t gfp_flags); |
| 28 | 23 | ||
| 24 | const struct file_operations afs_file_operations = { | ||
| 25 | .open = afs_open, | ||
| 26 | .release = afs_release, | ||
| 27 | .llseek = generic_file_llseek, | ||
| 28 | .read = do_sync_read, | ||
| 29 | .aio_read = generic_file_aio_read, | ||
| 30 | .mmap = generic_file_readonly_mmap, | ||
| 31 | .sendfile = generic_file_sendfile, | ||
| 32 | }; | ||
| 33 | |||
| 29 | const struct inode_operations afs_file_inode_operations = { | 34 | const struct inode_operations afs_file_inode_operations = { |
| 30 | .getattr = afs_inode_getattr, | 35 | .getattr = afs_inode_getattr, |
| 36 | .permission = afs_permission, | ||
| 31 | }; | 37 | }; |
| 32 | 38 | ||
| 33 | const struct address_space_operations afs_fs_aops = { | 39 | const struct address_space_operations afs_fs_aops = { |
| @@ -38,6 +44,41 @@ const struct address_space_operations afs_fs_aops = { | |||
| 38 | }; | 44 | }; |
| 39 | 45 | ||
| 40 | /* | 46 | /* |
| 47 | * open an AFS file or directory and attach a key to it | ||
| 48 | */ | ||
| 49 | int afs_open(struct inode *inode, struct file *file) | ||
| 50 | { | ||
| 51 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
| 52 | struct key *key; | ||
| 53 | |||
| 54 | _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); | ||
| 55 | |||
| 56 | key = afs_request_key(vnode->volume->cell); | ||
| 57 | if (IS_ERR(key)) { | ||
| 58 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
| 59 | return PTR_ERR(key); | ||
| 60 | } | ||
| 61 | |||
| 62 | file->private_data = key; | ||
| 63 | _leave(" = 0"); | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* | ||
| 68 | * release an AFS file or directory and discard its key | ||
| 69 | */ | ||
| 70 | int afs_release(struct inode *inode, struct file *file) | ||
| 71 | { | ||
| 72 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
| 73 | |||
| 74 | _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); | ||
| 75 | |||
| 76 | key_put(file->private_data); | ||
| 77 | _leave(" = 0"); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* | ||
| 41 | * deal with notification that a page was read from the cache | 82 | * deal with notification that a page was read from the cache |
| 42 | */ | 83 | */ |
| 43 | #ifdef AFS_CACHING_SUPPORT | 84 | #ifdef AFS_CACHING_SUPPORT |
| @@ -79,13 +120,18 @@ static int afs_file_readpage(struct file *file, struct page *page) | |||
| 79 | { | 120 | { |
| 80 | struct afs_vnode *vnode; | 121 | struct afs_vnode *vnode; |
| 81 | struct inode *inode; | 122 | struct inode *inode; |
| 123 | struct key *key; | ||
| 82 | size_t len; | 124 | size_t len; |
| 83 | off_t offset; | 125 | off_t offset; |
| 84 | int ret; | 126 | int ret; |
| 85 | 127 | ||
| 86 | inode = page->mapping->host; | 128 | inode = page->mapping->host; |
| 87 | 129 | ||
| 88 | _enter("{%lu},{%lu}", inode->i_ino, page->index); | 130 | ASSERT(file != NULL); |
| 131 | key = file->private_data; | ||
| 132 | ASSERT(key != NULL); | ||
| 133 | |||
| 134 | _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); | ||
| 89 | 135 | ||
| 90 | vnode = AFS_FS_I(inode); | 136 | vnode = AFS_FS_I(inode); |
| 91 | 137 | ||
| @@ -124,7 +170,7 @@ static int afs_file_readpage(struct file *file, struct page *page) | |||
| 124 | 170 | ||
| 125 | /* read the contents of the file from the server into the | 171 | /* read the contents of the file from the server into the |
| 126 | * page */ | 172 | * page */ |
| 127 | ret = afs_vnode_fetch_data(vnode, offset, len, page); | 173 | ret = afs_vnode_fetch_data(vnode, key, offset, len, page); |
| 128 | if (ret < 0) { | 174 | if (ret < 0) { |
| 129 | if (ret == -ENOENT) { | 175 | if (ret == -ENOENT) { |
| 130 | _debug("got NOENT from server" | 176 | _debug("got NOENT from server" |
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 167ca615c2e6..321b489aa90f 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
| @@ -148,6 +148,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call, | |||
| 148 | * FS.FetchStatus operation type | 148 | * FS.FetchStatus operation type |
| 149 | */ | 149 | */ |
| 150 | static const struct afs_call_type afs_RXFSFetchStatus = { | 150 | static const struct afs_call_type afs_RXFSFetchStatus = { |
| 151 | .name = "FS.FetchStatus", | ||
| 151 | .deliver = afs_deliver_fs_fetch_status, | 152 | .deliver = afs_deliver_fs_fetch_status, |
| 152 | .abort_to_error = afs_abort_to_error, | 153 | .abort_to_error = afs_abort_to_error, |
| 153 | .destructor = afs_flat_call_destructor, | 154 | .destructor = afs_flat_call_destructor, |
| @@ -157,6 +158,7 @@ static const struct afs_call_type afs_RXFSFetchStatus = { | |||
| 157 | * fetch the status information for a file | 158 | * fetch the status information for a file |
| 158 | */ | 159 | */ |
| 159 | int afs_fs_fetch_file_status(struct afs_server *server, | 160 | int afs_fs_fetch_file_status(struct afs_server *server, |
| 161 | struct key *key, | ||
| 160 | struct afs_vnode *vnode, | 162 | struct afs_vnode *vnode, |
| 161 | struct afs_volsync *volsync, | 163 | struct afs_volsync *volsync, |
| 162 | const struct afs_wait_mode *wait_mode) | 164 | const struct afs_wait_mode *wait_mode) |
| @@ -164,12 +166,13 @@ int afs_fs_fetch_file_status(struct afs_server *server, | |||
| 164 | struct afs_call *call; | 166 | struct afs_call *call; |
| 165 | __be32 *bp; | 167 | __be32 *bp; |
| 166 | 168 | ||
| 167 | _enter(""); | 169 | _enter(",%x,,,", key_serial(key)); |
| 168 | 170 | ||
| 169 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120); | 171 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120); |
| 170 | if (!call) | 172 | if (!call) |
| 171 | return -ENOMEM; | 173 | return -ENOMEM; |
| 172 | 174 | ||
| 175 | call->key = key; | ||
| 173 | call->reply = vnode; | 176 | call->reply = vnode; |
| 174 | call->reply2 = volsync; | 177 | call->reply2 = volsync; |
| 175 | call->service_id = FS_SERVICE; | 178 | call->service_id = FS_SERVICE; |
| @@ -279,6 +282,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, | |||
| 279 | * FS.FetchData operation type | 282 | * FS.FetchData operation type |
| 280 | */ | 283 | */ |
| 281 | static const struct afs_call_type afs_RXFSFetchData = { | 284 | static const struct afs_call_type afs_RXFSFetchData = { |
| 285 | .name = "FS.FetchData", | ||
| 282 | .deliver = afs_deliver_fs_fetch_data, | 286 | .deliver = afs_deliver_fs_fetch_data, |
| 283 | .abort_to_error = afs_abort_to_error, | 287 | .abort_to_error = afs_abort_to_error, |
| 284 | .destructor = afs_flat_call_destructor, | 288 | .destructor = afs_flat_call_destructor, |
| @@ -288,6 +292,7 @@ static const struct afs_call_type afs_RXFSFetchData = { | |||
| 288 | * fetch data from a file | 292 | * fetch data from a file |
| 289 | */ | 293 | */ |
| 290 | int afs_fs_fetch_data(struct afs_server *server, | 294 | int afs_fs_fetch_data(struct afs_server *server, |
| 295 | struct key *key, | ||
| 291 | struct afs_vnode *vnode, | 296 | struct afs_vnode *vnode, |
| 292 | off_t offset, size_t length, | 297 | off_t offset, size_t length, |
| 293 | struct page *buffer, | 298 | struct page *buffer, |
| @@ -303,6 +308,7 @@ int afs_fs_fetch_data(struct afs_server *server, | |||
| 303 | if (!call) | 308 | if (!call) |
| 304 | return -ENOMEM; | 309 | return -ENOMEM; |
| 305 | 310 | ||
| 311 | call->key = key; | ||
| 306 | call->reply = vnode; | 312 | call->reply = vnode; |
| 307 | call->reply2 = volsync; | 313 | call->reply2 = volsync; |
| 308 | call->reply3 = buffer; | 314 | call->reply3 = buffer; |
| @@ -338,6 +344,7 @@ static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, | |||
| 338 | * FS.GiveUpCallBacks operation type | 344 | * FS.GiveUpCallBacks operation type |
| 339 | */ | 345 | */ |
| 340 | static const struct afs_call_type afs_RXFSGiveUpCallBacks = { | 346 | static const struct afs_call_type afs_RXFSGiveUpCallBacks = { |
| 347 | .name = "FS.GiveUpCallBacks", | ||
| 341 | .deliver = afs_deliver_fs_give_up_callbacks, | 348 | .deliver = afs_deliver_fs_give_up_callbacks, |
| 342 | .abort_to_error = afs_abort_to_error, | 349 | .abort_to_error = afs_abort_to_error, |
| 343 | .destructor = afs_flat_call_destructor, | 350 | .destructor = afs_flat_call_destructor, |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 18863315211f..227336228299 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
| @@ -29,7 +29,7 @@ struct afs_iget_data { | |||
| 29 | /* | 29 | /* |
| 30 | * map the AFS file status to the inode member variables | 30 | * map the AFS file status to the inode member variables |
| 31 | */ | 31 | */ |
| 32 | static int afs_inode_map_status(struct afs_vnode *vnode) | 32 | static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) |
| 33 | { | 33 | { |
| 34 | struct inode *inode = AFS_VNODE_TO_I(vnode); | 34 | struct inode *inode = AFS_VNODE_TO_I(vnode); |
| 35 | 35 | ||
| @@ -44,7 +44,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode) | |||
| 44 | case AFS_FTYPE_FILE: | 44 | case AFS_FTYPE_FILE: |
| 45 | inode->i_mode = S_IFREG | vnode->status.mode; | 45 | inode->i_mode = S_IFREG | vnode->status.mode; |
| 46 | inode->i_op = &afs_file_inode_operations; | 46 | inode->i_op = &afs_file_inode_operations; |
| 47 | inode->i_fop = &generic_ro_fops; | 47 | inode->i_fop = &afs_file_operations; |
| 48 | break; | 48 | break; |
| 49 | case AFS_FTYPE_DIR: | 49 | case AFS_FTYPE_DIR: |
| 50 | inode->i_mode = S_IFDIR | vnode->status.mode; | 50 | inode->i_mode = S_IFDIR | vnode->status.mode; |
| @@ -73,7 +73,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode) | |||
| 73 | 73 | ||
| 74 | /* check to see whether a symbolic link is really a mountpoint */ | 74 | /* check to see whether a symbolic link is really a mountpoint */ |
| 75 | if (vnode->status.type == AFS_FTYPE_SYMLINK) { | 75 | if (vnode->status.type == AFS_FTYPE_SYMLINK) { |
| 76 | afs_mntpt_check_symlink(vnode); | 76 | afs_mntpt_check_symlink(vnode, key); |
| 77 | 77 | ||
| 78 | if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) { | 78 | if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) { |
| 79 | inode->i_mode = S_IFDIR | vnode->status.mode; | 79 | inode->i_mode = S_IFDIR | vnode->status.mode; |
| @@ -115,7 +115,8 @@ static int afs_iget5_set(struct inode *inode, void *opaque) | |||
| 115 | /* | 115 | /* |
| 116 | * inode retrieval | 116 | * inode retrieval |
| 117 | */ | 117 | */ |
| 118 | inline struct inode *afs_iget(struct super_block *sb, struct afs_fid *fid) | 118 | inline struct inode *afs_iget(struct super_block *sb, struct key *key, |
| 119 | struct afs_fid *fid) | ||
| 119 | { | 120 | { |
| 120 | struct afs_iget_data data = { .fid = *fid }; | 121 | struct afs_iget_data data = { .fid = *fid }; |
| 121 | struct afs_super_info *as; | 122 | struct afs_super_info *as; |
| @@ -157,10 +158,10 @@ inline struct inode *afs_iget(struct super_block *sb, struct afs_fid *fid) | |||
| 157 | 158 | ||
| 158 | /* okay... it's a new inode */ | 159 | /* okay... it's a new inode */ |
| 159 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | 160 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
| 160 | ret = afs_vnode_fetch_status(vnode); | 161 | ret = afs_vnode_fetch_status(vnode, NULL, key); |
| 161 | if (ret < 0) | 162 | if (ret < 0) |
| 162 | goto bad_inode; | 163 | goto bad_inode; |
| 163 | ret = afs_inode_map_status(vnode); | 164 | ret = afs_inode_map_status(vnode, key); |
| 164 | if (ret < 0) | 165 | if (ret < 0) |
| 165 | goto bad_inode; | 166 | goto bad_inode; |
| 166 | 167 | ||
| @@ -201,6 +202,7 @@ int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 201 | */ | 202 | */ |
| 202 | void afs_clear_inode(struct inode *inode) | 203 | void afs_clear_inode(struct inode *inode) |
| 203 | { | 204 | { |
| 205 | struct afs_permits *permits; | ||
| 204 | struct afs_vnode *vnode; | 206 | struct afs_vnode *vnode; |
| 205 | 207 | ||
| 206 | vnode = AFS_FS_I(inode); | 208 | vnode = AFS_FS_I(inode); |
| @@ -233,5 +235,12 @@ void afs_clear_inode(struct inode *inode) | |||
| 233 | vnode->cache = NULL; | 235 | vnode->cache = NULL; |
| 234 | #endif | 236 | #endif |
| 235 | 237 | ||
| 238 | mutex_lock(&vnode->permits_lock); | ||
| 239 | permits = vnode->permits; | ||
| 240 | rcu_assign_pointer(vnode->permits, NULL); | ||
| 241 | mutex_unlock(&vnode->permits_lock); | ||
| 242 | if (permits) | ||
| 243 | call_rcu(&permits->rcu, afs_zap_permits); | ||
| 244 | |||
| 236 | _leave(""); | 245 | _leave(""); |
| 237 | } | 246 | } |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index afc6f0f30259..8bed2429d01f 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/pagemap.h> | 15 | #include <linux/pagemap.h> |
| 16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
| 17 | #include <linux/rxrpc.h> | 17 | #include <linux/rxrpc.h> |
| 18 | #include <linux/key.h> | ||
| 18 | #include "afs.h" | 19 | #include "afs.h" |
| 19 | #include "afs_vl.h" | 20 | #include "afs_vl.h" |
| 20 | 21 | ||
| @@ -32,6 +33,17 @@ typedef enum { | |||
| 32 | AFS_VL_UNCERTAIN, /* uncertain state (update failed) */ | 33 | AFS_VL_UNCERTAIN, /* uncertain state (update failed) */ |
| 33 | } __attribute__((packed)) afs_vlocation_state_t; | 34 | } __attribute__((packed)) afs_vlocation_state_t; |
| 34 | 35 | ||
| 36 | struct afs_mount_params { | ||
| 37 | bool rwpath; /* T if the parent should be considered R/W */ | ||
| 38 | bool force; /* T to force cell type */ | ||
| 39 | afs_voltype_t type; /* type of volume requested */ | ||
| 40 | int volnamesz; /* size of volume name */ | ||
| 41 | const char *volname; /* name of volume to mount */ | ||
| 42 | struct afs_cell *cell; /* cell in which to find volume */ | ||
| 43 | struct afs_volume *volume; /* volume record */ | ||
| 44 | struct key *key; /* key to use for secure mounting */ | ||
| 45 | }; | ||
| 46 | |||
| 35 | /* | 47 | /* |
| 36 | * definition of how to wait for the completion of an operation | 48 | * definition of how to wait for the completion of an operation |
| 37 | */ | 49 | */ |
| @@ -95,6 +107,8 @@ struct afs_call { | |||
| 95 | }; | 107 | }; |
| 96 | 108 | ||
| 97 | struct afs_call_type { | 109 | struct afs_call_type { |
| 110 | const char *name; | ||
| 111 | |||
| 98 | /* deliver request or reply data to an call | 112 | /* deliver request or reply data to an call |
| 99 | * - returning an error will cause the call to be aborted | 113 | * - returning an error will cause the call to be aborted |
| 100 | */ | 114 | */ |
| @@ -128,8 +142,8 @@ extern struct file_system_type afs_fs_type; | |||
| 128 | * entry in the cached cell catalogue | 142 | * entry in the cached cell catalogue |
| 129 | */ | 143 | */ |
| 130 | struct afs_cache_cell { | 144 | struct afs_cache_cell { |
| 131 | char name[64]; /* cell name (padded with NULs) */ | 145 | char name[AFS_MAXCELLNAME]; /* cell name (padded with NULs) */ |
| 132 | struct in_addr vl_servers[15]; /* cached cell VL servers */ | 146 | struct in_addr vl_servers[15]; /* cached cell VL servers */ |
| 133 | }; | 147 | }; |
| 134 | 148 | ||
| 135 | /* | 149 | /* |
| @@ -138,6 +152,7 @@ struct afs_cache_cell { | |||
| 138 | struct afs_cell { | 152 | struct afs_cell { |
| 139 | atomic_t usage; | 153 | atomic_t usage; |
| 140 | struct list_head link; /* main cell list link */ | 154 | struct list_head link; /* main cell list link */ |
| 155 | struct key *anonymous_key; /* anonymous user key for this cell */ | ||
| 141 | struct list_head proc_link; /* /proc cell list link */ | 156 | struct list_head proc_link; /* /proc cell list link */ |
| 142 | struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ | 157 | struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ |
| 143 | #ifdef AFS_CACHING_SUPPORT | 158 | #ifdef AFS_CACHING_SUPPORT |
| @@ -163,7 +178,9 @@ struct afs_cell { | |||
| 163 | * entry in the cached volume location catalogue | 178 | * entry in the cached volume location catalogue |
| 164 | */ | 179 | */ |
| 165 | struct afs_cache_vlocation { | 180 | struct afs_cache_vlocation { |
| 166 | uint8_t name[64 + 1]; /* volume name (lowercase, padded with NULs) */ | 181 | /* volume name (lowercase, padded with NULs) */ |
| 182 | uint8_t name[AFS_MAXVOLNAME + 1]; | ||
| 183 | |||
| 167 | uint8_t nservers; /* number of entries used in servers[] */ | 184 | uint8_t nservers; /* number of entries used in servers[] */ |
| 168 | uint8_t vidmask; /* voltype mask for vid[] */ | 185 | uint8_t vidmask; /* voltype mask for vid[] */ |
| 169 | uint8_t srvtmask[8]; /* voltype masks for servers[] */ | 186 | uint8_t srvtmask[8]; /* voltype masks for servers[] */ |
| @@ -281,7 +298,8 @@ struct afs_vnode { | |||
| 281 | #ifdef AFS_CACHING_SUPPORT | 298 | #ifdef AFS_CACHING_SUPPORT |
| 282 | struct cachefs_cookie *cache; /* caching cookie */ | 299 | struct cachefs_cookie *cache; /* caching cookie */ |
| 283 | #endif | 300 | #endif |
| 284 | 301 | struct afs_permits *permits; /* cache of permits so far obtained */ | |
| 302 | struct mutex permits_lock; /* lock for altering permits list */ | ||
| 285 | wait_queue_head_t update_waitq; /* status fetch waitqueue */ | 303 | wait_queue_head_t update_waitq; /* status fetch waitqueue */ |
| 286 | unsigned update_cnt; /* number of outstanding ops that will update the | 304 | unsigned update_cnt; /* number of outstanding ops that will update the |
| 287 | * status */ | 305 | * status */ |
| @@ -296,12 +314,13 @@ struct afs_vnode { | |||
| 296 | #define AFS_VNODE_DIR_CHANGED 6 /* set if vnode's parent dir metadata changed */ | 314 | #define AFS_VNODE_DIR_CHANGED 6 /* set if vnode's parent dir metadata changed */ |
| 297 | #define AFS_VNODE_DIR_MODIFIED 7 /* set if vnode's parent dir data modified */ | 315 | #define AFS_VNODE_DIR_MODIFIED 7 /* set if vnode's parent dir data modified */ |
| 298 | 316 | ||
| 317 | long acl_order; /* ACL check count (callback break count) */ | ||
| 318 | |||
| 299 | /* outstanding callback notification on this file */ | 319 | /* outstanding callback notification on this file */ |
| 300 | struct rb_node server_rb; /* link in server->fs_vnodes */ | 320 | struct rb_node server_rb; /* link in server->fs_vnodes */ |
| 301 | struct rb_node cb_promise; /* link in server->cb_promises */ | 321 | struct rb_node cb_promise; /* link in server->cb_promises */ |
| 302 | struct work_struct cb_broken_work; /* work to be done on callback break */ | 322 | struct work_struct cb_broken_work; /* work to be done on callback break */ |
| 303 | struct mutex cb_broken_lock; /* lock against multiple attempts to fix break */ | 323 | struct mutex cb_broken_lock; /* lock against multiple attempts to fix break */ |
| 304 | // struct list_head cb_hash_link; /* link in master callback hash */ | ||
| 305 | time_t cb_expires; /* time at which callback expires */ | 324 | time_t cb_expires; /* time at which callback expires */ |
| 306 | time_t cb_expires_at; /* time used to order cb_promise */ | 325 | time_t cb_expires_at; /* time used to order cb_promise */ |
| 307 | unsigned cb_version; /* callback version */ | 326 | unsigned cb_version; /* callback version */ |
| @@ -310,6 +329,23 @@ struct afs_vnode { | |||
| 310 | bool cb_promised; /* true if promise still holds */ | 329 | bool cb_promised; /* true if promise still holds */ |
| 311 | }; | 330 | }; |
| 312 | 331 | ||
| 332 | /* | ||
| 333 | * cached security record for one user's attempt to access a vnode | ||
| 334 | */ | ||
| 335 | struct afs_permit { | ||
| 336 | struct key *key; /* RxRPC ticket holding a security context */ | ||
| 337 | afs_access_t access_mask; /* access mask for this key */ | ||
| 338 | }; | ||
| 339 | |||
| 340 | /* | ||
| 341 | * cache of security records from attempts to access a vnode | ||
| 342 | */ | ||
| 343 | struct afs_permits { | ||
| 344 | struct rcu_head rcu; /* disposal procedure */ | ||
| 345 | int count; /* number of records */ | ||
| 346 | struct afs_permit permits[0]; /* the permits so far examined */ | ||
| 347 | }; | ||
| 348 | |||
| 313 | /*****************************************************************************/ | 349 | /*****************************************************************************/ |
| 314 | /* | 350 | /* |
| 315 | * callback.c | 351 | * callback.c |
| @@ -352,11 +388,17 @@ extern bool afs_cm_incoming_call(struct afs_call *); | |||
| 352 | extern const struct inode_operations afs_dir_inode_operations; | 388 | extern const struct inode_operations afs_dir_inode_operations; |
| 353 | extern const struct file_operations afs_dir_file_operations; | 389 | extern const struct file_operations afs_dir_file_operations; |
| 354 | 390 | ||
| 391 | extern int afs_permission(struct inode *, int, struct nameidata *); | ||
| 392 | |||
| 355 | /* | 393 | /* |
| 356 | * file.c | 394 | * file.c |
| 357 | */ | 395 | */ |
| 358 | extern const struct address_space_operations afs_fs_aops; | 396 | extern const struct address_space_operations afs_fs_aops; |
| 359 | extern const struct inode_operations afs_file_inode_operations; | 397 | extern const struct inode_operations afs_file_inode_operations; |
| 398 | extern const struct file_operations afs_file_operations; | ||
| 399 | |||
| 400 | extern int afs_open(struct inode *, struct file *); | ||
| 401 | extern int afs_release(struct inode *, struct file *); | ||
| 360 | 402 | ||
| 361 | #ifdef AFS_CACHING_SUPPORT | 403 | #ifdef AFS_CACHING_SUPPORT |
| 362 | extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **); | 404 | extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **); |
| @@ -365,22 +407,24 @@ extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **); | |||
| 365 | /* | 407 | /* |
| 366 | * fsclient.c | 408 | * fsclient.c |
| 367 | */ | 409 | */ |
| 368 | extern int afs_fs_fetch_file_status(struct afs_server *, | 410 | extern int afs_fs_fetch_file_status(struct afs_server *, struct key *, |
| 369 | struct afs_vnode *, | 411 | struct afs_vnode *, struct afs_volsync *, |
| 370 | struct afs_volsync *, | ||
| 371 | const struct afs_wait_mode *); | 412 | const struct afs_wait_mode *); |
| 372 | extern int afs_fs_give_up_callbacks(struct afs_server *, | 413 | extern int afs_fs_give_up_callbacks(struct afs_server *, |
| 373 | const struct afs_wait_mode *); | 414 | const struct afs_wait_mode *); |
| 374 | extern int afs_fs_fetch_data(struct afs_server *, struct afs_vnode *, off_t, | 415 | extern int afs_fs_fetch_data(struct afs_server *, struct key *, |
| 375 | size_t, struct page *, struct afs_volsync *, | 416 | struct afs_vnode *, off_t, size_t, struct page *, |
| 417 | struct afs_volsync *, | ||
| 376 | const struct afs_wait_mode *); | 418 | const struct afs_wait_mode *); |
| 377 | 419 | ||
| 378 | /* | 420 | /* |
| 379 | * inode.c | 421 | * inode.c |
| 380 | */ | 422 | */ |
| 381 | extern struct inode *afs_iget(struct super_block *, struct afs_fid *); | 423 | extern struct inode *afs_iget(struct super_block *, struct key *, |
| 424 | struct afs_fid *); | ||
| 382 | extern int afs_inode_getattr(struct vfsmount *, struct dentry *, | 425 | extern int afs_inode_getattr(struct vfsmount *, struct dentry *, |
| 383 | struct kstat *); | 426 | struct kstat *); |
| 427 | extern void afs_zap_permits(struct rcu_head *); | ||
| 384 | extern void afs_clear_inode(struct inode *); | 428 | extern void afs_clear_inode(struct inode *); |
| 385 | 429 | ||
| 386 | /* | 430 | /* |
| @@ -402,17 +446,11 @@ extern const struct inode_operations afs_mntpt_inode_operations; | |||
| 402 | extern const struct file_operations afs_mntpt_file_operations; | 446 | extern const struct file_operations afs_mntpt_file_operations; |
| 403 | extern unsigned long afs_mntpt_expiry_timeout; | 447 | extern unsigned long afs_mntpt_expiry_timeout; |
| 404 | 448 | ||
| 405 | extern int afs_mntpt_check_symlink(struct afs_vnode *); | 449 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); |
| 406 | extern void afs_mntpt_kill_timer(void); | 450 | extern void afs_mntpt_kill_timer(void); |
| 407 | extern void afs_umount_begin(struct vfsmount *, int); | 451 | extern void afs_umount_begin(struct vfsmount *, int); |
| 408 | 452 | ||
| 409 | /* | 453 | /* |
| 410 | * super.c | ||
| 411 | */ | ||
| 412 | extern int afs_fs_init(void); | ||
| 413 | extern void afs_fs_exit(void); | ||
| 414 | |||
| 415 | /* | ||
| 416 | * proc.c | 454 | * proc.c |
| 417 | */ | 455 | */ |
| 418 | extern int afs_proc_init(void); | 456 | extern int afs_proc_init(void); |
| @@ -436,6 +474,14 @@ extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *, | |||
| 436 | size_t); | 474 | size_t); |
| 437 | 475 | ||
| 438 | /* | 476 | /* |
| 477 | * security.c | ||
| 478 | */ | ||
| 479 | extern void afs_clear_permits(struct afs_vnode *); | ||
| 480 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); | ||
| 481 | extern struct key *afs_request_key(struct afs_cell *); | ||
| 482 | extern int afs_permission(struct inode *, int, struct nameidata *); | ||
| 483 | |||
| 484 | /* | ||
| 439 | * server.c | 485 | * server.c |
| 440 | */ | 486 | */ |
| 441 | extern spinlock_t afs_server_peer_lock; | 487 | extern spinlock_t afs_server_peer_lock; |
| @@ -449,16 +495,23 @@ extern void afs_put_server(struct afs_server *); | |||
| 449 | extern void __exit afs_purge_servers(void); | 495 | extern void __exit afs_purge_servers(void); |
| 450 | 496 | ||
| 451 | /* | 497 | /* |
| 498 | * super.c | ||
| 499 | */ | ||
| 500 | extern int afs_fs_init(void); | ||
| 501 | extern void afs_fs_exit(void); | ||
| 502 | |||
| 503 | /* | ||
| 452 | * vlclient.c | 504 | * vlclient.c |
| 453 | */ | 505 | */ |
| 454 | #ifdef AFS_CACHING_SUPPORT | 506 | #ifdef AFS_CACHING_SUPPORT |
| 455 | extern struct cachefs_index_def afs_vlocation_cache_index_def; | 507 | extern struct cachefs_index_def afs_vlocation_cache_index_def; |
| 456 | #endif | 508 | #endif |
| 457 | 509 | ||
| 458 | extern int afs_vl_get_entry_by_name(struct in_addr *, const char *, | 510 | extern int afs_vl_get_entry_by_name(struct in_addr *, struct key *, |
| 459 | struct afs_cache_vlocation *, | 511 | const char *, struct afs_cache_vlocation *, |
| 460 | const struct afs_wait_mode *); | 512 | const struct afs_wait_mode *); |
| 461 | extern int afs_vl_get_entry_by_id(struct in_addr *, afs_volid_t, afs_voltype_t, | 513 | extern int afs_vl_get_entry_by_id(struct in_addr *, struct key *, |
| 514 | afs_volid_t, afs_voltype_t, | ||
| 462 | struct afs_cache_vlocation *, | 515 | struct afs_cache_vlocation *, |
| 463 | const struct afs_wait_mode *); | 516 | const struct afs_wait_mode *); |
| 464 | 517 | ||
| @@ -469,6 +522,7 @@ extern int afs_vl_get_entry_by_id(struct in_addr *, afs_volid_t, afs_voltype_t, | |||
| 469 | 522 | ||
| 470 | extern int __init afs_vlocation_update_init(void); | 523 | extern int __init afs_vlocation_update_init(void); |
| 471 | extern struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *, | 524 | extern struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *, |
| 525 | struct key *, | ||
| 472 | const char *, size_t); | 526 | const char *, size_t); |
| 473 | extern void afs_put_vlocation(struct afs_vlocation *); | 527 | extern void afs_put_vlocation(struct afs_vlocation *); |
| 474 | extern void __exit afs_vlocation_purge(void); | 528 | extern void __exit afs_vlocation_purge(void); |
| @@ -492,9 +546,10 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode) | |||
| 492 | return &vnode->vfs_inode; | 546 | return &vnode->vfs_inode; |
| 493 | } | 547 | } |
| 494 | 548 | ||
| 495 | extern int afs_vnode_fetch_status(struct afs_vnode *); | 549 | extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *, |
| 496 | extern int afs_vnode_fetch_data(struct afs_vnode *vnode, off_t, size_t, | 550 | struct key *); |
| 497 | struct page *); | 551 | extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *, |
| 552 | off_t, size_t, struct page *); | ||
| 498 | 553 | ||
| 499 | /* | 554 | /* |
| 500 | * volume.c | 555 | * volume.c |
| @@ -506,8 +561,7 @@ extern struct cachefs_index_def afs_volume_cache_index_def; | |||
| 506 | #define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0) | 561 | #define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0) |
| 507 | 562 | ||
| 508 | extern void afs_put_volume(struct afs_volume *); | 563 | extern void afs_put_volume(struct afs_volume *); |
| 509 | extern struct afs_volume *afs_volume_lookup(const char *, struct afs_cell *, | 564 | extern struct afs_volume *afs_volume_lookup(struct afs_mount_params *); |
| 510 | int); | ||
| 511 | extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *); | 565 | extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *); |
| 512 | extern int afs_volume_release_fileserver(struct afs_vnode *, | 566 | extern int afs_volume_release_fileserver(struct afs_vnode *, |
| 513 | struct afs_server *, int); | 567 | struct afs_server *, int); |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 08c11a0b66bd..b905ae37f912 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -48,8 +48,11 @@ unsigned long afs_mntpt_expiry_timeout = 10 * 60; | |||
| 48 | * check a symbolic link to see whether it actually encodes a mountpoint | 48 | * check a symbolic link to see whether it actually encodes a mountpoint |
| 49 | * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately | 49 | * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately |
| 50 | */ | 50 | */ |
| 51 | int afs_mntpt_check_symlink(struct afs_vnode *vnode) | 51 | int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) |
| 52 | { | 52 | { |
| 53 | struct file file = { | ||
| 54 | .private_data = key, | ||
| 55 | }; | ||
| 53 | struct page *page; | 56 | struct page *page; |
| 54 | size_t size; | 57 | size_t size; |
| 55 | char *buf; | 58 | char *buf; |
| @@ -58,7 +61,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) | |||
| 58 | _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); | 61 | _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); |
| 59 | 62 | ||
| 60 | /* read the contents of the symlink into the pagecache */ | 63 | /* read the contents of the symlink into the pagecache */ |
| 61 | page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, NULL); | 64 | page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file); |
| 62 | if (IS_ERR(page)) { | 65 | if (IS_ERR(page)) { |
| 63 | ret = PTR_ERR(page); | 66 | ret = PTR_ERR(page); |
| 64 | goto out; | 67 | goto out; |
| @@ -214,7 +217,7 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 214 | struct vfsmount *newmnt; | 217 | struct vfsmount *newmnt; |
| 215 | int err; | 218 | int err; |
| 216 | 219 | ||
| 217 | _enter("%p{%s},{%s:%p{%s}}", | 220 | _enter("%p{%s},{%s:%p{%s},}", |
| 218 | dentry, | 221 | dentry, |
| 219 | dentry->d_name.name, | 222 | dentry->d_name.name, |
| 220 | nd->mnt->mnt_devname, | 223 | nd->mnt->mnt_devname, |
| @@ -234,7 +237,8 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 234 | err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); | 237 | err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); |
| 235 | switch (err) { | 238 | switch (err) { |
| 236 | case 0: | 239 | case 0: |
| 237 | path_release(nd); | 240 | mntput(nd->mnt); |
| 241 | dput(nd->dentry); | ||
| 238 | nd->mnt = newmnt; | 242 | nd->mnt = newmnt; |
| 239 | nd->dentry = dget(newmnt->mnt_root); | 243 | nd->dentry = dget(newmnt->mnt_root); |
| 240 | schedule_delayed_work(&afs_mntpt_expiry_timer, | 244 | schedule_delayed_work(&afs_mntpt_expiry_timer, |
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index b92774231b3c..e86c527d87a1 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | static struct socket *afs_socket; /* my RxRPC socket */ | 18 | static struct socket *afs_socket; /* my RxRPC socket */ |
| 19 | static struct workqueue_struct *afs_async_calls; | 19 | static struct workqueue_struct *afs_async_calls; |
| 20 | static atomic_t afs_outstanding_calls; | ||
| 21 | static atomic_t afs_outstanding_skbs; | ||
| 20 | 22 | ||
| 21 | static void afs_wake_up_call_waiter(struct afs_call *); | 23 | static void afs_wake_up_call_waiter(struct afs_call *); |
| 22 | static int afs_wait_for_call_to_complete(struct afs_call *); | 24 | static int afs_wait_for_call_to_complete(struct afs_call *); |
| @@ -45,6 +47,7 @@ static const struct afs_wait_mode afs_async_incoming_call = { | |||
| 45 | 47 | ||
| 46 | /* asynchronous incoming call initial processing */ | 48 | /* asynchronous incoming call initial processing */ |
| 47 | static const struct afs_call_type afs_RXCMxxxx = { | 49 | static const struct afs_call_type afs_RXCMxxxx = { |
| 50 | .name = "CB.xxxx", | ||
| 48 | .deliver = afs_deliver_cm_op_id, | 51 | .deliver = afs_deliver_cm_op_id, |
| 49 | .abort_to_error = afs_abort_to_error, | 52 | .abort_to_error = afs_abort_to_error, |
| 50 | }; | 53 | }; |
| @@ -118,10 +121,67 @@ void afs_close_socket(void) | |||
| 118 | 121 | ||
| 119 | _debug("dework"); | 122 | _debug("dework"); |
| 120 | destroy_workqueue(afs_async_calls); | 123 | destroy_workqueue(afs_async_calls); |
| 124 | |||
| 125 | ASSERTCMP(atomic_read(&afs_outstanding_skbs), ==, 0); | ||
| 126 | ASSERTCMP(atomic_read(&afs_outstanding_calls), ==, 0); | ||
| 121 | _leave(""); | 127 | _leave(""); |
| 122 | } | 128 | } |
| 123 | 129 | ||
| 124 | /* | 130 | /* |
| 131 | * note that the data in a socket buffer is now delivered and that the buffer | ||
| 132 | * should be freed | ||
| 133 | */ | ||
| 134 | static void afs_data_delivered(struct sk_buff *skb) | ||
| 135 | { | ||
| 136 | if (!skb) { | ||
| 137 | _debug("DLVR NULL [%d]", atomic_read(&afs_outstanding_skbs)); | ||
| 138 | dump_stack(); | ||
| 139 | } else { | ||
| 140 | _debug("DLVR %p{%u} [%d]", | ||
| 141 | skb, skb->mark, atomic_read(&afs_outstanding_skbs)); | ||
| 142 | if (atomic_dec_return(&afs_outstanding_skbs) == -1) | ||
| 143 | BUG(); | ||
| 144 | rxrpc_kernel_data_delivered(skb); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 149 | * free a socket buffer | ||
| 150 | */ | ||
| 151 | static void afs_free_skb(struct sk_buff *skb) | ||
| 152 | { | ||
| 153 | if (!skb) { | ||
| 154 | _debug("FREE NULL [%d]", atomic_read(&afs_outstanding_skbs)); | ||
| 155 | dump_stack(); | ||
| 156 | } else { | ||
| 157 | _debug("FREE %p{%u} [%d]", | ||
| 158 | skb, skb->mark, atomic_read(&afs_outstanding_skbs)); | ||
| 159 | if (atomic_dec_return(&afs_outstanding_skbs) == -1) | ||
| 160 | BUG(); | ||
| 161 | rxrpc_kernel_free_skb(skb); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | /* | ||
| 166 | * free a call | ||
| 167 | */ | ||
| 168 | static void afs_free_call(struct afs_call *call) | ||
| 169 | { | ||
| 170 | _debug("DONE %p{%s} [%d]", | ||
| 171 | call, call->type->name, atomic_read(&afs_outstanding_calls)); | ||
| 172 | if (atomic_dec_return(&afs_outstanding_calls) == -1) | ||
| 173 | BUG(); | ||
| 174 | |||
| 175 | ASSERTCMP(call->rxcall, ==, NULL); | ||
| 176 | ASSERT(!work_pending(&call->async_work)); | ||
| 177 | ASSERT(skb_queue_empty(&call->rx_queue)); | ||
| 178 | ASSERT(call->type->name != NULL); | ||
| 179 | |||
| 180 | kfree(call->request); | ||
| 181 | kfree(call); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* | ||
| 125 | * allocate a call with flat request and reply buffers | 185 | * allocate a call with flat request and reply buffers |
| 126 | */ | 186 | */ |
| 127 | struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, | 187 | struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, |
| @@ -133,30 +193,32 @@ struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, | |||
| 133 | if (!call) | 193 | if (!call) |
| 134 | goto nomem_call; | 194 | goto nomem_call; |
| 135 | 195 | ||
| 196 | _debug("CALL %p{%s} [%d]", | ||
| 197 | call, type->name, atomic_read(&afs_outstanding_calls)); | ||
| 198 | atomic_inc(&afs_outstanding_calls); | ||
| 199 | |||
| 200 | call->type = type; | ||
| 201 | call->request_size = request_size; | ||
| 202 | call->reply_max = reply_size; | ||
| 203 | |||
| 136 | if (request_size) { | 204 | if (request_size) { |
| 137 | call->request = kmalloc(request_size, GFP_NOFS); | 205 | call->request = kmalloc(request_size, GFP_NOFS); |
| 138 | if (!call->request) | 206 | if (!call->request) |
| 139 | goto nomem_request; | 207 | goto nomem_free; |
| 140 | } | 208 | } |
| 141 | 209 | ||
| 142 | if (reply_size) { | 210 | if (reply_size) { |
| 143 | call->buffer = kmalloc(reply_size, GFP_NOFS); | 211 | call->buffer = kmalloc(reply_size, GFP_NOFS); |
| 144 | if (!call->buffer) | 212 | if (!call->buffer) |
| 145 | goto nomem_buffer; | 213 | goto nomem_free; |
| 146 | } | 214 | } |
| 147 | 215 | ||
| 148 | call->type = type; | ||
| 149 | call->request_size = request_size; | ||
| 150 | call->reply_max = reply_size; | ||
| 151 | |||
| 152 | init_waitqueue_head(&call->waitq); | 216 | init_waitqueue_head(&call->waitq); |
| 153 | skb_queue_head_init(&call->rx_queue); | 217 | skb_queue_head_init(&call->rx_queue); |
| 154 | return call; | 218 | return call; |
| 155 | 219 | ||
| 156 | nomem_buffer: | 220 | nomem_free: |
| 157 | kfree(call->request); | 221 | afs_free_call(call); |
| 158 | nomem_request: | ||
| 159 | kfree(call); | ||
| 160 | nomem_call: | 222 | nomem_call: |
| 161 | return NULL; | 223 | return NULL; |
| 162 | } | 224 | } |
| @@ -188,6 +250,12 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
| 188 | 250 | ||
| 189 | _enter("%x,{%d},", addr->s_addr, ntohs(call->port)); | 251 | _enter("%x,{%d},", addr->s_addr, ntohs(call->port)); |
| 190 | 252 | ||
| 253 | ASSERT(call->type != NULL); | ||
| 254 | ASSERT(call->type->name != NULL); | ||
| 255 | |||
| 256 | _debug("MAKE %p{%s} [%d]", | ||
| 257 | call, call->type->name, atomic_read(&afs_outstanding_calls)); | ||
| 258 | |||
| 191 | call->wait_mode = wait_mode; | 259 | call->wait_mode = wait_mode; |
| 192 | INIT_WORK(&call->async_work, afs_process_async_call); | 260 | INIT_WORK(&call->async_work, afs_process_async_call); |
| 193 | 261 | ||
| @@ -203,6 +271,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
| 203 | /* create a call */ | 271 | /* create a call */ |
| 204 | rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, | 272 | rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, |
| 205 | (unsigned long) call, gfp); | 273 | (unsigned long) call, gfp); |
| 274 | call->key = NULL; | ||
| 206 | if (IS_ERR(rxcall)) { | 275 | if (IS_ERR(rxcall)) { |
| 207 | ret = PTR_ERR(rxcall); | 276 | ret = PTR_ERR(rxcall); |
| 208 | goto error_kill_call; | 277 | goto error_kill_call; |
| @@ -237,10 +306,10 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
| 237 | error_do_abort: | 306 | error_do_abort: |
| 238 | rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT); | 307 | rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT); |
| 239 | rxrpc_kernel_end_call(rxcall); | 308 | rxrpc_kernel_end_call(rxcall); |
| 309 | call->rxcall = NULL; | ||
| 240 | error_kill_call: | 310 | error_kill_call: |
| 241 | call->type->destructor(call); | 311 | call->type->destructor(call); |
| 242 | ASSERT(skb_queue_empty(&call->rx_queue)); | 312 | afs_free_call(call); |
| 243 | kfree(call); | ||
| 244 | _leave(" = %d", ret); | 313 | _leave(" = %d", ret); |
| 245 | return ret; | 314 | return ret; |
| 246 | } | 315 | } |
| @@ -257,15 +326,19 @@ static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID, | |||
| 257 | 326 | ||
| 258 | _enter("%p,,%u", call, skb->mark); | 327 | _enter("%p,,%u", call, skb->mark); |
| 259 | 328 | ||
| 329 | _debug("ICPT %p{%u} [%d]", | ||
| 330 | skb, skb->mark, atomic_read(&afs_outstanding_skbs)); | ||
| 331 | |||
| 260 | ASSERTCMP(sk, ==, afs_socket->sk); | 332 | ASSERTCMP(sk, ==, afs_socket->sk); |
| 333 | atomic_inc(&afs_outstanding_skbs); | ||
| 261 | 334 | ||
| 262 | if (!call) { | 335 | if (!call) { |
| 263 | /* its an incoming call for our callback service */ | 336 | /* its an incoming call for our callback service */ |
| 264 | __skb_queue_tail(&afs_incoming_calls, skb); | 337 | skb_queue_tail(&afs_incoming_calls, skb); |
| 265 | schedule_work(&afs_collect_incoming_call_work); | 338 | schedule_work(&afs_collect_incoming_call_work); |
| 266 | } else { | 339 | } else { |
| 267 | /* route the messages directly to the appropriate call */ | 340 | /* route the messages directly to the appropriate call */ |
| 268 | __skb_queue_tail(&call->rx_queue, skb); | 341 | skb_queue_tail(&call->rx_queue, skb); |
| 269 | call->wait_mode->rx_wakeup(call); | 342 | call->wait_mode->rx_wakeup(call); |
| 270 | } | 343 | } |
| 271 | 344 | ||
| @@ -317,9 +390,9 @@ static void afs_deliver_to_call(struct afs_call *call) | |||
| 317 | call->state = AFS_CALL_ERROR; | 390 | call->state = AFS_CALL_ERROR; |
| 318 | break; | 391 | break; |
| 319 | } | 392 | } |
| 320 | rxrpc_kernel_data_delivered(skb); | 393 | afs_data_delivered(skb); |
| 321 | skb = NULL; | 394 | skb = NULL; |
| 322 | break; | 395 | continue; |
| 323 | case RXRPC_SKB_MARK_FINAL_ACK: | 396 | case RXRPC_SKB_MARK_FINAL_ACK: |
| 324 | _debug("Rcv ACK"); | 397 | _debug("Rcv ACK"); |
| 325 | call->state = AFS_CALL_COMPLETE; | 398 | call->state = AFS_CALL_COMPLETE; |
| @@ -350,19 +423,19 @@ static void afs_deliver_to_call(struct afs_call *call) | |||
| 350 | break; | 423 | break; |
| 351 | } | 424 | } |
| 352 | 425 | ||
| 353 | rxrpc_kernel_free_skb(skb); | 426 | afs_free_skb(skb); |
| 354 | } | 427 | } |
| 355 | 428 | ||
| 356 | /* make sure the queue is empty if the call is done with (we might have | 429 | /* make sure the queue is empty if the call is done with (we might have |
| 357 | * aborted the call early because of an unmarshalling error) */ | 430 | * aborted the call early because of an unmarshalling error) */ |
| 358 | if (call->state >= AFS_CALL_COMPLETE) { | 431 | if (call->state >= AFS_CALL_COMPLETE) { |
| 359 | while ((skb = skb_dequeue(&call->rx_queue))) | 432 | while ((skb = skb_dequeue(&call->rx_queue))) |
| 360 | rxrpc_kernel_free_skb(skb); | 433 | afs_free_skb(skb); |
| 361 | if (call->incoming) { | 434 | if (call->incoming) { |
| 362 | rxrpc_kernel_end_call(call->rxcall); | 435 | rxrpc_kernel_end_call(call->rxcall); |
| 436 | call->rxcall = NULL; | ||
| 363 | call->type->destructor(call); | 437 | call->type->destructor(call); |
| 364 | ASSERT(skb_queue_empty(&call->rx_queue)); | 438 | afs_free_call(call); |
| 365 | kfree(call); | ||
| 366 | } | 439 | } |
| 367 | } | 440 | } |
| 368 | 441 | ||
| @@ -409,14 +482,14 @@ static int afs_wait_for_call_to_complete(struct afs_call *call) | |||
| 409 | _debug("call incomplete"); | 482 | _debug("call incomplete"); |
| 410 | rxrpc_kernel_abort_call(call->rxcall, RX_CALL_DEAD); | 483 | rxrpc_kernel_abort_call(call->rxcall, RX_CALL_DEAD); |
| 411 | while ((skb = skb_dequeue(&call->rx_queue))) | 484 | while ((skb = skb_dequeue(&call->rx_queue))) |
| 412 | rxrpc_kernel_free_skb(skb); | 485 | afs_free_skb(skb); |
| 413 | } | 486 | } |
| 414 | 487 | ||
| 415 | _debug("call complete"); | 488 | _debug("call complete"); |
| 416 | rxrpc_kernel_end_call(call->rxcall); | 489 | rxrpc_kernel_end_call(call->rxcall); |
| 490 | call->rxcall = NULL; | ||
| 417 | call->type->destructor(call); | 491 | call->type->destructor(call); |
| 418 | ASSERT(skb_queue_empty(&call->rx_queue)); | 492 | afs_free_call(call); |
| 419 | kfree(call); | ||
| 420 | _leave(" = %d", ret); | 493 | _leave(" = %d", ret); |
| 421 | return ret; | 494 | return ret; |
| 422 | } | 495 | } |
| @@ -459,9 +532,7 @@ static void afs_delete_async_call(struct work_struct *work) | |||
| 459 | 532 | ||
| 460 | _enter(""); | 533 | _enter(""); |
| 461 | 534 | ||
| 462 | ASSERT(skb_queue_empty(&call->rx_queue)); | 535 | afs_free_call(call); |
| 463 | ASSERT(!work_pending(&call->async_work)); | ||
| 464 | kfree(call); | ||
| 465 | 536 | ||
| 466 | _leave(""); | 537 | _leave(""); |
| 467 | } | 538 | } |
| @@ -489,6 +560,7 @@ static void afs_process_async_call(struct work_struct *work) | |||
| 489 | 560 | ||
| 490 | /* kill the call */ | 561 | /* kill the call */ |
| 491 | rxrpc_kernel_end_call(call->rxcall); | 562 | rxrpc_kernel_end_call(call->rxcall); |
| 563 | call->rxcall = NULL; | ||
| 492 | if (call->type->destructor) | 564 | if (call->type->destructor) |
| 493 | call->type->destructor(call); | 565 | call->type->destructor(call); |
| 494 | 566 | ||
| @@ -526,7 +598,7 @@ static void afs_collect_incoming_call(struct work_struct *work) | |||
| 526 | _debug("new call"); | 598 | _debug("new call"); |
| 527 | 599 | ||
| 528 | /* don't need the notification */ | 600 | /* don't need the notification */ |
| 529 | rxrpc_kernel_free_skb(skb); | 601 | afs_free_skb(skb); |
| 530 | 602 | ||
| 531 | if (!call) { | 603 | if (!call) { |
| 532 | call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); | 604 | call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); |
| @@ -541,6 +613,11 @@ static void afs_collect_incoming_call(struct work_struct *work) | |||
| 541 | init_waitqueue_head(&call->waitq); | 613 | init_waitqueue_head(&call->waitq); |
| 542 | skb_queue_head_init(&call->rx_queue); | 614 | skb_queue_head_init(&call->rx_queue); |
| 543 | call->state = AFS_CALL_AWAIT_OP_ID; | 615 | call->state = AFS_CALL_AWAIT_OP_ID; |
| 616 | |||
| 617 | _debug("CALL %p{%s} [%d]", | ||
| 618 | call, call->type->name, | ||
| 619 | atomic_read(&afs_outstanding_calls)); | ||
| 620 | atomic_inc(&afs_outstanding_calls); | ||
| 544 | } | 621 | } |
| 545 | 622 | ||
| 546 | rxcall = rxrpc_kernel_accept_call(afs_socket, | 623 | rxcall = rxrpc_kernel_accept_call(afs_socket, |
| @@ -551,7 +628,8 @@ static void afs_collect_incoming_call(struct work_struct *work) | |||
| 551 | } | 628 | } |
| 552 | } | 629 | } |
| 553 | 630 | ||
| 554 | kfree(call); | 631 | if (call) |
| 632 | afs_free_call(call); | ||
| 555 | } | 633 | } |
| 556 | 634 | ||
| 557 | /* | 635 | /* |
| @@ -629,8 +707,7 @@ void afs_send_empty_reply(struct afs_call *call) | |||
| 629 | rxrpc_kernel_end_call(call->rxcall); | 707 | rxrpc_kernel_end_call(call->rxcall); |
| 630 | call->rxcall = NULL; | 708 | call->rxcall = NULL; |
| 631 | call->type->destructor(call); | 709 | call->type->destructor(call); |
| 632 | ASSERT(skb_queue_empty(&call->rx_queue)); | 710 | afs_free_call(call); |
| 633 | kfree(call); | ||
| 634 | _leave(" [error]"); | 711 | _leave(" [error]"); |
| 635 | return; | 712 | return; |
| 636 | } | 713 | } |
diff --git a/fs/afs/security.c b/fs/afs/security.c new file mode 100644 index 000000000000..cbdd7f7162fa --- /dev/null +++ b/fs/afs/security.c | |||
| @@ -0,0 +1,345 @@ | |||
| 1 | /* AFS security handling | ||
| 2 | * | ||
| 3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the License, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/fs.h> | ||
| 15 | #include <linux/ctype.h> | ||
| 16 | #include <keys/rxrpc-type.h> | ||
| 17 | #include "internal.h" | ||
| 18 | |||
| 19 | /* | ||
| 20 | * get a key | ||
| 21 | */ | ||
| 22 | struct key *afs_request_key(struct afs_cell *cell) | ||
| 23 | { | ||
| 24 | struct key *key; | ||
| 25 | |||
| 26 | _enter("{%x}", key_serial(cell->anonymous_key)); | ||
| 27 | |||
| 28 | _debug("key %s", cell->anonymous_key->description); | ||
| 29 | key = request_key(&key_type_rxrpc, cell->anonymous_key->description, | ||
| 30 | NULL); | ||
| 31 | if (IS_ERR(key)) { | ||
| 32 | if (PTR_ERR(key) != -ENOKEY) { | ||
| 33 | _leave(" = %ld", PTR_ERR(key)); | ||
| 34 | return key; | ||
| 35 | } | ||
| 36 | |||
| 37 | /* act as anonymous user */ | ||
| 38 | _leave(" = {%x} [anon]", key_serial(cell->anonymous_key)); | ||
| 39 | return key_get(cell->anonymous_key); | ||
| 40 | } else { | ||
| 41 | /* act as authorised user */ | ||
| 42 | _leave(" = {%x} [auth]", key_serial(key)); | ||
| 43 | return key; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | /* | ||
| 48 | * dispose of a permits list | ||
| 49 | */ | ||
| 50 | void afs_zap_permits(struct rcu_head *rcu) | ||
| 51 | { | ||
| 52 | struct afs_permits *permits = | ||
| 53 | container_of(rcu, struct afs_permits, rcu); | ||
| 54 | int loop; | ||
| 55 | |||
| 56 | _enter("{%d}", permits->count); | ||
| 57 | |||
| 58 | for (loop = permits->count - 1; loop >= 0; loop--) | ||
| 59 | key_put(permits->permits[loop].key); | ||
| 60 | kfree(permits); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* | ||
| 64 | * dispose of a permits list in which all the key pointers have been copied | ||
| 65 | */ | ||
| 66 | static void afs_dispose_of_permits(struct rcu_head *rcu) | ||
| 67 | { | ||
| 68 | struct afs_permits *permits = | ||
| 69 | container_of(rcu, struct afs_permits, rcu); | ||
| 70 | |||
| 71 | _enter("{%d}", permits->count); | ||
| 72 | |||
| 73 | kfree(permits); | ||
| 74 | } | ||
| 75 | |||
| 76 | /* | ||
| 77 | * get the authorising vnode - this is the specified inode itself if it's a | ||
| 78 | * directory or it's the parent directory if the specified inode is a file or | ||
| 79 | * symlink | ||
| 80 | * - the caller must release the ref on the inode | ||
| 81 | */ | ||
| 82 | static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode, | ||
| 83 | struct key *key) | ||
| 84 | { | ||
| 85 | struct afs_vnode *auth_vnode; | ||
| 86 | struct inode *auth_inode; | ||
| 87 | |||
| 88 | _enter(""); | ||
| 89 | |||
| 90 | if (S_ISDIR(vnode->vfs_inode.i_mode)) { | ||
| 91 | auth_inode = igrab(&vnode->vfs_inode); | ||
| 92 | ASSERT(auth_inode != NULL); | ||
| 93 | } else { | ||
| 94 | auth_inode = afs_iget(vnode->vfs_inode.i_sb, key, | ||
| 95 | &vnode->status.parent); | ||
| 96 | if (IS_ERR(auth_inode)) | ||
| 97 | return ERR_PTR(PTR_ERR(auth_inode)); | ||
| 98 | } | ||
| 99 | |||
| 100 | auth_vnode = AFS_FS_I(auth_inode); | ||
| 101 | _leave(" = {%x}", auth_vnode->fid.vnode); | ||
| 102 | return auth_vnode; | ||
| 103 | } | ||
| 104 | |||
| 105 | /* | ||
| 106 | * clear the permit cache on a directory vnode | ||
| 107 | */ | ||
| 108 | void afs_clear_permits(struct afs_vnode *vnode) | ||
| 109 | { | ||
| 110 | struct afs_permits *permits; | ||
| 111 | |||
| 112 | _enter("{%x}", vnode->fid.vnode); | ||
| 113 | |||
| 114 | mutex_lock(&vnode->permits_lock); | ||
| 115 | permits = vnode->permits; | ||
| 116 | rcu_assign_pointer(vnode->permits, NULL); | ||
| 117 | mutex_unlock(&vnode->permits_lock); | ||
| 118 | |||
| 119 | if (permits) | ||
| 120 | call_rcu(&permits->rcu, afs_zap_permits); | ||
| 121 | _leave(""); | ||
| 122 | } | ||
| 123 | |||
| 124 | /* | ||
| 125 | * add the result obtained for a vnode to its or its parent directory's cache | ||
| 126 | * for the key used to access it | ||
| 127 | */ | ||
| 128 | void afs_cache_permit(struct afs_vnode *vnode, struct key *key, long acl_order) | ||
| 129 | { | ||
| 130 | struct afs_permits *permits, *xpermits; | ||
| 131 | struct afs_permit *permit; | ||
| 132 | struct afs_vnode *auth_vnode; | ||
| 133 | int count, loop; | ||
| 134 | |||
| 135 | _enter("{%x},%x,%lx", vnode->fid.vnode, key_serial(key), acl_order); | ||
| 136 | |||
| 137 | auth_vnode = afs_get_auth_inode(vnode, key); | ||
| 138 | if (IS_ERR(auth_vnode)) { | ||
| 139 | _leave(" [get error %ld]", PTR_ERR(auth_vnode)); | ||
| 140 | return; | ||
| 141 | } | ||
| 142 | |||
| 143 | mutex_lock(&auth_vnode->permits_lock); | ||
| 144 | |||
| 145 | /* guard against a rename being detected whilst we waited for the | ||
| 146 | * lock */ | ||
| 147 | if (memcmp(&auth_vnode->fid, &vnode->status.parent, | ||
| 148 | sizeof(struct afs_fid)) != 0) { | ||
| 149 | _debug("renamed"); | ||
| 150 | goto out_unlock; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* have to be careful as the directory's callback may be broken between | ||
| 154 | * us receiving the status we're trying to cache and us getting the | ||
| 155 | * lock to update the cache for the status */ | ||
| 156 | if (auth_vnode->acl_order - acl_order > 0) { | ||
| 157 | _debug("ACL changed?"); | ||
| 158 | goto out_unlock; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* always update the anonymous mask */ | ||
| 162 | _debug("anon access %x", vnode->status.anon_access); | ||
| 163 | auth_vnode->status.anon_access = vnode->status.anon_access; | ||
| 164 | if (key == vnode->volume->cell->anonymous_key) | ||
| 165 | goto out_unlock; | ||
| 166 | |||
| 167 | xpermits = auth_vnode->permits; | ||
| 168 | count = 0; | ||
| 169 | if (xpermits) { | ||
| 170 | /* see if the permit is already in the list | ||
| 171 | * - if it is then we just amend the list | ||
| 172 | */ | ||
| 173 | count = xpermits->count; | ||
| 174 | permit = xpermits->permits; | ||
| 175 | for (loop = count; loop > 0; loop--) { | ||
| 176 | if (permit->key == key) { | ||
| 177 | permit->access_mask = | ||
| 178 | vnode->status.caller_access; | ||
| 179 | goto out_unlock; | ||
| 180 | } | ||
| 181 | permit++; | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | permits = kmalloc(sizeof(*permits) + sizeof(*permit) * (count + 1), | ||
| 186 | GFP_NOFS); | ||
| 187 | if (!permits) | ||
| 188 | goto out_unlock; | ||
| 189 | |||
| 190 | memcpy(permits->permits, xpermits->permits, | ||
| 191 | count * sizeof(struct afs_permit)); | ||
| 192 | |||
| 193 | _debug("key %x access %x", | ||
| 194 | key_serial(key), vnode->status.caller_access); | ||
| 195 | permits->permits[count].access_mask = vnode->status.caller_access; | ||
| 196 | permits->permits[count].key = key_get(key); | ||
| 197 | permits->count = count + 1; | ||
| 198 | |||
| 199 | rcu_assign_pointer(auth_vnode->permits, permits); | ||
| 200 | if (xpermits) | ||
| 201 | call_rcu(&xpermits->rcu, afs_dispose_of_permits); | ||
| 202 | |||
| 203 | out_unlock: | ||
| 204 | mutex_unlock(&auth_vnode->permits_lock); | ||
| 205 | iput(&auth_vnode->vfs_inode); | ||
| 206 | _leave(""); | ||
| 207 | } | ||
| 208 | |||
| 209 | /* | ||
| 210 | * check with the fileserver to see if the directory or parent directory is | ||
| 211 | * permitted to be accessed with this authorisation, and if so, what access it | ||
| 212 | * is granted | ||
| 213 | */ | ||
| 214 | static int afs_check_permit(struct afs_vnode *vnode, struct key *key, | ||
| 215 | afs_access_t *_access) | ||
| 216 | { | ||
| 217 | struct afs_permits *permits; | ||
| 218 | struct afs_permit *permit; | ||
| 219 | struct afs_vnode *auth_vnode; | ||
| 220 | bool valid; | ||
| 221 | int loop, ret; | ||
| 222 | |||
| 223 | _enter(""); | ||
| 224 | |||
| 225 | auth_vnode = afs_get_auth_inode(vnode, key); | ||
| 226 | if (IS_ERR(auth_vnode)) { | ||
| 227 | *_access = 0; | ||
| 228 | _leave(" = %ld", PTR_ERR(auth_vnode)); | ||
| 229 | return PTR_ERR(auth_vnode); | ||
| 230 | } | ||
| 231 | |||
| 232 | ASSERT(S_ISDIR(auth_vnode->vfs_inode.i_mode)); | ||
| 233 | |||
| 234 | /* check the permits to see if we've got one yet */ | ||
| 235 | if (key == auth_vnode->volume->cell->anonymous_key) { | ||
| 236 | _debug("anon"); | ||
| 237 | *_access = auth_vnode->status.anon_access; | ||
| 238 | valid = true; | ||
| 239 | } else { | ||
| 240 | valid = false; | ||
| 241 | rcu_read_lock(); | ||
| 242 | permits = rcu_dereference(auth_vnode->permits); | ||
| 243 | if (permits) { | ||
| 244 | permit = permits->permits; | ||
| 245 | for (loop = permits->count; loop > 0; loop--) { | ||
| 246 | if (permit->key == key) { | ||
| 247 | _debug("found in cache"); | ||
| 248 | *_access = permit->access_mask; | ||
| 249 | valid = true; | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | permit++; | ||
| 253 | } | ||
| 254 | } | ||
| 255 | rcu_read_unlock(); | ||
| 256 | } | ||
| 257 | |||
| 258 | if (!valid) { | ||
| 259 | /* check the status on the file we're actually interested in | ||
| 260 | * (the post-processing will cache the result on auth_vnode) */ | ||
| 261 | _debug("no valid permit"); | ||
| 262 | |||
| 263 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | ||
| 264 | ret = afs_vnode_fetch_status(vnode, auth_vnode, key); | ||
| 265 | if (ret < 0) { | ||
| 266 | iput(&auth_vnode->vfs_inode); | ||
| 267 | *_access = 0; | ||
| 268 | _leave(" = %d", ret); | ||
| 269 | return ret; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | *_access = vnode->status.caller_access; | ||
| 274 | iput(&auth_vnode->vfs_inode); | ||
| 275 | _leave(" = 0 [access %x]", *_access); | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* | ||
| 280 | * check the permissions on an AFS file | ||
| 281 | * - AFS ACLs are attached to directories only, and a file is controlled by its | ||
| 282 | * parent directory's ACL | ||
| 283 | */ | ||
| 284 | int afs_permission(struct inode *inode, int mask, struct nameidata *nd) | ||
| 285 | { | ||
| 286 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
| 287 | afs_access_t access; | ||
| 288 | struct key *key; | ||
| 289 | int ret; | ||
| 290 | |||
| 291 | _enter("{%x:%x},%x,", vnode->fid.vid, vnode->fid.vnode, mask); | ||
| 292 | |||
| 293 | key = afs_request_key(vnode->volume->cell); | ||
| 294 | if (IS_ERR(key)) { | ||
| 295 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
| 296 | return PTR_ERR(key); | ||
| 297 | } | ||
| 298 | |||
| 299 | /* check the permits to see if we've got one yet */ | ||
| 300 | ret = afs_check_permit(vnode, key, &access); | ||
| 301 | if (ret < 0) { | ||
| 302 | key_put(key); | ||
| 303 | _leave(" = %d [check]", ret); | ||
| 304 | return ret; | ||
| 305 | } | ||
| 306 | |||
| 307 | /* interpret the access mask */ | ||
| 308 | _debug("REQ %x ACC %x on %s", | ||
| 309 | mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file"); | ||
| 310 | |||
| 311 | if (S_ISDIR(inode->i_mode)) { | ||
| 312 | if (mask & MAY_EXEC) { | ||
| 313 | if (!(access & AFS_ACE_LOOKUP)) | ||
| 314 | goto permission_denied; | ||
| 315 | } else if (mask & MAY_READ) { | ||
| 316 | if (!(access & AFS_ACE_READ)) | ||
| 317 | goto permission_denied; | ||
| 318 | } else if (mask & MAY_WRITE) { | ||
| 319 | if (!(access & (AFS_ACE_DELETE | /* rmdir, unlink, rename from */ | ||
| 320 | AFS_ACE_INSERT | /* create, mkdir, symlink, rename to */ | ||
| 321 | AFS_ACE_WRITE))) /* chmod */ | ||
| 322 | goto permission_denied; | ||
| 323 | } else { | ||
| 324 | BUG(); | ||
| 325 | } | ||
| 326 | } else { | ||
| 327 | if (!(access & AFS_ACE_LOOKUP)) | ||
| 328 | goto permission_denied; | ||
| 329 | if (mask & (MAY_EXEC | MAY_READ)) { | ||
| 330 | if (!(access & AFS_ACE_READ)) | ||
| 331 | goto permission_denied; | ||
| 332 | } else if (mask & MAY_WRITE) { | ||
| 333 | if (!(access & AFS_ACE_WRITE)) | ||
| 334 | goto permission_denied; | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | key_put(key); | ||
| 339 | return generic_permission(inode, mask, NULL); | ||
| 340 | |||
| 341 | permission_denied: | ||
| 342 | key_put(key); | ||
| 343 | _leave(" = -EACCES"); | ||
| 344 | return -EACCES; | ||
| 345 | } | ||
diff --git a/fs/afs/super.c b/fs/afs/super.c index 77e68759788f..497350a5463b 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
| @@ -24,12 +24,6 @@ | |||
| 24 | 24 | ||
| 25 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ | 25 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ |
| 26 | 26 | ||
| 27 | struct afs_mount_params { | ||
| 28 | int rwpath; | ||
| 29 | struct afs_cell *default_cell; | ||
| 30 | struct afs_volume *volume; | ||
| 31 | }; | ||
| 32 | |||
| 33 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, | 27 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, |
| 34 | unsigned long flags); | 28 | unsigned long flags); |
| 35 | 29 | ||
| @@ -150,8 +144,8 @@ static int want_no_value(char *const *_value, const char *option) | |||
| 150 | * - this function has been shamelessly adapted from the ext3 fs which | 144 | * - this function has been shamelessly adapted from the ext3 fs which |
| 151 | * shamelessly adapted it from the msdos fs | 145 | * shamelessly adapted it from the msdos fs |
| 152 | */ | 146 | */ |
| 153 | static int afs_super_parse_options(struct afs_mount_params *params, | 147 | static int afs_parse_options(struct afs_mount_params *params, |
| 154 | char *options, const char **devname) | 148 | char *options, const char **devname) |
| 155 | { | 149 | { |
| 156 | struct afs_cell *cell; | 150 | struct afs_cell *cell; |
| 157 | char *key, *value; | 151 | char *key, *value; |
| @@ -183,8 +177,8 @@ static int afs_super_parse_options(struct afs_mount_params *params, | |||
| 183 | cell = afs_cell_lookup(value, strlen(value)); | 177 | cell = afs_cell_lookup(value, strlen(value)); |
| 184 | if (IS_ERR(cell)) | 178 | if (IS_ERR(cell)) |
| 185 | return PTR_ERR(cell); | 179 | return PTR_ERR(cell); |
| 186 | afs_put_cell(params->default_cell); | 180 | afs_put_cell(params->cell); |
| 187 | params->default_cell = cell; | 181 | params->cell = cell; |
| 188 | } else { | 182 | } else { |
| 189 | printk("kAFS: Unknown mount option: '%s'\n", key); | 183 | printk("kAFS: Unknown mount option: '%s'\n", key); |
| 190 | ret = -EINVAL; | 184 | ret = -EINVAL; |
| @@ -199,6 +193,99 @@ error: | |||
| 199 | } | 193 | } |
| 200 | 194 | ||
| 201 | /* | 195 | /* |
| 196 | * parse a device name to get cell name, volume name, volume type and R/W | ||
| 197 | * selector | ||
| 198 | * - this can be one of the following: | ||
| 199 | * "%[cell:]volume[.]" R/W volume | ||
| 200 | * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), | ||
| 201 | * or R/W (rwpath=1) volume | ||
| 202 | * "%[cell:]volume.readonly" R/O volume | ||
| 203 | * "#[cell:]volume.readonly" R/O volume | ||
| 204 | * "%[cell:]volume.backup" Backup volume | ||
| 205 | * "#[cell:]volume.backup" Backup volume | ||
| 206 | */ | ||
| 207 | static int afs_parse_device_name(struct afs_mount_params *params, | ||
| 208 | const char *name) | ||
| 209 | { | ||
| 210 | struct afs_cell *cell; | ||
| 211 | const char *cellname, *suffix; | ||
| 212 | int cellnamesz; | ||
| 213 | |||
| 214 | _enter(",%s", name); | ||
| 215 | |||
| 216 | if (!name) { | ||
| 217 | printk(KERN_ERR "kAFS: no volume name specified\n"); | ||
| 218 | return -EINVAL; | ||
| 219 | } | ||
| 220 | |||
| 221 | if ((name[0] != '%' && name[0] != '#') || !name[1]) { | ||
| 222 | printk(KERN_ERR "kAFS: unparsable volume name\n"); | ||
| 223 | return -EINVAL; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* determine the type of volume we're looking for */ | ||
| 227 | params->type = AFSVL_ROVOL; | ||
| 228 | params->force = false; | ||
| 229 | if (params->rwpath || name[0] == '%') { | ||
| 230 | params->type = AFSVL_RWVOL; | ||
| 231 | params->force = true; | ||
| 232 | } | ||
| 233 | name++; | ||
| 234 | |||
| 235 | /* split the cell name out if there is one */ | ||
| 236 | params->volname = strchr(name, ':'); | ||
| 237 | if (params->volname) { | ||
| 238 | cellname = name; | ||
| 239 | cellnamesz = params->volname - name; | ||
| 240 | params->volname++; | ||
| 241 | } else { | ||
| 242 | params->volname = name; | ||
| 243 | cellname = NULL; | ||
| 244 | cellnamesz = 0; | ||
| 245 | } | ||
| 246 | |||
| 247 | /* the volume type is further affected by a possible suffix */ | ||
| 248 | suffix = strrchr(params->volname, '.'); | ||
| 249 | if (suffix) { | ||
| 250 | if (strcmp(suffix, ".readonly") == 0) { | ||
| 251 | params->type = AFSVL_ROVOL; | ||
| 252 | params->force = true; | ||
| 253 | } else if (strcmp(suffix, ".backup") == 0) { | ||
| 254 | params->type = AFSVL_BACKVOL; | ||
| 255 | params->force = true; | ||
| 256 | } else if (suffix[1] == 0) { | ||
| 257 | } else { | ||
| 258 | suffix = NULL; | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | params->volnamesz = suffix ? | ||
| 263 | suffix - params->volname : strlen(params->volname); | ||
| 264 | |||
| 265 | _debug("cell %*.*s [%p]", | ||
| 266 | cellnamesz, cellnamesz, cellname ?: "", params->cell); | ||
| 267 | |||
| 268 | /* lookup the cell record */ | ||
| 269 | if (cellname || !params->cell) { | ||
| 270 | cell = afs_cell_lookup(cellname, cellnamesz); | ||
| 271 | if (IS_ERR(cell)) { | ||
| 272 | printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n", | ||
| 273 | cellname ?: ""); | ||
| 274 | return PTR_ERR(cell); | ||
| 275 | } | ||
| 276 | afs_put_cell(params->cell); | ||
| 277 | params->cell = cell; | ||
| 278 | } | ||
| 279 | |||
| 280 | _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", | ||
| 281 | params->cell->name, params->cell, | ||
| 282 | params->volnamesz, params->volnamesz, params->volname, | ||
| 283 | suffix ?: "-", params->type, params->force ? " FORCE" : ""); | ||
| 284 | |||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | /* | ||
| 202 | * check a superblock to see if it's the one we're looking for | 289 | * check a superblock to see if it's the one we're looking for |
| 203 | */ | 290 | */ |
| 204 | static int afs_test_super(struct super_block *sb, void *data) | 291 | static int afs_test_super(struct super_block *sb, void *data) |
| @@ -244,7 +331,7 @@ static int afs_fill_super(struct super_block *sb, void *data) | |||
| 244 | fid.vid = as->volume->vid; | 331 | fid.vid = as->volume->vid; |
| 245 | fid.vnode = 1; | 332 | fid.vnode = 1; |
| 246 | fid.unique = 1; | 333 | fid.unique = 1; |
| 247 | inode = afs_iget(sb, &fid); | 334 | inode = afs_iget(sb, params->key, &fid); |
| 248 | if (IS_ERR(inode)) | 335 | if (IS_ERR(inode)) |
| 249 | goto error_inode; | 336 | goto error_inode; |
| 250 | 337 | ||
| @@ -285,31 +372,40 @@ static int afs_get_sb(struct file_system_type *fs_type, | |||
| 285 | struct afs_mount_params params; | 372 | struct afs_mount_params params; |
| 286 | struct super_block *sb; | 373 | struct super_block *sb; |
| 287 | struct afs_volume *vol; | 374 | struct afs_volume *vol; |
| 375 | struct key *key; | ||
| 288 | int ret; | 376 | int ret; |
| 289 | 377 | ||
| 290 | _enter(",,%s,%p", dev_name, options); | 378 | _enter(",,%s,%p", dev_name, options); |
| 291 | 379 | ||
| 292 | memset(¶ms, 0, sizeof(params)); | 380 | memset(¶ms, 0, sizeof(params)); |
| 293 | 381 | ||
| 294 | /* parse the options */ | 382 | /* parse the options and device name */ |
| 295 | if (options) { | 383 | if (options) { |
| 296 | ret = afs_super_parse_options(¶ms, options, &dev_name); | 384 | ret = afs_parse_options(¶ms, options, &dev_name); |
| 297 | if (ret < 0) | 385 | if (ret < 0) |
| 298 | goto error; | 386 | goto error; |
| 299 | if (!dev_name) { | ||
| 300 | printk("kAFS: no volume name specified\n"); | ||
| 301 | ret = -EINVAL; | ||
| 302 | goto error; | ||
| 303 | } | ||
| 304 | } | 387 | } |
| 305 | 388 | ||
| 389 | |||
| 390 | ret = afs_parse_device_name(¶ms, dev_name); | ||
| 391 | if (ret < 0) | ||
| 392 | goto error; | ||
| 393 | |||
| 394 | /* try and do the mount securely */ | ||
| 395 | key = afs_request_key(params.cell); | ||
| 396 | if (IS_ERR(key)) { | ||
| 397 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
| 398 | ret = PTR_ERR(key); | ||
| 399 | goto error; | ||
| 400 | } | ||
| 401 | params.key = key; | ||
| 402 | |||
| 306 | /* parse the device name */ | 403 | /* parse the device name */ |
| 307 | vol = afs_volume_lookup(dev_name, params.default_cell, params.rwpath); | 404 | vol = afs_volume_lookup(¶ms); |
| 308 | if (IS_ERR(vol)) { | 405 | if (IS_ERR(vol)) { |
| 309 | ret = PTR_ERR(vol); | 406 | ret = PTR_ERR(vol); |
| 310 | goto error; | 407 | goto error; |
| 311 | } | 408 | } |
| 312 | |||
| 313 | params.volume = vol; | 409 | params.volume = vol; |
| 314 | 410 | ||
| 315 | /* allocate a deviceless superblock */ | 411 | /* allocate a deviceless superblock */ |
| @@ -337,13 +433,14 @@ static int afs_get_sb(struct file_system_type *fs_type, | |||
| 337 | 433 | ||
| 338 | simple_set_mnt(mnt, sb); | 434 | simple_set_mnt(mnt, sb); |
| 339 | afs_put_volume(params.volume); | 435 | afs_put_volume(params.volume); |
| 340 | afs_put_cell(params.default_cell); | 436 | afs_put_cell(params.cell); |
| 341 | _leave(" = 0 [%p]", sb); | 437 | _leave(" = 0 [%p]", sb); |
| 342 | return 0; | 438 | return 0; |
| 343 | 439 | ||
| 344 | error: | 440 | error: |
| 345 | afs_put_volume(params.volume); | 441 | afs_put_volume(params.volume); |
| 346 | afs_put_cell(params.default_cell); | 442 | afs_put_cell(params.cell); |
| 443 | key_put(params.key); | ||
| 347 | _leave(" = %d", ret); | 444 | _leave(" = %d", ret); |
| 348 | return ret; | 445 | return ret; |
| 349 | } | 446 | } |
| @@ -375,6 +472,7 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, | |||
| 375 | memset(vnode, 0, sizeof(*vnode)); | 472 | memset(vnode, 0, sizeof(*vnode)); |
| 376 | inode_init_once(&vnode->vfs_inode); | 473 | inode_init_once(&vnode->vfs_inode); |
| 377 | init_waitqueue_head(&vnode->update_waitq); | 474 | init_waitqueue_head(&vnode->update_waitq); |
| 475 | mutex_init(&vnode->permits_lock); | ||
| 378 | spin_lock_init(&vnode->lock); | 476 | spin_lock_init(&vnode->lock); |
| 379 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); | 477 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); |
| 380 | mutex_init(&vnode->cb_broken_lock); | 478 | mutex_init(&vnode->cb_broken_lock); |
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c index 0c7eba174836..36c1306e09e0 100644 --- a/fs/afs/vlclient.c +++ b/fs/afs/vlclient.c | |||
| @@ -127,6 +127,7 @@ static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call, | |||
| 127 | * VL.GetEntryByName operation type | 127 | * VL.GetEntryByName operation type |
| 128 | */ | 128 | */ |
| 129 | static const struct afs_call_type afs_RXVLGetEntryByName = { | 129 | static const struct afs_call_type afs_RXVLGetEntryByName = { |
| 130 | .name = "VL.GetEntryByName", | ||
| 130 | .deliver = afs_deliver_vl_get_entry_by_xxx, | 131 | .deliver = afs_deliver_vl_get_entry_by_xxx, |
| 131 | .abort_to_error = afs_vl_abort_to_error, | 132 | .abort_to_error = afs_vl_abort_to_error, |
| 132 | .destructor = afs_flat_call_destructor, | 133 | .destructor = afs_flat_call_destructor, |
| @@ -136,6 +137,7 @@ static const struct afs_call_type afs_RXVLGetEntryByName = { | |||
| 136 | * VL.GetEntryById operation type | 137 | * VL.GetEntryById operation type |
| 137 | */ | 138 | */ |
| 138 | static const struct afs_call_type afs_RXVLGetEntryById = { | 139 | static const struct afs_call_type afs_RXVLGetEntryById = { |
| 140 | .name = "VL.GetEntryById", | ||
| 139 | .deliver = afs_deliver_vl_get_entry_by_xxx, | 141 | .deliver = afs_deliver_vl_get_entry_by_xxx, |
| 140 | .abort_to_error = afs_vl_abort_to_error, | 142 | .abort_to_error = afs_vl_abort_to_error, |
| 141 | .destructor = afs_flat_call_destructor, | 143 | .destructor = afs_flat_call_destructor, |
| @@ -145,6 +147,7 @@ static const struct afs_call_type afs_RXVLGetEntryById = { | |||
| 145 | * dispatch a get volume entry by name operation | 147 | * dispatch a get volume entry by name operation |
| 146 | */ | 148 | */ |
| 147 | int afs_vl_get_entry_by_name(struct in_addr *addr, | 149 | int afs_vl_get_entry_by_name(struct in_addr *addr, |
| 150 | struct key *key, | ||
| 148 | const char *volname, | 151 | const char *volname, |
| 149 | struct afs_cache_vlocation *entry, | 152 | struct afs_cache_vlocation *entry, |
| 150 | const struct afs_wait_mode *wait_mode) | 153 | const struct afs_wait_mode *wait_mode) |
| @@ -163,6 +166,7 @@ int afs_vl_get_entry_by_name(struct in_addr *addr, | |||
| 163 | if (!call) | 166 | if (!call) |
| 164 | return -ENOMEM; | 167 | return -ENOMEM; |
| 165 | 168 | ||
| 169 | call->key = key; | ||
| 166 | call->reply = entry; | 170 | call->reply = entry; |
| 167 | call->service_id = VL_SERVICE; | 171 | call->service_id = VL_SERVICE; |
| 168 | call->port = htons(AFS_VL_PORT); | 172 | call->port = htons(AFS_VL_PORT); |
| @@ -183,6 +187,7 @@ int afs_vl_get_entry_by_name(struct in_addr *addr, | |||
| 183 | * dispatch a get volume entry by ID operation | 187 | * dispatch a get volume entry by ID operation |
| 184 | */ | 188 | */ |
| 185 | int afs_vl_get_entry_by_id(struct in_addr *addr, | 189 | int afs_vl_get_entry_by_id(struct in_addr *addr, |
| 190 | struct key *key, | ||
| 186 | afs_volid_t volid, | 191 | afs_volid_t volid, |
| 187 | afs_voltype_t voltype, | 192 | afs_voltype_t voltype, |
| 188 | struct afs_cache_vlocation *entry, | 193 | struct afs_cache_vlocation *entry, |
| @@ -197,6 +202,7 @@ int afs_vl_get_entry_by_id(struct in_addr *addr, | |||
| 197 | if (!call) | 202 | if (!call) |
| 198 | return -ENOMEM; | 203 | return -ENOMEM; |
| 199 | 204 | ||
| 205 | call->key = key; | ||
| 200 | call->reply = entry; | 206 | call->reply = entry; |
| 201 | call->service_id = VL_SERVICE; | 207 | call->service_id = VL_SERVICE; |
| 202 | call->port = htons(AFS_VL_PORT); | 208 | call->port = htons(AFS_VL_PORT); |
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index 60cb2f408c75..7d9815e9ae0f 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c | |||
| @@ -33,6 +33,7 @@ static struct workqueue_struct *afs_vlocation_update_worker; | |||
| 33 | * about the volume in question | 33 | * about the volume in question |
| 34 | */ | 34 | */ |
| 35 | static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, | 35 | static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, |
| 36 | struct key *key, | ||
| 36 | struct afs_cache_vlocation *vldb) | 37 | struct afs_cache_vlocation *vldb) |
| 37 | { | 38 | { |
| 38 | struct afs_cell *cell = vl->cell; | 39 | struct afs_cell *cell = vl->cell; |
| @@ -49,7 +50,7 @@ static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, | |||
| 49 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); | 50 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); |
| 50 | 51 | ||
| 51 | /* attempt to access the VL server */ | 52 | /* attempt to access the VL server */ |
| 52 | ret = afs_vl_get_entry_by_name(&addr, vl->vldb.name, vldb, | 53 | ret = afs_vl_get_entry_by_name(&addr, key, vl->vldb.name, vldb, |
| 53 | &afs_sync_call); | 54 | &afs_sync_call); |
| 54 | switch (ret) { | 55 | switch (ret) { |
| 55 | case 0: | 56 | case 0: |
| @@ -86,6 +87,7 @@ out: | |||
| 86 | * about the volume in question | 87 | * about the volume in question |
| 87 | */ | 88 | */ |
| 88 | static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl, | 89 | static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl, |
| 90 | struct key *key, | ||
| 89 | afs_volid_t volid, | 91 | afs_volid_t volid, |
| 90 | afs_voltype_t voltype, | 92 | afs_voltype_t voltype, |
| 91 | struct afs_cache_vlocation *vldb) | 93 | struct afs_cache_vlocation *vldb) |
| @@ -104,7 +106,7 @@ static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl, | |||
| 104 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); | 106 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); |
| 105 | 107 | ||
| 106 | /* attempt to access the VL server */ | 108 | /* attempt to access the VL server */ |
| 107 | ret = afs_vl_get_entry_by_id(&addr, volid, voltype, vldb, | 109 | ret = afs_vl_get_entry_by_id(&addr, key, volid, voltype, vldb, |
| 108 | &afs_sync_call); | 110 | &afs_sync_call); |
| 109 | switch (ret) { | 111 | switch (ret) { |
| 110 | case 0: | 112 | case 0: |
| @@ -188,6 +190,7 @@ static struct afs_vlocation *afs_vlocation_alloc(struct afs_cell *cell, | |||
| 188 | * update record if we found it in the cache | 190 | * update record if we found it in the cache |
| 189 | */ | 191 | */ |
| 190 | static int afs_vlocation_update_record(struct afs_vlocation *vl, | 192 | static int afs_vlocation_update_record(struct afs_vlocation *vl, |
| 193 | struct key *key, | ||
| 191 | struct afs_cache_vlocation *vldb) | 194 | struct afs_cache_vlocation *vldb) |
| 192 | { | 195 | { |
| 193 | afs_voltype_t voltype; | 196 | afs_voltype_t voltype; |
| @@ -228,7 +231,7 @@ static int afs_vlocation_update_record(struct afs_vlocation *vl, | |||
| 228 | /* contact the server to make sure the volume is still available | 231 | /* contact the server to make sure the volume is still available |
| 229 | * - TODO: need to handle disconnected operation here | 232 | * - TODO: need to handle disconnected operation here |
| 230 | */ | 233 | */ |
| 231 | ret = afs_vlocation_access_vl_by_id(vl, vid, voltype, vldb); | 234 | ret = afs_vlocation_access_vl_by_id(vl, key, vid, voltype, vldb); |
| 232 | switch (ret) { | 235 | switch (ret) { |
| 233 | /* net error */ | 236 | /* net error */ |
| 234 | default: | 237 | default: |
| @@ -287,7 +290,8 @@ static void afs_vlocation_apply_update(struct afs_vlocation *vl, | |||
| 287 | * fill in a volume location record, consulting the cache and the VL server | 290 | * fill in a volume location record, consulting the cache and the VL server |
| 288 | * both | 291 | * both |
| 289 | */ | 292 | */ |
| 290 | static int afs_vlocation_fill_in_record(struct afs_vlocation *vl) | 293 | static int afs_vlocation_fill_in_record(struct afs_vlocation *vl, |
| 294 | struct key *key) | ||
| 291 | { | 295 | { |
| 292 | struct afs_cache_vlocation vldb; | 296 | struct afs_cache_vlocation vldb; |
| 293 | int ret; | 297 | int ret; |
| @@ -310,11 +314,11 @@ static int afs_vlocation_fill_in_record(struct afs_vlocation *vl) | |||
| 310 | /* try to update a known volume in the cell VL databases by | 314 | /* try to update a known volume in the cell VL databases by |
| 311 | * ID as the name may have changed */ | 315 | * ID as the name may have changed */ |
| 312 | _debug("found in cache"); | 316 | _debug("found in cache"); |
| 313 | ret = afs_vlocation_update_record(vl, &vldb); | 317 | ret = afs_vlocation_update_record(vl, key, &vldb); |
| 314 | } else { | 318 | } else { |
| 315 | /* try to look up an unknown volume in the cell VL databases by | 319 | /* try to look up an unknown volume in the cell VL databases by |
| 316 | * name */ | 320 | * name */ |
| 317 | ret = afs_vlocation_access_vl_by_name(vl, &vldb); | 321 | ret = afs_vlocation_access_vl_by_name(vl, key, &vldb); |
| 318 | if (ret < 0) { | 322 | if (ret < 0) { |
| 319 | printk("kAFS: failed to locate '%s' in cell '%s'\n", | 323 | printk("kAFS: failed to locate '%s' in cell '%s'\n", |
| 320 | vl->vldb.name, vl->cell->name); | 324 | vl->vldb.name, vl->cell->name); |
| @@ -366,14 +370,16 @@ void afs_vlocation_queue_for_updates(struct afs_vlocation *vl) | |||
| 366 | * - insert/update in the local cache if did get a VL response | 370 | * - insert/update in the local cache if did get a VL response |
| 367 | */ | 371 | */ |
| 368 | struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, | 372 | struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, |
| 373 | struct key *key, | ||
| 369 | const char *name, | 374 | const char *name, |
| 370 | size_t namesz) | 375 | size_t namesz) |
| 371 | { | 376 | { |
| 372 | struct afs_vlocation *vl; | 377 | struct afs_vlocation *vl; |
| 373 | int ret; | 378 | int ret; |
| 374 | 379 | ||
| 375 | _enter("{%s},%*.*s,%zu", | 380 | _enter("{%s},{%x},%*.*s,%zu", |
| 376 | cell->name, (int) namesz, (int) namesz, name, namesz); | 381 | cell->name, key_serial(key), |
| 382 | (int) namesz, (int) namesz, name, namesz); | ||
| 377 | 383 | ||
| 378 | if (namesz > sizeof(vl->vldb.name)) { | 384 | if (namesz > sizeof(vl->vldb.name)) { |
| 379 | _leave(" = -ENAMETOOLONG"); | 385 | _leave(" = -ENAMETOOLONG"); |
| @@ -405,7 +411,7 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, | |||
| 405 | up_write(&cell->vl_sem); | 411 | up_write(&cell->vl_sem); |
| 406 | 412 | ||
| 407 | fill_in_record: | 413 | fill_in_record: |
| 408 | ret = afs_vlocation_fill_in_record(vl); | 414 | ret = afs_vlocation_fill_in_record(vl, key); |
| 409 | if (ret < 0) | 415 | if (ret < 0) |
| 410 | goto error_abandon; | 416 | goto error_abandon; |
| 411 | vl->state = AFS_VL_VALID; | 417 | vl->state = AFS_VL_VALID; |
| @@ -656,7 +662,7 @@ static void afs_vlocation_updater(struct work_struct *work) | |||
| 656 | vl->upd_rej_cnt = 0; | 662 | vl->upd_rej_cnt = 0; |
| 657 | vl->upd_busy_cnt = 0; | 663 | vl->upd_busy_cnt = 0; |
| 658 | 664 | ||
| 659 | ret = afs_vlocation_update_record(vl, &vldb); | 665 | ret = afs_vlocation_update_record(vl, NULL, &vldb); |
| 660 | switch (ret) { | 666 | switch (ret) { |
| 661 | case 0: | 667 | case 0: |
| 662 | afs_vlocation_apply_update(vl, &vldb); | 668 | afs_vlocation_apply_update(vl, &vldb); |
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index d2ca1398474f..160097619ec7 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c | |||
| @@ -238,9 +238,11 @@ static void afs_vnode_finalise_status_update(struct afs_vnode *vnode, | |||
| 238 | * - there are any outstanding ops that will fetch the status | 238 | * - there are any outstanding ops that will fetch the status |
| 239 | * - TODO implement local caching | 239 | * - TODO implement local caching |
| 240 | */ | 240 | */ |
| 241 | int afs_vnode_fetch_status(struct afs_vnode *vnode) | 241 | int afs_vnode_fetch_status(struct afs_vnode *vnode, |
| 242 | struct afs_vnode *auth_vnode, struct key *key) | ||
| 242 | { | 243 | { |
| 243 | struct afs_server *server; | 244 | struct afs_server *server; |
| 245 | unsigned long acl_order; | ||
| 244 | int ret; | 246 | int ret; |
| 245 | 247 | ||
| 246 | DECLARE_WAITQUEUE(myself, current); | 248 | DECLARE_WAITQUEUE(myself, current); |
| @@ -260,6 +262,10 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode) | |||
| 260 | return -ENOENT; | 262 | return -ENOENT; |
| 261 | } | 263 | } |
| 262 | 264 | ||
| 265 | acl_order = 0; | ||
| 266 | if (auth_vnode) | ||
| 267 | acl_order = auth_vnode->acl_order; | ||
| 268 | |||
| 263 | spin_lock(&vnode->lock); | 269 | spin_lock(&vnode->lock); |
| 264 | 270 | ||
| 265 | if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && | 271 | if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && |
| @@ -324,12 +330,14 @@ get_anyway: | |||
| 324 | _debug("USING SERVER: %p{%08x}", | 330 | _debug("USING SERVER: %p{%08x}", |
| 325 | server, ntohl(server->addr.s_addr)); | 331 | server, ntohl(server->addr.s_addr)); |
| 326 | 332 | ||
| 327 | ret = afs_fs_fetch_file_status(server, vnode, NULL, | 333 | ret = afs_fs_fetch_file_status(server, key, vnode, NULL, |
| 328 | &afs_sync_call); | 334 | &afs_sync_call); |
| 329 | 335 | ||
| 330 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | 336 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
| 331 | 337 | ||
| 332 | /* adjust the flags */ | 338 | /* adjust the flags */ |
| 339 | if (ret == 0 && auth_vnode) | ||
| 340 | afs_cache_permit(vnode, key, acl_order); | ||
| 333 | afs_vnode_finalise_status_update(vnode, server, ret); | 341 | afs_vnode_finalise_status_update(vnode, server, ret); |
| 334 | 342 | ||
| 335 | _leave(" = %d", ret); | 343 | _leave(" = %d", ret); |
| @@ -340,17 +348,18 @@ get_anyway: | |||
| 340 | * fetch file data from the volume | 348 | * fetch file data from the volume |
| 341 | * - TODO implement caching and server failover | 349 | * - TODO implement caching and server failover |
| 342 | */ | 350 | */ |
| 343 | int afs_vnode_fetch_data(struct afs_vnode *vnode, off_t offset, size_t length, | 351 | int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, |
| 344 | struct page *page) | 352 | off_t offset, size_t length, struct page *page) |
| 345 | { | 353 | { |
| 346 | struct afs_server *server; | 354 | struct afs_server *server; |
| 347 | int ret; | 355 | int ret; |
| 348 | 356 | ||
| 349 | _enter("%s,{%u,%u,%u}", | 357 | _enter("%s{%u,%u,%u},%x,,,", |
| 350 | vnode->volume->vlocation->vldb.name, | 358 | vnode->volume->vlocation->vldb.name, |
| 351 | vnode->fid.vid, | 359 | vnode->fid.vid, |
| 352 | vnode->fid.vnode, | 360 | vnode->fid.vnode, |
| 353 | vnode->fid.unique); | 361 | vnode->fid.unique, |
| 362 | key_serial(key)); | ||
| 354 | 363 | ||
| 355 | /* this op will fetch the status */ | 364 | /* this op will fetch the status */ |
| 356 | spin_lock(&vnode->lock); | 365 | spin_lock(&vnode->lock); |
| @@ -367,8 +376,8 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, off_t offset, size_t length, | |||
| 367 | 376 | ||
| 368 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | 377 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); |
| 369 | 378 | ||
| 370 | ret = afs_fs_fetch_data(server, vnode, offset, length, page, | 379 | ret = afs_fs_fetch_data(server, key, vnode, offset, length, |
| 371 | NULL, &afs_sync_call); | 380 | page, NULL, &afs_sync_call); |
| 372 | 381 | ||
| 373 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | 382 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
| 374 | 383 | ||
diff --git a/fs/afs/volume.c b/fs/afs/volume.c index 45491cfd4f4f..15e13678c216 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c | |||
| @@ -41,83 +41,20 @@ static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; | |||
| 41 | * - Rule 3: If parent volume is R/W, then only mount R/W volume unless | 41 | * - Rule 3: If parent volume is R/W, then only mount R/W volume unless |
| 42 | * explicitly told otherwise | 42 | * explicitly told otherwise |
| 43 | */ | 43 | */ |
| 44 | struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, | 44 | struct afs_volume *afs_volume_lookup(struct afs_mount_params *params) |
| 45 | int rwpath) | ||
| 46 | { | 45 | { |
| 47 | struct afs_vlocation *vlocation = NULL; | 46 | struct afs_vlocation *vlocation = NULL; |
| 48 | struct afs_volume *volume = NULL; | 47 | struct afs_volume *volume = NULL; |
| 49 | struct afs_server *server = NULL; | 48 | struct afs_server *server = NULL; |
| 50 | afs_voltype_t type; | ||
| 51 | const char *cellname, *volname, *suffix; | ||
| 52 | char srvtmask; | 49 | char srvtmask; |
| 53 | int force, ret, loop, cellnamesz, volnamesz; | 50 | int ret, loop; |
| 54 | 51 | ||
| 55 | _enter("%s,,%d,", name, rwpath); | 52 | _enter("{%*.*s,%d}", |
| 56 | 53 | params->volnamesz, params->volnamesz, params->volname, params->rwpath); | |
| 57 | if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) { | ||
| 58 | printk("kAFS: unparsable volume name\n"); | ||
| 59 | return ERR_PTR(-EINVAL); | ||
| 60 | } | ||
| 61 | |||
| 62 | /* determine the type of volume we're looking for */ | ||
| 63 | force = 0; | ||
| 64 | type = AFSVL_ROVOL; | ||
| 65 | |||
| 66 | if (rwpath || name[0] == '%') { | ||
| 67 | type = AFSVL_RWVOL; | ||
| 68 | force = 1; | ||
| 69 | } | ||
| 70 | |||
| 71 | suffix = strrchr(name, '.'); | ||
| 72 | if (suffix) { | ||
| 73 | if (strcmp(suffix, ".readonly") == 0) { | ||
| 74 | type = AFSVL_ROVOL; | ||
| 75 | force = 1; | ||
| 76 | } else if (strcmp(suffix, ".backup") == 0) { | ||
| 77 | type = AFSVL_BACKVOL; | ||
| 78 | force = 1; | ||
| 79 | } else if (suffix[1] == 0) { | ||
| 80 | } else { | ||
| 81 | suffix = NULL; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | /* split the cell and volume names */ | ||
| 86 | name++; | ||
| 87 | volname = strchr(name, ':'); | ||
| 88 | if (volname) { | ||
| 89 | cellname = name; | ||
| 90 | cellnamesz = volname - name; | ||
| 91 | volname++; | ||
| 92 | } else { | ||
| 93 | volname = name; | ||
| 94 | cellname = NULL; | ||
| 95 | cellnamesz = 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | volnamesz = suffix ? suffix - volname : strlen(volname); | ||
| 99 | |||
| 100 | _debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", | ||
| 101 | cellnamesz, cellnamesz, cellname ?: "", cell, | ||
| 102 | volnamesz, volnamesz, volname, suffix ?: "-", | ||
| 103 | type, | ||
| 104 | force ? " FORCE" : ""); | ||
| 105 | |||
| 106 | /* lookup the cell record */ | ||
| 107 | if (cellname || !cell) { | ||
| 108 | cell = afs_cell_lookup(cellname, cellnamesz); | ||
| 109 | if (IS_ERR(cell)) { | ||
| 110 | ret = PTR_ERR(cell); | ||
| 111 | printk("kAFS: unable to lookup cell '%s'\n", | ||
| 112 | cellname ?: ""); | ||
| 113 | goto error; | ||
| 114 | } | ||
| 115 | } else { | ||
| 116 | afs_get_cell(cell); | ||
| 117 | } | ||
| 118 | 54 | ||
| 119 | /* lookup the volume location record */ | 55 | /* lookup the volume location record */ |
| 120 | vlocation = afs_vlocation_lookup(cell, volname, volnamesz); | 56 | vlocation = afs_vlocation_lookup(params->cell, params->key, |
| 57 | params->volname, params->volnamesz); | ||
| 121 | if (IS_ERR(vlocation)) { | 58 | if (IS_ERR(vlocation)) { |
| 122 | ret = PTR_ERR(vlocation); | 59 | ret = PTR_ERR(vlocation); |
| 123 | vlocation = NULL; | 60 | vlocation = NULL; |
| @@ -126,30 +63,30 @@ struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, | |||
| 126 | 63 | ||
| 127 | /* make the final decision on the type we want */ | 64 | /* make the final decision on the type we want */ |
| 128 | ret = -ENOMEDIUM; | 65 | ret = -ENOMEDIUM; |
| 129 | if (force && !(vlocation->vldb.vidmask & (1 << type))) | 66 | if (params->force && !(vlocation->vldb.vidmask & (1 << params->type))) |
| 130 | goto error; | 67 | goto error; |
| 131 | 68 | ||
| 132 | srvtmask = 0; | 69 | srvtmask = 0; |
| 133 | for (loop = 0; loop < vlocation->vldb.nservers; loop++) | 70 | for (loop = 0; loop < vlocation->vldb.nservers; loop++) |
| 134 | srvtmask |= vlocation->vldb.srvtmask[loop]; | 71 | srvtmask |= vlocation->vldb.srvtmask[loop]; |
| 135 | 72 | ||
| 136 | if (force) { | 73 | if (params->force) { |
| 137 | if (!(srvtmask & (1 << type))) | 74 | if (!(srvtmask & (1 << params->type))) |
| 138 | goto error; | 75 | goto error; |
| 139 | } else if (srvtmask & AFS_VOL_VTM_RO) { | 76 | } else if (srvtmask & AFS_VOL_VTM_RO) { |
| 140 | type = AFSVL_ROVOL; | 77 | params->type = AFSVL_ROVOL; |
| 141 | } else if (srvtmask & AFS_VOL_VTM_RW) { | 78 | } else if (srvtmask & AFS_VOL_VTM_RW) { |
| 142 | type = AFSVL_RWVOL; | 79 | params->type = AFSVL_RWVOL; |
| 143 | } else { | 80 | } else { |
| 144 | goto error; | 81 | goto error; |
| 145 | } | 82 | } |
| 146 | 83 | ||
| 147 | down_write(&cell->vl_sem); | 84 | down_write(¶ms->cell->vl_sem); |
| 148 | 85 | ||
| 149 | /* is the volume already active? */ | 86 | /* is the volume already active? */ |
| 150 | if (vlocation->vols[type]) { | 87 | if (vlocation->vols[params->type]) { |
| 151 | /* yes - re-use it */ | 88 | /* yes - re-use it */ |
| 152 | volume = vlocation->vols[type]; | 89 | volume = vlocation->vols[params->type]; |
| 153 | afs_get_volume(volume); | 90 | afs_get_volume(volume); |
| 154 | goto success; | 91 | goto success; |
| 155 | } | 92 | } |
| @@ -163,10 +100,10 @@ struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, | |||
| 163 | goto error_up; | 100 | goto error_up; |
| 164 | 101 | ||
| 165 | atomic_set(&volume->usage, 1); | 102 | atomic_set(&volume->usage, 1); |
| 166 | volume->type = type; | 103 | volume->type = params->type; |
| 167 | volume->type_force = force; | 104 | volume->type_force = params->force; |
| 168 | volume->cell = cell; | 105 | volume->cell = params->cell; |
| 169 | volume->vid = vlocation->vldb.vid[type]; | 106 | volume->vid = vlocation->vldb.vid[params->type]; |
| 170 | 107 | ||
| 171 | init_rwsem(&volume->server_sem); | 108 | init_rwsem(&volume->server_sem); |
| 172 | 109 | ||
| @@ -196,28 +133,26 @@ struct afs_volume *afs_volume_lookup(const char *name, struct afs_cell *cell, | |||
| 196 | afs_get_vlocation(vlocation); | 133 | afs_get_vlocation(vlocation); |
| 197 | volume->vlocation = vlocation; | 134 | volume->vlocation = vlocation; |
| 198 | 135 | ||
| 199 | vlocation->vols[type] = volume; | 136 | vlocation->vols[volume->type] = volume; |
| 200 | 137 | ||
| 201 | success: | 138 | success: |
| 202 | _debug("kAFS selected %s volume %08x", | 139 | _debug("kAFS selected %s volume %08x", |
| 203 | afs_voltypes[volume->type], volume->vid); | 140 | afs_voltypes[volume->type], volume->vid); |
| 204 | up_write(&cell->vl_sem); | 141 | up_write(¶ms->cell->vl_sem); |
| 205 | afs_put_vlocation(vlocation); | 142 | afs_put_vlocation(vlocation); |
| 206 | afs_put_cell(cell); | ||
| 207 | _leave(" = %p", volume); | 143 | _leave(" = %p", volume); |
| 208 | return volume; | 144 | return volume; |
| 209 | 145 | ||
| 210 | /* clean up */ | 146 | /* clean up */ |
| 211 | error_up: | 147 | error_up: |
| 212 | up_write(&cell->vl_sem); | 148 | up_write(¶ms->cell->vl_sem); |
| 213 | error: | 149 | error: |
| 214 | afs_put_vlocation(vlocation); | 150 | afs_put_vlocation(vlocation); |
| 215 | afs_put_cell(cell); | ||
| 216 | _leave(" = %d", ret); | 151 | _leave(" = %d", ret); |
| 217 | return ERR_PTR(ret); | 152 | return ERR_PTR(ret); |
| 218 | 153 | ||
| 219 | error_discard: | 154 | error_discard: |
| 220 | up_write(&cell->vl_sem); | 155 | up_write(¶ms->cell->vl_sem); |
| 221 | 156 | ||
| 222 | for (loop = volume->nservers - 1; loop >= 0; loop--) | 157 | for (loop = volume->nservers - 1; loop >= 0; loop--) |
| 223 | afs_put_server(volume->servers[loop]); | 158 | afs_put_server(volume->servers[loop]); |
