diff options
Diffstat (limited to 'fs/afs')
43 files changed, 7427 insertions, 6080 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile index 4029c9da4b86..01545eb1d872 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile | |||
@@ -2,8 +2,6 @@ | |||
2 | # Makefile for Red Hat Linux AFS client. | 2 | # Makefile for Red Hat Linux AFS client. |
3 | # | 3 | # |
4 | 4 | ||
5 | #CFLAGS += -finstrument-functions | ||
6 | |||
7 | kafs-objs := \ | 5 | kafs-objs := \ |
8 | callback.o \ | 6 | callback.o \ |
9 | cell.o \ | 7 | cell.o \ |
@@ -12,14 +10,15 @@ kafs-objs := \ | |||
12 | file.o \ | 10 | file.o \ |
13 | fsclient.o \ | 11 | fsclient.o \ |
14 | inode.o \ | 12 | inode.o \ |
15 | kafsasyncd.o \ | ||
16 | kafstimod.o \ | ||
17 | main.o \ | 13 | main.o \ |
18 | misc.o \ | 14 | misc.o \ |
19 | mntpt.o \ | 15 | mntpt.o \ |
20 | proc.o \ | 16 | proc.o \ |
17 | rxrpc.o \ | ||
18 | security.o \ | ||
21 | server.o \ | 19 | server.o \ |
22 | super.o \ | 20 | super.o \ |
21 | use-rtnetlink.o \ | ||
23 | vlclient.o \ | 22 | vlclient.o \ |
24 | vlocation.o \ | 23 | vlocation.o \ |
25 | vnode.o \ | 24 | vnode.o \ |
diff --git a/fs/afs/afs.h b/fs/afs/afs.h new file mode 100644 index 000000000000..52d0752265b8 --- /dev/null +++ b/fs/afs/afs.h | |||
@@ -0,0 +1,146 @@ | |||
1 | /* AFS common types | ||
2 | * | ||
3 | * Copyright (C) 2002, 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 | #ifndef AFS_H | ||
13 | #define AFS_H | ||
14 | |||
15 | #include <linux/in.h> | ||
16 | |||
17 | #define AFS_MAXCELLNAME 64 /* maximum length of a cell name */ | ||
18 | #define AFS_MAXVOLNAME 64 /* maximum length of a volume name */ | ||
19 | |||
20 | typedef unsigned afs_volid_t; | ||
21 | typedef unsigned afs_vnodeid_t; | ||
22 | typedef unsigned long long afs_dataversion_t; | ||
23 | |||
24 | typedef enum { | ||
25 | AFSVL_RWVOL, /* read/write volume */ | ||
26 | AFSVL_ROVOL, /* read-only volume */ | ||
27 | AFSVL_BACKVOL, /* backup volume */ | ||
28 | } __attribute__((packed)) afs_voltype_t; | ||
29 | |||
30 | typedef enum { | ||
31 | AFS_FTYPE_INVALID = 0, | ||
32 | AFS_FTYPE_FILE = 1, | ||
33 | AFS_FTYPE_DIR = 2, | ||
34 | AFS_FTYPE_SYMLINK = 3, | ||
35 | } afs_file_type_t; | ||
36 | |||
37 | /* | ||
38 | * AFS file identifier | ||
39 | */ | ||
40 | struct afs_fid { | ||
41 | afs_volid_t vid; /* volume ID */ | ||
42 | afs_vnodeid_t vnode; /* file index within volume */ | ||
43 | unsigned unique; /* unique ID number (file index version) */ | ||
44 | }; | ||
45 | |||
46 | /* | ||
47 | * AFS callback notification | ||
48 | */ | ||
49 | typedef enum { | ||
50 | AFSCM_CB_UNTYPED = 0, /* no type set on CB break */ | ||
51 | AFSCM_CB_EXCLUSIVE = 1, /* CB exclusive to CM [not implemented] */ | ||
52 | AFSCM_CB_SHARED = 2, /* CB shared by other CM's */ | ||
53 | AFSCM_CB_DROPPED = 3, /* CB promise cancelled by file server */ | ||
54 | } afs_callback_type_t; | ||
55 | |||
56 | struct afs_callback { | ||
57 | struct afs_fid fid; /* file identifier */ | ||
58 | unsigned version; /* callback version */ | ||
59 | unsigned expiry; /* time at which expires */ | ||
60 | afs_callback_type_t type; /* type of callback */ | ||
61 | }; | ||
62 | |||
63 | #define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */ | ||
64 | |||
65 | /* | ||
66 | * AFS volume information | ||
67 | */ | ||
68 | struct afs_volume_info { | ||
69 | afs_volid_t vid; /* volume ID */ | ||
70 | afs_voltype_t type; /* type of this volume */ | ||
71 | afs_volid_t type_vids[5]; /* volume ID's for possible types for this vol */ | ||
72 | |||
73 | /* list of fileservers serving this volume */ | ||
74 | size_t nservers; /* number of entries used in servers[] */ | ||
75 | struct { | ||
76 | struct in_addr addr; /* fileserver address */ | ||
77 | } servers[8]; | ||
78 | }; | ||
79 | |||
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 | /* | ||
101 | * AFS file status information | ||
102 | */ | ||
103 | struct afs_file_status { | ||
104 | unsigned if_version; /* interface version */ | ||
105 | #define AFS_FSTATUS_VERSION 1 | ||
106 | |||
107 | afs_file_type_t type; /* file type */ | ||
108 | unsigned nlink; /* link count */ | ||
109 | u64 size; /* file size */ | ||
110 | afs_dataversion_t data_version; /* current data version */ | ||
111 | u32 author; /* author ID */ | ||
112 | u32 owner; /* owner ID */ | ||
113 | u32 group; /* group ID */ | ||
114 | afs_access_t caller_access; /* access rights for authenticated caller */ | ||
115 | afs_access_t anon_access; /* access rights for unauthenticated caller */ | ||
116 | umode_t mode; /* UNIX mode */ | ||
117 | struct afs_fid parent; /* parent dir ID for non-dirs only */ | ||
118 | time_t mtime_client; /* last time client changed data */ | ||
119 | time_t mtime_server; /* last time server changed data */ | ||
120 | }; | ||
121 | |||
122 | /* | ||
123 | * AFS file status change request | ||
124 | */ | ||
125 | struct afs_store_status { | ||
126 | u32 mask; /* which bits of the struct are set */ | ||
127 | u32 mtime_client; /* last time client changed data */ | ||
128 | u32 owner; /* owner ID */ | ||
129 | u32 group; /* group ID */ | ||
130 | umode_t mode; /* UNIX mode */ | ||
131 | }; | ||
132 | |||
133 | #define AFS_SET_MTIME 0x01 /* set the mtime */ | ||
134 | #define AFS_SET_OWNER 0x02 /* set the owner ID */ | ||
135 | #define AFS_SET_GROUP 0x04 /* set the group ID (unsupported?) */ | ||
136 | #define AFS_SET_MODE 0x08 /* set the UNIX mode */ | ||
137 | #define AFS_SET_SEG_SIZE 0x10 /* set the segment size (unsupported) */ | ||
138 | |||
139 | /* | ||
140 | * AFS volume synchronisation information | ||
141 | */ | ||
142 | struct afs_volsync { | ||
143 | time_t creation; /* volume creation time */ | ||
144 | }; | ||
145 | |||
146 | #endif /* AFS_H */ | ||
diff --git a/fs/afs/afs_cm.h b/fs/afs/afs_cm.h new file mode 100644 index 000000000000..7b4d4fab4c80 --- /dev/null +++ b/fs/afs/afs_cm.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* AFS Cache Manager definitions | ||
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 | #ifndef AFS_CM_H | ||
13 | #define AFS_CM_H | ||
14 | |||
15 | #define AFS_CM_PORT 7001 /* AFS file server port */ | ||
16 | #define CM_SERVICE 1 /* AFS File Service ID */ | ||
17 | |||
18 | enum AFS_CM_Operations { | ||
19 | CBCallBack = 204, /* break callback promises */ | ||
20 | CBInitCallBackState = 205, /* initialise callback state */ | ||
21 | CBProbe = 206, /* probe client */ | ||
22 | CBGetLock = 207, /* get contents of CM lock table */ | ||
23 | CBGetCE = 208, /* get cache file description */ | ||
24 | CBGetXStatsVersion = 209, /* get version of extended statistics */ | ||
25 | CBGetXStats = 210, /* get contents of extended statistics data */ | ||
26 | CBInitCallBackState3 = 213, /* initialise callback state, version 3 */ | ||
27 | CBGetCapabilities = 65538, /* get client capabilities */ | ||
28 | }; | ||
29 | |||
30 | #define AFS_CAP_ERROR_TRANSLATION 0x1 | ||
31 | |||
32 | #endif /* AFS_FS_H */ | ||
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h new file mode 100644 index 000000000000..89e0d1650a72 --- /dev/null +++ b/fs/afs/afs_fs.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* AFS File Service definitions | ||
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 | #ifndef AFS_FS_H | ||
13 | #define AFS_FS_H | ||
14 | |||
15 | #define AFS_FS_PORT 7000 /* AFS file server port */ | ||
16 | #define FS_SERVICE 1 /* AFS File Service ID */ | ||
17 | |||
18 | enum AFS_FS_Operations { | ||
19 | FSFETCHDATA = 130, /* AFS Fetch file data */ | ||
20 | FSFETCHSTATUS = 132, /* AFS Fetch file status */ | ||
21 | FSREMOVEFILE = 136, /* AFS Remove a file */ | ||
22 | FSCREATEFILE = 137, /* AFS Create a file */ | ||
23 | FSRENAME = 138, /* AFS Rename or move a file or directory */ | ||
24 | FSSYMLINK = 139, /* AFS Create a symbolic link */ | ||
25 | FSLINK = 140, /* AFS Create a hard link */ | ||
26 | FSMAKEDIR = 141, /* AFS Create a directory */ | ||
27 | FSREMOVEDIR = 142, /* AFS Remove a directory */ | ||
28 | FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */ | ||
29 | FSGETVOLUMEINFO = 148, /* AFS Get root volume information */ | ||
30 | FSGETROOTVOLUME = 151, /* AFS Get root volume name */ | ||
31 | FSLOOKUP = 161, /* AFS lookup file in directory */ | ||
32 | }; | ||
33 | |||
34 | enum AFS_FS_Errors { | ||
35 | VSALVAGE = 101, /* volume needs salvaging */ | ||
36 | VNOVNODE = 102, /* no such file/dir (vnode) */ | ||
37 | VNOVOL = 103, /* no such volume or volume unavailable */ | ||
38 | VVOLEXISTS = 104, /* volume name already exists */ | ||
39 | VNOSERVICE = 105, /* volume not currently in service */ | ||
40 | VOFFLINE = 106, /* volume is currently offline (more info available [VVL-spec]) */ | ||
41 | VONLINE = 107, /* volume is already online */ | ||
42 | VDISKFULL = 108, /* disk partition is full */ | ||
43 | VOVERQUOTA = 109, /* volume's maximum quota exceeded */ | ||
44 | VBUSY = 110, /* volume is temporarily unavailable */ | ||
45 | VMOVED = 111, /* volume moved to new server - ask this FS where */ | ||
46 | }; | ||
47 | |||
48 | #endif /* AFS_FS_H */ | ||
diff --git a/fs/afs/vlclient.h b/fs/afs/afs_vl.h index e3d601179c46..8bbefe009ed4 100644 --- a/fs/afs/vlclient.h +++ b/fs/afs/afs_vl.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* vlclient.h: Volume Location Service client interface | 1 | /* AFS Volume Location Service client interface |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -9,10 +9,19 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef _LINUX_AFS_VLCLIENT_H | 12 | #ifndef AFS_VL_H |
13 | #define _LINUX_AFS_VLCLIENT_H | 13 | #define AFS_VL_H |
14 | 14 | ||
15 | #include "types.h" | 15 | #include "afs.h" |
16 | |||
17 | #define AFS_VL_PORT 7003 /* volume location service port */ | ||
18 | #define VL_SERVICE 52 /* RxRPC service ID for the Volume Location service */ | ||
19 | |||
20 | enum AFSVL_Operations { | ||
21 | VLGETENTRYBYID = 503, /* AFS Get Cache Entry By ID operation ID */ | ||
22 | VLGETENTRYBYNAME = 504, /* AFS Get Cache Entry By Name operation ID */ | ||
23 | VLPROBE = 514, /* AFS Probe Volume Location Service operation ID */ | ||
24 | }; | ||
16 | 25 | ||
17 | enum AFSVL_Errors { | 26 | enum AFSVL_Errors { |
18 | AFSVL_IDEXIST = 363520, /* Volume Id entry exists in vl database */ | 27 | AFSVL_IDEXIST = 363520, /* Volume Id entry exists in vl database */ |
@@ -40,14 +49,16 @@ enum AFSVL_Errors { | |||
40 | AFSVL_BADVOLOPER = 363542, /* Bad volume operation code */ | 49 | AFSVL_BADVOLOPER = 363542, /* Bad volume operation code */ |
41 | AFSVL_BADRELLOCKTYPE = 363543, /* Bad release lock type */ | 50 | AFSVL_BADRELLOCKTYPE = 363543, /* Bad release lock type */ |
42 | AFSVL_RERELEASE = 363544, /* Status report: last release was aborted */ | 51 | AFSVL_RERELEASE = 363544, /* Status report: last release was aborted */ |
43 | AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server °ag */ | 52 | AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server °ag */ |
44 | AFSVL_PERM = 363546, /* No permission access */ | 53 | AFSVL_PERM = 363546, /* No permission access */ |
45 | AFSVL_NOMEM = 363547, /* malloc/realloc failed to alloc enough memory */ | 54 | AFSVL_NOMEM = 363547, /* malloc/realloc failed to alloc enough memory */ |
46 | }; | 55 | }; |
47 | 56 | ||
48 | /* maps to "struct vldbentry" in vvl-spec.pdf */ | 57 | /* |
58 | * maps to "struct vldbentry" in vvl-spec.pdf | ||
59 | */ | ||
49 | struct afs_vldbentry { | 60 | struct afs_vldbentry { |
50 | char name[65]; /* name of volume (including NUL char) */ | 61 | char name[65]; /* name of volume (with NUL char) */ |
51 | afs_voltype_t type; /* volume type */ | 62 | afs_voltype_t type; /* volume type */ |
52 | unsigned num_servers; /* num servers that hold instances of this vol */ | 63 | unsigned num_servers; /* num servers that hold instances of this vol */ |
53 | unsigned clone_id; /* cloning ID */ | 64 | unsigned clone_id; /* cloning ID */ |
@@ -68,26 +79,6 @@ struct afs_vldbentry { | |||
68 | #define AFS_VLSF_RWVOL 0x0004 /* this server holds a R/W instance of the volume */ | 79 | #define AFS_VLSF_RWVOL 0x0004 /* this server holds a R/W instance of the volume */ |
69 | #define AFS_VLSF_BACKVOL 0x0008 /* this server holds a backup instance of the volume */ | 80 | #define AFS_VLSF_BACKVOL 0x0008 /* this server holds a backup instance of the volume */ |
70 | } servers[8]; | 81 | } servers[8]; |
71 | |||
72 | }; | 82 | }; |
73 | 83 | ||
74 | /* look up a volume location database entry by name */ | 84 | #endif /* AFS_VL_H */ |
75 | extern int afs_rxvl_get_entry_by_name(struct afs_server *server, | ||
76 | const char *volname, | ||
77 | unsigned volnamesz, | ||
78 | struct afs_cache_vlocation *entry); | ||
79 | |||
80 | /* look up a volume location database entry by ID */ | ||
81 | extern int afs_rxvl_get_entry_by_id(struct afs_server *server, | ||
82 | afs_volid_t volid, | ||
83 | afs_voltype_t voltype, | ||
84 | struct afs_cache_vlocation *entry); | ||
85 | |||
86 | extern int afs_rxvl_get_entry_by_id_async(struct afs_async_op *op, | ||
87 | afs_volid_t volid, | ||
88 | afs_voltype_t voltype); | ||
89 | |||
90 | extern int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *op, | ||
91 | struct afs_cache_vlocation *entry); | ||
92 | |||
93 | #endif /* _LINUX_AFS_VLCLIENT_H */ | ||
diff --git a/fs/afs/cache.c b/fs/afs/cache.c new file mode 100644 index 000000000000..de0d7de69edc --- /dev/null +++ b/fs/afs/cache.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* AFS caching stuff | ||
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 | #ifdef AFS_CACHING_SUPPORT | ||
13 | static cachefs_match_val_t afs_cell_cache_match(void *target, | ||
14 | const void *entry); | ||
15 | static void afs_cell_cache_update(void *source, void *entry); | ||
16 | |||
17 | struct cachefs_index_def afs_cache_cell_index_def = { | ||
18 | .name = "cell_ix", | ||
19 | .data_size = sizeof(struct afs_cache_cell), | ||
20 | .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 }, | ||
21 | .match = afs_cell_cache_match, | ||
22 | .update = afs_cell_cache_update, | ||
23 | }; | ||
24 | #endif | ||
25 | |||
26 | /* | ||
27 | * match a cell record obtained from the cache | ||
28 | */ | ||
29 | #ifdef AFS_CACHING_SUPPORT | ||
30 | static cachefs_match_val_t afs_cell_cache_match(void *target, | ||
31 | const void *entry) | ||
32 | { | ||
33 | const struct afs_cache_cell *ccell = entry; | ||
34 | struct afs_cell *cell = target; | ||
35 | |||
36 | _enter("{%s},{%s}", ccell->name, cell->name); | ||
37 | |||
38 | if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) { | ||
39 | _leave(" = SUCCESS"); | ||
40 | return CACHEFS_MATCH_SUCCESS; | ||
41 | } | ||
42 | |||
43 | _leave(" = FAILED"); | ||
44 | return CACHEFS_MATCH_FAILED; | ||
45 | } | ||
46 | #endif | ||
47 | |||
48 | /* | ||
49 | * update a cell record in the cache | ||
50 | */ | ||
51 | #ifdef AFS_CACHING_SUPPORT | ||
52 | static void afs_cell_cache_update(void *source, void *entry) | ||
53 | { | ||
54 | struct afs_cache_cell *ccell = entry; | ||
55 | struct afs_cell *cell = source; | ||
56 | |||
57 | _enter("%p,%p", source, entry); | ||
58 | |||
59 | strncpy(ccell->name, cell->name, sizeof(ccell->name)); | ||
60 | |||
61 | memcpy(ccell->vl_servers, | ||
62 | cell->vl_addrs, | ||
63 | min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs))); | ||
64 | |||
65 | } | ||
66 | #endif | ||
67 | |||
68 | #ifdef AFS_CACHING_SUPPORT | ||
69 | static cachefs_match_val_t afs_vlocation_cache_match(void *target, | ||
70 | const void *entry); | ||
71 | static void afs_vlocation_cache_update(void *source, void *entry); | ||
72 | |||
73 | struct cachefs_index_def afs_vlocation_cache_index_def = { | ||
74 | .name = "vldb", | ||
75 | .data_size = sizeof(struct afs_cache_vlocation), | ||
76 | .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 }, | ||
77 | .match = afs_vlocation_cache_match, | ||
78 | .update = afs_vlocation_cache_update, | ||
79 | }; | ||
80 | #endif | ||
81 | |||
82 | /* | ||
83 | * match a VLDB record stored in the cache | ||
84 | * - may also load target from entry | ||
85 | */ | ||
86 | #ifdef AFS_CACHING_SUPPORT | ||
87 | static cachefs_match_val_t afs_vlocation_cache_match(void *target, | ||
88 | const void *entry) | ||
89 | { | ||
90 | const struct afs_cache_vlocation *vldb = entry; | ||
91 | struct afs_vlocation *vlocation = target; | ||
92 | |||
93 | _enter("{%s},{%s}", vlocation->vldb.name, vldb->name); | ||
94 | |||
95 | if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0 | ||
96 | ) { | ||
97 | if (!vlocation->valid || | ||
98 | vlocation->vldb.rtime == vldb->rtime | ||
99 | ) { | ||
100 | vlocation->vldb = *vldb; | ||
101 | vlocation->valid = 1; | ||
102 | _leave(" = SUCCESS [c->m]"); | ||
103 | return CACHEFS_MATCH_SUCCESS; | ||
104 | } else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) { | ||
105 | /* delete if VIDs for this name differ */ | ||
106 | if (memcmp(&vlocation->vldb.vid, | ||
107 | &vldb->vid, | ||
108 | sizeof(vldb->vid)) != 0) { | ||
109 | _leave(" = DELETE"); | ||
110 | return CACHEFS_MATCH_SUCCESS_DELETE; | ||
111 | } | ||
112 | |||
113 | _leave(" = UPDATE"); | ||
114 | return CACHEFS_MATCH_SUCCESS_UPDATE; | ||
115 | } else { | ||
116 | _leave(" = SUCCESS"); | ||
117 | return CACHEFS_MATCH_SUCCESS; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | _leave(" = FAILED"); | ||
122 | return CACHEFS_MATCH_FAILED; | ||
123 | } | ||
124 | #endif | ||
125 | |||
126 | /* | ||
127 | * update a VLDB record stored in the cache | ||
128 | */ | ||
129 | #ifdef AFS_CACHING_SUPPORT | ||
130 | static void afs_vlocation_cache_update(void *source, void *entry) | ||
131 | { | ||
132 | struct afs_cache_vlocation *vldb = entry; | ||
133 | struct afs_vlocation *vlocation = source; | ||
134 | |||
135 | _enter(""); | ||
136 | |||
137 | *vldb = vlocation->vldb; | ||
138 | } | ||
139 | #endif | ||
140 | |||
141 | #ifdef AFS_CACHING_SUPPORT | ||
142 | static cachefs_match_val_t afs_volume_cache_match(void *target, | ||
143 | const void *entry); | ||
144 | static void afs_volume_cache_update(void *source, void *entry); | ||
145 | |||
146 | struct cachefs_index_def afs_volume_cache_index_def = { | ||
147 | .name = "volume", | ||
148 | .data_size = sizeof(struct afs_cache_vhash), | ||
149 | .keys[0] = { CACHEFS_INDEX_KEYS_BIN, 1 }, | ||
150 | .keys[1] = { CACHEFS_INDEX_KEYS_BIN, 1 }, | ||
151 | .match = afs_volume_cache_match, | ||
152 | .update = afs_volume_cache_update, | ||
153 | }; | ||
154 | #endif | ||
155 | |||
156 | /* | ||
157 | * match a volume hash record stored in the cache | ||
158 | */ | ||
159 | #ifdef AFS_CACHING_SUPPORT | ||
160 | static cachefs_match_val_t afs_volume_cache_match(void *target, | ||
161 | const void *entry) | ||
162 | { | ||
163 | const struct afs_cache_vhash *vhash = entry; | ||
164 | struct afs_volume *volume = target; | ||
165 | |||
166 | _enter("{%u},{%u}", volume->type, vhash->vtype); | ||
167 | |||
168 | if (volume->type == vhash->vtype) { | ||
169 | _leave(" = SUCCESS"); | ||
170 | return CACHEFS_MATCH_SUCCESS; | ||
171 | } | ||
172 | |||
173 | _leave(" = FAILED"); | ||
174 | return CACHEFS_MATCH_FAILED; | ||
175 | } | ||
176 | #endif | ||
177 | |||
178 | /* | ||
179 | * update a volume hash record stored in the cache | ||
180 | */ | ||
181 | #ifdef AFS_CACHING_SUPPORT | ||
182 | static void afs_volume_cache_update(void *source, void *entry) | ||
183 | { | ||
184 | struct afs_cache_vhash *vhash = entry; | ||
185 | struct afs_volume *volume = source; | ||
186 | |||
187 | _enter(""); | ||
188 | |||
189 | vhash->vtype = volume->type; | ||
190 | } | ||
191 | #endif | ||
192 | |||
193 | #ifdef AFS_CACHING_SUPPORT | ||
194 | static cachefs_match_val_t afs_vnode_cache_match(void *target, | ||
195 | const void *entry); | ||
196 | static void afs_vnode_cache_update(void *source, void *entry); | ||
197 | |||
198 | struct cachefs_index_def afs_vnode_cache_index_def = { | ||
199 | .name = "vnode", | ||
200 | .data_size = sizeof(struct afs_cache_vnode), | ||
201 | .keys[0] = { CACHEFS_INDEX_KEYS_BIN, 4 }, | ||
202 | .match = afs_vnode_cache_match, | ||
203 | .update = afs_vnode_cache_update, | ||
204 | }; | ||
205 | #endif | ||
206 | |||
207 | /* | ||
208 | * match a vnode record stored in the cache | ||
209 | */ | ||
210 | #ifdef AFS_CACHING_SUPPORT | ||
211 | static cachefs_match_val_t afs_vnode_cache_match(void *target, | ||
212 | const void *entry) | ||
213 | { | ||
214 | const struct afs_cache_vnode *cvnode = entry; | ||
215 | struct afs_vnode *vnode = target; | ||
216 | |||
217 | _enter("{%x,%x,%Lx},{%x,%x,%Lx}", | ||
218 | vnode->fid.vnode, | ||
219 | vnode->fid.unique, | ||
220 | vnode->status.version, | ||
221 | cvnode->vnode_id, | ||
222 | cvnode->vnode_unique, | ||
223 | cvnode->data_version); | ||
224 | |||
225 | if (vnode->fid.vnode != cvnode->vnode_id) { | ||
226 | _leave(" = FAILED"); | ||
227 | return CACHEFS_MATCH_FAILED; | ||
228 | } | ||
229 | |||
230 | if (vnode->fid.unique != cvnode->vnode_unique || | ||
231 | vnode->status.version != cvnode->data_version) { | ||
232 | _leave(" = DELETE"); | ||
233 | return CACHEFS_MATCH_SUCCESS_DELETE; | ||
234 | } | ||
235 | |||
236 | _leave(" = SUCCESS"); | ||
237 | return CACHEFS_MATCH_SUCCESS; | ||
238 | } | ||
239 | #endif | ||
240 | |||
241 | /* | ||
242 | * update a vnode record stored in the cache | ||
243 | */ | ||
244 | #ifdef AFS_CACHING_SUPPORT | ||
245 | static void afs_vnode_cache_update(void *source, void *entry) | ||
246 | { | ||
247 | struct afs_cache_vnode *cvnode = entry; | ||
248 | struct afs_vnode *vnode = source; | ||
249 | |||
250 | _enter(""); | ||
251 | |||
252 | cvnode->vnode_id = vnode->fid.vnode; | ||
253 | cvnode->vnode_unique = vnode->fid.unique; | ||
254 | cvnode->data_version = vnode->status.version; | ||
255 | } | ||
256 | #endif | ||
diff --git a/fs/afs/cache.h b/fs/afs/cache.h index 9eb7722b34d5..36a3642cf90e 100644 --- a/fs/afs/cache.h +++ b/fs/afs/cache.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* cache.h: AFS local cache management interface | 1 | /* AFS local cache management interface |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -9,8 +9,8 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef _LINUX_AFS_CACHE_H | 12 | #ifndef AFS_CACHE_H |
13 | #define _LINUX_AFS_CACHE_H | 13 | #define AFS_CACHE_H |
14 | 14 | ||
15 | #undef AFS_CACHING_SUPPORT | 15 | #undef AFS_CACHING_SUPPORT |
16 | 16 | ||
@@ -20,8 +20,4 @@ | |||
20 | #endif | 20 | #endif |
21 | #include "types.h" | 21 | #include "types.h" |
22 | 22 | ||
23 | #ifdef __KERNEL__ | 23 | #endif /* AFS_CACHE_H */ |
24 | |||
25 | #endif /* __KERNEL__ */ | ||
26 | |||
27 | #endif /* _LINUX_AFS_CACHE_H */ | ||
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 9cb206e9d4be..639399f0ab6f 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2002 Red Hat, Inc. All rights reserved. | 2 | * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * This software may be freely redistributed under the terms of the | 4 | * This software may be freely redistributed under the terms of the |
5 | * GNU General Public License. | 5 | * GNU General Public License. |
@@ -16,85 +16,187 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include "server.h" | 19 | #include <linux/circ_buf.h> |
20 | #include "vnode.h" | ||
21 | #include "internal.h" | 20 | #include "internal.h" |
22 | #include "cmservice.h" | ||
23 | 21 | ||
24 | /*****************************************************************************/ | 22 | unsigned afs_vnode_update_timeout = 10; |
23 | |||
24 | #define afs_breakring_space(server) \ | ||
25 | CIRC_SPACE((server)->cb_break_head, (server)->cb_break_tail, \ | ||
26 | ARRAY_SIZE((server)->cb_break)) | ||
27 | |||
28 | //static void afs_callback_updater(struct work_struct *); | ||
29 | |||
30 | static struct workqueue_struct *afs_callback_update_worker; | ||
31 | |||
25 | /* | 32 | /* |
26 | * allow the fileserver to request callback state (re-)initialisation | 33 | * allow the fileserver to request callback state (re-)initialisation |
27 | */ | 34 | */ |
28 | int SRXAFSCM_InitCallBackState(struct afs_server *server) | 35 | void afs_init_callback_state(struct afs_server *server) |
29 | { | 36 | { |
30 | struct list_head callbacks; | 37 | struct afs_vnode *vnode; |
31 | 38 | ||
32 | _enter("%p", server); | 39 | _enter("{%p}", server); |
33 | 40 | ||
34 | INIT_LIST_HEAD(&callbacks); | ||
35 | |||
36 | /* transfer the callback list from the server to a temp holding area */ | ||
37 | spin_lock(&server->cb_lock); | 41 | spin_lock(&server->cb_lock); |
38 | 42 | ||
39 | list_add(&callbacks, &server->cb_promises); | 43 | /* kill all the promises on record from this server */ |
40 | list_del_init(&server->cb_promises); | 44 | while (!RB_EMPTY_ROOT(&server->cb_promises)) { |
45 | vnode = rb_entry(server->cb_promises.rb_node, | ||
46 | struct afs_vnode, cb_promise); | ||
47 | _debug("UNPROMISE { vid=%x vn=%u uq=%u}", | ||
48 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | ||
49 | rb_erase(&vnode->cb_promise, &server->cb_promises); | ||
50 | vnode->cb_promised = false; | ||
51 | } | ||
41 | 52 | ||
42 | /* munch our way through the list, grabbing the inode, dropping all the | 53 | spin_unlock(&server->cb_lock); |
43 | * locks and regetting them in the right order | 54 | _leave(""); |
44 | */ | 55 | } |
45 | while (!list_empty(&callbacks)) { | ||
46 | struct afs_vnode *vnode; | ||
47 | struct inode *inode; | ||
48 | 56 | ||
49 | vnode = list_entry(callbacks.next, struct afs_vnode, cb_link); | 57 | /* |
50 | list_del_init(&vnode->cb_link); | 58 | * handle the data invalidation side of a callback being broken |
59 | */ | ||
60 | void afs_broken_callback_work(struct work_struct *work) | ||
61 | { | ||
62 | struct afs_vnode *vnode = | ||
63 | container_of(work, struct afs_vnode, cb_broken_work); | ||
51 | 64 | ||
52 | /* try and grab the inode - may fail */ | 65 | _enter(""); |
53 | inode = igrab(AFS_VNODE_TO_I(vnode)); | ||
54 | if (inode) { | ||
55 | int release = 0; | ||
56 | 66 | ||
57 | spin_unlock(&server->cb_lock); | 67 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
58 | spin_lock(&vnode->lock); | 68 | return; |
59 | 69 | ||
60 | if (vnode->cb_server == server) { | 70 | /* we're only interested in dealing with a broken callback on *this* |
61 | vnode->cb_server = NULL; | 71 | * vnode and only if no-one else has dealt with it yet */ |
62 | afs_kafstimod_del_timer(&vnode->cb_timeout); | 72 | if (!mutex_trylock(&vnode->validate_lock)) |
63 | spin_lock(&afs_cb_hash_lock); | 73 | return; /* someone else is dealing with it */ |
64 | list_del_init(&vnode->cb_hash_link); | ||
65 | spin_unlock(&afs_cb_hash_lock); | ||
66 | release = 1; | ||
67 | } | ||
68 | 74 | ||
69 | spin_unlock(&vnode->lock); | 75 | if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { |
76 | if (S_ISDIR(vnode->vfs_inode.i_mode)) | ||
77 | afs_clear_permits(vnode); | ||
70 | 78 | ||
71 | iput(inode); | 79 | if (afs_vnode_fetch_status(vnode, NULL, NULL) < 0) |
72 | afs_put_server(server); | 80 | goto out; |
73 | 81 | ||
74 | spin_lock(&server->cb_lock); | 82 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
83 | goto out; | ||
84 | |||
85 | /* if the vnode's data version number changed then its contents | ||
86 | * are different */ | ||
87 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | ||
88 | _debug("zap data {%x:%u}", | ||
89 | vnode->fid.vid, vnode->fid.vnode); | ||
90 | invalidate_remote_inode(&vnode->vfs_inode); | ||
75 | } | 91 | } |
76 | } | 92 | } |
77 | 93 | ||
78 | spin_unlock(&server->cb_lock); | 94 | out: |
95 | mutex_unlock(&vnode->validate_lock); | ||
79 | 96 | ||
80 | _leave(" = 0"); | 97 | /* avoid the potential race whereby the mutex_trylock() in this |
81 | return 0; | 98 | * function happens again between the clear_bit() and the |
82 | } /* end SRXAFSCM_InitCallBackState() */ | 99 | * mutex_unlock() */ |
100 | if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { | ||
101 | _debug("requeue"); | ||
102 | queue_work(afs_callback_update_worker, &vnode->cb_broken_work); | ||
103 | } | ||
104 | _leave(""); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * actually break a callback | ||
109 | */ | ||
110 | static void afs_break_callback(struct afs_server *server, | ||
111 | struct afs_vnode *vnode) | ||
112 | { | ||
113 | _enter(""); | ||
114 | |||
115 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | ||
116 | |||
117 | if (vnode->cb_promised) { | ||
118 | spin_lock(&vnode->lock); | ||
119 | |||
120 | _debug("break callback"); | ||
121 | |||
122 | spin_lock(&server->cb_lock); | ||
123 | if (vnode->cb_promised) { | ||
124 | rb_erase(&vnode->cb_promise, &server->cb_promises); | ||
125 | vnode->cb_promised = false; | ||
126 | } | ||
127 | spin_unlock(&server->cb_lock); | ||
128 | |||
129 | queue_work(afs_callback_update_worker, &vnode->cb_broken_work); | ||
130 | spin_unlock(&vnode->lock); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * allow the fileserver to explicitly break one callback | ||
136 | * - happens when | ||
137 | * - the backing file is changed | ||
138 | * - a lock is released | ||
139 | */ | ||
140 | static void afs_break_one_callback(struct afs_server *server, | ||
141 | struct afs_fid *fid) | ||
142 | { | ||
143 | struct afs_vnode *vnode; | ||
144 | struct rb_node *p; | ||
145 | |||
146 | _debug("find"); | ||
147 | spin_lock(&server->fs_lock); | ||
148 | p = server->fs_vnodes.rb_node; | ||
149 | while (p) { | ||
150 | vnode = rb_entry(p, struct afs_vnode, server_rb); | ||
151 | if (fid->vid < vnode->fid.vid) | ||
152 | p = p->rb_left; | ||
153 | else if (fid->vid > vnode->fid.vid) | ||
154 | p = p->rb_right; | ||
155 | else if (fid->vnode < vnode->fid.vnode) | ||
156 | p = p->rb_left; | ||
157 | else if (fid->vnode > vnode->fid.vnode) | ||
158 | p = p->rb_right; | ||
159 | else if (fid->unique < vnode->fid.unique) | ||
160 | p = p->rb_left; | ||
161 | else if (fid->unique > vnode->fid.unique) | ||
162 | p = p->rb_right; | ||
163 | else | ||
164 | goto found; | ||
165 | } | ||
166 | |||
167 | /* not found so we just ignore it (it may have moved to another | ||
168 | * server) */ | ||
169 | not_available: | ||
170 | _debug("not avail"); | ||
171 | spin_unlock(&server->fs_lock); | ||
172 | _leave(""); | ||
173 | return; | ||
174 | |||
175 | found: | ||
176 | _debug("found"); | ||
177 | ASSERTCMP(server, ==, vnode->server); | ||
178 | |||
179 | if (!igrab(AFS_VNODE_TO_I(vnode))) | ||
180 | goto not_available; | ||
181 | spin_unlock(&server->fs_lock); | ||
182 | |||
183 | afs_break_callback(server, vnode); | ||
184 | iput(&vnode->vfs_inode); | ||
185 | _leave(""); | ||
186 | } | ||
83 | 187 | ||
84 | /*****************************************************************************/ | ||
85 | /* | 188 | /* |
86 | * allow the fileserver to break callback promises | 189 | * allow the fileserver to break callback promises |
87 | */ | 190 | */ |
88 | int SRXAFSCM_CallBack(struct afs_server *server, size_t count, | 191 | void afs_break_callbacks(struct afs_server *server, size_t count, |
89 | struct afs_callback callbacks[]) | 192 | struct afs_callback callbacks[]) |
90 | { | 193 | { |
91 | _enter("%p,%u,", server, count); | 194 | _enter("%p,%zu,", server, count); |
92 | 195 | ||
93 | for (; count > 0; callbacks++, count--) { | 196 | ASSERT(server != NULL); |
94 | struct afs_vnode *vnode = NULL; | 197 | ASSERTCMP(count, <=, AFSCBMAX); |
95 | struct inode *inode = NULL; | ||
96 | int valid = 0; | ||
97 | 198 | ||
199 | for (; count > 0; callbacks++, count--) { | ||
98 | _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", | 200 | _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", |
99 | callbacks->fid.vid, | 201 | callbacks->fid.vid, |
100 | callbacks->fid.vnode, | 202 | callbacks->fid.vnode, |
@@ -103,67 +205,270 @@ int SRXAFSCM_CallBack(struct afs_server *server, size_t count, | |||
103 | callbacks->expiry, | 205 | callbacks->expiry, |
104 | callbacks->type | 206 | callbacks->type |
105 | ); | 207 | ); |
208 | afs_break_one_callback(server, &callbacks->fid); | ||
209 | } | ||
106 | 210 | ||
107 | /* find the inode for this fid */ | 211 | _leave(""); |
108 | spin_lock(&afs_cb_hash_lock); | 212 | return; |
213 | } | ||
109 | 214 | ||
110 | list_for_each_entry(vnode, | 215 | /* |
111 | &afs_cb_hash(server, &callbacks->fid), | 216 | * record the callback for breaking |
112 | cb_hash_link) { | 217 | * - the caller must hold server->cb_lock |
113 | if (memcmp(&vnode->fid, &callbacks->fid, | 218 | */ |
114 | sizeof(struct afs_fid)) != 0) | 219 | static void afs_do_give_up_callback(struct afs_server *server, |
115 | continue; | 220 | struct afs_vnode *vnode) |
221 | { | ||
222 | struct afs_callback *cb; | ||
116 | 223 | ||
117 | /* right vnode, but is it same server? */ | 224 | _enter("%p,%p", server, vnode); |
118 | if (vnode->cb_server != server) | ||
119 | break; /* no */ | ||
120 | 225 | ||
121 | /* try and nail the inode down */ | 226 | cb = &server->cb_break[server->cb_break_head]; |
122 | inode = igrab(AFS_VNODE_TO_I(vnode)); | 227 | cb->fid = vnode->fid; |
123 | break; | 228 | cb->version = vnode->cb_version; |
229 | cb->expiry = vnode->cb_expiry; | ||
230 | cb->type = vnode->cb_type; | ||
231 | smp_wmb(); | ||
232 | server->cb_break_head = | ||
233 | (server->cb_break_head + 1) & | ||
234 | (ARRAY_SIZE(server->cb_break) - 1); | ||
235 | |||
236 | /* defer the breaking of callbacks to try and collect as many as | ||
237 | * possible to ship in one operation */ | ||
238 | switch (atomic_inc_return(&server->cb_break_n)) { | ||
239 | case 1 ... AFSCBMAX - 1: | ||
240 | queue_delayed_work(afs_callback_update_worker, | ||
241 | &server->cb_break_work, HZ * 2); | ||
242 | break; | ||
243 | case AFSCBMAX: | ||
244 | afs_flush_callback_breaks(server); | ||
245 | break; | ||
246 | default: | ||
247 | break; | ||
248 | } | ||
249 | |||
250 | ASSERT(server->cb_promises.rb_node != NULL); | ||
251 | rb_erase(&vnode->cb_promise, &server->cb_promises); | ||
252 | vnode->cb_promised = false; | ||
253 | _leave(""); | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * discard the callback on a deleted item | ||
258 | */ | ||
259 | void afs_discard_callback_on_delete(struct afs_vnode *vnode) | ||
260 | { | ||
261 | struct afs_server *server = vnode->server; | ||
262 | |||
263 | _enter("%d", vnode->cb_promised); | ||
264 | |||
265 | if (!vnode->cb_promised) { | ||
266 | _leave(" [not promised]"); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | ASSERT(server != NULL); | ||
271 | |||
272 | spin_lock(&server->cb_lock); | ||
273 | if (vnode->cb_promised) { | ||
274 | ASSERT(server->cb_promises.rb_node != NULL); | ||
275 | rb_erase(&vnode->cb_promise, &server->cb_promises); | ||
276 | vnode->cb_promised = false; | ||
277 | } | ||
278 | spin_unlock(&server->cb_lock); | ||
279 | _leave(""); | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * give up the callback registered for a vnode on the file server when the | ||
284 | * inode is being cleared | ||
285 | */ | ||
286 | void afs_give_up_callback(struct afs_vnode *vnode) | ||
287 | { | ||
288 | struct afs_server *server = vnode->server; | ||
289 | |||
290 | DECLARE_WAITQUEUE(myself, current); | ||
291 | |||
292 | _enter("%d", vnode->cb_promised); | ||
293 | |||
294 | _debug("GIVE UP INODE %p", &vnode->vfs_inode); | ||
295 | |||
296 | if (!vnode->cb_promised) { | ||
297 | _leave(" [not promised]"); | ||
298 | return; | ||
299 | } | ||
300 | |||
301 | ASSERT(server != NULL); | ||
302 | |||
303 | spin_lock(&server->cb_lock); | ||
304 | if (vnode->cb_promised && afs_breakring_space(server) == 0) { | ||
305 | add_wait_queue(&server->cb_break_waitq, &myself); | ||
306 | for (;;) { | ||
307 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
308 | if (!vnode->cb_promised || | ||
309 | afs_breakring_space(server) != 0) | ||
310 | break; | ||
311 | spin_unlock(&server->cb_lock); | ||
312 | schedule(); | ||
313 | spin_lock(&server->cb_lock); | ||
124 | } | 314 | } |
315 | remove_wait_queue(&server->cb_break_waitq, &myself); | ||
316 | __set_current_state(TASK_RUNNING); | ||
317 | } | ||
318 | |||
319 | /* of course, it's always possible for the server to break this vnode's | ||
320 | * callback first... */ | ||
321 | if (vnode->cb_promised) | ||
322 | afs_do_give_up_callback(server, vnode); | ||
323 | |||
324 | spin_unlock(&server->cb_lock); | ||
325 | _leave(""); | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * dispatch a deferred give up callbacks operation | ||
330 | */ | ||
331 | void afs_dispatch_give_up_callbacks(struct work_struct *work) | ||
332 | { | ||
333 | struct afs_server *server = | ||
334 | container_of(work, struct afs_server, cb_break_work.work); | ||
335 | |||
336 | _enter(""); | ||
337 | |||
338 | /* tell the fileserver to discard the callback promises it has | ||
339 | * - in the event of ENOMEM or some other error, we just forget that we | ||
340 | * had callbacks entirely, and the server will call us later to break | ||
341 | * them | ||
342 | */ | ||
343 | afs_fs_give_up_callbacks(server, &afs_async_call); | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * flush the outstanding callback breaks on a server | ||
348 | */ | ||
349 | void afs_flush_callback_breaks(struct afs_server *server) | ||
350 | { | ||
351 | cancel_delayed_work(&server->cb_break_work); | ||
352 | queue_delayed_work(afs_callback_update_worker, | ||
353 | &server->cb_break_work, 0); | ||
354 | } | ||
125 | 355 | ||
126 | spin_unlock(&afs_cb_hash_lock); | 356 | #if 0 |
127 | 357 | /* | |
128 | if (inode) { | 358 | * update a bunch of callbacks |
129 | /* we've found the record for this vnode */ | 359 | */ |
130 | spin_lock(&vnode->lock); | 360 | static void afs_callback_updater(struct work_struct *work) |
131 | if (vnode->cb_server == server) { | 361 | { |
132 | /* the callback _is_ on the calling server */ | 362 | struct afs_server *server; |
133 | vnode->cb_server = NULL; | 363 | struct afs_vnode *vnode, *xvnode; |
134 | valid = 1; | 364 | time_t now; |
135 | 365 | long timeout; | |
136 | afs_kafstimod_del_timer(&vnode->cb_timeout); | 366 | int ret; |
137 | vnode->flags |= AFS_VNODE_CHANGED; | 367 | |
138 | 368 | server = container_of(work, struct afs_server, updater); | |
139 | spin_lock(&server->cb_lock); | 369 | |
140 | list_del_init(&vnode->cb_link); | 370 | _enter(""); |
141 | spin_unlock(&server->cb_lock); | 371 | |
142 | 372 | now = get_seconds(); | |
143 | spin_lock(&afs_cb_hash_lock); | 373 | |
144 | list_del_init(&vnode->cb_hash_link); | 374 | /* find the first vnode to update */ |
145 | spin_unlock(&afs_cb_hash_lock); | 375 | spin_lock(&server->cb_lock); |
146 | } | 376 | for (;;) { |
147 | spin_unlock(&vnode->lock); | 377 | if (RB_EMPTY_ROOT(&server->cb_promises)) { |
148 | 378 | spin_unlock(&server->cb_lock); | |
149 | if (valid) { | 379 | _leave(" [nothing]"); |
150 | invalidate_remote_inode(inode); | 380 | return; |
151 | afs_put_server(server); | ||
152 | } | ||
153 | iput(inode); | ||
154 | } | 381 | } |
382 | |||
383 | vnode = rb_entry(rb_first(&server->cb_promises), | ||
384 | struct afs_vnode, cb_promise); | ||
385 | if (atomic_read(&vnode->usage) > 0) | ||
386 | break; | ||
387 | rb_erase(&vnode->cb_promise, &server->cb_promises); | ||
388 | vnode->cb_promised = false; | ||
155 | } | 389 | } |
156 | 390 | ||
157 | _leave(" = 0"); | 391 | timeout = vnode->update_at - now; |
158 | return 0; | 392 | if (timeout > 0) { |
159 | } /* end SRXAFSCM_CallBack() */ | 393 | queue_delayed_work(afs_vnode_update_worker, |
394 | &afs_vnode_update, timeout * HZ); | ||
395 | spin_unlock(&server->cb_lock); | ||
396 | _leave(" [nothing]"); | ||
397 | return; | ||
398 | } | ||
399 | |||
400 | list_del_init(&vnode->update); | ||
401 | atomic_inc(&vnode->usage); | ||
402 | spin_unlock(&server->cb_lock); | ||
403 | |||
404 | /* we can now perform the update */ | ||
405 | _debug("update %s", vnode->vldb.name); | ||
406 | vnode->state = AFS_VL_UPDATING; | ||
407 | vnode->upd_rej_cnt = 0; | ||
408 | vnode->upd_busy_cnt = 0; | ||
409 | |||
410 | ret = afs_vnode_update_record(vl, &vldb); | ||
411 | switch (ret) { | ||
412 | case 0: | ||
413 | afs_vnode_apply_update(vl, &vldb); | ||
414 | vnode->state = AFS_VL_UPDATING; | ||
415 | break; | ||
416 | case -ENOMEDIUM: | ||
417 | vnode->state = AFS_VL_VOLUME_DELETED; | ||
418 | break; | ||
419 | default: | ||
420 | vnode->state = AFS_VL_UNCERTAIN; | ||
421 | break; | ||
422 | } | ||
423 | |||
424 | /* and then reschedule */ | ||
425 | _debug("reschedule"); | ||
426 | vnode->update_at = get_seconds() + afs_vnode_update_timeout; | ||
427 | |||
428 | spin_lock(&server->cb_lock); | ||
429 | |||
430 | if (!list_empty(&server->cb_promises)) { | ||
431 | /* next update in 10 minutes, but wait at least 1 second more | ||
432 | * than the newest record already queued so that we don't spam | ||
433 | * the VL server suddenly with lots of requests | ||
434 | */ | ||
435 | xvnode = list_entry(server->cb_promises.prev, | ||
436 | struct afs_vnode, update); | ||
437 | if (vnode->update_at <= xvnode->update_at) | ||
438 | vnode->update_at = xvnode->update_at + 1; | ||
439 | xvnode = list_entry(server->cb_promises.next, | ||
440 | struct afs_vnode, update); | ||
441 | timeout = xvnode->update_at - now; | ||
442 | if (timeout < 0) | ||
443 | timeout = 0; | ||
444 | } else { | ||
445 | timeout = afs_vnode_update_timeout; | ||
446 | } | ||
447 | |||
448 | list_add_tail(&vnode->update, &server->cb_promises); | ||
449 | |||
450 | _debug("timeout %ld", timeout); | ||
451 | queue_delayed_work(afs_vnode_update_worker, | ||
452 | &afs_vnode_update, timeout * HZ); | ||
453 | spin_unlock(&server->cb_lock); | ||
454 | afs_put_vnode(vl); | ||
455 | } | ||
456 | #endif | ||
457 | |||
458 | /* | ||
459 | * initialise the callback update process | ||
460 | */ | ||
461 | int __init afs_callback_update_init(void) | ||
462 | { | ||
463 | afs_callback_update_worker = | ||
464 | create_singlethread_workqueue("kafs_callbackd"); | ||
465 | return afs_callback_update_worker ? 0 : -ENOMEM; | ||
466 | } | ||
160 | 467 | ||
161 | /*****************************************************************************/ | ||
162 | /* | 468 | /* |
163 | * allow the fileserver to see if the cache manager is still alive | 469 | * shut down the callback update process |
164 | */ | 470 | */ |
165 | int SRXAFSCM_Probe(struct afs_server *server) | 471 | void __exit afs_callback_update_kill(void) |
166 | { | 472 | { |
167 | _debug("SRXAFSCM_Probe(%p)\n", server); | 473 | destroy_workqueue(afs_callback_update_worker); |
168 | return 0; | 474 | } |
169 | } /* end SRXAFSCM_Probe() */ | ||
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 1fc578372759..9b1311a1df51 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* cell.c: AFS cell and server record management | 1 | /* AFS cell and server record management |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -11,15 +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 <rxrpc/peer.h> | 14 | #include <linux/key.h> |
15 | #include <rxrpc/connection.h> | 15 | #include <linux/ctype.h> |
16 | #include "volume.h" | 16 | #include <keys/rxrpc-type.h> |
17 | #include "cell.h" | ||
18 | #include "server.h" | ||
19 | #include "transport.h" | ||
20 | #include "vlclient.h" | ||
21 | #include "kafstimod.h" | ||
22 | #include "super.h" | ||
23 | #include "internal.h" | 17 | #include "internal.h" |
24 | 18 | ||
25 | DECLARE_RWSEM(afs_proc_cells_sem); | 19 | DECLARE_RWSEM(afs_proc_cells_sem); |
@@ -28,66 +22,47 @@ LIST_HEAD(afs_proc_cells); | |||
28 | static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells); | 22 | static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells); |
29 | static DEFINE_RWLOCK(afs_cells_lock); | 23 | static DEFINE_RWLOCK(afs_cells_lock); |
30 | static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */ | 24 | static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */ |
25 | static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq); | ||
31 | static struct afs_cell *afs_cell_root; | 26 | static struct afs_cell *afs_cell_root; |
32 | 27 | ||
33 | #ifdef AFS_CACHING_SUPPORT | ||
34 | static cachefs_match_val_t afs_cell_cache_match(void *target, | ||
35 | const void *entry); | ||
36 | static void afs_cell_cache_update(void *source, void *entry); | ||
37 | |||
38 | struct cachefs_index_def afs_cache_cell_index_def = { | ||
39 | .name = "cell_ix", | ||
40 | .data_size = sizeof(struct afs_cache_cell), | ||
41 | .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 }, | ||
42 | .match = afs_cell_cache_match, | ||
43 | .update = afs_cell_cache_update, | ||
44 | }; | ||
45 | #endif | ||
46 | |||
47 | /*****************************************************************************/ | ||
48 | /* | 28 | /* |
49 | * create a cell record | 29 | * allocate a cell record and fill in its name, VL server address list and |
50 | * - "name" is the name of the cell | 30 | * allocate an anonymous key |
51 | * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format | ||
52 | */ | 31 | */ |
53 | int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell) | 32 | static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) |
54 | { | 33 | { |
55 | struct afs_cell *cell; | 34 | struct afs_cell *cell; |
56 | char *next; | 35 | size_t namelen; |
36 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; | ||
57 | int ret; | 37 | int ret; |
58 | 38 | ||
59 | _enter("%s", name); | 39 | _enter("%s,%s", name, vllist); |
60 | 40 | ||
61 | 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 */ |
62 | 42 | ||
43 | namelen = strlen(name); | ||
44 | if (namelen > AFS_MAXCELLNAME) | ||
45 | return ERR_PTR(-ENAMETOOLONG); | ||
46 | |||
63 | /* allocate and initialise a cell record */ | 47 | /* allocate and initialise a cell record */ |
64 | cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL); | 48 | cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL); |
65 | if (!cell) { | 49 | if (!cell) { |
66 | _leave(" = -ENOMEM"); | 50 | _leave(" = -ENOMEM"); |
67 | return -ENOMEM; | 51 | return ERR_PTR(-ENOMEM); |
68 | } | 52 | } |
69 | 53 | ||
70 | down_write(&afs_cells_sem); | 54 | memcpy(cell->name, name, namelen); |
71 | 55 | cell->name[namelen] = 0; | |
72 | memset(cell, 0, sizeof(struct afs_cell)); | ||
73 | atomic_set(&cell->usage, 0); | ||
74 | 56 | ||
57 | atomic_set(&cell->usage, 1); | ||
75 | INIT_LIST_HEAD(&cell->link); | 58 | INIT_LIST_HEAD(&cell->link); |
76 | 59 | rwlock_init(&cell->servers_lock); | |
77 | rwlock_init(&cell->sv_lock); | 60 | INIT_LIST_HEAD(&cell->servers); |
78 | INIT_LIST_HEAD(&cell->sv_list); | ||
79 | INIT_LIST_HEAD(&cell->sv_graveyard); | ||
80 | spin_lock_init(&cell->sv_gylock); | ||
81 | |||
82 | init_rwsem(&cell->vl_sem); | 61 | init_rwsem(&cell->vl_sem); |
83 | INIT_LIST_HEAD(&cell->vl_list); | 62 | INIT_LIST_HEAD(&cell->vl_list); |
84 | INIT_LIST_HEAD(&cell->vl_graveyard); | 63 | spin_lock_init(&cell->vl_lock); |
85 | spin_lock_init(&cell->vl_gylock); | ||
86 | |||
87 | strcpy(cell->name,name); | ||
88 | 64 | ||
89 | /* 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 */ |
90 | ret = -EINVAL; | ||
91 | do { | 66 | do { |
92 | unsigned a, b, c, d; | 67 | unsigned a, b, c, d; |
93 | 68 | ||
@@ -96,20 +71,75 @@ int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell) | |||
96 | *next++ = 0; | 71 | *next++ = 0; |
97 | 72 | ||
98 | 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) |
99 | goto badaddr; | 74 | goto bad_address; |
100 | 75 | ||
101 | if (a > 255 || b > 255 || c > 255 || d > 255) | 76 | if (a > 255 || b > 255 || c > 255 || d > 255) |
102 | goto badaddr; | 77 | goto bad_address; |
103 | 78 | ||
104 | cell->vl_addrs[cell->vl_naddrs++].s_addr = | 79 | cell->vl_addrs[cell->vl_naddrs++].s_addr = |
105 | htonl((a << 24) | (b << 16) | (c << 8) | d); | 80 | htonl((a << 24) | (b << 16) | (c << 8) | d); |
106 | 81 | ||
107 | if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS) | 82 | } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next)); |
108 | 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 | } | ||
121 | |||
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); | ||
109 | 133 | ||
110 | } while(vllist = next, vllist); | 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); | ||
111 | 141 | ||
112 | /* add a proc dir for this cell */ | 142 | /* add a proc directory for this cell */ |
113 | ret = afs_proc_cell_setup(cell); | 143 | ret = afs_proc_cell_setup(cell); |
114 | if (ret < 0) | 144 | if (ret < 0) |
115 | goto error; | 145 | goto error; |
@@ -130,31 +160,28 @@ int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell) | |||
130 | down_write(&afs_proc_cells_sem); | 160 | down_write(&afs_proc_cells_sem); |
131 | list_add_tail(&cell->proc_link, &afs_proc_cells); | 161 | list_add_tail(&cell->proc_link, &afs_proc_cells); |
132 | up_write(&afs_proc_cells_sem); | 162 | up_write(&afs_proc_cells_sem); |
133 | |||
134 | *_cell = cell; | ||
135 | up_write(&afs_cells_sem); | 163 | up_write(&afs_cells_sem); |
136 | 164 | ||
137 | _leave(" = 0 (%p)", cell); | 165 | _leave(" = %p", cell); |
138 | return 0; | 166 | return cell; |
139 | 167 | ||
140 | badaddr: | 168 | error: |
141 | printk(KERN_ERR "kAFS: bad VL server IP address: '%s'\n", vllist); | ||
142 | error: | ||
143 | up_write(&afs_cells_sem); | 169 | up_write(&afs_cells_sem); |
170 | key_put(cell->anonymous_key); | ||
144 | kfree(cell); | 171 | kfree(cell); |
145 | _leave(" = %d", ret); | 172 | _leave(" = %d", ret); |
146 | return ret; | 173 | return ERR_PTR(ret); |
147 | } /* end afs_cell_create() */ | 174 | } |
148 | 175 | ||
149 | /*****************************************************************************/ | ||
150 | /* | 176 | /* |
151 | * initialise the cell database from module parameters | 177 | * set the root cell information |
178 | * - can be called with a module parameter string | ||
179 | * - can be called from a write to /proc/fs/afs/rootcell | ||
152 | */ | 180 | */ |
153 | int afs_cell_init(char *rootcell) | 181 | int afs_cell_init(char *rootcell) |
154 | { | 182 | { |
155 | struct afs_cell *old_root, *new_root; | 183 | struct afs_cell *old_root, *new_root; |
156 | char *cp; | 184 | char *cp; |
157 | int ret; | ||
158 | 185 | ||
159 | _enter(""); | 186 | _enter(""); |
160 | 187 | ||
@@ -162,82 +189,60 @@ int afs_cell_init(char *rootcell) | |||
162 | /* module is loaded with no parameters, or built statically. | 189 | /* module is loaded with no parameters, or built statically. |
163 | * - in the future we might initialize cell DB here. | 190 | * - in the future we might initialize cell DB here. |
164 | */ | 191 | */ |
165 | _leave(" = 0 (but no root)"); | 192 | _leave(" = 0 [no root]"); |
166 | return 0; | 193 | return 0; |
167 | } | 194 | } |
168 | 195 | ||
169 | cp = strchr(rootcell, ':'); | 196 | cp = strchr(rootcell, ':'); |
170 | if (!cp) { | 197 | if (!cp) { |
171 | printk(KERN_ERR "kAFS: no VL server IP addresses specified\n"); | 198 | printk(KERN_ERR "kAFS: no VL server IP addresses specified\n"); |
172 | _leave(" = %d (no colon)", -EINVAL); | 199 | _leave(" = -EINVAL"); |
173 | return -EINVAL; | 200 | return -EINVAL; |
174 | } | 201 | } |
175 | 202 | ||
176 | /* allocate a cell record for the root cell */ | 203 | /* allocate a cell record for the root cell */ |
177 | *cp++ = 0; | 204 | *cp++ = 0; |
178 | ret = afs_cell_create(rootcell, cp, &new_root); | 205 | new_root = afs_cell_create(rootcell, cp); |
179 | if (ret < 0) { | 206 | if (IS_ERR(new_root)) { |
180 | _leave(" = %d", ret); | 207 | _leave(" = %ld", PTR_ERR(new_root)); |
181 | return ret; | 208 | return PTR_ERR(new_root); |
182 | } | 209 | } |
183 | 210 | ||
184 | /* as afs_put_cell() takes locks by itself, we have to do | 211 | /* install the new cell */ |
185 | * a little gymnastics to be race-free. | ||
186 | */ | ||
187 | afs_get_cell(new_root); | ||
188 | |||
189 | write_lock(&afs_cells_lock); | 212 | write_lock(&afs_cells_lock); |
190 | while (afs_cell_root) { | 213 | old_root = afs_cell_root; |
191 | old_root = afs_cell_root; | ||
192 | afs_cell_root = NULL; | ||
193 | write_unlock(&afs_cells_lock); | ||
194 | afs_put_cell(old_root); | ||
195 | write_lock(&afs_cells_lock); | ||
196 | } | ||
197 | afs_cell_root = new_root; | 214 | afs_cell_root = new_root; |
198 | write_unlock(&afs_cells_lock); | 215 | write_unlock(&afs_cells_lock); |
216 | afs_put_cell(old_root); | ||
199 | 217 | ||
200 | _leave(" = %d", ret); | 218 | _leave(" = 0"); |
201 | return ret; | 219 | return 0; |
202 | 220 | } | |
203 | } /* end afs_cell_init() */ | ||
204 | 221 | ||
205 | /*****************************************************************************/ | ||
206 | /* | 222 | /* |
207 | * lookup a cell record | 223 | * lookup a cell record |
208 | */ | 224 | */ |
209 | int afs_cell_lookup(const char *name, unsigned namesz, struct afs_cell **_cell) | 225 | struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) |
210 | { | 226 | { |
211 | struct afs_cell *cell; | 227 | struct afs_cell *cell; |
212 | int ret; | ||
213 | 228 | ||
214 | _enter("\"%*.*s\",", namesz, namesz, name ? name : ""); | 229 | _enter("\"%*.*s\",", namesz, namesz, name ? name : ""); |
215 | 230 | ||
216 | *_cell = NULL; | 231 | down_read(&afs_cells_sem); |
232 | read_lock(&afs_cells_lock); | ||
217 | 233 | ||
218 | if (name) { | 234 | if (name) { |
219 | /* if the cell was named, look for it in the cell record list */ | 235 | /* if the cell was named, look for it in the cell record list */ |
220 | ret = -ENOENT; | ||
221 | cell = NULL; | ||
222 | read_lock(&afs_cells_lock); | ||
223 | |||
224 | list_for_each_entry(cell, &afs_cells, link) { | 236 | list_for_each_entry(cell, &afs_cells, link) { |
225 | if (strncmp(cell->name, name, namesz) == 0) { | 237 | if (strncmp(cell->name, name, namesz) == 0) { |
226 | afs_get_cell(cell); | 238 | afs_get_cell(cell); |
227 | goto found; | 239 | goto found; |
228 | } | 240 | } |
229 | } | 241 | } |
230 | cell = NULL; | 242 | cell = ERR_PTR(-ENOENT); |
231 | found: | 243 | found: |
232 | 244 | ; | |
233 | read_unlock(&afs_cells_lock); | 245 | } else { |
234 | |||
235 | if (cell) | ||
236 | ret = 0; | ||
237 | } | ||
238 | else { | ||
239 | read_lock(&afs_cells_lock); | ||
240 | |||
241 | cell = afs_cell_root; | 246 | cell = afs_cell_root; |
242 | if (!cell) { | 247 | if (!cell) { |
243 | /* this should not happen unless user tries to mount | 248 | /* this should not happen unless user tries to mount |
@@ -246,44 +251,35 @@ int afs_cell_lookup(const char *name, unsigned namesz, struct afs_cell **_cell) | |||
246 | * ENOENT might be "more appropriate" but they happen | 251 | * ENOENT might be "more appropriate" but they happen |
247 | * for other reasons. | 252 | * for other reasons. |
248 | */ | 253 | */ |
249 | ret = -EDESTADDRREQ; | 254 | cell = ERR_PTR(-EDESTADDRREQ); |
250 | } | 255 | } else { |
251 | else { | ||
252 | afs_get_cell(cell); | 256 | afs_get_cell(cell); |
253 | ret = 0; | ||
254 | } | 257 | } |
255 | 258 | ||
256 | read_unlock(&afs_cells_lock); | ||
257 | } | 259 | } |
258 | 260 | ||
259 | *_cell = cell; | 261 | read_unlock(&afs_cells_lock); |
260 | _leave(" = %d (%p)", ret, cell); | 262 | up_read(&afs_cells_sem); |
261 | return ret; | 263 | _leave(" = %p", cell); |
262 | 264 | return cell; | |
263 | } /* end afs_cell_lookup() */ | 265 | } |
264 | 266 | ||
265 | /*****************************************************************************/ | ||
266 | /* | 267 | /* |
267 | * try and get a cell record | 268 | * try and get a cell record |
268 | */ | 269 | */ |
269 | struct afs_cell *afs_get_cell_maybe(struct afs_cell **_cell) | 270 | struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell) |
270 | { | 271 | { |
271 | struct afs_cell *cell; | ||
272 | |||
273 | write_lock(&afs_cells_lock); | 272 | write_lock(&afs_cells_lock); |
274 | 273 | ||
275 | cell = *_cell; | ||
276 | if (cell && !list_empty(&cell->link)) | 274 | if (cell && !list_empty(&cell->link)) |
277 | afs_get_cell(cell); | 275 | afs_get_cell(cell); |
278 | else | 276 | else |
279 | cell = NULL; | 277 | cell = NULL; |
280 | 278 | ||
281 | write_unlock(&afs_cells_lock); | 279 | write_unlock(&afs_cells_lock); |
282 | |||
283 | return cell; | 280 | return cell; |
284 | } /* end afs_get_cell_maybe() */ | 281 | } |
285 | 282 | ||
286 | /*****************************************************************************/ | ||
287 | /* | 283 | /* |
288 | * destroy a cell record | 284 | * destroy a cell record |
289 | */ | 285 | */ |
@@ -294,8 +290,7 @@ void afs_put_cell(struct afs_cell *cell) | |||
294 | 290 | ||
295 | _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name); | 291 | _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name); |
296 | 292 | ||
297 | /* sanity check */ | 293 | ASSERTCMP(atomic_read(&cell->usage), >, 0); |
298 | BUG_ON(atomic_read(&cell->usage) <= 0); | ||
299 | 294 | ||
300 | /* to prevent a race, the decrement and the dequeue must be effectively | 295 | /* to prevent a race, the decrement and the dequeue must be effectively |
301 | * atomic */ | 296 | * atomic */ |
@@ -307,36 +302,49 @@ void afs_put_cell(struct afs_cell *cell) | |||
307 | return; | 302 | return; |
308 | } | 303 | } |
309 | 304 | ||
305 | ASSERT(list_empty(&cell->servers)); | ||
306 | ASSERT(list_empty(&cell->vl_list)); | ||
307 | |||
310 | write_unlock(&afs_cells_lock); | 308 | write_unlock(&afs_cells_lock); |
311 | 309 | ||
312 | BUG_ON(!list_empty(&cell->sv_list)); | 310 | wake_up(&afs_cells_freeable_wq); |
313 | BUG_ON(!list_empty(&cell->sv_graveyard)); | ||
314 | BUG_ON(!list_empty(&cell->vl_list)); | ||
315 | BUG_ON(!list_empty(&cell->vl_graveyard)); | ||
316 | 311 | ||
317 | _leave(" [unused]"); | 312 | _leave(" [unused]"); |
318 | } /* end afs_put_cell() */ | 313 | } |
319 | 314 | ||
320 | /*****************************************************************************/ | ||
321 | /* | 315 | /* |
322 | * destroy a cell record | 316 | * destroy a cell record |
317 | * - must be called with the afs_cells_sem write-locked | ||
318 | * - cell->link should have been broken by the caller | ||
323 | */ | 319 | */ |
324 | static void afs_cell_destroy(struct afs_cell *cell) | 320 | static void afs_cell_destroy(struct afs_cell *cell) |
325 | { | 321 | { |
326 | _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name); | 322 | _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name); |
327 | 323 | ||
328 | /* to prevent a race, the decrement and the dequeue must be effectively | 324 | ASSERTCMP(atomic_read(&cell->usage), >=, 0); |
329 | * atomic */ | 325 | ASSERT(list_empty(&cell->link)); |
330 | write_lock(&afs_cells_lock); | ||
331 | 326 | ||
332 | /* sanity check */ | 327 | /* wait for everyone to stop using the cell */ |
333 | BUG_ON(atomic_read(&cell->usage) != 0); | 328 | if (atomic_read(&cell->usage) > 0) { |
329 | DECLARE_WAITQUEUE(myself, current); | ||
334 | 330 | ||
335 | list_del_init(&cell->link); | 331 | _debug("wait for cell %s", cell->name); |
332 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
333 | add_wait_queue(&afs_cells_freeable_wq, &myself); | ||
336 | 334 | ||
337 | write_unlock(&afs_cells_lock); | 335 | while (atomic_read(&cell->usage) > 0) { |
336 | schedule(); | ||
337 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
338 | } | ||
338 | 339 | ||
339 | down_write(&afs_cells_sem); | 340 | remove_wait_queue(&afs_cells_freeable_wq, &myself); |
341 | set_current_state(TASK_RUNNING); | ||
342 | } | ||
343 | |||
344 | _debug("cell dead"); | ||
345 | ASSERTCMP(atomic_read(&cell->usage), ==, 0); | ||
346 | ASSERT(list_empty(&cell->servers)); | ||
347 | ASSERT(list_empty(&cell->vl_list)); | ||
340 | 348 | ||
341 | afs_proc_cell_remove(cell); | 349 | afs_proc_cell_remove(cell); |
342 | 350 | ||
@@ -348,104 +356,26 @@ static void afs_cell_destroy(struct afs_cell *cell) | |||
348 | cachefs_relinquish_cookie(cell->cache, 0); | 356 | cachefs_relinquish_cookie(cell->cache, 0); |
349 | #endif | 357 | #endif |
350 | 358 | ||
351 | up_write(&afs_cells_sem); | 359 | key_put(cell->anonymous_key); |
352 | |||
353 | BUG_ON(!list_empty(&cell->sv_list)); | ||
354 | BUG_ON(!list_empty(&cell->sv_graveyard)); | ||
355 | BUG_ON(!list_empty(&cell->vl_list)); | ||
356 | BUG_ON(!list_empty(&cell->vl_graveyard)); | ||
357 | |||
358 | /* finish cleaning up the cell */ | ||
359 | kfree(cell); | 360 | kfree(cell); |
360 | 361 | ||
361 | _leave(" [destroyed]"); | 362 | _leave(" [destroyed]"); |
362 | } /* end afs_cell_destroy() */ | 363 | } |
363 | |||
364 | /*****************************************************************************/ | ||
365 | /* | ||
366 | * lookup the server record corresponding to an Rx RPC peer | ||
367 | */ | ||
368 | int afs_server_find_by_peer(const struct rxrpc_peer *peer, | ||
369 | struct afs_server **_server) | ||
370 | { | ||
371 | struct afs_server *server; | ||
372 | struct afs_cell *cell; | ||
373 | |||
374 | _enter("%p{a=%08x},", peer, ntohl(peer->addr.s_addr)); | ||
375 | |||
376 | /* search the cell list */ | ||
377 | read_lock(&afs_cells_lock); | ||
378 | |||
379 | list_for_each_entry(cell, &afs_cells, link) { | ||
380 | |||
381 | _debug("? cell %s",cell->name); | ||
382 | |||
383 | write_lock(&cell->sv_lock); | ||
384 | |||
385 | /* check the active list */ | ||
386 | list_for_each_entry(server, &cell->sv_list, link) { | ||
387 | _debug("?? server %08x", ntohl(server->addr.s_addr)); | ||
388 | |||
389 | if (memcmp(&server->addr, &peer->addr, | ||
390 | sizeof(struct in_addr)) == 0) | ||
391 | goto found_server; | ||
392 | } | ||
393 | 364 | ||
394 | /* check the inactive list */ | ||
395 | spin_lock(&cell->sv_gylock); | ||
396 | list_for_each_entry(server, &cell->sv_graveyard, link) { | ||
397 | _debug("?? dead server %08x", | ||
398 | ntohl(server->addr.s_addr)); | ||
399 | |||
400 | if (memcmp(&server->addr, &peer->addr, | ||
401 | sizeof(struct in_addr)) == 0) | ||
402 | goto found_dead_server; | ||
403 | } | ||
404 | spin_unlock(&cell->sv_gylock); | ||
405 | |||
406 | write_unlock(&cell->sv_lock); | ||
407 | } | ||
408 | read_unlock(&afs_cells_lock); | ||
409 | |||
410 | _leave(" = -ENOENT"); | ||
411 | return -ENOENT; | ||
412 | |||
413 | /* we found it in the graveyard - resurrect it */ | ||
414 | found_dead_server: | ||
415 | list_move_tail(&server->link, &cell->sv_list); | ||
416 | afs_get_server(server); | ||
417 | afs_kafstimod_del_timer(&server->timeout); | ||
418 | spin_unlock(&cell->sv_gylock); | ||
419 | goto success; | ||
420 | |||
421 | /* we found it - increment its ref count and return it */ | ||
422 | found_server: | ||
423 | afs_get_server(server); | ||
424 | |||
425 | success: | ||
426 | write_unlock(&cell->sv_lock); | ||
427 | read_unlock(&afs_cells_lock); | ||
428 | |||
429 | *_server = server; | ||
430 | _leave(" = 0 (s=%p c=%p)", server, cell); | ||
431 | return 0; | ||
432 | |||
433 | } /* end afs_server_find_by_peer() */ | ||
434 | |||
435 | /*****************************************************************************/ | ||
436 | /* | 365 | /* |
437 | * purge in-memory cell database on module unload or afs_init() failure | 366 | * purge in-memory cell database on module unload or afs_init() failure |
438 | * - the timeout daemon is stopped before calling this | 367 | * - the timeout daemon is stopped before calling this |
439 | */ | 368 | */ |
440 | void afs_cell_purge(void) | 369 | void afs_cell_purge(void) |
441 | { | 370 | { |
442 | struct afs_vlocation *vlocation; | ||
443 | struct afs_cell *cell; | 371 | struct afs_cell *cell; |
444 | 372 | ||
445 | _enter(""); | 373 | _enter(""); |
446 | 374 | ||
447 | afs_put_cell(afs_cell_root); | 375 | afs_put_cell(afs_cell_root); |
448 | 376 | ||
377 | down_write(&afs_cells_sem); | ||
378 | |||
449 | while (!list_empty(&afs_cells)) { | 379 | while (!list_empty(&afs_cells)) { |
450 | cell = NULL; | 380 | cell = NULL; |
451 | 381 | ||
@@ -464,104 +394,11 @@ void afs_cell_purge(void) | |||
464 | _debug("PURGING CELL %s (%d)", | 394 | _debug("PURGING CELL %s (%d)", |
465 | cell->name, atomic_read(&cell->usage)); | 395 | cell->name, atomic_read(&cell->usage)); |
466 | 396 | ||
467 | BUG_ON(!list_empty(&cell->sv_list)); | ||
468 | BUG_ON(!list_empty(&cell->vl_list)); | ||
469 | |||
470 | /* purge the cell's VL graveyard list */ | ||
471 | _debug(" - clearing VL graveyard"); | ||
472 | |||
473 | spin_lock(&cell->vl_gylock); | ||
474 | |||
475 | while (!list_empty(&cell->vl_graveyard)) { | ||
476 | vlocation = list_entry(cell->vl_graveyard.next, | ||
477 | struct afs_vlocation, | ||
478 | link); | ||
479 | list_del_init(&vlocation->link); | ||
480 | |||
481 | afs_kafstimod_del_timer(&vlocation->timeout); | ||
482 | |||
483 | spin_unlock(&cell->vl_gylock); | ||
484 | |||
485 | afs_vlocation_do_timeout(vlocation); | ||
486 | /* TODO: race if move to use krxtimod instead | ||
487 | * of kafstimod */ | ||
488 | |||
489 | spin_lock(&cell->vl_gylock); | ||
490 | } | ||
491 | |||
492 | spin_unlock(&cell->vl_gylock); | ||
493 | |||
494 | /* purge the cell's server graveyard list */ | ||
495 | _debug(" - clearing server graveyard"); | ||
496 | |||
497 | spin_lock(&cell->sv_gylock); | ||
498 | |||
499 | while (!list_empty(&cell->sv_graveyard)) { | ||
500 | struct afs_server *server; | ||
501 | |||
502 | server = list_entry(cell->sv_graveyard.next, | ||
503 | struct afs_server, link); | ||
504 | list_del_init(&server->link); | ||
505 | |||
506 | afs_kafstimod_del_timer(&server->timeout); | ||
507 | |||
508 | spin_unlock(&cell->sv_gylock); | ||
509 | |||
510 | afs_server_do_timeout(server); | ||
511 | |||
512 | spin_lock(&cell->sv_gylock); | ||
513 | } | ||
514 | |||
515 | spin_unlock(&cell->sv_gylock); | ||
516 | |||
517 | /* now the cell should be left with no references */ | 397 | /* now the cell should be left with no references */ |
518 | afs_cell_destroy(cell); | 398 | afs_cell_destroy(cell); |
519 | } | 399 | } |
520 | } | 400 | } |
521 | 401 | ||
402 | up_write(&afs_cells_sem); | ||
522 | _leave(""); | 403 | _leave(""); |
523 | } /* end afs_cell_purge() */ | 404 | } |
524 | |||
525 | /*****************************************************************************/ | ||
526 | /* | ||
527 | * match a cell record obtained from the cache | ||
528 | */ | ||
529 | #ifdef AFS_CACHING_SUPPORT | ||
530 | static cachefs_match_val_t afs_cell_cache_match(void *target, | ||
531 | const void *entry) | ||
532 | { | ||
533 | const struct afs_cache_cell *ccell = entry; | ||
534 | struct afs_cell *cell = target; | ||
535 | |||
536 | _enter("{%s},{%s}", ccell->name, cell->name); | ||
537 | |||
538 | if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) { | ||
539 | _leave(" = SUCCESS"); | ||
540 | return CACHEFS_MATCH_SUCCESS; | ||
541 | } | ||
542 | |||
543 | _leave(" = FAILED"); | ||
544 | return CACHEFS_MATCH_FAILED; | ||
545 | } /* end afs_cell_cache_match() */ | ||
546 | #endif | ||
547 | |||
548 | /*****************************************************************************/ | ||
549 | /* | ||
550 | * update a cell record in the cache | ||
551 | */ | ||
552 | #ifdef AFS_CACHING_SUPPORT | ||
553 | static void afs_cell_cache_update(void *source, void *entry) | ||
554 | { | ||
555 | struct afs_cache_cell *ccell = entry; | ||
556 | struct afs_cell *cell = source; | ||
557 | |||
558 | _enter("%p,%p", source, entry); | ||
559 | |||
560 | strncpy(ccell->name, cell->name, sizeof(ccell->name)); | ||
561 | |||
562 | memcpy(ccell->vl_servers, | ||
563 | cell->vl_addrs, | ||
564 | min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs))); | ||
565 | |||
566 | } /* end afs_cell_cache_update() */ | ||
567 | #endif | ||
diff --git a/fs/afs/cell.h b/fs/afs/cell.h deleted file mode 100644 index 48349108fb00..000000000000 --- a/fs/afs/cell.h +++ /dev/null | |||
@@ -1,78 +0,0 @@ | |||
1 | /* cell.h: AFS cell record | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_CELL_H | ||
13 | #define _LINUX_AFS_CELL_H | ||
14 | |||
15 | #include "types.h" | ||
16 | #include "cache.h" | ||
17 | |||
18 | #define AFS_CELL_MAX_ADDRS 15 | ||
19 | |||
20 | extern volatile int afs_cells_being_purged; /* T when cells are being purged by rmmod */ | ||
21 | |||
22 | /*****************************************************************************/ | ||
23 | /* | ||
24 | * entry in the cached cell catalogue | ||
25 | */ | ||
26 | struct afs_cache_cell | ||
27 | { | ||
28 | char name[64]; /* cell name (padded with NULs) */ | ||
29 | struct in_addr vl_servers[15]; /* cached cell VL servers */ | ||
30 | }; | ||
31 | |||
32 | /*****************************************************************************/ | ||
33 | /* | ||
34 | * AFS cell record | ||
35 | */ | ||
36 | struct afs_cell | ||
37 | { | ||
38 | atomic_t usage; | ||
39 | struct list_head link; /* main cell list link */ | ||
40 | struct list_head proc_link; /* /proc cell list link */ | ||
41 | struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ | ||
42 | #ifdef AFS_CACHING_SUPPORT | ||
43 | struct cachefs_cookie *cache; /* caching cookie */ | ||
44 | #endif | ||
45 | |||
46 | /* server record management */ | ||
47 | rwlock_t sv_lock; /* active server list lock */ | ||
48 | struct list_head sv_list; /* active server list */ | ||
49 | struct list_head sv_graveyard; /* inactive server list */ | ||
50 | spinlock_t sv_gylock; /* inactive server list lock */ | ||
51 | |||
52 | /* volume location record management */ | ||
53 | struct rw_semaphore vl_sem; /* volume management serialisation semaphore */ | ||
54 | struct list_head vl_list; /* cell's active VL record list */ | ||
55 | struct list_head vl_graveyard; /* cell's inactive VL record list */ | ||
56 | spinlock_t vl_gylock; /* graveyard lock */ | ||
57 | unsigned short vl_naddrs; /* number of VL servers in addr list */ | ||
58 | unsigned short vl_curr_svix; /* current server index */ | ||
59 | struct in_addr vl_addrs[AFS_CELL_MAX_ADDRS]; /* cell VL server addresses */ | ||
60 | |||
61 | char name[0]; /* cell name - must go last */ | ||
62 | }; | ||
63 | |||
64 | extern int afs_cell_init(char *rootcell); | ||
65 | |||
66 | extern int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell); | ||
67 | |||
68 | extern int afs_cell_lookup(const char *name, unsigned nmsize, struct afs_cell **_cell); | ||
69 | |||
70 | #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) | ||
71 | |||
72 | extern struct afs_cell *afs_get_cell_maybe(struct afs_cell **_cell); | ||
73 | |||
74 | extern void afs_put_cell(struct afs_cell *cell); | ||
75 | |||
76 | extern void afs_cell_purge(void); | ||
77 | |||
78 | #endif /* _LINUX_AFS_CELL_H */ | ||
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 3d097fddcb7a..6685f4cbccb3 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* cmservice.c: AFS Cache Manager Service | 1 | /* AFS Cache Manager Service |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -12,641 +12,463 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/completion.h> | 15 | #include <linux/ip.h> |
16 | #include "server.h" | ||
17 | #include "cell.h" | ||
18 | #include "transport.h" | ||
19 | #include <rxrpc/rxrpc.h> | ||
20 | #include <rxrpc/transport.h> | ||
21 | #include <rxrpc/connection.h> | ||
22 | #include <rxrpc/call.h> | ||
23 | #include "cmservice.h" | ||
24 | #include "internal.h" | 16 | #include "internal.h" |
17 | #include "afs_cm.h" | ||
25 | 18 | ||
26 | static unsigned afscm_usage; /* AFS cache manager usage count */ | 19 | struct workqueue_struct *afs_cm_workqueue; |
27 | static struct rw_semaphore afscm_sem; /* AFS cache manager start/stop semaphore */ | ||
28 | |||
29 | static int afscm_new_call(struct rxrpc_call *call); | ||
30 | static void afscm_attention(struct rxrpc_call *call); | ||
31 | static void afscm_error(struct rxrpc_call *call); | ||
32 | static void afscm_aemap(struct rxrpc_call *call); | ||
33 | |||
34 | static void _SRXAFSCM_CallBack(struct rxrpc_call *call); | ||
35 | static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call); | ||
36 | static void _SRXAFSCM_Probe(struct rxrpc_call *call); | ||
37 | |||
38 | typedef void (*_SRXAFSCM_xxxx_t)(struct rxrpc_call *call); | ||
39 | |||
40 | static const struct rxrpc_operation AFSCM_ops[] = { | ||
41 | { | ||
42 | .id = 204, | ||
43 | .asize = RXRPC_APP_MARK_EOF, | ||
44 | .name = "CallBack", | ||
45 | .user = _SRXAFSCM_CallBack, | ||
46 | }, | ||
47 | { | ||
48 | .id = 205, | ||
49 | .asize = RXRPC_APP_MARK_EOF, | ||
50 | .name = "InitCallBackState", | ||
51 | .user = _SRXAFSCM_InitCallBackState, | ||
52 | }, | ||
53 | { | ||
54 | .id = 206, | ||
55 | .asize = RXRPC_APP_MARK_EOF, | ||
56 | .name = "Probe", | ||
57 | .user = _SRXAFSCM_Probe, | ||
58 | }, | ||
59 | #if 0 | ||
60 | { | ||
61 | .id = 207, | ||
62 | .asize = RXRPC_APP_MARK_EOF, | ||
63 | .name = "GetLock", | ||
64 | .user = _SRXAFSCM_GetLock, | ||
65 | }, | ||
66 | { | ||
67 | .id = 208, | ||
68 | .asize = RXRPC_APP_MARK_EOF, | ||
69 | .name = "GetCE", | ||
70 | .user = _SRXAFSCM_GetCE, | ||
71 | }, | ||
72 | { | ||
73 | .id = 209, | ||
74 | .asize = RXRPC_APP_MARK_EOF, | ||
75 | .name = "GetXStatsVersion", | ||
76 | .user = _SRXAFSCM_GetXStatsVersion, | ||
77 | }, | ||
78 | { | ||
79 | .id = 210, | ||
80 | .asize = RXRPC_APP_MARK_EOF, | ||
81 | .name = "GetXStats", | ||
82 | .user = _SRXAFSCM_GetXStats, | ||
83 | } | ||
84 | #endif | ||
85 | }; | ||
86 | 20 | ||
87 | static struct rxrpc_service AFSCM_service = { | 21 | static int afs_deliver_cb_init_call_back_state(struct afs_call *, |
88 | .name = "AFS/CM", | 22 | struct sk_buff *, bool); |
89 | .owner = THIS_MODULE, | 23 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *, |
90 | .link = LIST_HEAD_INIT(AFSCM_service.link), | 24 | struct sk_buff *, bool); |
91 | .new_call = afscm_new_call, | 25 | static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool); |
92 | .service_id = 1, | 26 | static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool); |
93 | .attn_func = afscm_attention, | 27 | static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *, |
94 | .error_func = afscm_error, | 28 | bool); |
95 | .aemap_func = afscm_aemap, | 29 | static void afs_cm_destructor(struct afs_call *); |
96 | .ops_begin = &AFSCM_ops[0], | ||
97 | .ops_end = &AFSCM_ops[ARRAY_SIZE(AFSCM_ops)], | ||
98 | }; | ||
99 | 30 | ||
100 | static DECLARE_COMPLETION(kafscmd_alive); | ||
101 | static DECLARE_COMPLETION(kafscmd_dead); | ||
102 | static DECLARE_WAIT_QUEUE_HEAD(kafscmd_sleepq); | ||
103 | static LIST_HEAD(kafscmd_attention_list); | ||
104 | static LIST_HEAD(afscm_calls); | ||
105 | static DEFINE_SPINLOCK(afscm_calls_lock); | ||
106 | static DEFINE_SPINLOCK(kafscmd_attention_lock); | ||
107 | static int kafscmd_die; | ||
108 | |||
109 | /*****************************************************************************/ | ||
110 | /* | 31 | /* |
111 | * AFS Cache Manager kernel thread | 32 | * CB.CallBack operation type |
112 | */ | 33 | */ |
113 | static int kafscmd(void *arg) | 34 | static const struct afs_call_type afs_SRXCBCallBack = { |
114 | { | 35 | .name = "CB.CallBack", |
115 | DECLARE_WAITQUEUE(myself, current); | 36 | .deliver = afs_deliver_cb_callback, |
116 | 37 | .abort_to_error = afs_abort_to_error, | |
117 | struct rxrpc_call *call; | 38 | .destructor = afs_cm_destructor, |
118 | _SRXAFSCM_xxxx_t func; | 39 | }; |
119 | int die; | ||
120 | |||
121 | printk(KERN_INFO "kAFS: Started kafscmd %d\n", current->pid); | ||
122 | |||
123 | daemonize("kafscmd"); | ||
124 | |||
125 | complete(&kafscmd_alive); | ||
126 | |||
127 | /* loop around looking for things to attend to */ | ||
128 | do { | ||
129 | if (list_empty(&kafscmd_attention_list)) { | ||
130 | set_current_state(TASK_INTERRUPTIBLE); | ||
131 | add_wait_queue(&kafscmd_sleepq, &myself); | ||
132 | |||
133 | for (;;) { | ||
134 | set_current_state(TASK_INTERRUPTIBLE); | ||
135 | if (!list_empty(&kafscmd_attention_list) || | ||
136 | signal_pending(current) || | ||
137 | kafscmd_die) | ||
138 | break; | ||
139 | |||
140 | schedule(); | ||
141 | } | ||
142 | |||
143 | remove_wait_queue(&kafscmd_sleepq, &myself); | ||
144 | set_current_state(TASK_RUNNING); | ||
145 | } | ||
146 | |||
147 | die = kafscmd_die; | ||
148 | |||
149 | /* dequeue the next call requiring attention */ | ||
150 | call = NULL; | ||
151 | spin_lock(&kafscmd_attention_lock); | ||
152 | |||
153 | if (!list_empty(&kafscmd_attention_list)) { | ||
154 | call = list_entry(kafscmd_attention_list.next, | ||
155 | struct rxrpc_call, | ||
156 | app_attn_link); | ||
157 | list_del_init(&call->app_attn_link); | ||
158 | die = 0; | ||
159 | } | ||
160 | |||
161 | spin_unlock(&kafscmd_attention_lock); | ||
162 | |||
163 | if (call) { | ||
164 | /* act upon it */ | ||
165 | _debug("@@@ Begin Attend Call %p", call); | ||
166 | |||
167 | func = call->app_user; | ||
168 | if (func) | ||
169 | func(call); | ||
170 | |||
171 | rxrpc_put_call(call); | ||
172 | |||
173 | _debug("@@@ End Attend Call %p", call); | ||
174 | } | ||
175 | |||
176 | } while(!die); | ||
177 | |||
178 | /* and that's all */ | ||
179 | complete_and_exit(&kafscmd_dead, 0); | ||
180 | |||
181 | } /* end kafscmd() */ | ||
182 | 40 | ||
183 | /*****************************************************************************/ | ||
184 | /* | 41 | /* |
185 | * handle a call coming in to the cache manager | 42 | * CB.InitCallBackState operation type |
186 | * - if I want to keep the call, I must increment its usage count | ||
187 | * - the return value will be negated and passed back in an abort packet if | ||
188 | * non-zero | ||
189 | * - serialised by virtue of there only being one krxiod | ||
190 | */ | 43 | */ |
191 | static int afscm_new_call(struct rxrpc_call *call) | 44 | static const struct afs_call_type afs_SRXCBInitCallBackState = { |
192 | { | 45 | .name = "CB.InitCallBackState", |
193 | _enter("%p{cid=%u u=%d}", | 46 | .deliver = afs_deliver_cb_init_call_back_state, |
194 | call, ntohl(call->call_id), atomic_read(&call->usage)); | 47 | .abort_to_error = afs_abort_to_error, |
195 | 48 | .destructor = afs_cm_destructor, | |
196 | rxrpc_get_call(call); | 49 | }; |
197 | |||
198 | /* add to my current call list */ | ||
199 | spin_lock(&afscm_calls_lock); | ||
200 | list_add(&call->app_link,&afscm_calls); | ||
201 | spin_unlock(&afscm_calls_lock); | ||
202 | |||
203 | _leave(" = 0"); | ||
204 | return 0; | ||
205 | |||
206 | } /* end afscm_new_call() */ | ||
207 | 50 | ||
208 | /*****************************************************************************/ | ||
209 | /* | 51 | /* |
210 | * queue on the kafscmd queue for attention | 52 | * CB.InitCallBackState3 operation type |
211 | */ | 53 | */ |
212 | static void afscm_attention(struct rxrpc_call *call) | 54 | static const struct afs_call_type afs_SRXCBInitCallBackState3 = { |
213 | { | 55 | .name = "CB.InitCallBackState3", |
214 | _enter("%p{cid=%u u=%d}", | 56 | .deliver = afs_deliver_cb_init_call_back_state3, |
215 | call, ntohl(call->call_id), atomic_read(&call->usage)); | 57 | .abort_to_error = afs_abort_to_error, |
216 | 58 | .destructor = afs_cm_destructor, | |
217 | spin_lock(&kafscmd_attention_lock); | 59 | }; |
218 | |||
219 | if (list_empty(&call->app_attn_link)) { | ||
220 | list_add_tail(&call->app_attn_link, &kafscmd_attention_list); | ||
221 | rxrpc_get_call(call); | ||
222 | } | ||
223 | |||
224 | spin_unlock(&kafscmd_attention_lock); | ||
225 | |||
226 | wake_up(&kafscmd_sleepq); | ||
227 | |||
228 | _leave(" {u=%d}", atomic_read(&call->usage)); | ||
229 | } /* end afscm_attention() */ | ||
230 | 60 | ||
231 | /*****************************************************************************/ | ||
232 | /* | 61 | /* |
233 | * handle my call being aborted | 62 | * CB.Probe operation type |
234 | * - clean up, dequeue and put my ref to the call | ||
235 | */ | 63 | */ |
236 | static void afscm_error(struct rxrpc_call *call) | 64 | static const struct afs_call_type afs_SRXCBProbe = { |
237 | { | 65 | .name = "CB.Probe", |
238 | int removed; | 66 | .deliver = afs_deliver_cb_probe, |
239 | 67 | .abort_to_error = afs_abort_to_error, | |
240 | _enter("%p{est=%s ac=%u er=%d}", | 68 | .destructor = afs_cm_destructor, |
241 | call, | 69 | }; |
242 | rxrpc_call_error_states[call->app_err_state], | ||
243 | call->app_abort_code, | ||
244 | call->app_errno); | ||
245 | |||
246 | spin_lock(&kafscmd_attention_lock); | ||
247 | |||
248 | if (list_empty(&call->app_attn_link)) { | ||
249 | list_add_tail(&call->app_attn_link, &kafscmd_attention_list); | ||
250 | rxrpc_get_call(call); | ||
251 | } | ||
252 | |||
253 | spin_unlock(&kafscmd_attention_lock); | ||
254 | |||
255 | removed = 0; | ||
256 | spin_lock(&afscm_calls_lock); | ||
257 | if (!list_empty(&call->app_link)) { | ||
258 | list_del_init(&call->app_link); | ||
259 | removed = 1; | ||
260 | } | ||
261 | spin_unlock(&afscm_calls_lock); | ||
262 | |||
263 | if (removed) | ||
264 | rxrpc_put_call(call); | ||
265 | |||
266 | wake_up(&kafscmd_sleepq); | ||
267 | 70 | ||
268 | _leave(""); | 71 | /* |
269 | } /* end afscm_error() */ | 72 | * CB.GetCapabilities operation type |
73 | */ | ||
74 | static const struct afs_call_type afs_SRXCBGetCapabilites = { | ||
75 | .name = "CB.GetCapabilities", | ||
76 | .deliver = afs_deliver_cb_get_capabilities, | ||
77 | .abort_to_error = afs_abort_to_error, | ||
78 | .destructor = afs_cm_destructor, | ||
79 | }; | ||
270 | 80 | ||
271 | /*****************************************************************************/ | ||
272 | /* | 81 | /* |
273 | * map afs abort codes to/from Linux error codes | 82 | * route an incoming cache manager call |
274 | * - called with call->lock held | 83 | * - return T if supported, F if not |
275 | */ | 84 | */ |
276 | static void afscm_aemap(struct rxrpc_call *call) | 85 | bool afs_cm_incoming_call(struct afs_call *call) |
277 | { | 86 | { |
278 | switch (call->app_err_state) { | 87 | u32 operation_id = ntohl(call->operation_ID); |
279 | case RXRPC_ESTATE_LOCAL_ABORT: | 88 | |
280 | call->app_abort_code = -call->app_errno; | 89 | _enter("{CB.OP %u}", operation_id); |
281 | break; | 90 | |
282 | case RXRPC_ESTATE_PEER_ABORT: | 91 | switch (operation_id) { |
283 | call->app_errno = -ECONNABORTED; | 92 | case CBCallBack: |
284 | break; | 93 | call->type = &afs_SRXCBCallBack; |
94 | return true; | ||
95 | case CBInitCallBackState: | ||
96 | call->type = &afs_SRXCBInitCallBackState; | ||
97 | return true; | ||
98 | case CBInitCallBackState3: | ||
99 | call->type = &afs_SRXCBInitCallBackState3; | ||
100 | return true; | ||
101 | case CBProbe: | ||
102 | call->type = &afs_SRXCBProbe; | ||
103 | return true; | ||
104 | case CBGetCapabilities: | ||
105 | call->type = &afs_SRXCBGetCapabilites; | ||
106 | return true; | ||
285 | default: | 107 | default: |
286 | break; | 108 | return false; |
287 | } | 109 | } |
288 | } /* end afscm_aemap() */ | 110 | } |
289 | 111 | ||
290 | /*****************************************************************************/ | ||
291 | /* | 112 | /* |
292 | * start the cache manager service if not already started | 113 | * clean up a cache manager call |
293 | */ | 114 | */ |
294 | int afscm_start(void) | 115 | static void afs_cm_destructor(struct afs_call *call) |
295 | { | 116 | { |
296 | int ret; | 117 | _enter(""); |
297 | |||
298 | down_write(&afscm_sem); | ||
299 | if (!afscm_usage) { | ||
300 | ret = kernel_thread(kafscmd, NULL, 0); | ||
301 | if (ret < 0) | ||
302 | goto out; | ||
303 | |||
304 | wait_for_completion(&kafscmd_alive); | ||
305 | |||
306 | ret = rxrpc_add_service(afs_transport, &AFSCM_service); | ||
307 | if (ret < 0) | ||
308 | goto kill; | ||
309 | |||
310 | afs_kafstimod_add_timer(&afs_mntpt_expiry_timer, | ||
311 | afs_mntpt_expiry_timeout * HZ); | ||
312 | } | ||
313 | |||
314 | afscm_usage++; | ||
315 | up_write(&afscm_sem); | ||
316 | |||
317 | return 0; | ||
318 | |||
319 | kill: | ||
320 | kafscmd_die = 1; | ||
321 | wake_up(&kafscmd_sleepq); | ||
322 | wait_for_completion(&kafscmd_dead); | ||
323 | |||
324 | out: | ||
325 | up_write(&afscm_sem); | ||
326 | return ret; | ||
327 | 118 | ||
328 | } /* end afscm_start() */ | 119 | afs_put_server(call->server); |
120 | call->server = NULL; | ||
121 | kfree(call->buffer); | ||
122 | call->buffer = NULL; | ||
123 | } | ||
329 | 124 | ||
330 | /*****************************************************************************/ | ||
331 | /* | 125 | /* |
332 | * stop the cache manager service | 126 | * allow the fileserver to see if the cache manager is still alive |
333 | */ | 127 | */ |
334 | void afscm_stop(void) | 128 | static void SRXAFSCB_CallBack(struct work_struct *work) |
335 | { | 129 | { |
336 | struct rxrpc_call *call; | 130 | struct afs_call *call = container_of(work, struct afs_call, work); |
337 | 131 | ||
338 | down_write(&afscm_sem); | 132 | _enter(""); |
339 | 133 | ||
340 | BUG_ON(afscm_usage == 0); | 134 | /* be sure to send the reply *before* attempting to spam the AFS server |
341 | afscm_usage--; | 135 | * with FSFetchStatus requests on the vnodes with broken callbacks lest |
136 | * the AFS server get into a vicious cycle of trying to break further | ||
137 | * callbacks because it hadn't received completion of the CBCallBack op | ||
138 | * yet */ | ||
139 | afs_send_empty_reply(call); | ||
342 | 140 | ||
343 | if (afscm_usage == 0) { | 141 | afs_break_callbacks(call->server, call->count, call->request); |
344 | /* don't want more incoming calls */ | 142 | _leave(""); |
345 | rxrpc_del_service(afs_transport, &AFSCM_service); | 143 | } |
346 | |||
347 | /* abort any calls I've still got open (the afscm_error() will | ||
348 | * dequeue them) */ | ||
349 | spin_lock(&afscm_calls_lock); | ||
350 | while (!list_empty(&afscm_calls)) { | ||
351 | call = list_entry(afscm_calls.next, | ||
352 | struct rxrpc_call, | ||
353 | app_link); | ||
354 | 144 | ||
355 | list_del_init(&call->app_link); | 145 | /* |
356 | rxrpc_get_call(call); | 146 | * deliver request data to a CB.CallBack call |
357 | spin_unlock(&afscm_calls_lock); | 147 | */ |
148 | static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, | ||
149 | bool last) | ||
150 | { | ||
151 | struct afs_callback *cb; | ||
152 | struct afs_server *server; | ||
153 | struct in_addr addr; | ||
154 | __be32 *bp; | ||
155 | u32 tmp; | ||
156 | int ret, loop; | ||
157 | |||
158 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | ||
159 | |||
160 | switch (call->unmarshall) { | ||
161 | case 0: | ||
162 | call->offset = 0; | ||
163 | call->unmarshall++; | ||
164 | |||
165 | /* extract the FID array and its count in two steps */ | ||
166 | case 1: | ||
167 | _debug("extract FID count"); | ||
168 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
169 | switch (ret) { | ||
170 | case 0: break; | ||
171 | case -EAGAIN: return 0; | ||
172 | default: return ret; | ||
173 | } | ||
358 | 174 | ||
359 | rxrpc_call_abort(call, -ESRCH); /* abort, dequeue and | 175 | call->count = ntohl(call->tmp); |
360 | * put */ | 176 | _debug("FID count: %u", call->count); |
177 | if (call->count > AFSCBMAX) | ||
178 | return -EBADMSG; | ||
179 | |||
180 | call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL); | ||
181 | if (!call->buffer) | ||
182 | return -ENOMEM; | ||
183 | call->offset = 0; | ||
184 | call->unmarshall++; | ||
185 | |||
186 | case 2: | ||
187 | _debug("extract FID array"); | ||
188 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
189 | call->count * 3 * 4); | ||
190 | switch (ret) { | ||
191 | case 0: break; | ||
192 | case -EAGAIN: return 0; | ||
193 | default: return ret; | ||
194 | } | ||
361 | 195 | ||
362 | _debug("nuking active call %08x.%d", | 196 | _debug("unmarshall FID array"); |
363 | ntohl(call->conn->conn_id), | 197 | call->request = kcalloc(call->count, |
364 | ntohl(call->call_id)); | 198 | sizeof(struct afs_callback), |
365 | rxrpc_put_call(call); | 199 | GFP_KERNEL); |
366 | rxrpc_put_call(call); | 200 | if (!call->request) |
201 | return -ENOMEM; | ||
202 | |||
203 | cb = call->request; | ||
204 | bp = call->buffer; | ||
205 | for (loop = call->count; loop > 0; loop--, cb++) { | ||
206 | cb->fid.vid = ntohl(*bp++); | ||
207 | cb->fid.vnode = ntohl(*bp++); | ||
208 | cb->fid.unique = ntohl(*bp++); | ||
209 | cb->type = AFSCM_CB_UNTYPED; | ||
210 | } | ||
367 | 211 | ||
368 | spin_lock(&afscm_calls_lock); | 212 | call->offset = 0; |
213 | call->unmarshall++; | ||
214 | |||
215 | /* extract the callback array and its count in two steps */ | ||
216 | case 3: | ||
217 | _debug("extract CB count"); | ||
218 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
219 | switch (ret) { | ||
220 | case 0: break; | ||
221 | case -EAGAIN: return 0; | ||
222 | default: return ret; | ||
369 | } | 223 | } |
370 | spin_unlock(&afscm_calls_lock); | ||
371 | 224 | ||
372 | /* get rid of my daemon */ | 225 | tmp = ntohl(call->tmp); |
373 | kafscmd_die = 1; | 226 | _debug("CB count: %u", tmp); |
374 | wake_up(&kafscmd_sleepq); | 227 | if (tmp != call->count && tmp != 0) |
375 | wait_for_completion(&kafscmd_dead); | 228 | return -EBADMSG; |
229 | call->offset = 0; | ||
230 | call->unmarshall++; | ||
231 | if (tmp == 0) | ||
232 | goto empty_cb_array; | ||
233 | |||
234 | case 4: | ||
235 | _debug("extract CB array"); | ||
236 | ret = afs_extract_data(call, skb, last, call->request, | ||
237 | call->count * 3 * 4); | ||
238 | switch (ret) { | ||
239 | case 0: break; | ||
240 | case -EAGAIN: return 0; | ||
241 | default: return ret; | ||
242 | } | ||
376 | 243 | ||
377 | /* dispose of any calls waiting for attention */ | 244 | _debug("unmarshall CB array"); |
378 | spin_lock(&kafscmd_attention_lock); | 245 | cb = call->request; |
379 | while (!list_empty(&kafscmd_attention_list)) { | 246 | bp = call->buffer; |
380 | call = list_entry(kafscmd_attention_list.next, | 247 | for (loop = call->count; loop > 0; loop--, cb++) { |
381 | struct rxrpc_call, | 248 | cb->version = ntohl(*bp++); |
382 | app_attn_link); | 249 | cb->expiry = ntohl(*bp++); |
250 | cb->type = ntohl(*bp++); | ||
251 | } | ||
383 | 252 | ||
384 | list_del_init(&call->app_attn_link); | 253 | empty_cb_array: |
385 | spin_unlock(&kafscmd_attention_lock); | 254 | call->offset = 0; |
255 | call->unmarshall++; | ||
386 | 256 | ||
387 | rxrpc_put_call(call); | 257 | case 5: |
258 | _debug("trailer"); | ||
259 | if (skb->len != 0) | ||
260 | return -EBADMSG; | ||
261 | break; | ||
262 | } | ||
388 | 263 | ||
389 | spin_lock(&kafscmd_attention_lock); | 264 | if (!last) |
390 | } | 265 | return 0; |
391 | spin_unlock(&kafscmd_attention_lock); | ||
392 | 266 | ||
393 | afs_kafstimod_del_timer(&afs_mntpt_expiry_timer); | 267 | call->state = AFS_CALL_REPLYING; |
394 | } | ||
395 | 268 | ||
396 | up_write(&afscm_sem); | 269 | /* we'll need the file server record as that tells us which set of |
270 | * vnodes to operate upon */ | ||
271 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); | ||
272 | server = afs_find_server(&addr); | ||
273 | if (!server) | ||
274 | return -ENOTCONN; | ||
275 | call->server = server; | ||
397 | 276 | ||
398 | } /* end afscm_stop() */ | 277 | INIT_WORK(&call->work, SRXAFSCB_CallBack); |
278 | schedule_work(&call->work); | ||
279 | return 0; | ||
280 | } | ||
399 | 281 | ||
400 | /*****************************************************************************/ | ||
401 | /* | 282 | /* |
402 | * handle the fileserver breaking a set of callbacks | 283 | * allow the fileserver to request callback state (re-)initialisation |
403 | */ | 284 | */ |
404 | static void _SRXAFSCM_CallBack(struct rxrpc_call *call) | 285 | static void SRXAFSCB_InitCallBackState(struct work_struct *work) |
405 | { | 286 | { |
406 | struct afs_server *server; | 287 | struct afs_call *call = container_of(work, struct afs_call, work); |
407 | size_t count, qty, tmp; | ||
408 | int ret = 0, removed; | ||
409 | |||
410 | _enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]); | ||
411 | |||
412 | server = afs_server_get_from_peer(call->conn->peer); | ||
413 | |||
414 | switch (call->app_call_state) { | ||
415 | /* we've received the last packet | ||
416 | * - drain all the data from the call and send the reply | ||
417 | */ | ||
418 | case RXRPC_CSTATE_SRVR_GOT_ARGS: | ||
419 | ret = -EBADMSG; | ||
420 | qty = call->app_ready_qty; | ||
421 | if (qty < 8 || qty > 50 * (6 * 4) + 8) | ||
422 | break; | ||
423 | |||
424 | { | ||
425 | struct afs_callback *cb, *pcb; | ||
426 | int loop; | ||
427 | __be32 *fp, *bp; | ||
428 | |||
429 | fp = rxrpc_call_alloc_scratch(call, qty); | ||
430 | |||
431 | /* drag the entire argument block out to the scratch | ||
432 | * space */ | ||
433 | ret = rxrpc_call_read_data(call, fp, qty, 0); | ||
434 | if (ret < 0) | ||
435 | break; | ||
436 | |||
437 | /* and unmarshall the parameter block */ | ||
438 | ret = -EBADMSG; | ||
439 | count = ntohl(*fp++); | ||
440 | if (count>AFSCBMAX || | ||
441 | (count * (3 * 4) + 8 != qty && | ||
442 | count * (6 * 4) + 8 != qty)) | ||
443 | break; | ||
444 | |||
445 | bp = fp + count*3; | ||
446 | tmp = ntohl(*bp++); | ||
447 | if (tmp > 0 && tmp != count) | ||
448 | break; | ||
449 | if (tmp == 0) | ||
450 | bp = NULL; | ||
451 | |||
452 | pcb = cb = rxrpc_call_alloc_scratch_s( | ||
453 | call, struct afs_callback); | ||
454 | |||
455 | for (loop = count - 1; loop >= 0; loop--) { | ||
456 | pcb->fid.vid = ntohl(*fp++); | ||
457 | pcb->fid.vnode = ntohl(*fp++); | ||
458 | pcb->fid.unique = ntohl(*fp++); | ||
459 | if (bp) { | ||
460 | pcb->version = ntohl(*bp++); | ||
461 | pcb->expiry = ntohl(*bp++); | ||
462 | pcb->type = ntohl(*bp++); | ||
463 | } | ||
464 | else { | ||
465 | pcb->version = 0; | ||
466 | pcb->expiry = 0; | ||
467 | pcb->type = AFSCM_CB_UNTYPED; | ||
468 | } | ||
469 | pcb++; | ||
470 | } | ||
471 | |||
472 | /* invoke the actual service routine */ | ||
473 | ret = SRXAFSCM_CallBack(server, count, cb); | ||
474 | if (ret < 0) | ||
475 | break; | ||
476 | } | ||
477 | 288 | ||
478 | /* send the reply */ | 289 | _enter("{%p}", call->server); |
479 | ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET, | ||
480 | GFP_KERNEL, 0, &count); | ||
481 | if (ret < 0) | ||
482 | break; | ||
483 | break; | ||
484 | |||
485 | /* operation complete */ | ||
486 | case RXRPC_CSTATE_COMPLETE: | ||
487 | call->app_user = NULL; | ||
488 | removed = 0; | ||
489 | spin_lock(&afscm_calls_lock); | ||
490 | if (!list_empty(&call->app_link)) { | ||
491 | list_del_init(&call->app_link); | ||
492 | removed = 1; | ||
493 | } | ||
494 | spin_unlock(&afscm_calls_lock); | ||
495 | 290 | ||
496 | if (removed) | 291 | afs_init_callback_state(call->server); |
497 | rxrpc_put_call(call); | 292 | afs_send_empty_reply(call); |
498 | break; | 293 | _leave(""); |
294 | } | ||
499 | 295 | ||
500 | /* operation terminated on error */ | 296 | /* |
501 | case RXRPC_CSTATE_ERROR: | 297 | * deliver request data to a CB.InitCallBackState call |
502 | call->app_user = NULL; | 298 | */ |
503 | break; | 299 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call, |
300 | struct sk_buff *skb, | ||
301 | bool last) | ||
302 | { | ||
303 | struct afs_server *server; | ||
304 | struct in_addr addr; | ||
504 | 305 | ||
505 | default: | 306 | _enter(",{%u},%d", skb->len, last); |
506 | break; | ||
507 | } | ||
508 | 307 | ||
509 | if (ret < 0) | 308 | if (skb->len > 0) |
510 | rxrpc_call_abort(call, ret); | 309 | return -EBADMSG; |
310 | if (!last) | ||
311 | return 0; | ||
511 | 312 | ||
512 | afs_put_server(server); | 313 | /* no unmarshalling required */ |
314 | call->state = AFS_CALL_REPLYING; | ||
513 | 315 | ||
514 | _leave(" = %d", ret); | 316 | /* we'll need the file server record as that tells us which set of |
317 | * vnodes to operate upon */ | ||
318 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); | ||
319 | server = afs_find_server(&addr); | ||
320 | if (!server) | ||
321 | return -ENOTCONN; | ||
322 | call->server = server; | ||
515 | 323 | ||
516 | } /* end _SRXAFSCM_CallBack() */ | 324 | INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); |
325 | schedule_work(&call->work); | ||
326 | return 0; | ||
327 | } | ||
517 | 328 | ||
518 | /*****************************************************************************/ | ||
519 | /* | 329 | /* |
520 | * handle the fileserver asking us to initialise our callback state | 330 | * deliver request data to a CB.InitCallBackState3 call |
521 | */ | 331 | */ |
522 | static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call) | 332 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call, |
333 | struct sk_buff *skb, | ||
334 | bool last) | ||
523 | { | 335 | { |
524 | struct afs_server *server; | 336 | struct afs_server *server; |
525 | size_t count; | 337 | struct in_addr addr; |
526 | int ret = 0, removed; | ||
527 | 338 | ||
528 | _enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]); | 339 | _enter(",{%u},%d", skb->len, last); |
529 | 340 | ||
530 | server = afs_server_get_from_peer(call->conn->peer); | 341 | if (!last) |
342 | return 0; | ||
531 | 343 | ||
532 | switch (call->app_call_state) { | 344 | /* no unmarshalling required */ |
533 | /* we've received the last packet - drain all the data from the | 345 | call->state = AFS_CALL_REPLYING; |
534 | * call */ | ||
535 | case RXRPC_CSTATE_SRVR_GOT_ARGS: | ||
536 | /* shouldn't be any args */ | ||
537 | ret = -EBADMSG; | ||
538 | break; | ||
539 | |||
540 | /* send the reply when asked for it */ | ||
541 | case RXRPC_CSTATE_SRVR_SND_REPLY: | ||
542 | /* invoke the actual service routine */ | ||
543 | ret = SRXAFSCM_InitCallBackState(server); | ||
544 | if (ret < 0) | ||
545 | break; | ||
546 | |||
547 | ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET, | ||
548 | GFP_KERNEL, 0, &count); | ||
549 | if (ret < 0) | ||
550 | break; | ||
551 | break; | ||
552 | 346 | ||
553 | /* operation complete */ | 347 | /* we'll need the file server record as that tells us which set of |
554 | case RXRPC_CSTATE_COMPLETE: | 348 | * vnodes to operate upon */ |
555 | call->app_user = NULL; | 349 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); |
556 | removed = 0; | 350 | server = afs_find_server(&addr); |
557 | spin_lock(&afscm_calls_lock); | 351 | if (!server) |
558 | if (!list_empty(&call->app_link)) { | 352 | return -ENOTCONN; |
559 | list_del_init(&call->app_link); | 353 | call->server = server; |
560 | removed = 1; | ||
561 | } | ||
562 | spin_unlock(&afscm_calls_lock); | ||
563 | 354 | ||
564 | if (removed) | 355 | INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); |
565 | rxrpc_put_call(call); | 356 | schedule_work(&call->work); |
566 | break; | 357 | return 0; |
567 | 358 | } | |
568 | /* operation terminated on error */ | ||
569 | case RXRPC_CSTATE_ERROR: | ||
570 | call->app_user = NULL; | ||
571 | break; | ||
572 | |||
573 | default: | ||
574 | break; | ||
575 | } | ||
576 | |||
577 | if (ret < 0) | ||
578 | rxrpc_call_abort(call, ret); | ||
579 | |||
580 | afs_put_server(server); | ||
581 | 359 | ||
582 | _leave(" = %d", ret); | 360 | /* |
361 | * allow the fileserver to see if the cache manager is still alive | ||
362 | */ | ||
363 | static void SRXAFSCB_Probe(struct work_struct *work) | ||
364 | { | ||
365 | struct afs_call *call = container_of(work, struct afs_call, work); | ||
583 | 366 | ||
584 | } /* end _SRXAFSCM_InitCallBackState() */ | 367 | _enter(""); |
368 | afs_send_empty_reply(call); | ||
369 | _leave(""); | ||
370 | } | ||
585 | 371 | ||
586 | /*****************************************************************************/ | ||
587 | /* | 372 | /* |
588 | * handle a probe from a fileserver | 373 | * deliver request data to a CB.Probe call |
589 | */ | 374 | */ |
590 | static void _SRXAFSCM_Probe(struct rxrpc_call *call) | 375 | static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb, |
376 | bool last) | ||
591 | { | 377 | { |
592 | struct afs_server *server; | 378 | _enter(",{%u},%d", skb->len, last); |
593 | size_t count; | ||
594 | int ret = 0, removed; | ||
595 | |||
596 | _enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]); | ||
597 | 379 | ||
598 | server = afs_server_get_from_peer(call->conn->peer); | 380 | if (skb->len > 0) |
381 | return -EBADMSG; | ||
382 | if (!last) | ||
383 | return 0; | ||
599 | 384 | ||
600 | switch (call->app_call_state) { | 385 | /* no unmarshalling required */ |
601 | /* we've received the last packet - drain all the data from the | 386 | call->state = AFS_CALL_REPLYING; |
602 | * call */ | ||
603 | case RXRPC_CSTATE_SRVR_GOT_ARGS: | ||
604 | /* shouldn't be any args */ | ||
605 | ret = -EBADMSG; | ||
606 | break; | ||
607 | 387 | ||
608 | /* send the reply when asked for it */ | 388 | INIT_WORK(&call->work, SRXAFSCB_Probe); |
609 | case RXRPC_CSTATE_SRVR_SND_REPLY: | 389 | schedule_work(&call->work); |
610 | /* invoke the actual service routine */ | 390 | return 0; |
611 | ret = SRXAFSCM_Probe(server); | 391 | } |
612 | if (ret < 0) | ||
613 | break; | ||
614 | |||
615 | ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET, | ||
616 | GFP_KERNEL, 0, &count); | ||
617 | if (ret < 0) | ||
618 | break; | ||
619 | break; | ||
620 | 392 | ||
621 | /* operation complete */ | 393 | /* |
622 | case RXRPC_CSTATE_COMPLETE: | 394 | * allow the fileserver to ask about the cache manager's capabilities |
623 | call->app_user = NULL; | 395 | */ |
624 | removed = 0; | 396 | static void SRXAFSCB_GetCapabilities(struct work_struct *work) |
625 | spin_lock(&afscm_calls_lock); | 397 | { |
626 | if (!list_empty(&call->app_link)) { | 398 | struct afs_interface *ifs; |
627 | list_del_init(&call->app_link); | 399 | struct afs_call *call = container_of(work, struct afs_call, work); |
628 | removed = 1; | 400 | int loop, nifs; |
401 | |||
402 | struct { | ||
403 | struct /* InterfaceAddr */ { | ||
404 | __be32 nifs; | ||
405 | __be32 uuid[11]; | ||
406 | __be32 ifaddr[32]; | ||
407 | __be32 netmask[32]; | ||
408 | __be32 mtu[32]; | ||
409 | } ia; | ||
410 | struct /* Capabilities */ { | ||
411 | __be32 capcount; | ||
412 | __be32 caps[1]; | ||
413 | } cap; | ||
414 | } reply; | ||
415 | |||
416 | _enter(""); | ||
417 | |||
418 | nifs = 0; | ||
419 | ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); | ||
420 | if (ifs) { | ||
421 | nifs = afs_get_ipv4_interfaces(ifs, 32, false); | ||
422 | if (nifs < 0) { | ||
423 | kfree(ifs); | ||
424 | ifs = NULL; | ||
425 | nifs = 0; | ||
629 | } | 426 | } |
630 | spin_unlock(&afscm_calls_lock); | 427 | } |
631 | 428 | ||
632 | if (removed) | 429 | memset(&reply, 0, sizeof(reply)); |
633 | rxrpc_put_call(call); | 430 | reply.ia.nifs = htonl(nifs); |
634 | break; | 431 | |
432 | reply.ia.uuid[0] = htonl(afs_uuid.time_low); | ||
433 | reply.ia.uuid[1] = htonl(afs_uuid.time_mid); | ||
434 | reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version); | ||
435 | reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved); | ||
436 | reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low); | ||
437 | for (loop = 0; loop < 6; loop++) | ||
438 | reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]); | ||
439 | |||
440 | if (ifs) { | ||
441 | for (loop = 0; loop < nifs; loop++) { | ||
442 | reply.ia.ifaddr[loop] = ifs[loop].address.s_addr; | ||
443 | reply.ia.netmask[loop] = ifs[loop].netmask.s_addr; | ||
444 | reply.ia.mtu[loop] = htonl(ifs[loop].mtu); | ||
445 | } | ||
446 | } | ||
635 | 447 | ||
636 | /* operation terminated on error */ | 448 | reply.cap.capcount = htonl(1); |
637 | case RXRPC_CSTATE_ERROR: | 449 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); |
638 | call->app_user = NULL; | 450 | afs_send_simple_reply(call, &reply, sizeof(reply)); |
639 | break; | ||
640 | 451 | ||
641 | default: | 452 | _leave(""); |
642 | break; | 453 | } |
643 | } | ||
644 | 454 | ||
645 | if (ret < 0) | 455 | /* |
646 | rxrpc_call_abort(call, ret); | 456 | * deliver request data to a CB.GetCapabilities call |
457 | */ | ||
458 | static int afs_deliver_cb_get_capabilities(struct afs_call *call, | ||
459 | struct sk_buff *skb, bool last) | ||
460 | { | ||
461 | _enter(",{%u},%d", skb->len, last); | ||
647 | 462 | ||
648 | afs_put_server(server); | 463 | if (skb->len > 0) |
464 | return -EBADMSG; | ||
465 | if (!last) | ||
466 | return 0; | ||
649 | 467 | ||
650 | _leave(" = %d", ret); | 468 | /* no unmarshalling required */ |
469 | call->state = AFS_CALL_REPLYING; | ||
651 | 470 | ||
652 | } /* end _SRXAFSCM_Probe() */ | 471 | INIT_WORK(&call->work, SRXAFSCB_GetCapabilities); |
472 | schedule_work(&call->work); | ||
473 | return 0; | ||
474 | } | ||
diff --git a/fs/afs/cmservice.h b/fs/afs/cmservice.h deleted file mode 100644 index af8d4d689cb2..000000000000 --- a/fs/afs/cmservice.h +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | /* cmservice.h: AFS Cache Manager Service declarations | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_CMSERVICE_H | ||
13 | #define _LINUX_AFS_CMSERVICE_H | ||
14 | |||
15 | #include <rxrpc/transport.h> | ||
16 | #include "types.h" | ||
17 | |||
18 | /* cache manager start/stop */ | ||
19 | extern int afscm_start(void); | ||
20 | extern void afscm_stop(void); | ||
21 | |||
22 | /* cache manager server functions */ | ||
23 | extern int SRXAFSCM_InitCallBackState(struct afs_server *server); | ||
24 | extern int SRXAFSCM_CallBack(struct afs_server *server, | ||
25 | size_t count, | ||
26 | struct afs_callback callbacks[]); | ||
27 | extern int SRXAFSCM_Probe(struct afs_server *server); | ||
28 | |||
29 | #endif /* _LINUX_AFS_CMSERVICE_H */ | ||
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index b6dc2ebe47a8..dac5b990c0cd 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -15,45 +15,53 @@ | |||
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/smp_lock.h> | 18 | #include <linux/ctype.h> |
19 | #include "vnode.h" | ||
20 | #include "volume.h" | ||
21 | #include <rxrpc/call.h> | ||
22 | #include "super.h" | ||
23 | #include "internal.h" | 19 | #include "internal.h" |
24 | 20 | ||
25 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | 21 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, |
26 | struct nameidata *nd); | 22 | struct nameidata *nd); |
27 | static int afs_dir_open(struct inode *inode, struct file *file); | 23 | static int afs_dir_open(struct inode *inode, struct file *file); |
28 | static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir); | 24 | static int afs_readdir(struct file *file, void *dirent, filldir_t filldir); |
29 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd); | 25 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd); |
30 | static int afs_d_delete(struct dentry *dentry); | 26 | static int afs_d_delete(struct dentry *dentry); |
31 | static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | 27 | static void afs_d_release(struct dentry *dentry); |
28 | static int afs_lookup_filldir(void *_cookie, const char *name, int nlen, | ||
32 | loff_t fpos, u64 ino, unsigned dtype); | 29 | loff_t fpos, u64 ino, unsigned dtype); |
30 | static int afs_create(struct inode *dir, struct dentry *dentry, int mode, | ||
31 | struct nameidata *nd); | ||
32 | static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode); | ||
33 | static int afs_rmdir(struct inode *dir, struct dentry *dentry); | ||
34 | static int afs_unlink(struct inode *dir, struct dentry *dentry); | ||
35 | static int afs_link(struct dentry *from, struct inode *dir, | ||
36 | struct dentry *dentry); | ||
37 | static int afs_symlink(struct inode *dir, struct dentry *dentry, | ||
38 | const char *content); | ||
39 | static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | ||
40 | struct inode *new_dir, struct dentry *new_dentry); | ||
33 | 41 | ||
34 | const struct file_operations afs_dir_file_operations = { | 42 | const struct file_operations afs_dir_file_operations = { |
35 | .open = afs_dir_open, | 43 | .open = afs_dir_open, |
36 | .readdir = afs_dir_readdir, | 44 | .release = afs_release, |
45 | .readdir = afs_readdir, | ||
37 | }; | 46 | }; |
38 | 47 | ||
39 | const struct inode_operations afs_dir_inode_operations = { | 48 | const struct inode_operations afs_dir_inode_operations = { |
40 | .lookup = afs_dir_lookup, | 49 | .create = afs_create, |
50 | .lookup = afs_lookup, | ||
51 | .link = afs_link, | ||
52 | .unlink = afs_unlink, | ||
53 | .symlink = afs_symlink, | ||
54 | .mkdir = afs_mkdir, | ||
55 | .rmdir = afs_rmdir, | ||
56 | .rename = afs_rename, | ||
57 | .permission = afs_permission, | ||
41 | .getattr = afs_inode_getattr, | 58 | .getattr = afs_inode_getattr, |
42 | #if 0 /* TODO */ | ||
43 | .create = afs_dir_create, | ||
44 | .link = afs_dir_link, | ||
45 | .unlink = afs_dir_unlink, | ||
46 | .symlink = afs_dir_symlink, | ||
47 | .mkdir = afs_dir_mkdir, | ||
48 | .rmdir = afs_dir_rmdir, | ||
49 | .mknod = afs_dir_mknod, | ||
50 | .rename = afs_dir_rename, | ||
51 | #endif | ||
52 | }; | 59 | }; |
53 | 60 | ||
54 | static struct dentry_operations afs_fs_dentry_operations = { | 61 | static struct dentry_operations afs_fs_dentry_operations = { |
55 | .d_revalidate = afs_d_revalidate, | 62 | .d_revalidate = afs_d_revalidate, |
56 | .d_delete = afs_d_delete, | 63 | .d_delete = afs_d_delete, |
64 | .d_release = afs_d_release, | ||
57 | }; | 65 | }; |
58 | 66 | ||
59 | #define AFS_DIR_HASHTBL_SIZE 128 | 67 | #define AFS_DIR_HASHTBL_SIZE 128 |
@@ -105,14 +113,13 @@ struct afs_dir_page { | |||
105 | union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)]; | 113 | union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)]; |
106 | }; | 114 | }; |
107 | 115 | ||
108 | struct afs_dir_lookup_cookie { | 116 | struct afs_lookup_cookie { |
109 | struct afs_fid fid; | 117 | struct afs_fid fid; |
110 | const char *name; | 118 | const char *name; |
111 | size_t nlen; | 119 | size_t nlen; |
112 | int found; | 120 | int found; |
113 | }; | 121 | }; |
114 | 122 | ||
115 | /*****************************************************************************/ | ||
116 | /* | 123 | /* |
117 | * check that a directory page is valid | 124 | * check that a directory page is valid |
118 | */ | 125 | */ |
@@ -128,9 +135,10 @@ static inline void afs_dir_check_page(struct inode *dir, struct page *page) | |||
128 | if (qty == 0) | 135 | if (qty == 0) |
129 | goto error; | 136 | goto error; |
130 | 137 | ||
131 | if (page->index==0 && qty!=ntohs(dbuf->blocks[0].pagehdr.npages)) { | 138 | if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) { |
132 | printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n", | 139 | printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n", |
133 | __FUNCTION__,dir->i_ino,qty,ntohs(dbuf->blocks[0].pagehdr.npages)); | 140 | __FUNCTION__, dir->i_ino, qty, |
141 | ntohs(dbuf->blocks[0].pagehdr.npages)); | ||
134 | goto error; | 142 | goto error; |
135 | } | 143 | } |
136 | #endif | 144 | #endif |
@@ -157,13 +165,11 @@ static inline void afs_dir_check_page(struct inode *dir, struct page *page) | |||
157 | SetPageChecked(page); | 165 | SetPageChecked(page); |
158 | return; | 166 | return; |
159 | 167 | ||
160 | error: | 168 | error: |
161 | SetPageChecked(page); | 169 | SetPageChecked(page); |
162 | SetPageError(page); | 170 | SetPageError(page); |
171 | } | ||
163 | 172 | ||
164 | } /* end afs_dir_check_page() */ | ||
165 | |||
166 | /*****************************************************************************/ | ||
167 | /* | 173 | /* |
168 | * discard a page cached in the pagecache | 174 | * discard a page cached in the pagecache |
169 | */ | 175 | */ |
@@ -171,20 +177,22 @@ static inline void afs_dir_put_page(struct page *page) | |||
171 | { | 177 | { |
172 | kunmap(page); | 178 | kunmap(page); |
173 | page_cache_release(page); | 179 | page_cache_release(page); |
180 | } | ||
174 | 181 | ||
175 | } /* end afs_dir_put_page() */ | ||
176 | |||
177 | /*****************************************************************************/ | ||
178 | /* | 182 | /* |
179 | * get a page into the pagecache | 183 | * get a page into the pagecache |
180 | */ | 184 | */ |
181 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) | 185 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index, |
186 | struct key *key) | ||
182 | { | 187 | { |
183 | struct page *page; | 188 | struct page *page; |
189 | struct file file = { | ||
190 | .private_data = key, | ||
191 | }; | ||
184 | 192 | ||
185 | _enter("{%lu},%lu", dir->i_ino, index); | 193 | _enter("{%lu},%lu", dir->i_ino, index); |
186 | 194 | ||
187 | page = read_mapping_page(dir->i_mapping, index, NULL); | 195 | page = read_mapping_page(dir->i_mapping, index, &file); |
188 | if (!IS_ERR(page)) { | 196 | if (!IS_ERR(page)) { |
189 | wait_on_page_locked(page); | 197 | wait_on_page_locked(page); |
190 | kmap(page); | 198 | kmap(page); |
@@ -197,12 +205,12 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index) | |||
197 | } | 205 | } |
198 | return page; | 206 | return page; |
199 | 207 | ||
200 | fail: | 208 | fail: |
201 | afs_dir_put_page(page); | 209 | afs_dir_put_page(page); |
210 | _leave(" = -EIO"); | ||
202 | return ERR_PTR(-EIO); | 211 | return ERR_PTR(-EIO); |
203 | } /* end afs_dir_get_page() */ | 212 | } |
204 | 213 | ||
205 | /*****************************************************************************/ | ||
206 | /* | 214 | /* |
207 | * open an AFS directory file | 215 | * open an AFS directory file |
208 | */ | 216 | */ |
@@ -213,15 +221,12 @@ static int afs_dir_open(struct inode *inode, struct file *file) | |||
213 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); | 221 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); |
214 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); | 222 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); |
215 | 223 | ||
216 | if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) | 224 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) |
217 | return -ENOENT; | 225 | return -ENOENT; |
218 | 226 | ||
219 | _leave(" = 0"); | 227 | return afs_open(inode, file); |
220 | return 0; | 228 | } |
221 | |||
222 | } /* end afs_dir_open() */ | ||
223 | 229 | ||
224 | /*****************************************************************************/ | ||
225 | /* | 230 | /* |
226 | * deal with one block in an AFS directory | 231 | * deal with one block in an AFS directory |
227 | */ | 232 | */ |
@@ -250,7 +255,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
250 | /* skip entries marked unused in the bitmap */ | 255 | /* skip entries marked unused in the bitmap */ |
251 | if (!(block->pagehdr.bitmap[offset / 8] & | 256 | if (!(block->pagehdr.bitmap[offset / 8] & |
252 | (1 << (offset % 8)))) { | 257 | (1 << (offset % 8)))) { |
253 | _debug("ENT[%Zu.%u]: unused\n", | 258 | _debug("ENT[%Zu.%u]: unused", |
254 | blkoff / sizeof(union afs_dir_block), offset); | 259 | blkoff / sizeof(union afs_dir_block), offset); |
255 | if (offset >= curr) | 260 | if (offset >= curr) |
256 | *fpos = blkoff + | 261 | *fpos = blkoff + |
@@ -264,7 +269,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
264 | sizeof(*block) - | 269 | sizeof(*block) - |
265 | offset * sizeof(union afs_dirent)); | 270 | offset * sizeof(union afs_dirent)); |
266 | 271 | ||
267 | _debug("ENT[%Zu.%u]: %s %Zu \"%s\"\n", | 272 | _debug("ENT[%Zu.%u]: %s %Zu \"%s\"", |
268 | blkoff / sizeof(union afs_dir_block), offset, | 273 | blkoff / sizeof(union afs_dir_block), offset, |
269 | (offset < curr ? "skip" : "fill"), | 274 | (offset < curr ? "skip" : "fill"), |
270 | nlen, dire->u.name); | 275 | nlen, dire->u.name); |
@@ -274,7 +279,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
274 | if (next >= AFS_DIRENT_PER_BLOCK) { | 279 | if (next >= AFS_DIRENT_PER_BLOCK) { |
275 | _debug("ENT[%Zu.%u]:" | 280 | _debug("ENT[%Zu.%u]:" |
276 | " %u travelled beyond end dir block" | 281 | " %u travelled beyond end dir block" |
277 | " (len %u/%Zu)\n", | 282 | " (len %u/%Zu)", |
278 | blkoff / sizeof(union afs_dir_block), | 283 | blkoff / sizeof(union afs_dir_block), |
279 | offset, next, tmp, nlen); | 284 | offset, next, tmp, nlen); |
280 | return -EIO; | 285 | return -EIO; |
@@ -282,13 +287,13 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
282 | if (!(block->pagehdr.bitmap[next / 8] & | 287 | if (!(block->pagehdr.bitmap[next / 8] & |
283 | (1 << (next % 8)))) { | 288 | (1 << (next % 8)))) { |
284 | _debug("ENT[%Zu.%u]:" | 289 | _debug("ENT[%Zu.%u]:" |
285 | " %u unmarked extension (len %u/%Zu)\n", | 290 | " %u unmarked extension (len %u/%Zu)", |
286 | blkoff / sizeof(union afs_dir_block), | 291 | blkoff / sizeof(union afs_dir_block), |
287 | offset, next, tmp, nlen); | 292 | offset, next, tmp, nlen); |
288 | return -EIO; | 293 | return -EIO; |
289 | } | 294 | } |
290 | 295 | ||
291 | _debug("ENT[%Zu.%u]: ext %u/%Zu\n", | 296 | _debug("ENT[%Zu.%u]: ext %u/%Zu", |
292 | blkoff / sizeof(union afs_dir_block), | 297 | blkoff / sizeof(union afs_dir_block), |
293 | next, tmp, nlen); | 298 | next, tmp, nlen); |
294 | next++; | 299 | next++; |
@@ -304,7 +309,7 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
304 | nlen, | 309 | nlen, |
305 | blkoff + offset * sizeof(union afs_dirent), | 310 | blkoff + offset * sizeof(union afs_dirent), |
306 | ntohl(dire->u.vnode), | 311 | ntohl(dire->u.vnode), |
307 | filldir == afs_dir_lookup_filldir ? | 312 | filldir == afs_lookup_filldir ? |
308 | ntohl(dire->u.unique) : DT_UNKNOWN); | 313 | ntohl(dire->u.unique) : DT_UNKNOWN); |
309 | if (ret < 0) { | 314 | if (ret < 0) { |
310 | _leave(" = 0 [full]"); | 315 | _leave(" = 0 [full]"); |
@@ -316,16 +321,15 @@ static int afs_dir_iterate_block(unsigned *fpos, | |||
316 | 321 | ||
317 | _leave(" = 1 [more]"); | 322 | _leave(" = 1 [more]"); |
318 | return 1; | 323 | return 1; |
319 | } /* end afs_dir_iterate_block() */ | 324 | } |
320 | 325 | ||
321 | /*****************************************************************************/ | ||
322 | /* | 326 | /* |
323 | * read an AFS directory | 327 | * iterate through the data blob that lists the contents of an AFS directory |
324 | */ | 328 | */ |
325 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | 329 | static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, |
326 | filldir_t filldir) | 330 | filldir_t filldir, struct key *key) |
327 | { | 331 | { |
328 | union afs_dir_block *dblock; | 332 | union afs_dir_block *dblock; |
329 | struct afs_dir_page *dbuf; | 333 | struct afs_dir_page *dbuf; |
330 | struct page *page; | 334 | struct page *page; |
331 | unsigned blkoff, limit; | 335 | unsigned blkoff, limit; |
@@ -333,7 +337,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | |||
333 | 337 | ||
334 | _enter("{%lu},%u,,", dir->i_ino, *fpos); | 338 | _enter("{%lu},%u,,", dir->i_ino, *fpos); |
335 | 339 | ||
336 | if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) { | 340 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) { |
337 | _leave(" = -ESTALE"); | 341 | _leave(" = -ESTALE"); |
338 | return -ESTALE; | 342 | return -ESTALE; |
339 | } | 343 | } |
@@ -348,7 +352,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | |||
348 | blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); | 352 | blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); |
349 | 353 | ||
350 | /* fetch the appropriate page from the directory */ | 354 | /* fetch the appropriate page from the directory */ |
351 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE); | 355 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key); |
352 | if (IS_ERR(page)) { | 356 | if (IS_ERR(page)) { |
353 | ret = PTR_ERR(page); | 357 | ret = PTR_ERR(page); |
354 | break; | 358 | break; |
@@ -377,43 +381,50 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, | |||
377 | ret = 0; | 381 | ret = 0; |
378 | } | 382 | } |
379 | 383 | ||
380 | out: | 384 | out: |
381 | _leave(" = %d", ret); | 385 | _leave(" = %d", ret); |
382 | return ret; | 386 | return ret; |
383 | } /* end afs_dir_iterate() */ | 387 | } |
384 | 388 | ||
385 | /*****************************************************************************/ | ||
386 | /* | 389 | /* |
387 | * read an AFS directory | 390 | * read an AFS directory |
388 | */ | 391 | */ |
389 | static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir) | 392 | static int afs_readdir(struct file *file, void *cookie, filldir_t filldir) |
390 | { | 393 | { |
391 | unsigned fpos; | 394 | unsigned fpos; |
392 | int ret; | 395 | int ret; |
393 | 396 | ||
394 | _enter("{%Ld,{%lu}}", file->f_pos, file->f_path.dentry->d_inode->i_ino); | 397 | _enter("{%Ld,{%lu}}", |
398 | file->f_pos, file->f_path.dentry->d_inode->i_ino); | ||
399 | |||
400 | ASSERT(file->private_data != NULL); | ||
395 | 401 | ||
396 | fpos = file->f_pos; | 402 | fpos = file->f_pos; |
397 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, cookie, filldir); | 403 | ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, |
404 | cookie, filldir, file->private_data); | ||
398 | file->f_pos = fpos; | 405 | file->f_pos = fpos; |
399 | 406 | ||
400 | _leave(" = %d", ret); | 407 | _leave(" = %d", ret); |
401 | return ret; | 408 | return ret; |
402 | } /* end afs_dir_readdir() */ | 409 | } |
403 | 410 | ||
404 | /*****************************************************************************/ | ||
405 | /* | 411 | /* |
406 | * search the directory for a name | 412 | * search the directory for a name |
407 | * - if afs_dir_iterate_block() spots this function, it'll pass the FID | 413 | * - if afs_dir_iterate_block() spots this function, it'll pass the FID |
408 | * uniquifier through dtype | 414 | * uniquifier through dtype |
409 | */ | 415 | */ |
410 | static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | 416 | static int afs_lookup_filldir(void *_cookie, const char *name, int nlen, |
411 | loff_t fpos, u64 ino, unsigned dtype) | 417 | loff_t fpos, u64 ino, unsigned dtype) |
412 | { | 418 | { |
413 | struct afs_dir_lookup_cookie *cookie = _cookie; | 419 | struct afs_lookup_cookie *cookie = _cookie; |
414 | 420 | ||
415 | _enter("{%s,%Zu},%s,%u,,%lu,%u", | 421 | _enter("{%s,%Zu},%s,%u,,%llu,%u", |
416 | cookie->name, cookie->nlen, name, nlen, ino, dtype); | 422 | cookie->name, cookie->nlen, name, nlen, |
423 | (unsigned long long) ino, dtype); | ||
424 | |||
425 | /* insanity checks first */ | ||
426 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); | ||
427 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); | ||
417 | 428 | ||
418 | if (cookie->nlen != nlen || memcmp(cookie->name, name, nlen) != 0) { | 429 | if (cookie->nlen != nlen || memcmp(cookie->name, name, nlen) != 0) { |
419 | _leave(" = 0 [no]"); | 430 | _leave(" = 0 [no]"); |
@@ -426,216 +437,254 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, | |||
426 | 437 | ||
427 | _leave(" = -1 [found]"); | 438 | _leave(" = -1 [found]"); |
428 | return -1; | 439 | return -1; |
429 | } /* end afs_dir_lookup_filldir() */ | 440 | } |
430 | 441 | ||
431 | /*****************************************************************************/ | ||
432 | /* | 442 | /* |
433 | * look up an entry in a directory | 443 | * do a lookup in a directory |
444 | * - just returns the FID the dentry name maps to if found | ||
434 | */ | 445 | */ |
435 | static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, | 446 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, |
436 | struct nameidata *nd) | 447 | struct afs_fid *fid, struct key *key) |
437 | { | 448 | { |
438 | struct afs_dir_lookup_cookie cookie; | 449 | struct afs_lookup_cookie cookie; |
439 | struct afs_super_info *as; | 450 | struct afs_super_info *as; |
451 | unsigned fpos; | ||
452 | int ret; | ||
453 | |||
454 | _enter("{%lu},%p{%s},", dir->i_ino, dentry, dentry->d_name.name); | ||
455 | |||
456 | as = dir->i_sb->s_fs_info; | ||
457 | |||
458 | /* search the directory */ | ||
459 | cookie.name = dentry->d_name.name; | ||
460 | cookie.nlen = dentry->d_name.len; | ||
461 | cookie.fid.vid = as->volume->vid; | ||
462 | cookie.found = 0; | ||
463 | |||
464 | fpos = 0; | ||
465 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_lookup_filldir, | ||
466 | key); | ||
467 | if (ret < 0) { | ||
468 | _leave(" = %d [iter]", ret); | ||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | ret = -ENOENT; | ||
473 | if (!cookie.found) { | ||
474 | _leave(" = -ENOENT [not found]"); | ||
475 | return -ENOENT; | ||
476 | } | ||
477 | |||
478 | *fid = cookie.fid; | ||
479 | _leave(" = 0 { vn=%u u=%u }", fid->vnode, fid->unique); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * look up an entry in a directory | ||
485 | */ | ||
486 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | ||
487 | struct nameidata *nd) | ||
488 | { | ||
440 | struct afs_vnode *vnode; | 489 | struct afs_vnode *vnode; |
490 | struct afs_fid fid; | ||
441 | struct inode *inode; | 491 | struct inode *inode; |
442 | unsigned fpos; | 492 | struct key *key; |
443 | int ret; | 493 | int ret; |
444 | 494 | ||
445 | _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); | 495 | vnode = AFS_FS_I(dir); |
446 | 496 | ||
447 | /* insanity checks first */ | 497 | _enter("{%x:%d},%p{%s},", |
448 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); | 498 | vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name); |
449 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); | 499 | |
500 | ASSERTCMP(dentry->d_inode, ==, NULL); | ||
450 | 501 | ||
451 | if (dentry->d_name.len > 255) { | 502 | if (dentry->d_name.len > 255) { |
452 | _leave(" = -ENAMETOOLONG"); | 503 | _leave(" = -ENAMETOOLONG"); |
453 | return ERR_PTR(-ENAMETOOLONG); | 504 | return ERR_PTR(-ENAMETOOLONG); |
454 | } | 505 | } |
455 | 506 | ||
456 | vnode = AFS_FS_I(dir); | 507 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { |
457 | if (vnode->flags & AFS_VNODE_DELETED) { | ||
458 | _leave(" = -ESTALE"); | 508 | _leave(" = -ESTALE"); |
459 | return ERR_PTR(-ESTALE); | 509 | return ERR_PTR(-ESTALE); |
460 | } | 510 | } |
461 | 511 | ||
462 | as = dir->i_sb->s_fs_info; | 512 | key = afs_request_key(vnode->volume->cell); |
463 | 513 | if (IS_ERR(key)) { | |
464 | /* search the directory */ | 514 | _leave(" = %ld [key]", PTR_ERR(key)); |
465 | cookie.name = dentry->d_name.name; | 515 | return ERR_PTR(PTR_ERR(key)); |
466 | cookie.nlen = dentry->d_name.len; | 516 | } |
467 | cookie.fid.vid = as->volume->vid; | ||
468 | cookie.found = 0; | ||
469 | 517 | ||
470 | fpos = 0; | 518 | ret = afs_validate(vnode, key); |
471 | ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir); | ||
472 | if (ret < 0) { | 519 | if (ret < 0) { |
473 | _leave(" = %d", ret); | 520 | key_put(key); |
521 | _leave(" = %d [val]", ret); | ||
474 | return ERR_PTR(ret); | 522 | return ERR_PTR(ret); |
475 | } | 523 | } |
476 | 524 | ||
477 | ret = -ENOENT; | 525 | ret = afs_do_lookup(dir, dentry, &fid, key); |
478 | if (!cookie.found) { | 526 | if (ret < 0) { |
479 | _leave(" = %d", ret); | 527 | key_put(key); |
528 | if (ret == -ENOENT) { | ||
529 | d_add(dentry, NULL); | ||
530 | _leave(" = NULL [negative]"); | ||
531 | return NULL; | ||
532 | } | ||
533 | _leave(" = %d [do]", ret); | ||
480 | return ERR_PTR(ret); | 534 | return ERR_PTR(ret); |
481 | } | 535 | } |
536 | dentry->d_fsdata = (void *)(unsigned long) vnode->status.data_version; | ||
482 | 537 | ||
483 | /* instantiate the dentry */ | 538 | /* instantiate the dentry */ |
484 | ret = afs_iget(dir->i_sb, &cookie.fid, &inode); | 539 | inode = afs_iget(dir->i_sb, key, &fid, NULL, NULL); |
485 | if (ret < 0) { | 540 | key_put(key); |
486 | _leave(" = %d", ret); | 541 | if (IS_ERR(inode)) { |
487 | return ERR_PTR(ret); | 542 | _leave(" = %ld", PTR_ERR(inode)); |
543 | return ERR_PTR(PTR_ERR(inode)); | ||
488 | } | 544 | } |
489 | 545 | ||
490 | dentry->d_op = &afs_fs_dentry_operations; | 546 | dentry->d_op = &afs_fs_dentry_operations; |
491 | dentry->d_fsdata = (void *) (unsigned long) vnode->status.version; | ||
492 | 547 | ||
493 | d_add(dentry, inode); | 548 | d_add(dentry, inode); |
494 | _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%lu }", | 549 | _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%lu }", |
495 | cookie.fid.vnode, | 550 | fid.vnode, |
496 | cookie.fid.unique, | 551 | fid.unique, |
497 | dentry->d_inode->i_ino, | 552 | dentry->d_inode->i_ino, |
498 | dentry->d_inode->i_version); | 553 | dentry->d_inode->i_version); |
499 | 554 | ||
500 | return NULL; | 555 | return NULL; |
501 | } /* end afs_dir_lookup() */ | 556 | } |
502 | 557 | ||
503 | /*****************************************************************************/ | ||
504 | /* | 558 | /* |
505 | * check that a dentry lookup hit has found a valid entry | 559 | * check that a dentry lookup hit has found a valid entry |
506 | * - NOTE! the hit can be a negative hit too, so we can't assume we have an | 560 | * - NOTE! the hit can be a negative hit too, so we can't assume we have an |
507 | * inode | 561 | * inode |
508 | * (derived from nfs_lookup_revalidate) | ||
509 | */ | 562 | */ |
510 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | 563 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) |
511 | { | 564 | { |
512 | struct afs_dir_lookup_cookie cookie; | 565 | struct afs_vnode *vnode, *dir; |
566 | struct afs_fid fid; | ||
513 | struct dentry *parent; | 567 | struct dentry *parent; |
514 | struct inode *inode, *dir; | 568 | struct key *key; |
515 | unsigned fpos; | 569 | void *dir_version; |
516 | int ret; | 570 | int ret; |
517 | 571 | ||
518 | _enter("{sb=%p n=%s},", dentry->d_sb, dentry->d_name.name); | 572 | vnode = AFS_FS_I(dentry->d_inode); |
519 | 573 | ||
520 | /* lock down the parent dentry so we can peer at it */ | 574 | if (dentry->d_inode) |
521 | parent = dget_parent(dentry->d_parent); | 575 | _enter("{v={%x:%u} n=%s fl=%lx},", |
576 | vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name, | ||
577 | vnode->flags); | ||
578 | else | ||
579 | _enter("{neg n=%s}", dentry->d_name.name); | ||
522 | 580 | ||
523 | dir = parent->d_inode; | 581 | key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell); |
524 | inode = dentry->d_inode; | 582 | if (IS_ERR(key)) |
583 | key = NULL; | ||
525 | 584 | ||
526 | /* handle a negative dentry */ | 585 | /* lock down the parent dentry so we can peer at it */ |
527 | if (!inode) | 586 | parent = dget_parent(dentry); |
587 | if (!parent->d_inode) | ||
528 | goto out_bad; | 588 | goto out_bad; |
529 | 589 | ||
530 | /* handle a bad inode */ | 590 | dir = AFS_FS_I(parent->d_inode); |
531 | if (is_bad_inode(inode)) { | ||
532 | printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n", | ||
533 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
534 | goto out_bad; | ||
535 | } | ||
536 | 591 | ||
537 | /* force a full look up if the parent directory changed since last the | 592 | /* validate the parent directory */ |
538 | * server was consulted | 593 | if (test_bit(AFS_VNODE_MODIFIED, &dir->flags)) |
539 | * - otherwise this inode must still exist, even if the inode details | 594 | afs_validate(dir, key); |
540 | * themselves have changed | ||
541 | */ | ||
542 | if (AFS_FS_I(dir)->flags & AFS_VNODE_CHANGED) | ||
543 | afs_vnode_fetch_status(AFS_FS_I(dir)); | ||
544 | 595 | ||
545 | if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) { | 596 | if (test_bit(AFS_VNODE_DELETED, &dir->flags)) { |
546 | _debug("%s: parent dir deleted", dentry->d_name.name); | 597 | _debug("%s: parent dir deleted", dentry->d_name.name); |
547 | goto out_bad; | 598 | goto out_bad; |
548 | } | 599 | } |
549 | 600 | ||
550 | if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) { | 601 | dir_version = (void *) (unsigned long) dir->status.data_version; |
551 | _debug("%s: file already deleted", dentry->d_name.name); | 602 | if (dentry->d_fsdata == dir_version) |
552 | goto out_bad; | 603 | goto out_valid; /* the dir contents are unchanged */ |
553 | } | ||
554 | |||
555 | if ((unsigned long) dentry->d_fsdata != | ||
556 | (unsigned long) AFS_FS_I(dir)->status.version) { | ||
557 | _debug("%s: parent changed %lu -> %u", | ||
558 | dentry->d_name.name, | ||
559 | (unsigned long) dentry->d_fsdata, | ||
560 | (unsigned) AFS_FS_I(dir)->status.version); | ||
561 | 604 | ||
562 | /* search the directory for this vnode */ | 605 | _debug("dir modified"); |
563 | cookie.name = dentry->d_name.name; | ||
564 | cookie.nlen = dentry->d_name.len; | ||
565 | cookie.fid.vid = AFS_FS_I(inode)->volume->vid; | ||
566 | cookie.found = 0; | ||
567 | 606 | ||
568 | fpos = 0; | 607 | /* search the directory for this vnode */ |
569 | ret = afs_dir_iterate(dir, &fpos, &cookie, | 608 | ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key); |
570 | afs_dir_lookup_filldir); | 609 | switch (ret) { |
571 | if (ret < 0) { | 610 | case 0: |
572 | _debug("failed to iterate dir %s: %d", | 611 | /* the filename maps to something */ |
573 | parent->d_name.name, ret); | 612 | if (!dentry->d_inode) |
613 | goto out_bad; | ||
614 | if (is_bad_inode(dentry->d_inode)) { | ||
615 | printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n", | ||
616 | parent->d_name.name, dentry->d_name.name); | ||
574 | goto out_bad; | 617 | goto out_bad; |
575 | } | ||
576 | |||
577 | if (!cookie.found) { | ||
578 | _debug("%s: dirent not found", dentry->d_name.name); | ||
579 | goto not_found; | ||
580 | } | 618 | } |
581 | 619 | ||
582 | /* if the vnode ID has changed, then the dirent points to a | 620 | /* if the vnode ID has changed, then the dirent points to a |
583 | * different file */ | 621 | * different file */ |
584 | if (cookie.fid.vnode != AFS_FS_I(inode)->fid.vnode) { | 622 | if (fid.vnode != vnode->fid.vnode) { |
585 | _debug("%s: dirent changed", dentry->d_name.name); | 623 | _debug("%s: dirent changed [%u != %u]", |
624 | dentry->d_name.name, fid.vnode, | ||
625 | vnode->fid.vnode); | ||
586 | goto not_found; | 626 | goto not_found; |
587 | } | 627 | } |
588 | 628 | ||
589 | /* if the vnode ID uniqifier has changed, then the file has | 629 | /* if the vnode ID uniqifier has changed, then the file has |
590 | * been deleted */ | 630 | * been deleted and replaced, and the original vnode ID has |
591 | if (cookie.fid.unique != AFS_FS_I(inode)->fid.unique) { | 631 | * been reused */ |
632 | if (fid.unique != vnode->fid.unique) { | ||
592 | _debug("%s: file deleted (uq %u -> %u I:%lu)", | 633 | _debug("%s: file deleted (uq %u -> %u I:%lu)", |
593 | dentry->d_name.name, | 634 | dentry->d_name.name, fid.unique, |
594 | cookie.fid.unique, | 635 | vnode->fid.unique, dentry->d_inode->i_version); |
595 | AFS_FS_I(inode)->fid.unique, | 636 | spin_lock(&vnode->lock); |
596 | inode->i_version); | 637 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
597 | spin_lock(&AFS_FS_I(inode)->lock); | 638 | spin_unlock(&vnode->lock); |
598 | AFS_FS_I(inode)->flags |= AFS_VNODE_DELETED; | 639 | goto not_found; |
599 | spin_unlock(&AFS_FS_I(inode)->lock); | ||
600 | invalidate_remote_inode(inode); | ||
601 | goto out_bad; | ||
602 | } | 640 | } |
641 | goto out_valid; | ||
642 | |||
643 | case -ENOENT: | ||
644 | /* the filename is unknown */ | ||
645 | _debug("%s: dirent not found", dentry->d_name.name); | ||
646 | if (dentry->d_inode) | ||
647 | goto not_found; | ||
648 | goto out_valid; | ||
603 | 649 | ||
604 | dentry->d_fsdata = | 650 | default: |
605 | (void *) (unsigned long) AFS_FS_I(dir)->status.version; | 651 | _debug("failed to iterate dir %s: %d", |
652 | parent->d_name.name, ret); | ||
653 | goto out_bad; | ||
606 | } | 654 | } |
607 | 655 | ||
608 | out_valid: | 656 | out_valid: |
657 | dentry->d_fsdata = dir_version; | ||
658 | out_skip: | ||
609 | dput(parent); | 659 | dput(parent); |
660 | key_put(key); | ||
610 | _leave(" = 1 [valid]"); | 661 | _leave(" = 1 [valid]"); |
611 | return 1; | 662 | return 1; |
612 | 663 | ||
613 | /* the dirent, if it exists, now points to a different vnode */ | 664 | /* the dirent, if it exists, now points to a different vnode */ |
614 | not_found: | 665 | not_found: |
615 | spin_lock(&dentry->d_lock); | 666 | spin_lock(&dentry->d_lock); |
616 | dentry->d_flags |= DCACHE_NFSFS_RENAMED; | 667 | dentry->d_flags |= DCACHE_NFSFS_RENAMED; |
617 | spin_unlock(&dentry->d_lock); | 668 | spin_unlock(&dentry->d_lock); |
618 | 669 | ||
619 | out_bad: | 670 | out_bad: |
620 | if (inode) { | 671 | if (dentry->d_inode) { |
621 | /* don't unhash if we have submounts */ | 672 | /* don't unhash if we have submounts */ |
622 | if (have_submounts(dentry)) | 673 | if (have_submounts(dentry)) |
623 | goto out_valid; | 674 | goto out_skip; |
624 | } | 675 | } |
625 | 676 | ||
626 | shrink_dcache_parent(dentry); | ||
627 | |||
628 | _debug("dropping dentry %s/%s", | 677 | _debug("dropping dentry %s/%s", |
629 | dentry->d_parent->d_name.name, dentry->d_name.name); | 678 | parent->d_name.name, dentry->d_name.name); |
679 | shrink_dcache_parent(dentry); | ||
630 | d_drop(dentry); | 680 | d_drop(dentry); |
631 | |||
632 | dput(parent); | 681 | dput(parent); |
682 | key_put(key); | ||
633 | 683 | ||
634 | _leave(" = 0 [bad]"); | 684 | _leave(" = 0 [bad]"); |
635 | return 0; | 685 | return 0; |
636 | } /* end afs_d_revalidate() */ | 686 | } |
637 | 687 | ||
638 | /*****************************************************************************/ | ||
639 | /* | 688 | /* |
640 | * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't | 689 | * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't |
641 | * sleep) | 690 | * sleep) |
@@ -649,15 +698,444 @@ static int afs_d_delete(struct dentry *dentry) | |||
649 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) | 698 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) |
650 | goto zap; | 699 | goto zap; |
651 | 700 | ||
652 | if (dentry->d_inode) { | 701 | if (dentry->d_inode && |
653 | if (AFS_FS_I(dentry->d_inode)->flags & AFS_VNODE_DELETED) | 702 | test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags)) |
654 | goto zap; | 703 | goto zap; |
655 | } | ||
656 | 704 | ||
657 | _leave(" = 0 [keep]"); | 705 | _leave(" = 0 [keep]"); |
658 | return 0; | 706 | return 0; |
659 | 707 | ||
660 | zap: | 708 | zap: |
661 | _leave(" = 1 [zap]"); | 709 | _leave(" = 1 [zap]"); |
662 | return 1; | 710 | return 1; |
663 | } /* end afs_d_delete() */ | 711 | } |
712 | |||
713 | /* | ||
714 | * handle dentry release | ||
715 | */ | ||
716 | static void afs_d_release(struct dentry *dentry) | ||
717 | { | ||
718 | _enter("%s", dentry->d_name.name); | ||
719 | } | ||
720 | |||
721 | /* | ||
722 | * create a directory on an AFS filesystem | ||
723 | */ | ||
724 | static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | ||
725 | { | ||
726 | struct afs_file_status status; | ||
727 | struct afs_callback cb; | ||
728 | struct afs_server *server; | ||
729 | struct afs_vnode *dvnode, *vnode; | ||
730 | struct afs_fid fid; | ||
731 | struct inode *inode; | ||
732 | struct key *key; | ||
733 | int ret; | ||
734 | |||
735 | dvnode = AFS_FS_I(dir); | ||
736 | |||
737 | _enter("{%x:%d},{%s},%o", | ||
738 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | ||
739 | |||
740 | ret = -ENAMETOOLONG; | ||
741 | if (dentry->d_name.len > 255) | ||
742 | goto error; | ||
743 | |||
744 | key = afs_request_key(dvnode->volume->cell); | ||
745 | if (IS_ERR(key)) { | ||
746 | ret = PTR_ERR(key); | ||
747 | goto error; | ||
748 | } | ||
749 | |||
750 | mode |= S_IFDIR; | ||
751 | ret = afs_vnode_create(dvnode, key, dentry->d_name.name, | ||
752 | mode, &fid, &status, &cb, &server); | ||
753 | if (ret < 0) | ||
754 | goto mkdir_error; | ||
755 | |||
756 | inode = afs_iget(dir->i_sb, key, &fid, &status, &cb); | ||
757 | if (IS_ERR(inode)) { | ||
758 | /* ENOMEM at a really inconvenient time - just abandon the new | ||
759 | * directory on the server */ | ||
760 | ret = PTR_ERR(inode); | ||
761 | goto iget_error; | ||
762 | } | ||
763 | |||
764 | /* apply the status report we've got for the new vnode */ | ||
765 | vnode = AFS_FS_I(inode); | ||
766 | spin_lock(&vnode->lock); | ||
767 | vnode->update_cnt++; | ||
768 | spin_unlock(&vnode->lock); | ||
769 | afs_vnode_finalise_status_update(vnode, server); | ||
770 | afs_put_server(server); | ||
771 | |||
772 | d_instantiate(dentry, inode); | ||
773 | if (d_unhashed(dentry)) { | ||
774 | _debug("not hashed"); | ||
775 | d_rehash(dentry); | ||
776 | } | ||
777 | key_put(key); | ||
778 | _leave(" = 0"); | ||
779 | return 0; | ||
780 | |||
781 | iget_error: | ||
782 | afs_put_server(server); | ||
783 | mkdir_error: | ||
784 | key_put(key); | ||
785 | error: | ||
786 | d_drop(dentry); | ||
787 | _leave(" = %d", ret); | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | /* | ||
792 | * remove a directory from an AFS filesystem | ||
793 | */ | ||
794 | static int afs_rmdir(struct inode *dir, struct dentry *dentry) | ||
795 | { | ||
796 | struct afs_vnode *dvnode, *vnode; | ||
797 | struct key *key; | ||
798 | int ret; | ||
799 | |||
800 | dvnode = AFS_FS_I(dir); | ||
801 | |||
802 | _enter("{%x:%d},{%s}", | ||
803 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | ||
804 | |||
805 | ret = -ENAMETOOLONG; | ||
806 | if (dentry->d_name.len > 255) | ||
807 | goto error; | ||
808 | |||
809 | key = afs_request_key(dvnode->volume->cell); | ||
810 | if (IS_ERR(key)) { | ||
811 | ret = PTR_ERR(key); | ||
812 | goto error; | ||
813 | } | ||
814 | |||
815 | ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, true); | ||
816 | if (ret < 0) | ||
817 | goto rmdir_error; | ||
818 | |||
819 | if (dentry->d_inode) { | ||
820 | vnode = AFS_FS_I(dentry->d_inode); | ||
821 | clear_nlink(&vnode->vfs_inode); | ||
822 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | ||
823 | afs_discard_callback_on_delete(vnode); | ||
824 | } | ||
825 | |||
826 | key_put(key); | ||
827 | _leave(" = 0"); | ||
828 | return 0; | ||
829 | |||
830 | rmdir_error: | ||
831 | key_put(key); | ||
832 | error: | ||
833 | _leave(" = %d", ret); | ||
834 | return ret; | ||
835 | } | ||
836 | |||
837 | /* | ||
838 | * remove a file from an AFS filesystem | ||
839 | */ | ||
840 | static int afs_unlink(struct inode *dir, struct dentry *dentry) | ||
841 | { | ||
842 | struct afs_vnode *dvnode, *vnode; | ||
843 | struct key *key; | ||
844 | int ret; | ||
845 | |||
846 | dvnode = AFS_FS_I(dir); | ||
847 | |||
848 | _enter("{%x:%d},{%s}", | ||
849 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | ||
850 | |||
851 | ret = -ENAMETOOLONG; | ||
852 | if (dentry->d_name.len > 255) | ||
853 | goto error; | ||
854 | |||
855 | key = afs_request_key(dvnode->volume->cell); | ||
856 | if (IS_ERR(key)) { | ||
857 | ret = PTR_ERR(key); | ||
858 | goto error; | ||
859 | } | ||
860 | |||
861 | if (dentry->d_inode) { | ||
862 | vnode = AFS_FS_I(dentry->d_inode); | ||
863 | |||
864 | /* make sure we have a callback promise on the victim */ | ||
865 | ret = afs_validate(vnode, key); | ||
866 | if (ret < 0) | ||
867 | goto error; | ||
868 | } | ||
869 | |||
870 | ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, false); | ||
871 | if (ret < 0) | ||
872 | goto remove_error; | ||
873 | |||
874 | if (dentry->d_inode) { | ||
875 | /* if the file wasn't deleted due to excess hard links, the | ||
876 | * fileserver will break the callback promise on the file - if | ||
877 | * it had one - before it returns to us, and if it was deleted, | ||
878 | * it won't | ||
879 | * | ||
880 | * however, if we didn't have a callback promise outstanding, | ||
881 | * or it was outstanding on a different server, then it won't | ||
882 | * break it either... | ||
883 | */ | ||
884 | vnode = AFS_FS_I(dentry->d_inode); | ||
885 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) | ||
886 | _debug("AFS_VNODE_DELETED"); | ||
887 | if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) | ||
888 | _debug("AFS_VNODE_CB_BROKEN"); | ||
889 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | ||
890 | ret = afs_validate(vnode, key); | ||
891 | _debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, ret); | ||
892 | } | ||
893 | |||
894 | key_put(key); | ||
895 | _leave(" = 0"); | ||
896 | return 0; | ||
897 | |||
898 | remove_error: | ||
899 | key_put(key); | ||
900 | error: | ||
901 | _leave(" = %d", ret); | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | /* | ||
906 | * create a regular file on an AFS filesystem | ||
907 | */ | ||
908 | static int afs_create(struct inode *dir, struct dentry *dentry, int mode, | ||
909 | struct nameidata *nd) | ||
910 | { | ||
911 | struct afs_file_status status; | ||
912 | struct afs_callback cb; | ||
913 | struct afs_server *server; | ||
914 | struct afs_vnode *dvnode, *vnode; | ||
915 | struct afs_fid fid; | ||
916 | struct inode *inode; | ||
917 | struct key *key; | ||
918 | int ret; | ||
919 | |||
920 | dvnode = AFS_FS_I(dir); | ||
921 | |||
922 | _enter("{%x:%d},{%s},%o,", | ||
923 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | ||
924 | |||
925 | ret = -ENAMETOOLONG; | ||
926 | if (dentry->d_name.len > 255) | ||
927 | goto error; | ||
928 | |||
929 | key = afs_request_key(dvnode->volume->cell); | ||
930 | if (IS_ERR(key)) { | ||
931 | ret = PTR_ERR(key); | ||
932 | goto error; | ||
933 | } | ||
934 | |||
935 | mode |= S_IFREG; | ||
936 | ret = afs_vnode_create(dvnode, key, dentry->d_name.name, | ||
937 | mode, &fid, &status, &cb, &server); | ||
938 | if (ret < 0) | ||
939 | goto create_error; | ||
940 | |||
941 | inode = afs_iget(dir->i_sb, key, &fid, &status, &cb); | ||
942 | if (IS_ERR(inode)) { | ||
943 | /* ENOMEM at a really inconvenient time - just abandon the new | ||
944 | * directory on the server */ | ||
945 | ret = PTR_ERR(inode); | ||
946 | goto iget_error; | ||
947 | } | ||
948 | |||
949 | /* apply the status report we've got for the new vnode */ | ||
950 | vnode = AFS_FS_I(inode); | ||
951 | spin_lock(&vnode->lock); | ||
952 | vnode->update_cnt++; | ||
953 | spin_unlock(&vnode->lock); | ||
954 | afs_vnode_finalise_status_update(vnode, server); | ||
955 | afs_put_server(server); | ||
956 | |||
957 | d_instantiate(dentry, inode); | ||
958 | if (d_unhashed(dentry)) { | ||
959 | _debug("not hashed"); | ||
960 | d_rehash(dentry); | ||
961 | } | ||
962 | key_put(key); | ||
963 | _leave(" = 0"); | ||
964 | return 0; | ||
965 | |||
966 | iget_error: | ||
967 | afs_put_server(server); | ||
968 | create_error: | ||
969 | key_put(key); | ||
970 | error: | ||
971 | d_drop(dentry); | ||
972 | _leave(" = %d", ret); | ||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | /* | ||
977 | * create a hard link between files in an AFS filesystem | ||
978 | */ | ||
979 | static int afs_link(struct dentry *from, struct inode *dir, | ||
980 | struct dentry *dentry) | ||
981 | { | ||
982 | struct afs_vnode *dvnode, *vnode; | ||
983 | struct key *key; | ||
984 | int ret; | ||
985 | |||
986 | vnode = AFS_FS_I(from->d_inode); | ||
987 | dvnode = AFS_FS_I(dir); | ||
988 | |||
989 | _enter("{%x:%d},{%x:%d},{%s}", | ||
990 | vnode->fid.vid, vnode->fid.vnode, | ||
991 | dvnode->fid.vid, dvnode->fid.vnode, | ||
992 | dentry->d_name.name); | ||
993 | |||
994 | ret = -ENAMETOOLONG; | ||
995 | if (dentry->d_name.len > 255) | ||
996 | goto error; | ||
997 | |||
998 | key = afs_request_key(dvnode->volume->cell); | ||
999 | if (IS_ERR(key)) { | ||
1000 | ret = PTR_ERR(key); | ||
1001 | goto error; | ||
1002 | } | ||
1003 | |||
1004 | ret = afs_vnode_link(dvnode, vnode, key, dentry->d_name.name); | ||
1005 | if (ret < 0) | ||
1006 | goto link_error; | ||
1007 | |||
1008 | atomic_inc(&vnode->vfs_inode.i_count); | ||
1009 | d_instantiate(dentry, &vnode->vfs_inode); | ||
1010 | key_put(key); | ||
1011 | _leave(" = 0"); | ||
1012 | return 0; | ||
1013 | |||
1014 | link_error: | ||
1015 | key_put(key); | ||
1016 | error: | ||
1017 | d_drop(dentry); | ||
1018 | _leave(" = %d", ret); | ||
1019 | return ret; | ||
1020 | } | ||
1021 | |||
1022 | /* | ||
1023 | * create a symlink in an AFS filesystem | ||
1024 | */ | ||
1025 | static int afs_symlink(struct inode *dir, struct dentry *dentry, | ||
1026 | const char *content) | ||
1027 | { | ||
1028 | struct afs_file_status status; | ||
1029 | struct afs_server *server; | ||
1030 | struct afs_vnode *dvnode, *vnode; | ||
1031 | struct afs_fid fid; | ||
1032 | struct inode *inode; | ||
1033 | struct key *key; | ||
1034 | int ret; | ||
1035 | |||
1036 | dvnode = AFS_FS_I(dir); | ||
1037 | |||
1038 | _enter("{%x:%d},{%s},%s", | ||
1039 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, | ||
1040 | content); | ||
1041 | |||
1042 | ret = -ENAMETOOLONG; | ||
1043 | if (dentry->d_name.len > 255) | ||
1044 | goto error; | ||
1045 | |||
1046 | ret = -EINVAL; | ||
1047 | if (strlen(content) > 1023) | ||
1048 | goto error; | ||
1049 | |||
1050 | key = afs_request_key(dvnode->volume->cell); | ||
1051 | if (IS_ERR(key)) { | ||
1052 | ret = PTR_ERR(key); | ||
1053 | goto error; | ||
1054 | } | ||
1055 | |||
1056 | ret = afs_vnode_symlink(dvnode, key, dentry->d_name.name, content, | ||
1057 | &fid, &status, &server); | ||
1058 | if (ret < 0) | ||
1059 | goto create_error; | ||
1060 | |||
1061 | inode = afs_iget(dir->i_sb, key, &fid, &status, NULL); | ||
1062 | if (IS_ERR(inode)) { | ||
1063 | /* ENOMEM at a really inconvenient time - just abandon the new | ||
1064 | * directory on the server */ | ||
1065 | ret = PTR_ERR(inode); | ||
1066 | goto iget_error; | ||
1067 | } | ||
1068 | |||
1069 | /* apply the status report we've got for the new vnode */ | ||
1070 | vnode = AFS_FS_I(inode); | ||
1071 | spin_lock(&vnode->lock); | ||
1072 | vnode->update_cnt++; | ||
1073 | spin_unlock(&vnode->lock); | ||
1074 | afs_vnode_finalise_status_update(vnode, server); | ||
1075 | afs_put_server(server); | ||
1076 | |||
1077 | d_instantiate(dentry, inode); | ||
1078 | if (d_unhashed(dentry)) { | ||
1079 | _debug("not hashed"); | ||
1080 | d_rehash(dentry); | ||
1081 | } | ||
1082 | key_put(key); | ||
1083 | _leave(" = 0"); | ||
1084 | return 0; | ||
1085 | |||
1086 | iget_error: | ||
1087 | afs_put_server(server); | ||
1088 | create_error: | ||
1089 | key_put(key); | ||
1090 | error: | ||
1091 | d_drop(dentry); | ||
1092 | _leave(" = %d", ret); | ||
1093 | return ret; | ||
1094 | } | ||
1095 | |||
1096 | /* | ||
1097 | * rename a file in an AFS filesystem and/or move it between directories | ||
1098 | */ | ||
1099 | static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | ||
1100 | struct inode *new_dir, struct dentry *new_dentry) | ||
1101 | { | ||
1102 | struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; | ||
1103 | struct key *key; | ||
1104 | int ret; | ||
1105 | |||
1106 | vnode = AFS_FS_I(old_dentry->d_inode); | ||
1107 | orig_dvnode = AFS_FS_I(old_dir); | ||
1108 | new_dvnode = AFS_FS_I(new_dir); | ||
1109 | |||
1110 | _enter("{%x:%d},{%x:%d},{%x:%d},{%s}", | ||
1111 | orig_dvnode->fid.vid, orig_dvnode->fid.vnode, | ||
1112 | vnode->fid.vid, vnode->fid.vnode, | ||
1113 | new_dvnode->fid.vid, new_dvnode->fid.vnode, | ||
1114 | new_dentry->d_name.name); | ||
1115 | |||
1116 | ret = -ENAMETOOLONG; | ||
1117 | if (new_dentry->d_name.len > 255) | ||
1118 | goto error; | ||
1119 | |||
1120 | key = afs_request_key(orig_dvnode->volume->cell); | ||
1121 | if (IS_ERR(key)) { | ||
1122 | ret = PTR_ERR(key); | ||
1123 | goto error; | ||
1124 | } | ||
1125 | |||
1126 | ret = afs_vnode_rename(orig_dvnode, new_dvnode, key, | ||
1127 | old_dentry->d_name.name, | ||
1128 | new_dentry->d_name.name); | ||
1129 | if (ret < 0) | ||
1130 | goto rename_error; | ||
1131 | key_put(key); | ||
1132 | _leave(" = 0"); | ||
1133 | return 0; | ||
1134 | |||
1135 | rename_error: | ||
1136 | key_put(key); | ||
1137 | error: | ||
1138 | d_drop(new_dentry); | ||
1139 | _leave(" = %d", ret); | ||
1140 | return ret; | ||
1141 | } | ||
diff --git a/fs/afs/errors.h b/fs/afs/errors.h deleted file mode 100644 index 574d94ac8d05..000000000000 --- a/fs/afs/errors.h +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | /* errors.h: AFS abort/error codes | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_ERRORS_H | ||
13 | #define _LINUX_AFS_ERRORS_H | ||
14 | |||
15 | #include "types.h" | ||
16 | |||
17 | /* file server abort codes */ | ||
18 | typedef enum { | ||
19 | VSALVAGE = 101, /* volume needs salvaging */ | ||
20 | VNOVNODE = 102, /* no such file/dir (vnode) */ | ||
21 | VNOVOL = 103, /* no such volume or volume unavailable */ | ||
22 | VVOLEXISTS = 104, /* volume name already exists */ | ||
23 | VNOSERVICE = 105, /* volume not currently in service */ | ||
24 | VOFFLINE = 106, /* volume is currently offline (more info available [VVL-spec]) */ | ||
25 | VONLINE = 107, /* volume is already online */ | ||
26 | VDISKFULL = 108, /* disk partition is full */ | ||
27 | VOVERQUOTA = 109, /* volume's maximum quota exceeded */ | ||
28 | VBUSY = 110, /* volume is temporarily unavailable */ | ||
29 | VMOVED = 111, /* volume moved to new server - ask this FS where */ | ||
30 | } afs_rxfs_abort_t; | ||
31 | |||
32 | extern int afs_abort_to_error(int abortcode); | ||
33 | |||
34 | #endif /* _LINUX_AFS_ERRORS_H */ | ||
diff --git a/fs/afs/file.c b/fs/afs/file.c index b17634541f67..ae256498f4f7 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* file.c: AFS filesystem file handling | 1 | /* AFS filesystem file handling |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -15,22 +15,25 @@ | |||
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 "volume.h" | ||
19 | #include "vnode.h" | ||
20 | #include <rxrpc/call.h> | ||
21 | #include "internal.h" | 18 | #include "internal.h" |
22 | 19 | ||
23 | #if 0 | ||
24 | static int afs_file_open(struct inode *inode, struct file *file); | ||
25 | static int afs_file_release(struct inode *inode, struct file *file); | ||
26 | #endif | ||
27 | |||
28 | static int afs_file_readpage(struct file *file, struct page *page); | 20 | static int afs_file_readpage(struct file *file, struct page *page); |
29 | static void afs_file_invalidatepage(struct page *page, unsigned long offset); | 21 | static void afs_file_invalidatepage(struct page *page, unsigned long offset); |
30 | 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); |
31 | 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 | |||
32 | const struct inode_operations afs_file_inode_operations = { | 34 | const struct inode_operations afs_file_inode_operations = { |
33 | .getattr = afs_inode_getattr, | 35 | .getattr = afs_inode_getattr, |
36 | .permission = afs_permission, | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | const struct address_space_operations afs_fs_aops = { | 39 | const struct address_space_operations afs_fs_aops = { |
@@ -40,7 +43,48 @@ const struct address_space_operations afs_fs_aops = { | |||
40 | .invalidatepage = afs_file_invalidatepage, | 43 | .invalidatepage = afs_file_invalidatepage, |
41 | }; | 44 | }; |
42 | 45 | ||
43 | /*****************************************************************************/ | 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 | int ret; | ||
54 | |||
55 | _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); | ||
56 | |||
57 | key = afs_request_key(vnode->volume->cell); | ||
58 | if (IS_ERR(key)) { | ||
59 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
60 | return PTR_ERR(key); | ||
61 | } | ||
62 | |||
63 | ret = afs_validate(vnode, key); | ||
64 | if (ret < 0) { | ||
65 | _leave(" = %d [val]", ret); | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | file->private_data = key; | ||
70 | _leave(" = 0"); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * release an AFS file or directory and discard its key | ||
76 | */ | ||
77 | int afs_release(struct inode *inode, struct file *file) | ||
78 | { | ||
79 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
80 | |||
81 | _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); | ||
82 | |||
83 | key_put(file->private_data); | ||
84 | _leave(" = 0"); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
44 | /* | 88 | /* |
45 | * deal with notification that a page was read from the cache | 89 | * deal with notification that a page was read from the cache |
46 | */ | 90 | */ |
@@ -58,10 +102,9 @@ static void afs_file_readpage_read_complete(void *cookie_data, | |||
58 | SetPageUptodate(page); | 102 | SetPageUptodate(page); |
59 | unlock_page(page); | 103 | unlock_page(page); |
60 | 104 | ||
61 | } /* end afs_file_readpage_read_complete() */ | 105 | } |
62 | #endif | 106 | #endif |
63 | 107 | ||
64 | /*****************************************************************************/ | ||
65 | /* | 108 | /* |
66 | * deal with notification that a page was written to the cache | 109 | * deal with notification that a page was written to the cache |
67 | */ | 110 | */ |
@@ -74,41 +117,38 @@ static void afs_file_readpage_write_complete(void *cookie_data, | |||
74 | _enter("%p,%p,%p,%d", cookie_data, page, data, error); | 117 | _enter("%p,%p,%p,%d", cookie_data, page, data, error); |
75 | 118 | ||
76 | unlock_page(page); | 119 | unlock_page(page); |
77 | 120 | } | |
78 | } /* end afs_file_readpage_write_complete() */ | ||
79 | #endif | 121 | #endif |
80 | 122 | ||
81 | /*****************************************************************************/ | ||
82 | /* | 123 | /* |
83 | * AFS read page from file (or symlink) | 124 | * AFS read page from file (or symlink) |
84 | */ | 125 | */ |
85 | static int afs_file_readpage(struct file *file, struct page *page) | 126 | static int afs_file_readpage(struct file *file, struct page *page) |
86 | { | 127 | { |
87 | struct afs_rxfs_fetch_descriptor desc; | ||
88 | #ifdef AFS_CACHING_SUPPORT | ||
89 | struct cachefs_page *pageio; | ||
90 | #endif | ||
91 | struct afs_vnode *vnode; | 128 | struct afs_vnode *vnode; |
92 | struct inode *inode; | 129 | struct inode *inode; |
130 | struct key *key; | ||
131 | size_t len; | ||
132 | off_t offset; | ||
93 | int ret; | 133 | int ret; |
94 | 134 | ||
95 | inode = page->mapping->host; | 135 | inode = page->mapping->host; |
96 | 136 | ||
97 | _enter("{%lu},{%lu}", inode->i_ino, page->index); | 137 | ASSERT(file != NULL); |
138 | key = file->private_data; | ||
139 | ASSERT(key != NULL); | ||
140 | |||
141 | _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); | ||
98 | 142 | ||
99 | vnode = AFS_FS_I(inode); | 143 | vnode = AFS_FS_I(inode); |
100 | 144 | ||
101 | BUG_ON(!PageLocked(page)); | 145 | BUG_ON(!PageLocked(page)); |
102 | 146 | ||
103 | ret = -ESTALE; | 147 | ret = -ESTALE; |
104 | if (vnode->flags & AFS_VNODE_DELETED) | 148 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
105 | goto error; | 149 | goto error; |
106 | 150 | ||
107 | #ifdef AFS_CACHING_SUPPORT | 151 | #ifdef AFS_CACHING_SUPPORT |
108 | ret = cachefs_page_get_private(page, &pageio, GFP_NOIO); | ||
109 | if (ret < 0) | ||
110 | goto error; | ||
111 | |||
112 | /* is it cached? */ | 152 | /* is it cached? */ |
113 | ret = cachefs_read_or_alloc_page(vnode->cache, | 153 | ret = cachefs_read_or_alloc_page(vnode->cache, |
114 | page, | 154 | page, |
@@ -132,26 +172,19 @@ static int afs_file_readpage(struct file *file, struct page *page) | |||
132 | case -ENOBUFS: | 172 | case -ENOBUFS: |
133 | case -ENODATA: | 173 | case -ENODATA: |
134 | default: | 174 | default: |
135 | desc.fid = vnode->fid; | 175 | offset = page->index << PAGE_CACHE_SHIFT; |
136 | desc.offset = page->index << PAGE_CACHE_SHIFT; | 176 | len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); |
137 | desc.size = min((size_t) (inode->i_size - desc.offset), | ||
138 | (size_t) PAGE_SIZE); | ||
139 | desc.buffer = kmap(page); | ||
140 | |||
141 | clear_page(desc.buffer); | ||
142 | 177 | ||
143 | /* read the contents of the file from the server into the | 178 | /* read the contents of the file from the server into the |
144 | * page */ | 179 | * page */ |
145 | ret = afs_vnode_fetch_data(vnode, &desc); | 180 | ret = afs_vnode_fetch_data(vnode, key, offset, len, page); |
146 | kunmap(page); | ||
147 | if (ret < 0) { | 181 | if (ret < 0) { |
148 | if (ret==-ENOENT) { | 182 | if (ret == -ENOENT) { |
149 | _debug("got NOENT from server" | 183 | _debug("got NOENT from server" |
150 | " - marking file deleted and stale"); | 184 | " - marking file deleted and stale"); |
151 | vnode->flags |= AFS_VNODE_DELETED; | 185 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
152 | ret = -ESTALE; | 186 | ret = -ESTALE; |
153 | } | 187 | } |
154 | |||
155 | #ifdef AFS_CACHING_SUPPORT | 188 | #ifdef AFS_CACHING_SUPPORT |
156 | cachefs_uncache_page(vnode->cache, page); | 189 | cachefs_uncache_page(vnode->cache, page); |
157 | #endif | 190 | #endif |
@@ -178,16 +211,13 @@ static int afs_file_readpage(struct file *file, struct page *page) | |||
178 | _leave(" = 0"); | 211 | _leave(" = 0"); |
179 | return 0; | 212 | return 0; |
180 | 213 | ||
181 | error: | 214 | error: |
182 | SetPageError(page); | 215 | SetPageError(page); |
183 | unlock_page(page); | 216 | unlock_page(page); |
184 | |||
185 | _leave(" = %d", ret); | 217 | _leave(" = %d", ret); |
186 | return ret; | 218 | return ret; |
219 | } | ||
187 | 220 | ||
188 | } /* end afs_file_readpage() */ | ||
189 | |||
190 | /*****************************************************************************/ | ||
191 | /* | 221 | /* |
192 | * get a page cookie for the specified page | 222 | * get a page cookie for the specified page |
193 | */ | 223 | */ |
@@ -202,10 +232,9 @@ int afs_cache_get_page_cookie(struct page *page, | |||
202 | 232 | ||
203 | _leave(" = %d", ret); | 233 | _leave(" = %d", ret); |
204 | return ret; | 234 | return ret; |
205 | } /* end afs_cache_get_page_cookie() */ | 235 | } |
206 | #endif | 236 | #endif |
207 | 237 | ||
208 | /*****************************************************************************/ | ||
209 | /* | 238 | /* |
210 | * invalidate part or all of a page | 239 | * invalidate part or all of a page |
211 | */ | 240 | */ |
@@ -240,9 +269,8 @@ static void afs_file_invalidatepage(struct page *page, unsigned long offset) | |||
240 | } | 269 | } |
241 | 270 | ||
242 | _leave(" = %d", ret); | 271 | _leave(" = %d", ret); |
243 | } /* end afs_file_invalidatepage() */ | 272 | } |
244 | 273 | ||
245 | /*****************************************************************************/ | ||
246 | /* | 274 | /* |
247 | * release a page and cleanup its private data | 275 | * release a page and cleanup its private data |
248 | */ | 276 | */ |
@@ -267,4 +295,4 @@ static int afs_file_releasepage(struct page *page, gfp_t gfp_flags) | |||
267 | 295 | ||
268 | _leave(" = 0"); | 296 | _leave(" = 0"); |
269 | return 0; | 297 | return 0; |
270 | } /* end afs_file_releasepage() */ | 298 | } |
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 61bc371532ab..2393d2a08d79 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* fsclient.c: AFS File Server client stubs | 1 | /* AFS File Server client stubs |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -11,827 +11,927 @@ | |||
11 | 11 | ||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <rxrpc/rxrpc.h> | 14 | #include <linux/circ_buf.h> |
15 | #include <rxrpc/transport.h> | ||
16 | #include <rxrpc/connection.h> | ||
17 | #include <rxrpc/call.h> | ||
18 | #include "fsclient.h" | ||
19 | #include "cmservice.h" | ||
20 | #include "vnode.h" | ||
21 | #include "server.h" | ||
22 | #include "errors.h" | ||
23 | #include "internal.h" | 15 | #include "internal.h" |
16 | #include "afs_fs.h" | ||
24 | 17 | ||
25 | #define FSFETCHSTATUS 132 /* AFS Fetch file status */ | ||
26 | #define FSFETCHDATA 130 /* AFS Fetch file data */ | ||
27 | #define FSGIVEUPCALLBACKS 147 /* AFS Discard callback promises */ | ||
28 | #define FSGETVOLUMEINFO 148 /* AFS Get root volume information */ | ||
29 | #define FSGETROOTVOLUME 151 /* AFS Get root volume name */ | ||
30 | #define FSLOOKUP 161 /* AFS lookup file in directory */ | ||
31 | |||
32 | /*****************************************************************************/ | ||
33 | /* | 18 | /* |
34 | * map afs abort codes to/from Linux error codes | 19 | * decode an AFSFid block |
35 | * - called with call->lock held | ||
36 | */ | 20 | */ |
37 | static void afs_rxfs_aemap(struct rxrpc_call *call) | 21 | static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) |
38 | { | 22 | { |
39 | switch (call->app_err_state) { | 23 | const __be32 *bp = *_bp; |
40 | case RXRPC_ESTATE_LOCAL_ABORT: | 24 | |
41 | call->app_abort_code = -call->app_errno; | 25 | fid->vid = ntohl(*bp++); |
42 | break; | 26 | fid->vnode = ntohl(*bp++); |
43 | case RXRPC_ESTATE_PEER_ABORT: | 27 | fid->unique = ntohl(*bp++); |
44 | call->app_errno = afs_abort_to_error(call->app_abort_code); | 28 | *_bp = bp; |
45 | break; | 29 | } |
46 | default: | ||
47 | break; | ||
48 | } | ||
49 | } /* end afs_rxfs_aemap() */ | ||
50 | 30 | ||
51 | /*****************************************************************************/ | ||
52 | /* | 31 | /* |
53 | * get the root volume name from a fileserver | 32 | * decode an AFSFetchStatus block |
54 | * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2 | ||
55 | */ | 33 | */ |
56 | #if 0 | 34 | static void xdr_decode_AFSFetchStatus(const __be32 **_bp, |
57 | int afs_rxfs_get_root_volume(struct afs_server *server, | 35 | struct afs_file_status *status, |
58 | char *buf, size_t *buflen) | 36 | struct afs_vnode *vnode) |
59 | { | 37 | { |
60 | struct rxrpc_connection *conn; | 38 | const __be32 *bp = *_bp; |
61 | struct rxrpc_call *call; | 39 | umode_t mode; |
62 | struct kvec piov[2]; | 40 | u64 data_version, size; |
63 | size_t sent; | 41 | u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ |
64 | int ret; | 42 | |
65 | u32 param[1]; | 43 | #define EXTRACT(DST) \ |
44 | do { \ | ||
45 | u32 x = ntohl(*bp++); \ | ||
46 | changed |= DST - x; \ | ||
47 | DST = x; \ | ||
48 | } while (0) | ||
49 | |||
50 | status->if_version = ntohl(*bp++); | ||
51 | EXTRACT(status->type); | ||
52 | EXTRACT(status->nlink); | ||
53 | size = ntohl(*bp++); | ||
54 | data_version = ntohl(*bp++); | ||
55 | EXTRACT(status->author); | ||
56 | EXTRACT(status->owner); | ||
57 | EXTRACT(status->caller_access); /* call ticket dependent */ | ||
58 | EXTRACT(status->anon_access); | ||
59 | EXTRACT(status->mode); | ||
60 | EXTRACT(status->parent.vnode); | ||
61 | EXTRACT(status->parent.unique); | ||
62 | bp++; /* seg size */ | ||
63 | status->mtime_client = ntohl(*bp++); | ||
64 | status->mtime_server = ntohl(*bp++); | ||
65 | EXTRACT(status->group); | ||
66 | bp++; /* sync counter */ | ||
67 | data_version |= (u64) ntohl(*bp++) << 32; | ||
68 | bp++; /* lock count */ | ||
69 | size |= (u64) ntohl(*bp++) << 32; | ||
70 | bp++; /* spare 4 */ | ||
71 | *_bp = bp; | ||
72 | |||
73 | if (size != status->size) { | ||
74 | status->size = size; | ||
75 | changed |= true; | ||
76 | } | ||
77 | status->mode &= S_IALLUGO; | ||
78 | |||
79 | _debug("vnode time %lx, %lx", | ||
80 | status->mtime_client, status->mtime_server); | ||
81 | |||
82 | if (vnode) { | ||
83 | status->parent.vid = vnode->fid.vid; | ||
84 | if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | ||
85 | _debug("vnode changed"); | ||
86 | i_size_write(&vnode->vfs_inode, size); | ||
87 | vnode->vfs_inode.i_uid = status->owner; | ||
88 | vnode->vfs_inode.i_gid = status->group; | ||
89 | vnode->vfs_inode.i_version = vnode->fid.unique; | ||
90 | vnode->vfs_inode.i_nlink = status->nlink; | ||
91 | |||
92 | mode = vnode->vfs_inode.i_mode; | ||
93 | mode &= ~S_IALLUGO; | ||
94 | mode |= status->mode; | ||
95 | barrier(); | ||
96 | vnode->vfs_inode.i_mode = mode; | ||
97 | } | ||
66 | 98 | ||
67 | DECLARE_WAITQUEUE(myself, current); | 99 | vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server; |
100 | vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; | ||
101 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; | ||
102 | } | ||
68 | 103 | ||
69 | kenter("%p,%p,%u",server, buf, *buflen); | 104 | if (status->data_version != data_version) { |
105 | status->data_version = data_version; | ||
106 | if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | ||
107 | _debug("vnode modified %llx on {%x:%u}", | ||
108 | (unsigned long long) data_version, | ||
109 | vnode->fid.vid, vnode->fid.vnode); | ||
110 | set_bit(AFS_VNODE_MODIFIED, &vnode->flags); | ||
111 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | ||
112 | } | ||
113 | } | ||
114 | } | ||
70 | 115 | ||
71 | /* get hold of the fileserver connection */ | 116 | /* |
72 | ret = afs_server_get_fsconn(server, &conn); | 117 | * decode an AFSCallBack block |
73 | if (ret < 0) | 118 | */ |
74 | goto out; | 119 | static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode) |
120 | { | ||
121 | const __be32 *bp = *_bp; | ||
75 | 122 | ||
76 | /* create a call through that connection */ | 123 | vnode->cb_version = ntohl(*bp++); |
77 | ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call); | 124 | vnode->cb_expiry = ntohl(*bp++); |
78 | if (ret < 0) { | 125 | vnode->cb_type = ntohl(*bp++); |
79 | printk("kAFS: Unable to create call: %d\n", ret); | 126 | vnode->cb_expires = vnode->cb_expiry + get_seconds(); |
80 | goto out_put_conn; | 127 | *_bp = bp; |
81 | } | 128 | } |
82 | call->app_opcode = FSGETROOTVOLUME; | ||
83 | 129 | ||
84 | /* we want to get event notifications from the call */ | 130 | static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, |
85 | add_wait_queue(&call->waitq, &myself); | 131 | struct afs_callback *cb) |
132 | { | ||
133 | const __be32 *bp = *_bp; | ||
86 | 134 | ||
87 | /* marshall the parameters */ | 135 | cb->version = ntohl(*bp++); |
88 | param[0] = htonl(FSGETROOTVOLUME); | 136 | cb->expiry = ntohl(*bp++); |
89 | 137 | cb->type = ntohl(*bp++); | |
90 | piov[0].iov_len = sizeof(param); | 138 | *_bp = bp; |
91 | piov[0].iov_base = param; | 139 | } |
92 | |||
93 | /* send the parameters to the server */ | ||
94 | ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS, | ||
95 | 0, &sent); | ||
96 | if (ret < 0) | ||
97 | goto abort; | ||
98 | |||
99 | /* wait for the reply to completely arrive */ | ||
100 | for (;;) { | ||
101 | set_current_state(TASK_INTERRUPTIBLE); | ||
102 | if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY || | ||
103 | signal_pending(current)) | ||
104 | break; | ||
105 | schedule(); | ||
106 | } | ||
107 | set_current_state(TASK_RUNNING); | ||
108 | 140 | ||
109 | ret = -EINTR; | 141 | /* |
110 | if (signal_pending(current)) | 142 | * decode an AFSVolSync block |
111 | goto abort; | 143 | */ |
144 | static void xdr_decode_AFSVolSync(const __be32 **_bp, | ||
145 | struct afs_volsync *volsync) | ||
146 | { | ||
147 | const __be32 *bp = *_bp; | ||
112 | 148 | ||
113 | switch (call->app_call_state) { | 149 | volsync->creation = ntohl(*bp++); |
114 | case RXRPC_CSTATE_ERROR: | 150 | bp++; /* spare2 */ |
115 | ret = call->app_errno; | 151 | bp++; /* spare3 */ |
116 | kdebug("Got Error: %d", ret); | 152 | bp++; /* spare4 */ |
117 | goto out_unwait; | 153 | bp++; /* spare5 */ |
154 | bp++; /* spare6 */ | ||
155 | *_bp = bp; | ||
156 | } | ||
118 | 157 | ||
119 | case RXRPC_CSTATE_CLNT_GOT_REPLY: | 158 | /* |
120 | /* read the reply */ | 159 | * deliver reply data to an FS.FetchStatus |
121 | kdebug("Got Reply: qty=%d", call->app_ready_qty); | 160 | */ |
161 | static int afs_deliver_fs_fetch_status(struct afs_call *call, | ||
162 | struct sk_buff *skb, bool last) | ||
163 | { | ||
164 | struct afs_vnode *vnode = call->reply; | ||
165 | const __be32 *bp; | ||
122 | 166 | ||
123 | ret = -EBADMSG; | 167 | _enter(",,%u", last); |
124 | if (call->app_ready_qty <= 4) | ||
125 | goto abort; | ||
126 | 168 | ||
127 | ret = rxrpc_call_read_data(call, NULL, call->app_ready_qty, 0); | 169 | afs_transfer_reply(call, skb); |
128 | if (ret < 0) | 170 | if (!last) |
129 | goto abort; | 171 | return 0; |
130 | 172 | ||
131 | #if 0 | 173 | if (call->reply_size != call->reply_max) |
132 | /* unmarshall the reply */ | 174 | return -EBADMSG; |
133 | bp = buffer; | ||
134 | for (loop = 0; loop < 65; loop++) | ||
135 | entry->name[loop] = ntohl(*bp++); | ||
136 | entry->name[64] = 0; | ||
137 | 175 | ||
138 | entry->type = ntohl(*bp++); | 176 | /* unmarshall the reply once we've received all of it */ |
139 | entry->num_servers = ntohl(*bp++); | 177 | bp = call->buffer; |
178 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
179 | xdr_decode_AFSCallBack(&bp, vnode); | ||
180 | if (call->reply2) | ||
181 | xdr_decode_AFSVolSync(&bp, call->reply2); | ||
140 | 182 | ||
141 | for (loop = 0; loop < 8; loop++) | 183 | _leave(" = 0 [done]"); |
142 | entry->servers[loop].addr.s_addr = *bp++; | 184 | return 0; |
185 | } | ||
143 | 186 | ||
144 | for (loop = 0; loop < 8; loop++) | 187 | /* |
145 | entry->servers[loop].partition = ntohl(*bp++); | 188 | * FS.FetchStatus operation type |
189 | */ | ||
190 | static const struct afs_call_type afs_RXFSFetchStatus = { | ||
191 | .name = "FS.FetchStatus", | ||
192 | .deliver = afs_deliver_fs_fetch_status, | ||
193 | .abort_to_error = afs_abort_to_error, | ||
194 | .destructor = afs_flat_call_destructor, | ||
195 | }; | ||
146 | 196 | ||
147 | for (loop = 0; loop < 8; loop++) | 197 | /* |
148 | entry->servers[loop].flags = ntohl(*bp++); | 198 | * fetch the status information for a file |
199 | */ | ||
200 | int afs_fs_fetch_file_status(struct afs_server *server, | ||
201 | struct key *key, | ||
202 | struct afs_vnode *vnode, | ||
203 | struct afs_volsync *volsync, | ||
204 | const struct afs_wait_mode *wait_mode) | ||
205 | { | ||
206 | struct afs_call *call; | ||
207 | __be32 *bp; | ||
149 | 208 | ||
150 | for (loop = 0; loop < 3; loop++) | 209 | _enter(",%x,{%x:%d},,", |
151 | entry->volume_ids[loop] = ntohl(*bp++); | 210 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); |
152 | 211 | ||
153 | entry->clone_id = ntohl(*bp++); | 212 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); |
154 | entry->flags = ntohl(*bp); | 213 | if (!call) |
155 | #endif | 214 | return -ENOMEM; |
156 | 215 | ||
157 | /* success */ | 216 | call->key = key; |
158 | ret = 0; | 217 | call->reply = vnode; |
159 | goto out_unwait; | 218 | call->reply2 = volsync; |
219 | call->service_id = FS_SERVICE; | ||
220 | call->port = htons(AFS_FS_PORT); | ||
160 | 221 | ||
161 | default: | 222 | /* marshall the parameters */ |
162 | BUG(); | 223 | bp = call->request; |
163 | } | 224 | bp[0] = htonl(FSFETCHSTATUS); |
225 | bp[1] = htonl(vnode->fid.vid); | ||
226 | bp[2] = htonl(vnode->fid.vnode); | ||
227 | bp[3] = htonl(vnode->fid.unique); | ||
228 | |||
229 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
230 | } | ||
164 | 231 | ||
165 | abort: | ||
166 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
167 | rxrpc_call_abort(call, ret); | ||
168 | schedule(); | ||
169 | out_unwait: | ||
170 | set_current_state(TASK_RUNNING); | ||
171 | remove_wait_queue(&call->waitq, &myself); | ||
172 | rxrpc_put_call(call); | ||
173 | out_put_conn: | ||
174 | afs_server_release_fsconn(server, conn); | ||
175 | out: | ||
176 | kleave(""); | ||
177 | return ret; | ||
178 | } /* end afs_rxfs_get_root_volume() */ | ||
179 | #endif | ||
180 | |||
181 | /*****************************************************************************/ | ||
182 | /* | 232 | /* |
183 | * get information about a volume | 233 | * deliver reply data to an FS.FetchData |
184 | */ | 234 | */ |
185 | #if 0 | 235 | static int afs_deliver_fs_fetch_data(struct afs_call *call, |
186 | int afs_rxfs_get_volume_info(struct afs_server *server, | 236 | struct sk_buff *skb, bool last) |
187 | const char *name, | ||
188 | struct afs_volume_info *vinfo) | ||
189 | { | 237 | { |
190 | struct rxrpc_connection *conn; | 238 | struct afs_vnode *vnode = call->reply; |
191 | struct rxrpc_call *call; | 239 | const __be32 *bp; |
192 | struct kvec piov[3]; | 240 | struct page *page; |
193 | size_t sent; | 241 | void *buffer; |
194 | int ret; | 242 | int ret; |
195 | u32 param[2], *bp, zero; | ||
196 | 243 | ||
197 | DECLARE_WAITQUEUE(myself, current); | 244 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); |
245 | |||
246 | switch (call->unmarshall) { | ||
247 | case 0: | ||
248 | call->offset = 0; | ||
249 | call->unmarshall++; | ||
250 | |||
251 | /* extract the returned data length */ | ||
252 | case 1: | ||
253 | _debug("extract data length"); | ||
254 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
255 | switch (ret) { | ||
256 | case 0: break; | ||
257 | case -EAGAIN: return 0; | ||
258 | default: return ret; | ||
259 | } | ||
198 | 260 | ||
199 | _enter("%p,%s,%p", server, name, vinfo); | 261 | call->count = ntohl(call->tmp); |
262 | _debug("DATA length: %u", call->count); | ||
263 | if (call->count > PAGE_SIZE) | ||
264 | return -EBADMSG; | ||
265 | call->offset = 0; | ||
266 | call->unmarshall++; | ||
267 | |||
268 | if (call->count < PAGE_SIZE) { | ||
269 | buffer = kmap_atomic(call->reply3, KM_USER0); | ||
270 | memset(buffer + PAGE_SIZE - call->count, 0, | ||
271 | call->count); | ||
272 | kunmap_atomic(buffer, KM_USER0); | ||
273 | } | ||
200 | 274 | ||
201 | /* get hold of the fileserver connection */ | 275 | /* extract the returned data */ |
202 | ret = afs_server_get_fsconn(server, &conn); | 276 | case 2: |
203 | if (ret < 0) | 277 | _debug("extract data"); |
204 | goto out; | 278 | page = call->reply3; |
279 | buffer = kmap_atomic(page, KM_USER0); | ||
280 | ret = afs_extract_data(call, skb, last, buffer, call->count); | ||
281 | kunmap_atomic(buffer, KM_USER0); | ||
282 | switch (ret) { | ||
283 | case 0: break; | ||
284 | case -EAGAIN: return 0; | ||
285 | default: return ret; | ||
286 | } | ||
205 | 287 | ||
206 | /* create a call through that connection */ | 288 | call->offset = 0; |
207 | ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call); | 289 | call->unmarshall++; |
208 | if (ret < 0) { | 290 | |
209 | printk("kAFS: Unable to create call: %d\n", ret); | 291 | /* extract the metadata */ |
210 | goto out_put_conn; | 292 | case 3: |
211 | } | 293 | ret = afs_extract_data(call, skb, last, call->buffer, |
212 | call->app_opcode = FSGETVOLUMEINFO; | 294 | (21 + 3 + 6) * 4); |
295 | switch (ret) { | ||
296 | case 0: break; | ||
297 | case -EAGAIN: return 0; | ||
298 | default: return ret; | ||
299 | } | ||
213 | 300 | ||
214 | /* we want to get event notifications from the call */ | 301 | bp = call->buffer; |
215 | add_wait_queue(&call->waitq, &myself); | 302 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); |
303 | xdr_decode_AFSCallBack(&bp, vnode); | ||
304 | if (call->reply2) | ||
305 | xdr_decode_AFSVolSync(&bp, call->reply2); | ||
216 | 306 | ||
217 | /* marshall the parameters */ | 307 | call->offset = 0; |
218 | piov[1].iov_len = strlen(name); | 308 | call->unmarshall++; |
219 | piov[1].iov_base = (char *) name; | 309 | |
220 | 310 | case 4: | |
221 | zero = 0; | 311 | _debug("trailer"); |
222 | piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3; | 312 | if (skb->len != 0) |
223 | piov[2].iov_base = &zero; | 313 | return -EBADMSG; |
224 | 314 | break; | |
225 | param[0] = htonl(FSGETVOLUMEINFO); | ||
226 | param[1] = htonl(piov[1].iov_len); | ||
227 | |||
228 | piov[0].iov_len = sizeof(param); | ||
229 | piov[0].iov_base = param; | ||
230 | |||
231 | /* send the parameters to the server */ | ||
232 | ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS, | ||
233 | 0, &sent); | ||
234 | if (ret < 0) | ||
235 | goto abort; | ||
236 | |||
237 | /* wait for the reply to completely arrive */ | ||
238 | bp = rxrpc_call_alloc_scratch(call, 64); | ||
239 | |||
240 | ret = rxrpc_call_read_data(call, bp, 64, | ||
241 | RXRPC_CALL_READ_BLOCK | | ||
242 | RXRPC_CALL_READ_ALL); | ||
243 | if (ret < 0) { | ||
244 | if (ret == -ECONNABORTED) { | ||
245 | ret = call->app_errno; | ||
246 | goto out_unwait; | ||
247 | } | ||
248 | goto abort; | ||
249 | } | 315 | } |
250 | 316 | ||
251 | /* unmarshall the reply */ | 317 | if (!last) |
252 | vinfo->vid = ntohl(*bp++); | 318 | return 0; |
253 | vinfo->type = ntohl(*bp++); | 319 | |
254 | 320 | _leave(" = 0 [done]"); | |
255 | vinfo->type_vids[0] = ntohl(*bp++); | 321 | return 0; |
256 | vinfo->type_vids[1] = ntohl(*bp++); | 322 | } |
257 | vinfo->type_vids[2] = ntohl(*bp++); | 323 | |
258 | vinfo->type_vids[3] = ntohl(*bp++); | ||
259 | vinfo->type_vids[4] = ntohl(*bp++); | ||
260 | |||
261 | vinfo->nservers = ntohl(*bp++); | ||
262 | vinfo->servers[0].addr.s_addr = *bp++; | ||
263 | vinfo->servers[1].addr.s_addr = *bp++; | ||
264 | vinfo->servers[2].addr.s_addr = *bp++; | ||
265 | vinfo->servers[3].addr.s_addr = *bp++; | ||
266 | vinfo->servers[4].addr.s_addr = *bp++; | ||
267 | vinfo->servers[5].addr.s_addr = *bp++; | ||
268 | vinfo->servers[6].addr.s_addr = *bp++; | ||
269 | vinfo->servers[7].addr.s_addr = *bp++; | ||
270 | |||
271 | ret = -EBADMSG; | ||
272 | if (vinfo->nservers > 8) | ||
273 | goto abort; | ||
274 | |||
275 | /* success */ | ||
276 | ret = 0; | ||
277 | |||
278 | out_unwait: | ||
279 | set_current_state(TASK_RUNNING); | ||
280 | remove_wait_queue(&call->waitq, &myself); | ||
281 | rxrpc_put_call(call); | ||
282 | out_put_conn: | ||
283 | afs_server_release_fsconn(server, conn); | ||
284 | out: | ||
285 | _leave(""); | ||
286 | return ret; | ||
287 | |||
288 | abort: | ||
289 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
290 | rxrpc_call_abort(call, ret); | ||
291 | schedule(); | ||
292 | goto out_unwait; | ||
293 | |||
294 | } /* end afs_rxfs_get_volume_info() */ | ||
295 | #endif | ||
296 | |||
297 | /*****************************************************************************/ | ||
298 | /* | 324 | /* |
299 | * fetch the status information for a file | 325 | * FS.FetchData operation type |
326 | */ | ||
327 | static const struct afs_call_type afs_RXFSFetchData = { | ||
328 | .name = "FS.FetchData", | ||
329 | .deliver = afs_deliver_fs_fetch_data, | ||
330 | .abort_to_error = afs_abort_to_error, | ||
331 | .destructor = afs_flat_call_destructor, | ||
332 | }; | ||
333 | |||
334 | /* | ||
335 | * fetch data from a file | ||
300 | */ | 336 | */ |
301 | int afs_rxfs_fetch_file_status(struct afs_server *server, | 337 | int afs_fs_fetch_data(struct afs_server *server, |
302 | struct afs_vnode *vnode, | 338 | struct key *key, |
303 | struct afs_volsync *volsync) | 339 | struct afs_vnode *vnode, |
340 | off_t offset, size_t length, | ||
341 | struct page *buffer, | ||
342 | const struct afs_wait_mode *wait_mode) | ||
304 | { | 343 | { |
305 | struct afs_server_callslot callslot; | 344 | struct afs_call *call; |
306 | struct rxrpc_call *call; | ||
307 | struct kvec piov[1]; | ||
308 | size_t sent; | ||
309 | int ret; | ||
310 | __be32 *bp; | 345 | __be32 *bp; |
311 | 346 | ||
312 | DECLARE_WAITQUEUE(myself, current); | 347 | _enter(""); |
313 | 348 | ||
314 | _enter("%p,{%u,%u,%u}", | 349 | call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); |
315 | server, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | 350 | if (!call) |
351 | return -ENOMEM; | ||
316 | 352 | ||
317 | /* get hold of the fileserver connection */ | 353 | call->key = key; |
318 | ret = afs_server_request_callslot(server, &callslot); | 354 | call->reply = vnode; |
319 | if (ret < 0) | 355 | call->reply2 = NULL; /* volsync */ |
320 | goto out; | 356 | call->reply3 = buffer; |
321 | 357 | call->service_id = FS_SERVICE; | |
322 | /* create a call through that connection */ | 358 | call->port = htons(AFS_FS_PORT); |
323 | ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap, | ||
324 | &call); | ||
325 | if (ret < 0) { | ||
326 | printk("kAFS: Unable to create call: %d\n", ret); | ||
327 | goto out_put_conn; | ||
328 | } | ||
329 | call->app_opcode = FSFETCHSTATUS; | ||
330 | |||
331 | /* we want to get event notifications from the call */ | ||
332 | add_wait_queue(&call->waitq, &myself); | ||
333 | 359 | ||
334 | /* marshall the parameters */ | 360 | /* marshall the parameters */ |
335 | bp = rxrpc_call_alloc_scratch(call, 16); | 361 | bp = call->request; |
336 | bp[0] = htonl(FSFETCHSTATUS); | 362 | bp[0] = htonl(FSFETCHDATA); |
337 | bp[1] = htonl(vnode->fid.vid); | 363 | bp[1] = htonl(vnode->fid.vid); |
338 | bp[2] = htonl(vnode->fid.vnode); | 364 | bp[2] = htonl(vnode->fid.vnode); |
339 | bp[3] = htonl(vnode->fid.unique); | 365 | bp[3] = htonl(vnode->fid.unique); |
366 | bp[4] = htonl(offset); | ||
367 | bp[5] = htonl(length); | ||
340 | 368 | ||
341 | piov[0].iov_len = 16; | 369 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
342 | piov[0].iov_base = bp; | 370 | } |
343 | |||
344 | /* send the parameters to the server */ | ||
345 | ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS, | ||
346 | 0, &sent); | ||
347 | if (ret < 0) | ||
348 | goto abort; | ||
349 | |||
350 | /* wait for the reply to completely arrive */ | ||
351 | bp = rxrpc_call_alloc_scratch(call, 120); | ||
352 | |||
353 | ret = rxrpc_call_read_data(call, bp, 120, | ||
354 | RXRPC_CALL_READ_BLOCK | | ||
355 | RXRPC_CALL_READ_ALL); | ||
356 | if (ret < 0) { | ||
357 | if (ret == -ECONNABORTED) { | ||
358 | ret = call->app_errno; | ||
359 | goto out_unwait; | ||
360 | } | ||
361 | goto abort; | ||
362 | } | ||
363 | 371 | ||
364 | /* unmarshall the reply */ | 372 | /* |
365 | vnode->status.if_version = ntohl(*bp++); | 373 | * deliver reply data to an FS.GiveUpCallBacks |
366 | vnode->status.type = ntohl(*bp++); | 374 | */ |
367 | vnode->status.nlink = ntohl(*bp++); | 375 | static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, |
368 | vnode->status.size = ntohl(*bp++); | 376 | struct sk_buff *skb, bool last) |
369 | vnode->status.version = ntohl(*bp++); | 377 | { |
370 | vnode->status.author = ntohl(*bp++); | 378 | _enter(",{%u},%d", skb->len, last); |
371 | vnode->status.owner = ntohl(*bp++); | ||
372 | vnode->status.caller_access = ntohl(*bp++); | ||
373 | vnode->status.anon_access = ntohl(*bp++); | ||
374 | vnode->status.mode = ntohl(*bp++); | ||
375 | vnode->status.parent.vid = vnode->fid.vid; | ||
376 | vnode->status.parent.vnode = ntohl(*bp++); | ||
377 | vnode->status.parent.unique = ntohl(*bp++); | ||
378 | bp++; /* seg size */ | ||
379 | vnode->status.mtime_client = ntohl(*bp++); | ||
380 | vnode->status.mtime_server = ntohl(*bp++); | ||
381 | bp++; /* group */ | ||
382 | bp++; /* sync counter */ | ||
383 | vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32; | ||
384 | bp++; /* spare2 */ | ||
385 | bp++; /* spare3 */ | ||
386 | bp++; /* spare4 */ | ||
387 | 379 | ||
388 | vnode->cb_version = ntohl(*bp++); | 380 | if (skb->len > 0) |
389 | vnode->cb_expiry = ntohl(*bp++); | 381 | return -EBADMSG; /* shouldn't be any reply data */ |
390 | vnode->cb_type = ntohl(*bp++); | 382 | return 0; |
391 | 383 | } | |
392 | if (volsync) { | ||
393 | volsync->creation = ntohl(*bp++); | ||
394 | bp++; /* spare2 */ | ||
395 | bp++; /* spare3 */ | ||
396 | bp++; /* spare4 */ | ||
397 | bp++; /* spare5 */ | ||
398 | bp++; /* spare6 */ | ||
399 | } | ||
400 | 384 | ||
401 | /* success */ | ||
402 | ret = 0; | ||
403 | |||
404 | out_unwait: | ||
405 | set_current_state(TASK_RUNNING); | ||
406 | remove_wait_queue(&call->waitq, &myself); | ||
407 | rxrpc_put_call(call); | ||
408 | out_put_conn: | ||
409 | afs_server_release_callslot(server, &callslot); | ||
410 | out: | ||
411 | _leave(""); | ||
412 | return ret; | ||
413 | |||
414 | abort: | ||
415 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
416 | rxrpc_call_abort(call, ret); | ||
417 | schedule(); | ||
418 | goto out_unwait; | ||
419 | } /* end afs_rxfs_fetch_file_status() */ | ||
420 | |||
421 | /*****************************************************************************/ | ||
422 | /* | 385 | /* |
423 | * fetch the contents of a file or directory | 386 | * FS.GiveUpCallBacks operation type |
424 | */ | 387 | */ |
425 | int afs_rxfs_fetch_file_data(struct afs_server *server, | 388 | static const struct afs_call_type afs_RXFSGiveUpCallBacks = { |
426 | struct afs_vnode *vnode, | 389 | .name = "FS.GiveUpCallBacks", |
427 | struct afs_rxfs_fetch_descriptor *desc, | 390 | .deliver = afs_deliver_fs_give_up_callbacks, |
428 | struct afs_volsync *volsync) | 391 | .abort_to_error = afs_abort_to_error, |
392 | .destructor = afs_flat_call_destructor, | ||
393 | }; | ||
394 | |||
395 | /* | ||
396 | * give up a set of callbacks | ||
397 | * - the callbacks are held in the server->cb_break ring | ||
398 | */ | ||
399 | int afs_fs_give_up_callbacks(struct afs_server *server, | ||
400 | const struct afs_wait_mode *wait_mode) | ||
429 | { | 401 | { |
430 | struct afs_server_callslot callslot; | 402 | struct afs_call *call; |
431 | struct rxrpc_call *call; | 403 | size_t ncallbacks; |
432 | struct kvec piov[1]; | 404 | __be32 *bp, *tp; |
433 | size_t sent; | 405 | int loop; |
434 | int ret; | ||
435 | __be32 *bp; | ||
436 | 406 | ||
437 | DECLARE_WAITQUEUE(myself, current); | 407 | ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail, |
438 | 408 | ARRAY_SIZE(server->cb_break)); | |
439 | _enter("%p,{fid={%u,%u,%u},sz=%Zu,of=%lu}", | 409 | |
440 | server, | 410 | _enter("{%zu},", ncallbacks); |
441 | desc->fid.vid, | 411 | |
442 | desc->fid.vnode, | 412 | if (ncallbacks == 0) |
443 | desc->fid.unique, | 413 | return 0; |
444 | desc->size, | 414 | if (ncallbacks > AFSCBMAX) |
445 | desc->offset); | 415 | ncallbacks = AFSCBMAX; |
446 | 416 | ||
447 | /* get hold of the fileserver connection */ | 417 | _debug("break %zu callbacks", ncallbacks); |
448 | ret = afs_server_request_callslot(server, &callslot); | ||
449 | if (ret < 0) | ||
450 | goto out; | ||
451 | |||
452 | /* create a call through that connection */ | ||
453 | ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap, &call); | ||
454 | if (ret < 0) { | ||
455 | printk("kAFS: Unable to create call: %d\n", ret); | ||
456 | goto out_put_conn; | ||
457 | } | ||
458 | call->app_opcode = FSFETCHDATA; | ||
459 | 418 | ||
460 | /* we want to get event notifications from the call */ | 419 | call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks, |
461 | add_wait_queue(&call->waitq, &myself); | 420 | 12 + ncallbacks * 6 * 4, 0); |
421 | if (!call) | ||
422 | return -ENOMEM; | ||
423 | |||
424 | call->service_id = FS_SERVICE; | ||
425 | call->port = htons(AFS_FS_PORT); | ||
462 | 426 | ||
463 | /* marshall the parameters */ | 427 | /* marshall the parameters */ |
464 | bp = rxrpc_call_alloc_scratch(call, 24); | 428 | bp = call->request; |
465 | bp[0] = htonl(FSFETCHDATA); | 429 | tp = bp + 2 + ncallbacks * 3; |
466 | bp[1] = htonl(desc->fid.vid); | 430 | *bp++ = htonl(FSGIVEUPCALLBACKS); |
467 | bp[2] = htonl(desc->fid.vnode); | 431 | *bp++ = htonl(ncallbacks); |
468 | bp[3] = htonl(desc->fid.unique); | 432 | *tp++ = htonl(ncallbacks); |
469 | bp[4] = htonl(desc->offset); | 433 | |
470 | bp[5] = htonl(desc->size); | 434 | atomic_sub(ncallbacks, &server->cb_break_n); |
471 | 435 | for (loop = ncallbacks; loop > 0; loop--) { | |
472 | piov[0].iov_len = 24; | 436 | struct afs_callback *cb = |
473 | piov[0].iov_base = bp; | 437 | &server->cb_break[server->cb_break_tail]; |
474 | 438 | ||
475 | /* send the parameters to the server */ | 439 | *bp++ = htonl(cb->fid.vid); |
476 | ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS, | 440 | *bp++ = htonl(cb->fid.vnode); |
477 | 0, &sent); | 441 | *bp++ = htonl(cb->fid.unique); |
478 | if (ret < 0) | 442 | *tp++ = htonl(cb->version); |
479 | goto abort; | 443 | *tp++ = htonl(cb->expiry); |
480 | 444 | *tp++ = htonl(cb->type); | |
481 | /* wait for the data count to arrive */ | 445 | smp_mb(); |
482 | ret = rxrpc_call_read_data(call, bp, 4, RXRPC_CALL_READ_BLOCK); | 446 | server->cb_break_tail = |
483 | if (ret < 0) | 447 | (server->cb_break_tail + 1) & |
484 | goto read_failed; | 448 | (ARRAY_SIZE(server->cb_break) - 1); |
485 | |||
486 | desc->actual = ntohl(bp[0]); | ||
487 | if (desc->actual != desc->size) { | ||
488 | ret = -EBADMSG; | ||
489 | goto abort; | ||
490 | } | 449 | } |
491 | 450 | ||
492 | /* call the app to read the actual data */ | 451 | ASSERT(ncallbacks > 0); |
493 | rxrpc_call_reset_scratch(call); | 452 | wake_up_nr(&server->cb_break_waitq, ncallbacks); |
494 | |||
495 | ret = rxrpc_call_read_data(call, desc->buffer, desc->actual, | ||
496 | RXRPC_CALL_READ_BLOCK); | ||
497 | if (ret < 0) | ||
498 | goto read_failed; | ||
499 | |||
500 | /* wait for the rest of the reply to completely arrive */ | ||
501 | rxrpc_call_reset_scratch(call); | ||
502 | bp = rxrpc_call_alloc_scratch(call, 120); | ||
503 | |||
504 | ret = rxrpc_call_read_data(call, bp, 120, | ||
505 | RXRPC_CALL_READ_BLOCK | | ||
506 | RXRPC_CALL_READ_ALL); | ||
507 | if (ret < 0) | ||
508 | goto read_failed; | ||
509 | |||
510 | /* unmarshall the reply */ | ||
511 | vnode->status.if_version = ntohl(*bp++); | ||
512 | vnode->status.type = ntohl(*bp++); | ||
513 | vnode->status.nlink = ntohl(*bp++); | ||
514 | vnode->status.size = ntohl(*bp++); | ||
515 | vnode->status.version = ntohl(*bp++); | ||
516 | vnode->status.author = ntohl(*bp++); | ||
517 | vnode->status.owner = ntohl(*bp++); | ||
518 | vnode->status.caller_access = ntohl(*bp++); | ||
519 | vnode->status.anon_access = ntohl(*bp++); | ||
520 | vnode->status.mode = ntohl(*bp++); | ||
521 | vnode->status.parent.vid = desc->fid.vid; | ||
522 | vnode->status.parent.vnode = ntohl(*bp++); | ||
523 | vnode->status.parent.unique = ntohl(*bp++); | ||
524 | bp++; /* seg size */ | ||
525 | vnode->status.mtime_client = ntohl(*bp++); | ||
526 | vnode->status.mtime_server = ntohl(*bp++); | ||
527 | bp++; /* group */ | ||
528 | bp++; /* sync counter */ | ||
529 | vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32; | ||
530 | bp++; /* spare2 */ | ||
531 | bp++; /* spare3 */ | ||
532 | bp++; /* spare4 */ | ||
533 | 453 | ||
534 | vnode->cb_version = ntohl(*bp++); | 454 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
535 | vnode->cb_expiry = ntohl(*bp++); | 455 | } |
536 | vnode->cb_type = ntohl(*bp++); | ||
537 | |||
538 | if (volsync) { | ||
539 | volsync->creation = ntohl(*bp++); | ||
540 | bp++; /* spare2 */ | ||
541 | bp++; /* spare3 */ | ||
542 | bp++; /* spare4 */ | ||
543 | bp++; /* spare5 */ | ||
544 | bp++; /* spare6 */ | ||
545 | } | ||
546 | 456 | ||
547 | /* success */ | 457 | /* |
548 | ret = 0; | 458 | * deliver reply data to an FS.CreateFile or an FS.MakeDir |
549 | 459 | */ | |
550 | out_unwait: | 460 | static int afs_deliver_fs_create_vnode(struct afs_call *call, |
551 | set_current_state(TASK_RUNNING); | 461 | struct sk_buff *skb, bool last) |
552 | remove_wait_queue(&call->waitq,&myself); | 462 | { |
553 | rxrpc_put_call(call); | 463 | struct afs_vnode *vnode = call->reply; |
554 | out_put_conn: | 464 | const __be32 *bp; |
555 | afs_server_release_callslot(server, &callslot); | 465 | |
556 | out: | 466 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); |
557 | _leave(" = %d", ret); | ||
558 | return ret; | ||
559 | |||
560 | read_failed: | ||
561 | if (ret == -ECONNABORTED) { | ||
562 | ret = call->app_errno; | ||
563 | goto out_unwait; | ||
564 | } | ||
565 | 467 | ||
566 | abort: | 468 | afs_transfer_reply(call, skb); |
567 | set_current_state(TASK_UNINTERRUPTIBLE); | 469 | if (!last) |
568 | rxrpc_call_abort(call, ret); | 470 | return 0; |
569 | schedule(); | ||
570 | goto out_unwait; | ||
571 | 471 | ||
572 | } /* end afs_rxfs_fetch_file_data() */ | 472 | if (call->reply_size != call->reply_max) |
473 | return -EBADMSG; | ||
474 | |||
475 | /* unmarshall the reply once we've received all of it */ | ||
476 | bp = call->buffer; | ||
477 | xdr_decode_AFSFid(&bp, call->reply2); | ||
478 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); | ||
479 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
480 | xdr_decode_AFSCallBack_raw(&bp, call->reply4); | ||
481 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
482 | |||
483 | _leave(" = 0 [done]"); | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | /* | ||
488 | * FS.CreateFile and FS.MakeDir operation type | ||
489 | */ | ||
490 | static const struct afs_call_type afs_RXFSCreateXXXX = { | ||
491 | .name = "FS.CreateXXXX", | ||
492 | .deliver = afs_deliver_fs_create_vnode, | ||
493 | .abort_to_error = afs_abort_to_error, | ||
494 | .destructor = afs_flat_call_destructor, | ||
495 | }; | ||
573 | 496 | ||
574 | /*****************************************************************************/ | ||
575 | /* | 497 | /* |
576 | * ask the AFS fileserver to discard a callback request on a file | 498 | * create a file or make a directory |
577 | */ | 499 | */ |
578 | int afs_rxfs_give_up_callback(struct afs_server *server, | 500 | int afs_fs_create(struct afs_server *server, |
579 | struct afs_vnode *vnode) | 501 | struct key *key, |
502 | struct afs_vnode *vnode, | ||
503 | const char *name, | ||
504 | umode_t mode, | ||
505 | struct afs_fid *newfid, | ||
506 | struct afs_file_status *newstatus, | ||
507 | struct afs_callback *newcb, | ||
508 | const struct afs_wait_mode *wait_mode) | ||
580 | { | 509 | { |
581 | struct afs_server_callslot callslot; | 510 | struct afs_call *call; |
582 | struct rxrpc_call *call; | 511 | size_t namesz, reqsz, padsz; |
583 | struct kvec piov[1]; | ||
584 | size_t sent; | ||
585 | int ret; | ||
586 | __be32 *bp; | 512 | __be32 *bp; |
587 | 513 | ||
588 | DECLARE_WAITQUEUE(myself, current); | 514 | _enter(""); |
589 | 515 | ||
590 | _enter("%p,{%u,%u,%u}", | 516 | namesz = strlen(name); |
591 | server, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | 517 | padsz = (4 - (namesz & 3)) & 3; |
518 | reqsz = (5 * 4) + namesz + padsz + (6 * 4); | ||
592 | 519 | ||
593 | /* get hold of the fileserver connection */ | 520 | call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz, |
594 | ret = afs_server_request_callslot(server, &callslot); | 521 | (3 + 21 + 21 + 3 + 6) * 4); |
595 | if (ret < 0) | 522 | if (!call) |
596 | goto out; | 523 | return -ENOMEM; |
597 | 524 | ||
598 | /* create a call through that connection */ | 525 | call->key = key; |
599 | ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap, &call); | 526 | call->reply = vnode; |
600 | if (ret < 0) { | 527 | call->reply2 = newfid; |
601 | printk("kAFS: Unable to create call: %d\n", ret); | 528 | call->reply3 = newstatus; |
602 | goto out_put_conn; | 529 | call->reply4 = newcb; |
530 | call->service_id = FS_SERVICE; | ||
531 | call->port = htons(AFS_FS_PORT); | ||
532 | |||
533 | /* marshall the parameters */ | ||
534 | bp = call->request; | ||
535 | *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); | ||
536 | *bp++ = htonl(vnode->fid.vid); | ||
537 | *bp++ = htonl(vnode->fid.vnode); | ||
538 | *bp++ = htonl(vnode->fid.unique); | ||
539 | *bp++ = htonl(namesz); | ||
540 | memcpy(bp, name, namesz); | ||
541 | bp = (void *) bp + namesz; | ||
542 | if (padsz > 0) { | ||
543 | memset(bp, 0, padsz); | ||
544 | bp = (void *) bp + padsz; | ||
603 | } | 545 | } |
604 | call->app_opcode = FSGIVEUPCALLBACKS; | 546 | *bp++ = htonl(AFS_SET_MODE); |
547 | *bp++ = 0; /* mtime */ | ||
548 | *bp++ = 0; /* owner */ | ||
549 | *bp++ = 0; /* group */ | ||
550 | *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ | ||
551 | *bp++ = 0; /* segment size */ | ||
605 | 552 | ||
606 | /* we want to get event notifications from the call */ | 553 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
607 | add_wait_queue(&call->waitq, &myself); | 554 | } |
608 | 555 | ||
609 | /* marshall the parameters */ | 556 | /* |
610 | bp = rxrpc_call_alloc_scratch(call, (1 + 4 + 4) * 4); | 557 | * deliver reply data to an FS.RemoveFile or FS.RemoveDir |
558 | */ | ||
559 | static int afs_deliver_fs_remove(struct afs_call *call, | ||
560 | struct sk_buff *skb, bool last) | ||
561 | { | ||
562 | struct afs_vnode *vnode = call->reply; | ||
563 | const __be32 *bp; | ||
611 | 564 | ||
612 | piov[0].iov_len = (1 + 4 + 4) * 4; | 565 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); |
613 | piov[0].iov_base = bp; | ||
614 | 566 | ||
615 | *bp++ = htonl(FSGIVEUPCALLBACKS); | 567 | afs_transfer_reply(call, skb); |
616 | *bp++ = htonl(1); | 568 | if (!last) |
569 | return 0; | ||
570 | |||
571 | if (call->reply_size != call->reply_max) | ||
572 | return -EBADMSG; | ||
573 | |||
574 | /* unmarshall the reply once we've received all of it */ | ||
575 | bp = call->buffer; | ||
576 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
577 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
578 | |||
579 | _leave(" = 0 [done]"); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | /* | ||
584 | * FS.RemoveDir/FS.RemoveFile operation type | ||
585 | */ | ||
586 | static const struct afs_call_type afs_RXFSRemoveXXXX = { | ||
587 | .name = "FS.RemoveXXXX", | ||
588 | .deliver = afs_deliver_fs_remove, | ||
589 | .abort_to_error = afs_abort_to_error, | ||
590 | .destructor = afs_flat_call_destructor, | ||
591 | }; | ||
592 | |||
593 | /* | ||
594 | * remove a file or directory | ||
595 | */ | ||
596 | int afs_fs_remove(struct afs_server *server, | ||
597 | struct key *key, | ||
598 | struct afs_vnode *vnode, | ||
599 | const char *name, | ||
600 | bool isdir, | ||
601 | const struct afs_wait_mode *wait_mode) | ||
602 | { | ||
603 | struct afs_call *call; | ||
604 | size_t namesz, reqsz, padsz; | ||
605 | __be32 *bp; | ||
606 | |||
607 | _enter(""); | ||
608 | |||
609 | namesz = strlen(name); | ||
610 | padsz = (4 - (namesz & 3)) & 3; | ||
611 | reqsz = (5 * 4) + namesz + padsz; | ||
612 | |||
613 | call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4); | ||
614 | if (!call) | ||
615 | return -ENOMEM; | ||
616 | |||
617 | call->key = key; | ||
618 | call->reply = vnode; | ||
619 | call->service_id = FS_SERVICE; | ||
620 | call->port = htons(AFS_FS_PORT); | ||
621 | |||
622 | /* marshall the parameters */ | ||
623 | bp = call->request; | ||
624 | *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); | ||
617 | *bp++ = htonl(vnode->fid.vid); | 625 | *bp++ = htonl(vnode->fid.vid); |
618 | *bp++ = htonl(vnode->fid.vnode); | 626 | *bp++ = htonl(vnode->fid.vnode); |
619 | *bp++ = htonl(vnode->fid.unique); | 627 | *bp++ = htonl(vnode->fid.unique); |
620 | *bp++ = htonl(1); | 628 | *bp++ = htonl(namesz); |
621 | *bp++ = htonl(vnode->cb_version); | 629 | memcpy(bp, name, namesz); |
622 | *bp++ = htonl(vnode->cb_expiry); | 630 | bp = (void *) bp + namesz; |
623 | *bp++ = htonl(vnode->cb_type); | 631 | if (padsz > 0) { |
624 | 632 | memset(bp, 0, padsz); | |
625 | /* send the parameters to the server */ | 633 | bp = (void *) bp + padsz; |
626 | ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS, | ||
627 | 0, &sent); | ||
628 | if (ret < 0) | ||
629 | goto abort; | ||
630 | |||
631 | /* wait for the reply to completely arrive */ | ||
632 | for (;;) { | ||
633 | set_current_state(TASK_INTERRUPTIBLE); | ||
634 | if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY || | ||
635 | signal_pending(current)) | ||
636 | break; | ||
637 | schedule(); | ||
638 | } | 634 | } |
639 | set_current_state(TASK_RUNNING); | ||
640 | 635 | ||
641 | ret = -EINTR; | 636 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
642 | if (signal_pending(current)) | 637 | } |
643 | goto abort; | ||
644 | 638 | ||
645 | switch (call->app_call_state) { | 639 | /* |
646 | case RXRPC_CSTATE_ERROR: | 640 | * deliver reply data to an FS.Link |
647 | ret = call->app_errno; | 641 | */ |
648 | goto out_unwait; | 642 | static int afs_deliver_fs_link(struct afs_call *call, |
643 | struct sk_buff *skb, bool last) | ||
644 | { | ||
645 | struct afs_vnode *dvnode = call->reply, *vnode = call->reply2; | ||
646 | const __be32 *bp; | ||
649 | 647 | ||
650 | case RXRPC_CSTATE_CLNT_GOT_REPLY: | 648 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); |
651 | ret = 0; | ||
652 | goto out_unwait; | ||
653 | 649 | ||
654 | default: | 650 | afs_transfer_reply(call, skb); |
655 | BUG(); | 651 | if (!last) |
656 | } | 652 | return 0; |
653 | |||
654 | if (call->reply_size != call->reply_max) | ||
655 | return -EBADMSG; | ||
656 | |||
657 | /* unmarshall the reply once we've received all of it */ | ||
658 | bp = call->buffer; | ||
659 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
660 | xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode); | ||
661 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
662 | |||
663 | _leave(" = 0 [done]"); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | /* | ||
668 | * FS.Link operation type | ||
669 | */ | ||
670 | static const struct afs_call_type afs_RXFSLink = { | ||
671 | .name = "FS.Link", | ||
672 | .deliver = afs_deliver_fs_link, | ||
673 | .abort_to_error = afs_abort_to_error, | ||
674 | .destructor = afs_flat_call_destructor, | ||
675 | }; | ||
657 | 676 | ||
658 | out_unwait: | ||
659 | set_current_state(TASK_RUNNING); | ||
660 | remove_wait_queue(&call->waitq, &myself); | ||
661 | rxrpc_put_call(call); | ||
662 | out_put_conn: | ||
663 | afs_server_release_callslot(server, &callslot); | ||
664 | out: | ||
665 | _leave(""); | ||
666 | return ret; | ||
667 | |||
668 | abort: | ||
669 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
670 | rxrpc_call_abort(call, ret); | ||
671 | schedule(); | ||
672 | goto out_unwait; | ||
673 | } /* end afs_rxfs_give_up_callback() */ | ||
674 | |||
675 | /*****************************************************************************/ | ||
676 | /* | 677 | /* |
677 | * look a filename up in a directory | 678 | * make a hard link |
678 | * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2 | ||
679 | */ | 679 | */ |
680 | #if 0 | 680 | int afs_fs_link(struct afs_server *server, |
681 | int afs_rxfs_lookup(struct afs_server *server, | 681 | struct key *key, |
682 | struct afs_vnode *dir, | 682 | struct afs_vnode *dvnode, |
683 | const char *filename, | 683 | struct afs_vnode *vnode, |
684 | struct afs_vnode *vnode, | 684 | const char *name, |
685 | struct afs_volsync *volsync) | 685 | const struct afs_wait_mode *wait_mode) |
686 | { | 686 | { |
687 | struct rxrpc_connection *conn; | 687 | struct afs_call *call; |
688 | struct rxrpc_call *call; | 688 | size_t namesz, reqsz, padsz; |
689 | struct kvec piov[3]; | 689 | __be32 *bp; |
690 | size_t sent; | ||
691 | int ret; | ||
692 | u32 *bp, zero; | ||
693 | 690 | ||
694 | DECLARE_WAITQUEUE(myself, current); | 691 | _enter(""); |
695 | 692 | ||
696 | kenter("%p,{%u,%u,%u},%s", | 693 | namesz = strlen(name); |
697 | server, fid->vid, fid->vnode, fid->unique, filename); | 694 | padsz = (4 - (namesz & 3)) & 3; |
695 | reqsz = (5 * 4) + namesz + padsz + (3 * 4); | ||
698 | 696 | ||
699 | /* get hold of the fileserver connection */ | 697 | call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); |
700 | ret = afs_server_get_fsconn(server, &conn); | 698 | if (!call) |
701 | if (ret < 0) | 699 | return -ENOMEM; |
702 | goto out; | ||
703 | 700 | ||
704 | /* create a call through that connection */ | 701 | call->key = key; |
705 | ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call); | 702 | call->reply = dvnode; |
706 | if (ret < 0) { | 703 | call->reply2 = vnode; |
707 | printk("kAFS: Unable to create call: %d\n", ret); | 704 | call->service_id = FS_SERVICE; |
708 | goto out_put_conn; | 705 | call->port = htons(AFS_FS_PORT); |
706 | |||
707 | /* marshall the parameters */ | ||
708 | bp = call->request; | ||
709 | *bp++ = htonl(FSLINK); | ||
710 | *bp++ = htonl(dvnode->fid.vid); | ||
711 | *bp++ = htonl(dvnode->fid.vnode); | ||
712 | *bp++ = htonl(dvnode->fid.unique); | ||
713 | *bp++ = htonl(namesz); | ||
714 | memcpy(bp, name, namesz); | ||
715 | bp = (void *) bp + namesz; | ||
716 | if (padsz > 0) { | ||
717 | memset(bp, 0, padsz); | ||
718 | bp = (void *) bp + padsz; | ||
709 | } | 719 | } |
710 | call->app_opcode = FSLOOKUP; | 720 | *bp++ = htonl(vnode->fid.vid); |
721 | *bp++ = htonl(vnode->fid.vnode); | ||
722 | *bp++ = htonl(vnode->fid.unique); | ||
723 | |||
724 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
725 | } | ||
726 | |||
727 | /* | ||
728 | * deliver reply data to an FS.Symlink | ||
729 | */ | ||
730 | static int afs_deliver_fs_symlink(struct afs_call *call, | ||
731 | struct sk_buff *skb, bool last) | ||
732 | { | ||
733 | struct afs_vnode *vnode = call->reply; | ||
734 | const __be32 *bp; | ||
711 | 735 | ||
712 | /* we want to get event notifications from the call */ | 736 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); |
713 | add_wait_queue(&call->waitq,&myself); | 737 | |
738 | afs_transfer_reply(call, skb); | ||
739 | if (!last) | ||
740 | return 0; | ||
741 | |||
742 | if (call->reply_size != call->reply_max) | ||
743 | return -EBADMSG; | ||
744 | |||
745 | /* unmarshall the reply once we've received all of it */ | ||
746 | bp = call->buffer; | ||
747 | xdr_decode_AFSFid(&bp, call->reply2); | ||
748 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); | ||
749 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | ||
750 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
751 | |||
752 | _leave(" = 0 [done]"); | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | /* | ||
757 | * FS.Symlink operation type | ||
758 | */ | ||
759 | static const struct afs_call_type afs_RXFSSymlink = { | ||
760 | .name = "FS.Symlink", | ||
761 | .deliver = afs_deliver_fs_symlink, | ||
762 | .abort_to_error = afs_abort_to_error, | ||
763 | .destructor = afs_flat_call_destructor, | ||
764 | }; | ||
765 | |||
766 | /* | ||
767 | * create a symbolic link | ||
768 | */ | ||
769 | int afs_fs_symlink(struct afs_server *server, | ||
770 | struct key *key, | ||
771 | struct afs_vnode *vnode, | ||
772 | const char *name, | ||
773 | const char *contents, | ||
774 | struct afs_fid *newfid, | ||
775 | struct afs_file_status *newstatus, | ||
776 | const struct afs_wait_mode *wait_mode) | ||
777 | { | ||
778 | struct afs_call *call; | ||
779 | size_t namesz, reqsz, padsz, c_namesz, c_padsz; | ||
780 | __be32 *bp; | ||
781 | |||
782 | _enter(""); | ||
783 | |||
784 | namesz = strlen(name); | ||
785 | padsz = (4 - (namesz & 3)) & 3; | ||
786 | |||
787 | c_namesz = strlen(contents); | ||
788 | c_padsz = (4 - (c_namesz & 3)) & 3; | ||
789 | |||
790 | reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); | ||
791 | |||
792 | call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz, | ||
793 | (3 + 21 + 21 + 6) * 4); | ||
794 | if (!call) | ||
795 | return -ENOMEM; | ||
796 | |||
797 | call->key = key; | ||
798 | call->reply = vnode; | ||
799 | call->reply2 = newfid; | ||
800 | call->reply3 = newstatus; | ||
801 | call->service_id = FS_SERVICE; | ||
802 | call->port = htons(AFS_FS_PORT); | ||
714 | 803 | ||
715 | /* marshall the parameters */ | 804 | /* marshall the parameters */ |
716 | bp = rxrpc_call_alloc_scratch(call, 20); | 805 | bp = call->request; |
717 | 806 | *bp++ = htonl(FSSYMLINK); | |
718 | zero = 0; | 807 | *bp++ = htonl(vnode->fid.vid); |
719 | 808 | *bp++ = htonl(vnode->fid.vnode); | |
720 | piov[0].iov_len = 20; | 809 | *bp++ = htonl(vnode->fid.unique); |
721 | piov[0].iov_base = bp; | 810 | *bp++ = htonl(namesz); |
722 | piov[1].iov_len = strlen(filename); | 811 | memcpy(bp, name, namesz); |
723 | piov[1].iov_base = (char *) filename; | 812 | bp = (void *) bp + namesz; |
724 | piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3; | 813 | if (padsz > 0) { |
725 | piov[2].iov_base = &zero; | 814 | memset(bp, 0, padsz); |
726 | 815 | bp = (void *) bp + padsz; | |
727 | *bp++ = htonl(FSLOOKUP); | ||
728 | *bp++ = htonl(dirfid->vid); | ||
729 | *bp++ = htonl(dirfid->vnode); | ||
730 | *bp++ = htonl(dirfid->unique); | ||
731 | *bp++ = htonl(piov[1].iov_len); | ||
732 | |||
733 | /* send the parameters to the server */ | ||
734 | ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS, | ||
735 | 0, &sent); | ||
736 | if (ret < 0) | ||
737 | goto abort; | ||
738 | |||
739 | /* wait for the reply to completely arrive */ | ||
740 | bp = rxrpc_call_alloc_scratch(call, 220); | ||
741 | |||
742 | ret = rxrpc_call_read_data(call, bp, 220, | ||
743 | RXRPC_CALL_READ_BLOCK | | ||
744 | RXRPC_CALL_READ_ALL); | ||
745 | if (ret < 0) { | ||
746 | if (ret == -ECONNABORTED) { | ||
747 | ret = call->app_errno; | ||
748 | goto out_unwait; | ||
749 | } | ||
750 | goto abort; | ||
751 | } | 816 | } |
817 | *bp++ = htonl(c_namesz); | ||
818 | memcpy(bp, contents, c_namesz); | ||
819 | bp = (void *) bp + c_namesz; | ||
820 | if (c_padsz > 0) { | ||
821 | memset(bp, 0, c_padsz); | ||
822 | bp = (void *) bp + c_padsz; | ||
823 | } | ||
824 | *bp++ = htonl(AFS_SET_MODE); | ||
825 | *bp++ = 0; /* mtime */ | ||
826 | *bp++ = 0; /* owner */ | ||
827 | *bp++ = 0; /* group */ | ||
828 | *bp++ = htonl(S_IRWXUGO); /* unix mode */ | ||
829 | *bp++ = 0; /* segment size */ | ||
752 | 830 | ||
753 | /* unmarshall the reply */ | 831 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
754 | fid->vid = ntohl(*bp++); | 832 | } |
755 | fid->vnode = ntohl(*bp++); | ||
756 | fid->unique = ntohl(*bp++); | ||
757 | 833 | ||
758 | vnode->status.if_version = ntohl(*bp++); | 834 | /* |
759 | vnode->status.type = ntohl(*bp++); | 835 | * deliver reply data to an FS.Rename |
760 | vnode->status.nlink = ntohl(*bp++); | 836 | */ |
761 | vnode->status.size = ntohl(*bp++); | 837 | static int afs_deliver_fs_rename(struct afs_call *call, |
762 | vnode->status.version = ntohl(*bp++); | 838 | struct sk_buff *skb, bool last) |
763 | vnode->status.author = ntohl(*bp++); | 839 | { |
764 | vnode->status.owner = ntohl(*bp++); | 840 | struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2; |
765 | vnode->status.caller_access = ntohl(*bp++); | 841 | const __be32 *bp; |
766 | vnode->status.anon_access = ntohl(*bp++); | ||
767 | vnode->status.mode = ntohl(*bp++); | ||
768 | vnode->status.parent.vid = dirfid->vid; | ||
769 | vnode->status.parent.vnode = ntohl(*bp++); | ||
770 | vnode->status.parent.unique = ntohl(*bp++); | ||
771 | bp++; /* seg size */ | ||
772 | vnode->status.mtime_client = ntohl(*bp++); | ||
773 | vnode->status.mtime_server = ntohl(*bp++); | ||
774 | bp++; /* group */ | ||
775 | bp++; /* sync counter */ | ||
776 | vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32; | ||
777 | bp++; /* spare2 */ | ||
778 | bp++; /* spare3 */ | ||
779 | bp++; /* spare4 */ | ||
780 | 842 | ||
781 | dir->status.if_version = ntohl(*bp++); | 843 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); |
782 | dir->status.type = ntohl(*bp++); | 844 | |
783 | dir->status.nlink = ntohl(*bp++); | 845 | afs_transfer_reply(call, skb); |
784 | dir->status.size = ntohl(*bp++); | 846 | if (!last) |
785 | dir->status.version = ntohl(*bp++); | 847 | return 0; |
786 | dir->status.author = ntohl(*bp++); | 848 | |
787 | dir->status.owner = ntohl(*bp++); | 849 | if (call->reply_size != call->reply_max) |
788 | dir->status.caller_access = ntohl(*bp++); | 850 | return -EBADMSG; |
789 | dir->status.anon_access = ntohl(*bp++); | 851 | |
790 | dir->status.mode = ntohl(*bp++); | 852 | /* unmarshall the reply once we've received all of it */ |
791 | dir->status.parent.vid = dirfid->vid; | 853 | bp = call->buffer; |
792 | dir->status.parent.vnode = ntohl(*bp++); | 854 | xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode); |
793 | dir->status.parent.unique = ntohl(*bp++); | 855 | if (new_dvnode != orig_dvnode) |
794 | bp++; /* seg size */ | 856 | xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode); |
795 | dir->status.mtime_client = ntohl(*bp++); | 857 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ |
796 | dir->status.mtime_server = ntohl(*bp++); | 858 | |
797 | bp++; /* group */ | 859 | _leave(" = 0 [done]"); |
798 | bp++; /* sync counter */ | 860 | return 0; |
799 | dir->status.version |= ((unsigned long long) ntohl(*bp++)) << 32; | 861 | } |
800 | bp++; /* spare2 */ | 862 | |
801 | bp++; /* spare3 */ | 863 | /* |
802 | bp++; /* spare4 */ | 864 | * FS.Rename operation type |
865 | */ | ||
866 | static const struct afs_call_type afs_RXFSRename = { | ||
867 | .name = "FS.Rename", | ||
868 | .deliver = afs_deliver_fs_rename, | ||
869 | .abort_to_error = afs_abort_to_error, | ||
870 | .destructor = afs_flat_call_destructor, | ||
871 | }; | ||
872 | |||
873 | /* | ||
874 | * create a symbolic link | ||
875 | */ | ||
876 | int afs_fs_rename(struct afs_server *server, | ||
877 | struct key *key, | ||
878 | struct afs_vnode *orig_dvnode, | ||
879 | const char *orig_name, | ||
880 | struct afs_vnode *new_dvnode, | ||
881 | const char *new_name, | ||
882 | const struct afs_wait_mode *wait_mode) | ||
883 | { | ||
884 | struct afs_call *call; | ||
885 | size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; | ||
886 | __be32 *bp; | ||
887 | |||
888 | _enter(""); | ||
889 | |||
890 | o_namesz = strlen(orig_name); | ||
891 | o_padsz = (4 - (o_namesz & 3)) & 3; | ||
892 | |||
893 | n_namesz = strlen(new_name); | ||
894 | n_padsz = (4 - (n_namesz & 3)) & 3; | ||
895 | |||
896 | reqsz = (4 * 4) + | ||
897 | 4 + o_namesz + o_padsz + | ||
898 | (3 * 4) + | ||
899 | 4 + n_namesz + n_padsz; | ||
900 | |||
901 | call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); | ||
902 | if (!call) | ||
903 | return -ENOMEM; | ||
904 | |||
905 | call->key = key; | ||
906 | call->reply = orig_dvnode; | ||
907 | call->reply2 = new_dvnode; | ||
908 | call->service_id = FS_SERVICE; | ||
909 | call->port = htons(AFS_FS_PORT); | ||
910 | |||
911 | /* marshall the parameters */ | ||
912 | bp = call->request; | ||
913 | *bp++ = htonl(FSRENAME); | ||
914 | *bp++ = htonl(orig_dvnode->fid.vid); | ||
915 | *bp++ = htonl(orig_dvnode->fid.vnode); | ||
916 | *bp++ = htonl(orig_dvnode->fid.unique); | ||
917 | *bp++ = htonl(o_namesz); | ||
918 | memcpy(bp, orig_name, o_namesz); | ||
919 | bp = (void *) bp + o_namesz; | ||
920 | if (o_padsz > 0) { | ||
921 | memset(bp, 0, o_padsz); | ||
922 | bp = (void *) bp + o_padsz; | ||
923 | } | ||
803 | 924 | ||
804 | callback->fid = *fid; | 925 | *bp++ = htonl(new_dvnode->fid.vid); |
805 | callback->version = ntohl(*bp++); | 926 | *bp++ = htonl(new_dvnode->fid.vnode); |
806 | callback->expiry = ntohl(*bp++); | 927 | *bp++ = htonl(new_dvnode->fid.unique); |
807 | callback->type = ntohl(*bp++); | 928 | *bp++ = htonl(n_namesz); |
808 | 929 | memcpy(bp, new_name, n_namesz); | |
809 | if (volsync) { | 930 | bp = (void *) bp + n_namesz; |
810 | volsync->creation = ntohl(*bp++); | 931 | if (n_padsz > 0) { |
811 | bp++; /* spare2 */ | 932 | memset(bp, 0, n_padsz); |
812 | bp++; /* spare3 */ | 933 | bp = (void *) bp + n_padsz; |
813 | bp++; /* spare4 */ | ||
814 | bp++; /* spare5 */ | ||
815 | bp++; /* spare6 */ | ||
816 | } | 934 | } |
817 | 935 | ||
818 | /* success */ | 936 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
819 | ret = 0; | 937 | } |
820 | |||
821 | out_unwait: | ||
822 | set_current_state(TASK_RUNNING); | ||
823 | remove_wait_queue(&call->waitq, &myself); | ||
824 | rxrpc_put_call(call); | ||
825 | out_put_conn: | ||
826 | afs_server_release_fsconn(server, conn); | ||
827 | out: | ||
828 | kleave(""); | ||
829 | return ret; | ||
830 | |||
831 | abort: | ||
832 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
833 | rxrpc_call_abort(call, ret); | ||
834 | schedule(); | ||
835 | goto out_unwait; | ||
836 | } /* end afs_rxfs_lookup() */ | ||
837 | #endif | ||
diff --git a/fs/afs/fsclient.h b/fs/afs/fsclient.h deleted file mode 100644 index 8ba3e749ee3c..000000000000 --- a/fs/afs/fsclient.h +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | /* fsclient.h: AFS File Server client stub declarations | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_FSCLIENT_H | ||
13 | #define _LINUX_AFS_FSCLIENT_H | ||
14 | |||
15 | #include "server.h" | ||
16 | |||
17 | extern int afs_rxfs_get_volume_info(struct afs_server *server, | ||
18 | const char *name, | ||
19 | struct afs_volume_info *vinfo); | ||
20 | |||
21 | extern int afs_rxfs_fetch_file_status(struct afs_server *server, | ||
22 | struct afs_vnode *vnode, | ||
23 | struct afs_volsync *volsync); | ||
24 | |||
25 | struct afs_rxfs_fetch_descriptor { | ||
26 | struct afs_fid fid; /* file ID to fetch */ | ||
27 | size_t size; /* total number of bytes to fetch */ | ||
28 | off_t offset; /* offset in file to start from */ | ||
29 | void *buffer; /* read buffer */ | ||
30 | size_t actual; /* actual size sent back by server */ | ||
31 | }; | ||
32 | |||
33 | extern int afs_rxfs_fetch_file_data(struct afs_server *server, | ||
34 | struct afs_vnode *vnode, | ||
35 | struct afs_rxfs_fetch_descriptor *desc, | ||
36 | struct afs_volsync *volsync); | ||
37 | |||
38 | extern int afs_rxfs_give_up_callback(struct afs_server *server, | ||
39 | struct afs_vnode *vnode); | ||
40 | |||
41 | /* this doesn't appear to work in OpenAFS server */ | ||
42 | extern int afs_rxfs_lookup(struct afs_server *server, | ||
43 | struct afs_vnode *dir, | ||
44 | const char *filename, | ||
45 | struct afs_vnode *vnode, | ||
46 | struct afs_volsync *volsync); | ||
47 | |||
48 | /* this is apparently mis-implemented in OpenAFS server */ | ||
49 | extern int afs_rxfs_get_root_volume(struct afs_server *server, | ||
50 | char *buf, | ||
51 | size_t *buflen); | ||
52 | |||
53 | |||
54 | #endif /* _LINUX_AFS_FSCLIENT_H */ | ||
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 9d9bca6c28b5..c184a4ee5995 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -19,9 +19,6 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/pagemap.h> | 21 | #include <linux/pagemap.h> |
22 | #include "volume.h" | ||
23 | #include "vnode.h" | ||
24 | #include "super.h" | ||
25 | #include "internal.h" | 22 | #include "internal.h" |
26 | 23 | ||
27 | struct afs_iget_data { | 24 | struct afs_iget_data { |
@@ -29,26 +26,25 @@ struct afs_iget_data { | |||
29 | struct afs_volume *volume; /* volume on which resides */ | 26 | struct afs_volume *volume; /* volume on which resides */ |
30 | }; | 27 | }; |
31 | 28 | ||
32 | /*****************************************************************************/ | ||
33 | /* | 29 | /* |
34 | * map the AFS file status to the inode member variables | 30 | * map the AFS file status to the inode member variables |
35 | */ | 31 | */ |
36 | static int afs_inode_map_status(struct afs_vnode *vnode) | 32 | static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) |
37 | { | 33 | { |
38 | struct inode *inode = AFS_VNODE_TO_I(vnode); | 34 | struct inode *inode = AFS_VNODE_TO_I(vnode); |
39 | 35 | ||
40 | _debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu", | 36 | _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu", |
41 | vnode->status.type, | 37 | vnode->status.type, |
42 | vnode->status.nlink, | 38 | vnode->status.nlink, |
43 | vnode->status.size, | 39 | (unsigned long long) vnode->status.size, |
44 | vnode->status.version, | 40 | vnode->status.data_version, |
45 | vnode->status.mode); | 41 | vnode->status.mode); |
46 | 42 | ||
47 | switch (vnode->status.type) { | 43 | switch (vnode->status.type) { |
48 | case AFS_FTYPE_FILE: | 44 | case AFS_FTYPE_FILE: |
49 | inode->i_mode = S_IFREG | vnode->status.mode; | 45 | inode->i_mode = S_IFREG | vnode->status.mode; |
50 | inode->i_op = &afs_file_inode_operations; | 46 | inode->i_op = &afs_file_inode_operations; |
51 | inode->i_fop = &generic_ro_fops; | 47 | inode->i_fop = &afs_file_operations; |
52 | break; | 48 | break; |
53 | case AFS_FTYPE_DIR: | 49 | case AFS_FTYPE_DIR: |
54 | inode->i_mode = S_IFDIR | vnode->status.mode; | 50 | inode->i_mode = S_IFDIR | vnode->status.mode; |
@@ -77,9 +73,9 @@ static int afs_inode_map_status(struct afs_vnode *vnode) | |||
77 | 73 | ||
78 | /* check to see whether a symbolic link is really a mountpoint */ | 74 | /* check to see whether a symbolic link is really a mountpoint */ |
79 | if (vnode->status.type == AFS_FTYPE_SYMLINK) { | 75 | if (vnode->status.type == AFS_FTYPE_SYMLINK) { |
80 | afs_mntpt_check_symlink(vnode); | 76 | afs_mntpt_check_symlink(vnode, key); |
81 | 77 | ||
82 | if (vnode->flags & AFS_VNODE_MOUNTPOINT) { | 78 | if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) { |
83 | inode->i_mode = S_IFDIR | vnode->status.mode; | 79 | inode->i_mode = S_IFDIR | vnode->status.mode; |
84 | inode->i_op = &afs_mntpt_inode_operations; | 80 | inode->i_op = &afs_mntpt_inode_operations; |
85 | inode->i_fop = &afs_mntpt_file_operations; | 81 | inode->i_fop = &afs_mntpt_file_operations; |
@@ -87,30 +83,8 @@ static int afs_inode_map_status(struct afs_vnode *vnode) | |||
87 | } | 83 | } |
88 | 84 | ||
89 | return 0; | 85 | return 0; |
90 | } /* end afs_inode_map_status() */ | 86 | } |
91 | 87 | ||
92 | /*****************************************************************************/ | ||
93 | /* | ||
94 | * attempt to fetch the status of an inode, coelescing multiple simultaneous | ||
95 | * fetches | ||
96 | */ | ||
97 | static int afs_inode_fetch_status(struct inode *inode) | ||
98 | { | ||
99 | struct afs_vnode *vnode; | ||
100 | int ret; | ||
101 | |||
102 | vnode = AFS_FS_I(inode); | ||
103 | |||
104 | ret = afs_vnode_fetch_status(vnode); | ||
105 | |||
106 | if (ret == 0) | ||
107 | ret = afs_inode_map_status(vnode); | ||
108 | |||
109 | return ret; | ||
110 | |||
111 | } /* end afs_inode_fetch_status() */ | ||
112 | |||
113 | /*****************************************************************************/ | ||
114 | /* | 88 | /* |
115 | * iget5() comparator | 89 | * iget5() comparator |
116 | */ | 90 | */ |
@@ -120,9 +94,8 @@ static int afs_iget5_test(struct inode *inode, void *opaque) | |||
120 | 94 | ||
121 | return inode->i_ino == data->fid.vnode && | 95 | return inode->i_ino == data->fid.vnode && |
122 | inode->i_version == data->fid.unique; | 96 | inode->i_version == data->fid.unique; |
123 | } /* end afs_iget5_test() */ | 97 | } |
124 | 98 | ||
125 | /*****************************************************************************/ | ||
126 | /* | 99 | /* |
127 | * iget5() inode initialiser | 100 | * iget5() inode initialiser |
128 | */ | 101 | */ |
@@ -137,14 +110,14 @@ static int afs_iget5_set(struct inode *inode, void *opaque) | |||
137 | vnode->volume = data->volume; | 110 | vnode->volume = data->volume; |
138 | 111 | ||
139 | return 0; | 112 | return 0; |
140 | } /* end afs_iget5_set() */ | 113 | } |
141 | 114 | ||
142 | /*****************************************************************************/ | ||
143 | /* | 115 | /* |
144 | * inode retrieval | 116 | * inode retrieval |
145 | */ | 117 | */ |
146 | inline int afs_iget(struct super_block *sb, struct afs_fid *fid, | 118 | struct inode *afs_iget(struct super_block *sb, struct key *key, |
147 | struct inode **_inode) | 119 | struct afs_fid *fid, struct afs_file_status *status, |
120 | struct afs_callback *cb) | ||
148 | { | 121 | { |
149 | struct afs_iget_data data = { .fid = *fid }; | 122 | struct afs_iget_data data = { .fid = *fid }; |
150 | struct afs_super_info *as; | 123 | struct afs_super_info *as; |
@@ -161,20 +134,18 @@ inline int afs_iget(struct super_block *sb, struct afs_fid *fid, | |||
161 | &data); | 134 | &data); |
162 | if (!inode) { | 135 | if (!inode) { |
163 | _leave(" = -ENOMEM"); | 136 | _leave(" = -ENOMEM"); |
164 | return -ENOMEM; | 137 | return ERR_PTR(-ENOMEM); |
165 | } | 138 | } |
166 | 139 | ||
140 | _debug("GOT INODE %p { vl=%x vn=%x, u=%x }", | ||
141 | inode, fid->vid, fid->vnode, fid->unique); | ||
142 | |||
167 | vnode = AFS_FS_I(inode); | 143 | vnode = AFS_FS_I(inode); |
168 | 144 | ||
169 | /* deal with an existing inode */ | 145 | /* deal with an existing inode */ |
170 | if (!(inode->i_state & I_NEW)) { | 146 | if (!(inode->i_state & I_NEW)) { |
171 | ret = afs_vnode_fetch_status(vnode); | 147 | _leave(" = %p", inode); |
172 | if (ret==0) | 148 | return inode; |
173 | *_inode = inode; | ||
174 | else | ||
175 | iput(inode); | ||
176 | _leave(" = %d", ret); | ||
177 | return ret; | ||
178 | } | 149 | } |
179 | 150 | ||
180 | #ifdef AFS_CACHING_SUPPORT | 151 | #ifdef AFS_CACHING_SUPPORT |
@@ -186,100 +157,185 @@ inline int afs_iget(struct super_block *sb, struct afs_fid *fid, | |||
186 | &vnode->cache); | 157 | &vnode->cache); |
187 | #endif | 158 | #endif |
188 | 159 | ||
189 | /* okay... it's a new inode */ | 160 | if (!status) { |
190 | inode->i_flags |= S_NOATIME; | 161 | /* it's a remotely extant inode */ |
191 | vnode->flags |= AFS_VNODE_CHANGED; | 162 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
192 | ret = afs_inode_fetch_status(inode); | 163 | ret = afs_vnode_fetch_status(vnode, NULL, key); |
193 | if (ret<0) | 164 | if (ret < 0) |
165 | goto bad_inode; | ||
166 | } else { | ||
167 | /* it's an inode we just created */ | ||
168 | memcpy(&vnode->status, status, sizeof(vnode->status)); | ||
169 | |||
170 | if (!cb) { | ||
171 | /* it's a symlink we just created (the fileserver | ||
172 | * didn't give us a callback) */ | ||
173 | vnode->cb_version = 0; | ||
174 | vnode->cb_expiry = 0; | ||
175 | vnode->cb_type = 0; | ||
176 | vnode->cb_expires = get_seconds(); | ||
177 | } else { | ||
178 | vnode->cb_version = cb->version; | ||
179 | vnode->cb_expiry = cb->expiry; | ||
180 | vnode->cb_type = cb->type; | ||
181 | vnode->cb_expires = vnode->cb_expiry + get_seconds(); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | ret = afs_inode_map_status(vnode, key); | ||
186 | if (ret < 0) | ||
194 | goto bad_inode; | 187 | goto bad_inode; |
195 | 188 | ||
196 | /* success */ | 189 | /* success */ |
190 | clear_bit(AFS_VNODE_UNSET, &vnode->flags); | ||
191 | inode->i_flags |= S_NOATIME; | ||
197 | unlock_new_inode(inode); | 192 | unlock_new_inode(inode); |
198 | 193 | _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type); | |
199 | *_inode = inode; | 194 | return inode; |
200 | _leave(" = 0 [CB { v=%u x=%lu t=%u }]", | ||
201 | vnode->cb_version, | ||
202 | vnode->cb_timeout.timo_jif, | ||
203 | vnode->cb_type); | ||
204 | return 0; | ||
205 | 195 | ||
206 | /* failure */ | 196 | /* failure */ |
207 | bad_inode: | 197 | bad_inode: |
208 | make_bad_inode(inode); | 198 | make_bad_inode(inode); |
209 | unlock_new_inode(inode); | 199 | unlock_new_inode(inode); |
210 | iput(inode); | 200 | iput(inode); |
211 | 201 | ||
212 | _leave(" = %d [bad]", ret); | 202 | _leave(" = %d [bad]", ret); |
203 | return ERR_PTR(ret); | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * validate a vnode/inode | ||
208 | * - there are several things we need to check | ||
209 | * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, | ||
210 | * symlink) | ||
211 | * - parent dir metadata changed (security changes) | ||
212 | * - dentry data changed (write, truncate) | ||
213 | * - dentry metadata changed (security changes) | ||
214 | */ | ||
215 | int afs_validate(struct afs_vnode *vnode, struct key *key) | ||
216 | { | ||
217 | int ret; | ||
218 | |||
219 | _enter("{v={%x:%u} fl=%lx},%x", | ||
220 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, | ||
221 | key_serial(key)); | ||
222 | |||
223 | if (vnode->cb_promised && | ||
224 | !test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && | ||
225 | !test_bit(AFS_VNODE_MODIFIED, &vnode->flags) && | ||
226 | !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | ||
227 | if (vnode->cb_expires < get_seconds() + 10) { | ||
228 | _debug("callback expired"); | ||
229 | set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | ||
230 | } else { | ||
231 | goto valid; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) | ||
236 | goto valid; | ||
237 | |||
238 | mutex_lock(&vnode->validate_lock); | ||
239 | |||
240 | /* if the promise has expired, we need to check the server again to get | ||
241 | * a new promise - note that if the (parent) directory's metadata was | ||
242 | * changed then the security may be different and we may no longer have | ||
243 | * access */ | ||
244 | if (!vnode->cb_promised || | ||
245 | test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { | ||
246 | _debug("not promised"); | ||
247 | ret = afs_vnode_fetch_status(vnode, NULL, key); | ||
248 | if (ret < 0) | ||
249 | goto error_unlock; | ||
250 | _debug("new promise [fl=%lx]", vnode->flags); | ||
251 | } | ||
252 | |||
253 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | ||
254 | _debug("file already deleted"); | ||
255 | ret = -ESTALE; | ||
256 | goto error_unlock; | ||
257 | } | ||
258 | |||
259 | /* if the vnode's data version number changed then its contents are | ||
260 | * different */ | ||
261 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | ||
262 | _debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode); | ||
263 | invalidate_remote_inode(&vnode->vfs_inode); | ||
264 | } | ||
265 | |||
266 | clear_bit(AFS_VNODE_MODIFIED, &vnode->flags); | ||
267 | mutex_unlock(&vnode->validate_lock); | ||
268 | valid: | ||
269 | _leave(" = 0"); | ||
270 | return 0; | ||
271 | |||
272 | error_unlock: | ||
273 | mutex_unlock(&vnode->validate_lock); | ||
274 | _leave(" = %d", ret); | ||
213 | return ret; | 275 | return ret; |
214 | } /* end afs_iget() */ | 276 | } |
215 | 277 | ||
216 | /*****************************************************************************/ | ||
217 | /* | 278 | /* |
218 | * read the attributes of an inode | 279 | * read the attributes of an inode |
219 | */ | 280 | */ |
220 | int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, | 281 | int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, |
221 | struct kstat *stat) | 282 | struct kstat *stat) |
222 | { | 283 | { |
223 | struct afs_vnode *vnode; | ||
224 | struct inode *inode; | 284 | struct inode *inode; |
225 | int ret; | ||
226 | 285 | ||
227 | inode = dentry->d_inode; | 286 | inode = dentry->d_inode; |
228 | 287 | ||
229 | _enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version); | 288 | _enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version); |
230 | 289 | ||
231 | vnode = AFS_FS_I(inode); | ||
232 | |||
233 | ret = afs_inode_fetch_status(inode); | ||
234 | if (ret == -ENOENT) { | ||
235 | _leave(" = %d [%d %p]", | ||
236 | ret, atomic_read(&dentry->d_count), dentry->d_inode); | ||
237 | return ret; | ||
238 | } | ||
239 | else if (ret < 0) { | ||
240 | make_bad_inode(inode); | ||
241 | _leave(" = %d", ret); | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | /* transfer attributes from the inode structure to the stat | ||
246 | * structure */ | ||
247 | generic_fillattr(inode, stat); | 290 | generic_fillattr(inode, stat); |
248 | |||
249 | _leave(" = 0 CB { v=%u x=%u t=%u }", | ||
250 | vnode->cb_version, | ||
251 | vnode->cb_expiry, | ||
252 | vnode->cb_type); | ||
253 | |||
254 | return 0; | 291 | return 0; |
255 | } /* end afs_inode_getattr() */ | 292 | } |
256 | 293 | ||
257 | /*****************************************************************************/ | ||
258 | /* | 294 | /* |
259 | * clear an AFS inode | 295 | * clear an AFS inode |
260 | */ | 296 | */ |
261 | void afs_clear_inode(struct inode *inode) | 297 | void afs_clear_inode(struct inode *inode) |
262 | { | 298 | { |
299 | struct afs_permits *permits; | ||
263 | struct afs_vnode *vnode; | 300 | struct afs_vnode *vnode; |
264 | 301 | ||
265 | vnode = AFS_FS_I(inode); | 302 | vnode = AFS_FS_I(inode); |
266 | 303 | ||
267 | _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }", | 304 | _enter("{%x:%d.%d} v=%u x=%u t=%u }", |
268 | inode->i_ino, | 305 | vnode->fid.vid, |
269 | vnode->fid.vnode, | 306 | vnode->fid.vnode, |
307 | vnode->fid.unique, | ||
270 | vnode->cb_version, | 308 | vnode->cb_version, |
271 | vnode->cb_expiry, | 309 | vnode->cb_expiry, |
272 | vnode->cb_type | 310 | vnode->cb_type); |
273 | ); | ||
274 | 311 | ||
275 | BUG_ON(inode->i_ino != vnode->fid.vnode); | 312 | _debug("CLEAR INODE %p", inode); |
276 | 313 | ||
277 | afs_vnode_give_up_callback(vnode); | 314 | ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode); |
315 | |||
316 | afs_give_up_callback(vnode); | ||
317 | |||
318 | if (vnode->server) { | ||
319 | spin_lock(&vnode->server->fs_lock); | ||
320 | rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes); | ||
321 | spin_unlock(&vnode->server->fs_lock); | ||
322 | afs_put_server(vnode->server); | ||
323 | vnode->server = NULL; | ||
324 | } | ||
325 | |||
326 | ASSERT(!vnode->cb_promised); | ||
278 | 327 | ||
279 | #ifdef AFS_CACHING_SUPPORT | 328 | #ifdef AFS_CACHING_SUPPORT |
280 | cachefs_relinquish_cookie(vnode->cache, 0); | 329 | cachefs_relinquish_cookie(vnode->cache, 0); |
281 | vnode->cache = NULL; | 330 | vnode->cache = NULL; |
282 | #endif | 331 | #endif |
283 | 332 | ||
333 | mutex_lock(&vnode->permits_lock); | ||
334 | permits = vnode->permits; | ||
335 | rcu_assign_pointer(vnode->permits, NULL); | ||
336 | mutex_unlock(&vnode->permits_lock); | ||
337 | if (permits) | ||
338 | call_rcu(&permits->rcu, afs_zap_permits); | ||
339 | |||
284 | _leave(""); | 340 | _leave(""); |
285 | } /* end afs_clear_inode() */ | 341 | } |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 5151d5da2c2f..6dd3197d1d8d 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* internal.h: internal AFS stuff | 1 | /* internal AFS stuff |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -9,48 +9,391 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef AFS_INTERNAL_H | ||
13 | #define AFS_INTERNAL_H | ||
14 | |||
15 | #include <linux/compiler.h> | 12 | #include <linux/compiler.h> |
16 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
17 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
18 | #include <linux/pagemap.h> | 15 | #include <linux/pagemap.h> |
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/rxrpc.h> | ||
18 | #include <linux/key.h> | ||
19 | #include "afs.h" | ||
20 | #include "afs_vl.h" | ||
21 | |||
22 | #define AFS_CELL_MAX_ADDRS 15 | ||
23 | |||
24 | struct afs_call; | ||
25 | |||
26 | typedef enum { | ||
27 | AFS_VL_NEW, /* new, uninitialised record */ | ||
28 | AFS_VL_CREATING, /* creating record */ | ||
29 | AFS_VL_VALID, /* record is pending */ | ||
30 | AFS_VL_NO_VOLUME, /* no such volume available */ | ||
31 | AFS_VL_UPDATING, /* update in progress */ | ||
32 | AFS_VL_VOLUME_DELETED, /* volume was deleted */ | ||
33 | AFS_VL_UNCERTAIN, /* uncertain state (update failed) */ | ||
34 | } __attribute__((packed)) afs_vlocation_state_t; | ||
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 | }; | ||
19 | 46 | ||
20 | /* | 47 | /* |
21 | * debug tracing | 48 | * definition of how to wait for the completion of an operation |
22 | */ | 49 | */ |
23 | #define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ## a) | 50 | struct afs_wait_mode { |
24 | #define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ## a) | 51 | /* RxRPC received message notification */ |
25 | #define kdebug(FMT, a...) printk(FMT"\n" , ## a) | 52 | void (*rx_wakeup)(struct afs_call *call); |
26 | #define kproto(FMT, a...) printk("### "FMT"\n" , ## a) | ||
27 | #define knet(FMT, a...) printk(FMT"\n" , ## a) | ||
28 | |||
29 | #ifdef __KDEBUG | ||
30 | #define _enter(FMT, a...) kenter(FMT , ## a) | ||
31 | #define _leave(FMT, a...) kleave(FMT , ## a) | ||
32 | #define _debug(FMT, a...) kdebug(FMT , ## a) | ||
33 | #define _proto(FMT, a...) kproto(FMT , ## a) | ||
34 | #define _net(FMT, a...) knet(FMT , ## a) | ||
35 | #else | ||
36 | #define _enter(FMT, a...) do { } while(0) | ||
37 | #define _leave(FMT, a...) do { } while(0) | ||
38 | #define _debug(FMT, a...) do { } while(0) | ||
39 | #define _proto(FMT, a...) do { } while(0) | ||
40 | #define _net(FMT, a...) do { } while(0) | ||
41 | #endif | ||
42 | 53 | ||
43 | static inline void afs_discard_my_signals(void) | 54 | /* synchronous call waiter and call dispatched notification */ |
44 | { | 55 | int (*wait)(struct afs_call *call); |
45 | while (signal_pending(current)) { | 56 | |
46 | siginfo_t sinfo; | 57 | /* asynchronous call completion */ |
58 | void (*async_complete)(void *reply, int error); | ||
59 | }; | ||
60 | |||
61 | extern const struct afs_wait_mode afs_sync_call; | ||
62 | extern const struct afs_wait_mode afs_async_call; | ||
47 | 63 | ||
48 | spin_lock_irq(¤t->sighand->siglock); | 64 | /* |
49 | dequeue_signal(current,¤t->blocked, &sinfo); | 65 | * a record of an in-progress RxRPC call |
50 | spin_unlock_irq(¤t->sighand->siglock); | 66 | */ |
51 | } | 67 | struct afs_call { |
68 | const struct afs_call_type *type; /* type of call */ | ||
69 | const struct afs_wait_mode *wait_mode; /* completion wait mode */ | ||
70 | wait_queue_head_t waitq; /* processes awaiting completion */ | ||
71 | struct work_struct async_work; /* asynchronous work processor */ | ||
72 | struct work_struct work; /* actual work processor */ | ||
73 | struct sk_buff_head rx_queue; /* received packets */ | ||
74 | struct rxrpc_call *rxcall; /* RxRPC call handle */ | ||
75 | struct key *key; /* security for this call */ | ||
76 | struct afs_server *server; /* server affected by incoming CM call */ | ||
77 | void *request; /* request data (first part) */ | ||
78 | void *request2; /* request data (second part) */ | ||
79 | void *buffer; /* reply receive buffer */ | ||
80 | void *reply; /* reply buffer (first part) */ | ||
81 | void *reply2; /* reply buffer (second part) */ | ||
82 | void *reply3; /* reply buffer (third part) */ | ||
83 | void *reply4; /* reply buffer (fourth part) */ | ||
84 | enum { /* call state */ | ||
85 | AFS_CALL_REQUESTING, /* request is being sent for outgoing call */ | ||
86 | AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */ | ||
87 | AFS_CALL_AWAIT_OP_ID, /* awaiting op ID on incoming call */ | ||
88 | AFS_CALL_AWAIT_REQUEST, /* awaiting request data on incoming call */ | ||
89 | AFS_CALL_REPLYING, /* replying to incoming call */ | ||
90 | AFS_CALL_AWAIT_ACK, /* awaiting final ACK of incoming call */ | ||
91 | AFS_CALL_COMPLETE, /* successfully completed */ | ||
92 | AFS_CALL_BUSY, /* server was busy */ | ||
93 | AFS_CALL_ABORTED, /* call was aborted */ | ||
94 | AFS_CALL_ERROR, /* call failed due to error */ | ||
95 | } state; | ||
96 | int error; /* error code */ | ||
97 | unsigned request_size; /* size of request data */ | ||
98 | unsigned reply_max; /* maximum size of reply */ | ||
99 | unsigned reply_size; /* current size of reply */ | ||
100 | unsigned short offset; /* offset into received data store */ | ||
101 | unsigned char unmarshall; /* unmarshalling phase */ | ||
102 | bool incoming; /* T if incoming call */ | ||
103 | u16 service_id; /* RxRPC service ID to call */ | ||
104 | __be16 port; /* target UDP port */ | ||
105 | __be32 operation_ID; /* operation ID for an incoming call */ | ||
106 | u32 count; /* count for use in unmarshalling */ | ||
107 | __be32 tmp; /* place to extract temporary data */ | ||
108 | }; | ||
109 | |||
110 | struct afs_call_type { | ||
111 | const char *name; | ||
112 | |||
113 | /* deliver request or reply data to an call | ||
114 | * - returning an error will cause the call to be aborted | ||
115 | */ | ||
116 | int (*deliver)(struct afs_call *call, struct sk_buff *skb, | ||
117 | bool last); | ||
118 | |||
119 | /* map an abort code to an error number */ | ||
120 | int (*abort_to_error)(u32 abort_code); | ||
121 | |||
122 | /* clean up a call */ | ||
123 | void (*destructor)(struct afs_call *call); | ||
124 | }; | ||
125 | |||
126 | /* | ||
127 | * AFS superblock private data | ||
128 | * - there's one superblock per volume | ||
129 | */ | ||
130 | struct afs_super_info { | ||
131 | struct afs_volume *volume; /* volume record */ | ||
132 | char rwparent; /* T if parent is R/W AFS volume */ | ||
133 | }; | ||
134 | |||
135 | static inline struct afs_super_info *AFS_FS_S(struct super_block *sb) | ||
136 | { | ||
137 | return sb->s_fs_info; | ||
52 | } | 138 | } |
53 | 139 | ||
140 | extern struct file_system_type afs_fs_type; | ||
141 | |||
142 | /* | ||
143 | * entry in the cached cell catalogue | ||
144 | */ | ||
145 | struct afs_cache_cell { | ||
146 | char name[AFS_MAXCELLNAME]; /* cell name (padded with NULs) */ | ||
147 | struct in_addr vl_servers[15]; /* cached cell VL servers */ | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * AFS cell record | ||
152 | */ | ||
153 | struct afs_cell { | ||
154 | atomic_t usage; | ||
155 | struct list_head link; /* main cell list link */ | ||
156 | struct key *anonymous_key; /* anonymous user key for this cell */ | ||
157 | struct list_head proc_link; /* /proc cell list link */ | ||
158 | struct proc_dir_entry *proc_dir; /* /proc dir for this cell */ | ||
159 | #ifdef AFS_CACHING_SUPPORT | ||
160 | struct cachefs_cookie *cache; /* caching cookie */ | ||
161 | #endif | ||
162 | |||
163 | /* server record management */ | ||
164 | rwlock_t servers_lock; /* active server list lock */ | ||
165 | struct list_head servers; /* active server list */ | ||
166 | |||
167 | /* volume location record management */ | ||
168 | struct rw_semaphore vl_sem; /* volume management serialisation semaphore */ | ||
169 | struct list_head vl_list; /* cell's active VL record list */ | ||
170 | spinlock_t vl_lock; /* vl_list lock */ | ||
171 | unsigned short vl_naddrs; /* number of VL servers in addr list */ | ||
172 | unsigned short vl_curr_svix; /* current server index */ | ||
173 | struct in_addr vl_addrs[AFS_CELL_MAX_ADDRS]; /* cell VL server addresses */ | ||
174 | |||
175 | char name[0]; /* cell name - must go last */ | ||
176 | }; | ||
177 | |||
178 | /* | ||
179 | * entry in the cached volume location catalogue | ||
180 | */ | ||
181 | struct afs_cache_vlocation { | ||
182 | /* volume name (lowercase, padded with NULs) */ | ||
183 | uint8_t name[AFS_MAXVOLNAME + 1]; | ||
184 | |||
185 | uint8_t nservers; /* number of entries used in servers[] */ | ||
186 | uint8_t vidmask; /* voltype mask for vid[] */ | ||
187 | uint8_t srvtmask[8]; /* voltype masks for servers[] */ | ||
188 | #define AFS_VOL_VTM_RW 0x01 /* R/W version of the volume is available (on this server) */ | ||
189 | #define AFS_VOL_VTM_RO 0x02 /* R/O version of the volume is available (on this server) */ | ||
190 | #define AFS_VOL_VTM_BAK 0x04 /* backup version of the volume is available (on this server) */ | ||
191 | |||
192 | afs_volid_t vid[3]; /* volume IDs for R/W, R/O and Bak volumes */ | ||
193 | struct in_addr servers[8]; /* fileserver addresses */ | ||
194 | time_t rtime; /* last retrieval time */ | ||
195 | }; | ||
196 | |||
197 | /* | ||
198 | * volume -> vnode hash table entry | ||
199 | */ | ||
200 | struct afs_cache_vhash { | ||
201 | afs_voltype_t vtype; /* which volume variation */ | ||
202 | uint8_t hash_bucket; /* which hash bucket this represents */ | ||
203 | } __attribute__((packed)); | ||
204 | |||
205 | /* | ||
206 | * AFS volume location record | ||
207 | */ | ||
208 | struct afs_vlocation { | ||
209 | atomic_t usage; | ||
210 | time_t time_of_death; /* time at which put reduced usage to 0 */ | ||
211 | struct list_head link; /* link in cell volume location list */ | ||
212 | struct list_head grave; /* link in master graveyard list */ | ||
213 | struct list_head update; /* link in master update list */ | ||
214 | struct afs_cell *cell; /* cell to which volume belongs */ | ||
215 | #ifdef AFS_CACHING_SUPPORT | ||
216 | struct cachefs_cookie *cache; /* caching cookie */ | ||
217 | #endif | ||
218 | struct afs_cache_vlocation vldb; /* volume information DB record */ | ||
219 | struct afs_volume *vols[3]; /* volume access record pointer (index by type) */ | ||
220 | wait_queue_head_t waitq; /* status change waitqueue */ | ||
221 | time_t update_at; /* time at which record should be updated */ | ||
222 | spinlock_t lock; /* access lock */ | ||
223 | afs_vlocation_state_t state; /* volume location state */ | ||
224 | unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */ | ||
225 | unsigned short upd_busy_cnt; /* EBUSY count during update */ | ||
226 | bool valid; /* T if valid */ | ||
227 | }; | ||
228 | |||
229 | /* | ||
230 | * AFS fileserver record | ||
231 | */ | ||
232 | struct afs_server { | ||
233 | atomic_t usage; | ||
234 | time_t time_of_death; /* time at which put reduced usage to 0 */ | ||
235 | struct in_addr addr; /* server address */ | ||
236 | struct afs_cell *cell; /* cell in which server resides */ | ||
237 | struct list_head link; /* link in cell's server list */ | ||
238 | struct list_head grave; /* link in master graveyard list */ | ||
239 | struct rb_node master_rb; /* link in master by-addr tree */ | ||
240 | struct rw_semaphore sem; /* access lock */ | ||
241 | |||
242 | /* file service access */ | ||
243 | struct rb_root fs_vnodes; /* vnodes backed by this server (ordered by FID) */ | ||
244 | unsigned long fs_act_jif; /* time at which last activity occurred */ | ||
245 | unsigned long fs_dead_jif; /* time at which no longer to be considered dead */ | ||
246 | spinlock_t fs_lock; /* access lock */ | ||
247 | int fs_state; /* 0 or reason FS currently marked dead (-errno) */ | ||
248 | |||
249 | /* callback promise management */ | ||
250 | struct rb_root cb_promises; /* vnode expiration list (ordered earliest first) */ | ||
251 | struct delayed_work cb_updater; /* callback updater */ | ||
252 | struct delayed_work cb_break_work; /* collected break dispatcher */ | ||
253 | wait_queue_head_t cb_break_waitq; /* space available in cb_break waitqueue */ | ||
254 | spinlock_t cb_lock; /* access lock */ | ||
255 | struct afs_callback cb_break[64]; /* ring of callbacks awaiting breaking */ | ||
256 | atomic_t cb_break_n; /* number of pending breaks */ | ||
257 | u8 cb_break_head; /* head of callback breaking ring */ | ||
258 | u8 cb_break_tail; /* tail of callback breaking ring */ | ||
259 | }; | ||
260 | |||
261 | /* | ||
262 | * AFS volume access record | ||
263 | */ | ||
264 | struct afs_volume { | ||
265 | atomic_t usage; | ||
266 | struct afs_cell *cell; /* cell to which belongs (unrefd ptr) */ | ||
267 | struct afs_vlocation *vlocation; /* volume location */ | ||
268 | #ifdef AFS_CACHING_SUPPORT | ||
269 | struct cachefs_cookie *cache; /* caching cookie */ | ||
270 | #endif | ||
271 | afs_volid_t vid; /* volume ID */ | ||
272 | afs_voltype_t type; /* type of volume */ | ||
273 | char type_force; /* force volume type (suppress R/O -> R/W) */ | ||
274 | unsigned short nservers; /* number of server slots filled */ | ||
275 | unsigned short rjservers; /* number of servers discarded due to -ENOMEDIUM */ | ||
276 | struct afs_server *servers[8]; /* servers on which volume resides (ordered) */ | ||
277 | struct rw_semaphore server_sem; /* lock for accessing current server */ | ||
278 | }; | ||
279 | |||
280 | /* | ||
281 | * vnode catalogue entry | ||
282 | */ | ||
283 | struct afs_cache_vnode { | ||
284 | afs_vnodeid_t vnode_id; /* vnode ID */ | ||
285 | unsigned vnode_unique; /* vnode ID uniquifier */ | ||
286 | afs_dataversion_t data_version; /* data version */ | ||
287 | }; | ||
288 | |||
289 | /* | ||
290 | * AFS inode private data | ||
291 | */ | ||
292 | struct afs_vnode { | ||
293 | struct inode vfs_inode; /* the VFS's inode record */ | ||
294 | |||
295 | struct afs_volume *volume; /* volume on which vnode resides */ | ||
296 | struct afs_server *server; /* server currently supplying this file */ | ||
297 | struct afs_fid fid; /* the file identifier for this inode */ | ||
298 | struct afs_file_status status; /* AFS status info for this file */ | ||
299 | #ifdef AFS_CACHING_SUPPORT | ||
300 | struct cachefs_cookie *cache; /* caching cookie */ | ||
301 | #endif | ||
302 | struct afs_permits *permits; /* cache of permits so far obtained */ | ||
303 | struct mutex permits_lock; /* lock for altering permits list */ | ||
304 | struct mutex validate_lock; /* lock for validating this vnode */ | ||
305 | wait_queue_head_t update_waitq; /* status fetch waitqueue */ | ||
306 | int update_cnt; /* number of outstanding ops that will update the | ||
307 | * status */ | ||
308 | spinlock_t lock; /* waitqueue/flags lock */ | ||
309 | unsigned long flags; | ||
310 | #define AFS_VNODE_CB_BROKEN 0 /* set if vnode's callback was broken */ | ||
311 | #define AFS_VNODE_UNSET 1 /* set if vnode attributes not yet set */ | ||
312 | #define AFS_VNODE_MODIFIED 2 /* set if vnode's data modified */ | ||
313 | #define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */ | ||
314 | #define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */ | ||
315 | #define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */ | ||
316 | |||
317 | long acl_order; /* ACL check count (callback break count) */ | ||
318 | |||
319 | /* outstanding callback notification on this file */ | ||
320 | struct rb_node server_rb; /* link in server->fs_vnodes */ | ||
321 | struct rb_node cb_promise; /* link in server->cb_promises */ | ||
322 | struct work_struct cb_broken_work; /* work to be done on callback break */ | ||
323 | time_t cb_expires; /* time at which callback expires */ | ||
324 | time_t cb_expires_at; /* time used to order cb_promise */ | ||
325 | unsigned cb_version; /* callback version */ | ||
326 | unsigned cb_expiry; /* callback expiry time */ | ||
327 | afs_callback_type_t cb_type; /* type of callback */ | ||
328 | bool cb_promised; /* true if promise still holds */ | ||
329 | }; | ||
330 | |||
331 | /* | ||
332 | * cached security record for one user's attempt to access a vnode | ||
333 | */ | ||
334 | struct afs_permit { | ||
335 | struct key *key; /* RxRPC ticket holding a security context */ | ||
336 | afs_access_t access_mask; /* access mask for this key */ | ||
337 | }; | ||
338 | |||
339 | /* | ||
340 | * cache of security records from attempts to access a vnode | ||
341 | */ | ||
342 | struct afs_permits { | ||
343 | struct rcu_head rcu; /* disposal procedure */ | ||
344 | int count; /* number of records */ | ||
345 | struct afs_permit permits[0]; /* the permits so far examined */ | ||
346 | }; | ||
347 | |||
348 | /* | ||
349 | * record of one of a system's set of network interfaces | ||
350 | */ | ||
351 | struct afs_interface { | ||
352 | unsigned index; /* interface index */ | ||
353 | struct in_addr address; /* IPv4 address bound to interface */ | ||
354 | struct in_addr netmask; /* netmask applied to address */ | ||
355 | unsigned mtu; /* MTU of interface */ | ||
356 | }; | ||
357 | |||
358 | /* | ||
359 | * UUID definition [internet draft] | ||
360 | * - the timestamp is a 60-bit value, split 32/16/12, and goes in 100ns | ||
361 | * increments since midnight 15th October 1582 | ||
362 | * - add AFS_UUID_TO_UNIX_TIME to convert unix time in 100ns units to UUID | ||
363 | * time | ||
364 | * - the clock sequence is a 14-bit counter to avoid duplicate times | ||
365 | */ | ||
366 | struct afs_uuid { | ||
367 | u32 time_low; /* low part of timestamp */ | ||
368 | u16 time_mid; /* mid part of timestamp */ | ||
369 | u16 time_hi_and_version; /* high part of timestamp and version */ | ||
370 | #define AFS_UUID_TO_UNIX_TIME 0x01b21dd213814000 | ||
371 | #define AFS_UUID_TIMEHI_MASK 0x0fff | ||
372 | #define AFS_UUID_VERSION_TIME 0x1000 /* time-based UUID */ | ||
373 | #define AFS_UUID_VERSION_NAME 0x3000 /* name-based UUID */ | ||
374 | #define AFS_UUID_VERSION_RANDOM 0x4000 /* (pseudo-)random generated UUID */ | ||
375 | u8 clock_seq_hi_and_reserved; /* clock seq hi and variant */ | ||
376 | #define AFS_UUID_CLOCKHI_MASK 0x3f | ||
377 | #define AFS_UUID_VARIANT_STD 0x80 | ||
378 | u8 clock_seq_low; /* clock seq low */ | ||
379 | u8 node[6]; /* spatially unique node ID (MAC addr) */ | ||
380 | }; | ||
381 | |||
382 | /*****************************************************************************/ | ||
383 | /* | ||
384 | * callback.c | ||
385 | */ | ||
386 | extern void afs_init_callback_state(struct afs_server *); | ||
387 | extern void afs_broken_callback_work(struct work_struct *); | ||
388 | extern void afs_break_callbacks(struct afs_server *, size_t, | ||
389 | struct afs_callback[]); | ||
390 | extern void afs_discard_callback_on_delete(struct afs_vnode *); | ||
391 | extern void afs_give_up_callback(struct afs_vnode *); | ||
392 | extern void afs_dispatch_give_up_callbacks(struct work_struct *); | ||
393 | extern void afs_flush_callback_breaks(struct afs_server *); | ||
394 | extern int __init afs_callback_update_init(void); | ||
395 | extern void __exit afs_callback_update_kill(void); | ||
396 | |||
54 | /* | 397 | /* |
55 | * cell.c | 398 | * cell.c |
56 | */ | 399 | */ |
@@ -60,57 +403,156 @@ extern struct list_head afs_proc_cells; | |||
60 | extern struct cachefs_index_def afs_cache_cell_index_def; | 403 | extern struct cachefs_index_def afs_cache_cell_index_def; |
61 | #endif | 404 | #endif |
62 | 405 | ||
406 | #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) | ||
407 | extern int afs_cell_init(char *); | ||
408 | extern struct afs_cell *afs_cell_create(const char *, char *); | ||
409 | extern struct afs_cell *afs_cell_lookup(const char *, unsigned); | ||
410 | extern struct afs_cell *afs_grab_cell(struct afs_cell *); | ||
411 | extern void afs_put_cell(struct afs_cell *); | ||
412 | extern void afs_cell_purge(void); | ||
413 | |||
414 | /* | ||
415 | * cmservice.c | ||
416 | */ | ||
417 | extern bool afs_cm_incoming_call(struct afs_call *); | ||
418 | |||
63 | /* | 419 | /* |
64 | * dir.c | 420 | * dir.c |
65 | */ | 421 | */ |
66 | extern const struct inode_operations afs_dir_inode_operations; | 422 | extern const struct inode_operations afs_dir_inode_operations; |
67 | extern const struct file_operations afs_dir_file_operations; | 423 | extern const struct file_operations afs_dir_file_operations; |
68 | 424 | ||
425 | extern int afs_permission(struct inode *, int, struct nameidata *); | ||
426 | |||
69 | /* | 427 | /* |
70 | * file.c | 428 | * file.c |
71 | */ | 429 | */ |
72 | extern const struct address_space_operations afs_fs_aops; | 430 | extern const struct address_space_operations afs_fs_aops; |
73 | extern const struct inode_operations afs_file_inode_operations; | 431 | extern const struct inode_operations afs_file_inode_operations; |
432 | extern const struct file_operations afs_file_operations; | ||
433 | |||
434 | extern int afs_open(struct inode *, struct file *); | ||
435 | extern int afs_release(struct inode *, struct file *); | ||
74 | 436 | ||
75 | #ifdef AFS_CACHING_SUPPORT | 437 | #ifdef AFS_CACHING_SUPPORT |
76 | extern int afs_cache_get_page_cookie(struct page *page, | 438 | extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **); |
77 | struct cachefs_page **_page_cookie); | ||
78 | #endif | 439 | #endif |
79 | 440 | ||
80 | /* | 441 | /* |
81 | * inode.c | 442 | * fsclient.c |
82 | */ | 443 | */ |
83 | extern int afs_iget(struct super_block *sb, struct afs_fid *fid, | 444 | extern int afs_fs_fetch_file_status(struct afs_server *, struct key *, |
84 | struct inode **_inode); | 445 | struct afs_vnode *, struct afs_volsync *, |
85 | extern int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, | 446 | const struct afs_wait_mode *); |
86 | struct kstat *stat); | 447 | extern int afs_fs_give_up_callbacks(struct afs_server *, |
87 | extern void afs_clear_inode(struct inode *inode); | 448 | const struct afs_wait_mode *); |
449 | extern int afs_fs_fetch_data(struct afs_server *, struct key *, | ||
450 | struct afs_vnode *, off_t, size_t, struct page *, | ||
451 | const struct afs_wait_mode *); | ||
452 | extern int afs_fs_create(struct afs_server *, struct key *, | ||
453 | struct afs_vnode *, const char *, umode_t, | ||
454 | struct afs_fid *, struct afs_file_status *, | ||
455 | struct afs_callback *, | ||
456 | const struct afs_wait_mode *); | ||
457 | extern int afs_fs_remove(struct afs_server *, struct key *, | ||
458 | struct afs_vnode *, const char *, bool, | ||
459 | const struct afs_wait_mode *); | ||
460 | extern int afs_fs_link(struct afs_server *, struct key *, struct afs_vnode *, | ||
461 | struct afs_vnode *, const char *, | ||
462 | const struct afs_wait_mode *); | ||
463 | extern int afs_fs_symlink(struct afs_server *, struct key *, | ||
464 | struct afs_vnode *, const char *, const char *, | ||
465 | struct afs_fid *, struct afs_file_status *, | ||
466 | const struct afs_wait_mode *); | ||
467 | extern int afs_fs_rename(struct afs_server *, struct key *, | ||
468 | struct afs_vnode *, const char *, | ||
469 | struct afs_vnode *, const char *, | ||
470 | const struct afs_wait_mode *); | ||
88 | 471 | ||
89 | /* | 472 | /* |
90 | * key_afs.c | 473 | * inode.c |
91 | */ | 474 | */ |
92 | #ifdef CONFIG_KEYS | 475 | extern struct inode *afs_iget(struct super_block *, struct key *, |
93 | extern int afs_key_register(void); | 476 | struct afs_fid *, struct afs_file_status *, |
94 | extern void afs_key_unregister(void); | 477 | struct afs_callback *); |
95 | #endif | 478 | extern int afs_validate(struct afs_vnode *, struct key *); |
479 | extern int afs_inode_getattr(struct vfsmount *, struct dentry *, | ||
480 | struct kstat *); | ||
481 | extern void afs_zap_permits(struct rcu_head *); | ||
482 | extern void afs_clear_inode(struct inode *); | ||
96 | 483 | ||
97 | /* | 484 | /* |
98 | * main.c | 485 | * main.c |
99 | */ | 486 | */ |
487 | extern struct afs_uuid afs_uuid; | ||
100 | #ifdef AFS_CACHING_SUPPORT | 488 | #ifdef AFS_CACHING_SUPPORT |
101 | extern struct cachefs_netfs afs_cache_netfs; | 489 | extern struct cachefs_netfs afs_cache_netfs; |
102 | #endif | 490 | #endif |
103 | 491 | ||
104 | /* | 492 | /* |
493 | * misc.c | ||
494 | */ | ||
495 | extern int afs_abort_to_error(u32); | ||
496 | |||
497 | /* | ||
105 | * mntpt.c | 498 | * mntpt.c |
106 | */ | 499 | */ |
107 | extern const struct inode_operations afs_mntpt_inode_operations; | 500 | extern const struct inode_operations afs_mntpt_inode_operations; |
108 | extern const struct file_operations afs_mntpt_file_operations; | 501 | extern const struct file_operations afs_mntpt_file_operations; |
109 | extern struct afs_timer afs_mntpt_expiry_timer; | ||
110 | extern struct afs_timer_ops afs_mntpt_expiry_timer_ops; | ||
111 | extern unsigned long afs_mntpt_expiry_timeout; | 502 | extern unsigned long afs_mntpt_expiry_timeout; |
112 | 503 | ||
113 | extern int afs_mntpt_check_symlink(struct afs_vnode *vnode); | 504 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); |
505 | extern void afs_mntpt_kill_timer(void); | ||
506 | extern void afs_umount_begin(struct vfsmount *, int); | ||
507 | |||
508 | /* | ||
509 | * proc.c | ||
510 | */ | ||
511 | extern int afs_proc_init(void); | ||
512 | extern void afs_proc_cleanup(void); | ||
513 | extern int afs_proc_cell_setup(struct afs_cell *); | ||
514 | extern void afs_proc_cell_remove(struct afs_cell *); | ||
515 | |||
516 | /* | ||
517 | * rxrpc.c | ||
518 | */ | ||
519 | extern int afs_open_socket(void); | ||
520 | extern void afs_close_socket(void); | ||
521 | extern int afs_make_call(struct in_addr *, struct afs_call *, gfp_t, | ||
522 | const struct afs_wait_mode *); | ||
523 | extern struct afs_call *afs_alloc_flat_call(const struct afs_call_type *, | ||
524 | size_t, size_t); | ||
525 | extern void afs_flat_call_destructor(struct afs_call *); | ||
526 | extern void afs_transfer_reply(struct afs_call *, struct sk_buff *); | ||
527 | extern void afs_send_empty_reply(struct afs_call *); | ||
528 | extern void afs_send_simple_reply(struct afs_call *, const void *, size_t); | ||
529 | extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *, | ||
530 | size_t); | ||
531 | |||
532 | /* | ||
533 | * security.c | ||
534 | */ | ||
535 | extern void afs_clear_permits(struct afs_vnode *); | ||
536 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); | ||
537 | extern struct key *afs_request_key(struct afs_cell *); | ||
538 | extern int afs_permission(struct inode *, int, struct nameidata *); | ||
539 | |||
540 | /* | ||
541 | * server.c | ||
542 | */ | ||
543 | extern spinlock_t afs_server_peer_lock; | ||
544 | |||
545 | #define afs_get_server(S) \ | ||
546 | do { \ | ||
547 | _debug("GET SERVER %d", atomic_read(&(S)->usage)); \ | ||
548 | atomic_inc(&(S)->usage); \ | ||
549 | } while(0) | ||
550 | |||
551 | extern struct afs_server *afs_lookup_server(struct afs_cell *, | ||
552 | const struct in_addr *); | ||
553 | extern struct afs_server *afs_find_server(const struct in_addr *); | ||
554 | extern void afs_put_server(struct afs_server *); | ||
555 | extern void __exit afs_purge_servers(void); | ||
114 | 556 | ||
115 | /* | 557 | /* |
116 | * super.c | 558 | * super.c |
@@ -118,22 +560,211 @@ extern int afs_mntpt_check_symlink(struct afs_vnode *vnode); | |||
118 | extern int afs_fs_init(void); | 560 | extern int afs_fs_init(void); |
119 | extern void afs_fs_exit(void); | 561 | extern void afs_fs_exit(void); |
120 | 562 | ||
121 | #define AFS_CB_HASH_COUNT (PAGE_SIZE / sizeof(struct list_head)) | 563 | /* |
564 | * use-rtnetlink.c | ||
565 | */ | ||
566 | extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool); | ||
567 | extern int afs_get_MAC_address(u8 [6]); | ||
122 | 568 | ||
123 | extern struct list_head afs_cb_hash_tbl[]; | 569 | /* |
124 | extern spinlock_t afs_cb_hash_lock; | 570 | * vlclient.c |
571 | */ | ||
572 | #ifdef AFS_CACHING_SUPPORT | ||
573 | extern struct cachefs_index_def afs_vlocation_cache_index_def; | ||
574 | #endif | ||
125 | 575 | ||
126 | #define afs_cb_hash(SRV,FID) \ | 576 | extern int afs_vl_get_entry_by_name(struct in_addr *, struct key *, |
127 | afs_cb_hash_tbl[((unsigned long)(SRV) + \ | 577 | const char *, struct afs_cache_vlocation *, |
128 | (FID)->vid + (FID)->vnode + (FID)->unique) % \ | 578 | const struct afs_wait_mode *); |
129 | AFS_CB_HASH_COUNT] | 579 | extern int afs_vl_get_entry_by_id(struct in_addr *, struct key *, |
580 | afs_volid_t, afs_voltype_t, | ||
581 | struct afs_cache_vlocation *, | ||
582 | const struct afs_wait_mode *); | ||
130 | 583 | ||
131 | /* | 584 | /* |
132 | * proc.c | 585 | * vlocation.c |
133 | */ | 586 | */ |
134 | extern int afs_proc_init(void); | 587 | #define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0) |
135 | extern void afs_proc_cleanup(void); | 588 | |
136 | extern int afs_proc_cell_setup(struct afs_cell *cell); | 589 | extern int __init afs_vlocation_update_init(void); |
137 | extern void afs_proc_cell_remove(struct afs_cell *cell); | 590 | extern struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *, |
591 | struct key *, | ||
592 | const char *, size_t); | ||
593 | extern void afs_put_vlocation(struct afs_vlocation *); | ||
594 | extern void __exit afs_vlocation_purge(void); | ||
595 | |||
596 | /* | ||
597 | * vnode.c | ||
598 | */ | ||
599 | #ifdef AFS_CACHING_SUPPORT | ||
600 | extern struct cachefs_index_def afs_vnode_cache_index_def; | ||
601 | #endif | ||
602 | |||
603 | extern struct afs_timer_ops afs_vnode_cb_timed_out_ops; | ||
604 | |||
605 | static inline struct afs_vnode *AFS_FS_I(struct inode *inode) | ||
606 | { | ||
607 | return container_of(inode, struct afs_vnode, vfs_inode); | ||
608 | } | ||
609 | |||
610 | static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode) | ||
611 | { | ||
612 | return &vnode->vfs_inode; | ||
613 | } | ||
614 | |||
615 | extern void afs_vnode_finalise_status_update(struct afs_vnode *, | ||
616 | struct afs_server *); | ||
617 | extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *, | ||
618 | struct key *); | ||
619 | extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *, | ||
620 | off_t, size_t, struct page *); | ||
621 | extern int afs_vnode_create(struct afs_vnode *, struct key *, const char *, | ||
622 | umode_t, struct afs_fid *, struct afs_file_status *, | ||
623 | struct afs_callback *, struct afs_server **); | ||
624 | extern int afs_vnode_remove(struct afs_vnode *, struct key *, const char *, | ||
625 | bool); | ||
626 | extern int afs_vnode_link(struct afs_vnode *, struct afs_vnode *, struct key *, | ||
627 | const char *); | ||
628 | extern int afs_vnode_symlink(struct afs_vnode *, struct key *, const char *, | ||
629 | const char *, struct afs_fid *, | ||
630 | struct afs_file_status *, struct afs_server **); | ||
631 | extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *, | ||
632 | struct key *, const char *, const char *); | ||
633 | |||
634 | /* | ||
635 | * volume.c | ||
636 | */ | ||
637 | #ifdef AFS_CACHING_SUPPORT | ||
638 | extern struct cachefs_index_def afs_volume_cache_index_def; | ||
639 | #endif | ||
640 | |||
641 | #define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0) | ||
642 | |||
643 | extern void afs_put_volume(struct afs_volume *); | ||
644 | extern struct afs_volume *afs_volume_lookup(struct afs_mount_params *); | ||
645 | extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *); | ||
646 | extern int afs_volume_release_fileserver(struct afs_vnode *, | ||
647 | struct afs_server *, int); | ||
648 | |||
649 | /*****************************************************************************/ | ||
650 | /* | ||
651 | * debug tracing | ||
652 | */ | ||
653 | extern unsigned afs_debug; | ||
654 | |||
655 | #define dbgprintk(FMT,...) \ | ||
656 | printk("[%x%-6.6s] "FMT"\n", smp_processor_id(), current->comm ,##__VA_ARGS__) | ||
657 | |||
658 | /* make sure we maintain the format strings, even when debugging is disabled */ | ||
659 | static inline __attribute__((format(printf,1,2))) | ||
660 | void _dbprintk(const char *fmt, ...) | ||
661 | { | ||
662 | } | ||
663 | |||
664 | #define kenter(FMT,...) dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__) | ||
665 | #define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__) | ||
666 | #define kdebug(FMT,...) dbgprintk(" "FMT ,##__VA_ARGS__) | ||
667 | |||
668 | |||
669 | #if defined(__KDEBUG) | ||
670 | #define _enter(FMT,...) kenter(FMT,##__VA_ARGS__) | ||
671 | #define _leave(FMT,...) kleave(FMT,##__VA_ARGS__) | ||
672 | #define _debug(FMT,...) kdebug(FMT,##__VA_ARGS__) | ||
673 | |||
674 | #elif defined(CONFIG_AFS_DEBUG) | ||
675 | #define AFS_DEBUG_KENTER 0x01 | ||
676 | #define AFS_DEBUG_KLEAVE 0x02 | ||
677 | #define AFS_DEBUG_KDEBUG 0x04 | ||
678 | |||
679 | #define _enter(FMT,...) \ | ||
680 | do { \ | ||
681 | if (unlikely(afs_debug & AFS_DEBUG_KENTER)) \ | ||
682 | kenter(FMT,##__VA_ARGS__); \ | ||
683 | } while (0) | ||
684 | |||
685 | #define _leave(FMT,...) \ | ||
686 | do { \ | ||
687 | if (unlikely(afs_debug & AFS_DEBUG_KLEAVE)) \ | ||
688 | kleave(FMT,##__VA_ARGS__); \ | ||
689 | } while (0) | ||
690 | |||
691 | #define _debug(FMT,...) \ | ||
692 | do { \ | ||
693 | if (unlikely(afs_debug & AFS_DEBUG_KDEBUG)) \ | ||
694 | kdebug(FMT,##__VA_ARGS__); \ | ||
695 | } while (0) | ||
696 | |||
697 | #else | ||
698 | #define _enter(FMT,...) _dbprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__) | ||
699 | #define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__) | ||
700 | #define _debug(FMT,...) _dbprintk(" "FMT ,##__VA_ARGS__) | ||
701 | #endif | ||
702 | |||
703 | /* | ||
704 | * debug assertion checking | ||
705 | */ | ||
706 | #if 1 // defined(__KDEBUGALL) | ||
707 | |||
708 | #define ASSERT(X) \ | ||
709 | do { \ | ||
710 | if (unlikely(!(X))) { \ | ||
711 | printk(KERN_ERR "\n"); \ | ||
712 | printk(KERN_ERR "AFS: Assertion failed\n"); \ | ||
713 | BUG(); \ | ||
714 | } \ | ||
715 | } while(0) | ||
716 | |||
717 | #define ASSERTCMP(X, OP, Y) \ | ||
718 | do { \ | ||
719 | if (unlikely(!((X) OP (Y)))) { \ | ||
720 | printk(KERN_ERR "\n"); \ | ||
721 | printk(KERN_ERR "AFS: Assertion failed\n"); \ | ||
722 | printk(KERN_ERR "%lu " #OP " %lu is false\n", \ | ||
723 | (unsigned long)(X), (unsigned long)(Y)); \ | ||
724 | printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \ | ||
725 | (unsigned long)(X), (unsigned long)(Y)); \ | ||
726 | BUG(); \ | ||
727 | } \ | ||
728 | } while(0) | ||
729 | |||
730 | #define ASSERTIF(C, X) \ | ||
731 | do { \ | ||
732 | if (unlikely((C) && !(X))) { \ | ||
733 | printk(KERN_ERR "\n"); \ | ||
734 | printk(KERN_ERR "AFS: Assertion failed\n"); \ | ||
735 | BUG(); \ | ||
736 | } \ | ||
737 | } while(0) | ||
738 | |||
739 | #define ASSERTIFCMP(C, X, OP, Y) \ | ||
740 | do { \ | ||
741 | if (unlikely((C) && !((X) OP (Y)))) { \ | ||
742 | printk(KERN_ERR "\n"); \ | ||
743 | printk(KERN_ERR "AFS: Assertion failed\n"); \ | ||
744 | printk(KERN_ERR "%lu " #OP " %lu is false\n", \ | ||
745 | (unsigned long)(X), (unsigned long)(Y)); \ | ||
746 | printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \ | ||
747 | (unsigned long)(X), (unsigned long)(Y)); \ | ||
748 | BUG(); \ | ||
749 | } \ | ||
750 | } while(0) | ||
751 | |||
752 | #else | ||
753 | |||
754 | #define ASSERT(X) \ | ||
755 | do { \ | ||
756 | } while(0) | ||
757 | |||
758 | #define ASSERTCMP(X, OP, Y) \ | ||
759 | do { \ | ||
760 | } while(0) | ||
761 | |||
762 | #define ASSERTIF(C, X) \ | ||
763 | do { \ | ||
764 | } while(0) | ||
765 | |||
766 | #define ASSERTIFCMP(C, X, OP, Y) \ | ||
767 | do { \ | ||
768 | } while(0) | ||
138 | 769 | ||
139 | #endif /* AFS_INTERNAL_H */ | 770 | #endif /* __KDEBUGALL */ |
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c deleted file mode 100644 index 615df2407cb2..000000000000 --- a/fs/afs/kafsasyncd.c +++ /dev/null | |||
@@ -1,255 +0,0 @@ | |||
1 | /* kafsasyncd.c: AFS asynchronous operation daemon | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | * The AFS async daemon is used to the following: | ||
13 | * - probe "dead" servers to see whether they've come back to life yet. | ||
14 | * - probe "live" servers that we haven't talked to for a while to see if they are better | ||
15 | * candidates for serving than what we're currently using | ||
16 | * - poll volume location servers to keep up to date volume location lists | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/completion.h> | ||
23 | #include <linux/freezer.h> | ||
24 | #include "cell.h" | ||
25 | #include "server.h" | ||
26 | #include "volume.h" | ||
27 | #include "kafsasyncd.h" | ||
28 | #include "kafstimod.h" | ||
29 | #include <rxrpc/call.h> | ||
30 | #include <asm/errno.h> | ||
31 | #include "internal.h" | ||
32 | |||
33 | static DECLARE_COMPLETION(kafsasyncd_alive); | ||
34 | static DECLARE_COMPLETION(kafsasyncd_dead); | ||
35 | static DECLARE_WAIT_QUEUE_HEAD(kafsasyncd_sleepq); | ||
36 | static struct task_struct *kafsasyncd_task; | ||
37 | static int kafsasyncd_die; | ||
38 | |||
39 | static int kafsasyncd(void *arg); | ||
40 | |||
41 | static LIST_HEAD(kafsasyncd_async_attnq); | ||
42 | static LIST_HEAD(kafsasyncd_async_busyq); | ||
43 | static DEFINE_SPINLOCK(kafsasyncd_async_lock); | ||
44 | |||
45 | static void kafsasyncd_null_call_attn_func(struct rxrpc_call *call) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | static void kafsasyncd_null_call_error_func(struct rxrpc_call *call) | ||
50 | { | ||
51 | } | ||
52 | |||
53 | /*****************************************************************************/ | ||
54 | /* | ||
55 | * start the async daemon | ||
56 | */ | ||
57 | int afs_kafsasyncd_start(void) | ||
58 | { | ||
59 | int ret; | ||
60 | |||
61 | ret = kernel_thread(kafsasyncd, NULL, 0); | ||
62 | if (ret < 0) | ||
63 | return ret; | ||
64 | |||
65 | wait_for_completion(&kafsasyncd_alive); | ||
66 | |||
67 | return ret; | ||
68 | } /* end afs_kafsasyncd_start() */ | ||
69 | |||
70 | /*****************************************************************************/ | ||
71 | /* | ||
72 | * stop the async daemon | ||
73 | */ | ||
74 | void afs_kafsasyncd_stop(void) | ||
75 | { | ||
76 | /* get rid of my daemon */ | ||
77 | kafsasyncd_die = 1; | ||
78 | wake_up(&kafsasyncd_sleepq); | ||
79 | wait_for_completion(&kafsasyncd_dead); | ||
80 | |||
81 | } /* end afs_kafsasyncd_stop() */ | ||
82 | |||
83 | /*****************************************************************************/ | ||
84 | /* | ||
85 | * probing daemon | ||
86 | */ | ||
87 | static int kafsasyncd(void *arg) | ||
88 | { | ||
89 | struct afs_async_op *op; | ||
90 | int die; | ||
91 | |||
92 | DECLARE_WAITQUEUE(myself, current); | ||
93 | |||
94 | kafsasyncd_task = current; | ||
95 | |||
96 | printk("kAFS: Started kafsasyncd %d\n", current->pid); | ||
97 | |||
98 | daemonize("kafsasyncd"); | ||
99 | |||
100 | complete(&kafsasyncd_alive); | ||
101 | |||
102 | /* loop around looking for things to attend to */ | ||
103 | do { | ||
104 | set_current_state(TASK_INTERRUPTIBLE); | ||
105 | add_wait_queue(&kafsasyncd_sleepq, &myself); | ||
106 | |||
107 | for (;;) { | ||
108 | if (!list_empty(&kafsasyncd_async_attnq) || | ||
109 | signal_pending(current) || | ||
110 | kafsasyncd_die) | ||
111 | break; | ||
112 | |||
113 | schedule(); | ||
114 | set_current_state(TASK_INTERRUPTIBLE); | ||
115 | } | ||
116 | |||
117 | remove_wait_queue(&kafsasyncd_sleepq, &myself); | ||
118 | set_current_state(TASK_RUNNING); | ||
119 | |||
120 | try_to_freeze(); | ||
121 | |||
122 | /* discard pending signals */ | ||
123 | afs_discard_my_signals(); | ||
124 | |||
125 | die = kafsasyncd_die; | ||
126 | |||
127 | /* deal with the next asynchronous operation requiring | ||
128 | * attention */ | ||
129 | if (!list_empty(&kafsasyncd_async_attnq)) { | ||
130 | struct afs_async_op *op; | ||
131 | |||
132 | _debug("@@@ Begin Asynchronous Operation"); | ||
133 | |||
134 | op = NULL; | ||
135 | spin_lock(&kafsasyncd_async_lock); | ||
136 | |||
137 | if (!list_empty(&kafsasyncd_async_attnq)) { | ||
138 | op = list_entry(kafsasyncd_async_attnq.next, | ||
139 | struct afs_async_op, link); | ||
140 | list_move_tail(&op->link, | ||
141 | &kafsasyncd_async_busyq); | ||
142 | } | ||
143 | |||
144 | spin_unlock(&kafsasyncd_async_lock); | ||
145 | |||
146 | _debug("@@@ Operation %p {%p}\n", | ||
147 | op, op ? op->ops : NULL); | ||
148 | |||
149 | if (op) | ||
150 | op->ops->attend(op); | ||
151 | |||
152 | _debug("@@@ End Asynchronous Operation"); | ||
153 | } | ||
154 | |||
155 | } while(!die); | ||
156 | |||
157 | /* need to kill all outstanding asynchronous operations before | ||
158 | * exiting */ | ||
159 | kafsasyncd_task = NULL; | ||
160 | spin_lock(&kafsasyncd_async_lock); | ||
161 | |||
162 | /* fold the busy and attention queues together */ | ||
163 | list_splice_init(&kafsasyncd_async_busyq, | ||
164 | &kafsasyncd_async_attnq); | ||
165 | |||
166 | /* dequeue kafsasyncd from all their wait queues */ | ||
167 | list_for_each_entry(op, &kafsasyncd_async_attnq, link) { | ||
168 | op->call->app_attn_func = kafsasyncd_null_call_attn_func; | ||
169 | op->call->app_error_func = kafsasyncd_null_call_error_func; | ||
170 | remove_wait_queue(&op->call->waitq, &op->waiter); | ||
171 | } | ||
172 | |||
173 | spin_unlock(&kafsasyncd_async_lock); | ||
174 | |||
175 | /* abort all the operations */ | ||
176 | while (!list_empty(&kafsasyncd_async_attnq)) { | ||
177 | op = list_entry(kafsasyncd_async_attnq.next, struct afs_async_op, link); | ||
178 | list_del_init(&op->link); | ||
179 | |||
180 | rxrpc_call_abort(op->call, -EIO); | ||
181 | rxrpc_put_call(op->call); | ||
182 | op->call = NULL; | ||
183 | |||
184 | op->ops->discard(op); | ||
185 | } | ||
186 | |||
187 | /* and that's all */ | ||
188 | _leave(""); | ||
189 | complete_and_exit(&kafsasyncd_dead, 0); | ||
190 | |||
191 | } /* end kafsasyncd() */ | ||
192 | |||
193 | /*****************************************************************************/ | ||
194 | /* | ||
195 | * begin an operation | ||
196 | * - place operation on busy queue | ||
197 | */ | ||
198 | void afs_kafsasyncd_begin_op(struct afs_async_op *op) | ||
199 | { | ||
200 | _enter(""); | ||
201 | |||
202 | spin_lock(&kafsasyncd_async_lock); | ||
203 | |||
204 | init_waitqueue_entry(&op->waiter, kafsasyncd_task); | ||
205 | add_wait_queue(&op->call->waitq, &op->waiter); | ||
206 | |||
207 | list_move_tail(&op->link, &kafsasyncd_async_busyq); | ||
208 | |||
209 | spin_unlock(&kafsasyncd_async_lock); | ||
210 | |||
211 | _leave(""); | ||
212 | } /* end afs_kafsasyncd_begin_op() */ | ||
213 | |||
214 | /*****************************************************************************/ | ||
215 | /* | ||
216 | * request attention for an operation | ||
217 | * - move to attention queue | ||
218 | */ | ||
219 | void afs_kafsasyncd_attend_op(struct afs_async_op *op) | ||
220 | { | ||
221 | _enter(""); | ||
222 | |||
223 | spin_lock(&kafsasyncd_async_lock); | ||
224 | |||
225 | list_move_tail(&op->link, &kafsasyncd_async_attnq); | ||
226 | |||
227 | spin_unlock(&kafsasyncd_async_lock); | ||
228 | |||
229 | wake_up(&kafsasyncd_sleepq); | ||
230 | |||
231 | _leave(""); | ||
232 | } /* end afs_kafsasyncd_attend_op() */ | ||
233 | |||
234 | /*****************************************************************************/ | ||
235 | /* | ||
236 | * terminate an operation | ||
237 | * - remove from either queue | ||
238 | */ | ||
239 | void afs_kafsasyncd_terminate_op(struct afs_async_op *op) | ||
240 | { | ||
241 | _enter(""); | ||
242 | |||
243 | spin_lock(&kafsasyncd_async_lock); | ||
244 | |||
245 | if (!list_empty(&op->link)) { | ||
246 | list_del_init(&op->link); | ||
247 | remove_wait_queue(&op->call->waitq, &op->waiter); | ||
248 | } | ||
249 | |||
250 | spin_unlock(&kafsasyncd_async_lock); | ||
251 | |||
252 | wake_up(&kafsasyncd_sleepq); | ||
253 | |||
254 | _leave(""); | ||
255 | } /* end afs_kafsasyncd_terminate_op() */ | ||
diff --git a/fs/afs/kafsasyncd.h b/fs/afs/kafsasyncd.h deleted file mode 100644 index 791803f9a6fb..000000000000 --- a/fs/afs/kafsasyncd.h +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | /* kafsasyncd.h: AFS asynchronous operation daemon | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_KAFSASYNCD_H | ||
13 | #define _LINUX_AFS_KAFSASYNCD_H | ||
14 | |||
15 | #include "types.h" | ||
16 | |||
17 | struct afs_async_op; | ||
18 | |||
19 | struct afs_async_op_ops { | ||
20 | void (*attend)(struct afs_async_op *op); | ||
21 | void (*discard)(struct afs_async_op *op); | ||
22 | }; | ||
23 | |||
24 | /*****************************************************************************/ | ||
25 | /* | ||
26 | * asynchronous operation record | ||
27 | */ | ||
28 | struct afs_async_op | ||
29 | { | ||
30 | struct list_head link; | ||
31 | struct afs_server *server; /* server being contacted */ | ||
32 | struct rxrpc_call *call; /* RxRPC call performing op */ | ||
33 | wait_queue_t waiter; /* wait queue for kafsasyncd */ | ||
34 | const struct afs_async_op_ops *ops; /* operations */ | ||
35 | }; | ||
36 | |||
37 | static inline void afs_async_op_init(struct afs_async_op *op, | ||
38 | const struct afs_async_op_ops *ops) | ||
39 | { | ||
40 | INIT_LIST_HEAD(&op->link); | ||
41 | op->call = NULL; | ||
42 | op->ops = ops; | ||
43 | } | ||
44 | |||
45 | extern int afs_kafsasyncd_start(void); | ||
46 | extern void afs_kafsasyncd_stop(void); | ||
47 | |||
48 | extern void afs_kafsasyncd_begin_op(struct afs_async_op *op); | ||
49 | extern void afs_kafsasyncd_attend_op(struct afs_async_op *op); | ||
50 | extern void afs_kafsasyncd_terminate_op(struct afs_async_op *op); | ||
51 | |||
52 | #endif /* _LINUX_AFS_KAFSASYNCD_H */ | ||
diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c deleted file mode 100644 index 694344e4d3c7..000000000000 --- a/fs/afs/kafstimod.c +++ /dev/null | |||
@@ -1,205 +0,0 @@ | |||
1 | /* kafstimod.c: AFS timeout daemon | ||
2 | * | ||
3 | * Copyright (C) 2002 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/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/completion.h> | ||
16 | #include <linux/freezer.h> | ||
17 | #include "cell.h" | ||
18 | #include "volume.h" | ||
19 | #include "kafstimod.h" | ||
20 | #include <asm/errno.h> | ||
21 | #include "internal.h" | ||
22 | |||
23 | static DECLARE_COMPLETION(kafstimod_alive); | ||
24 | static DECLARE_COMPLETION(kafstimod_dead); | ||
25 | static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq); | ||
26 | static int kafstimod_die; | ||
27 | |||
28 | static LIST_HEAD(kafstimod_list); | ||
29 | static DEFINE_SPINLOCK(kafstimod_lock); | ||
30 | |||
31 | static int kafstimod(void *arg); | ||
32 | |||
33 | /*****************************************************************************/ | ||
34 | /* | ||
35 | * start the timeout daemon | ||
36 | */ | ||
37 | int afs_kafstimod_start(void) | ||
38 | { | ||
39 | int ret; | ||
40 | |||
41 | ret = kernel_thread(kafstimod, NULL, 0); | ||
42 | if (ret < 0) | ||
43 | return ret; | ||
44 | |||
45 | wait_for_completion(&kafstimod_alive); | ||
46 | |||
47 | return ret; | ||
48 | } /* end afs_kafstimod_start() */ | ||
49 | |||
50 | /*****************************************************************************/ | ||
51 | /* | ||
52 | * stop the timeout daemon | ||
53 | */ | ||
54 | void afs_kafstimod_stop(void) | ||
55 | { | ||
56 | /* get rid of my daemon */ | ||
57 | kafstimod_die = 1; | ||
58 | wake_up(&kafstimod_sleepq); | ||
59 | wait_for_completion(&kafstimod_dead); | ||
60 | |||
61 | } /* end afs_kafstimod_stop() */ | ||
62 | |||
63 | /*****************************************************************************/ | ||
64 | /* | ||
65 | * timeout processing daemon | ||
66 | */ | ||
67 | static int kafstimod(void *arg) | ||
68 | { | ||
69 | struct afs_timer *timer; | ||
70 | |||
71 | DECLARE_WAITQUEUE(myself, current); | ||
72 | |||
73 | printk("kAFS: Started kafstimod %d\n", current->pid); | ||
74 | |||
75 | daemonize("kafstimod"); | ||
76 | |||
77 | complete(&kafstimod_alive); | ||
78 | |||
79 | /* loop around looking for things to attend to */ | ||
80 | loop: | ||
81 | set_current_state(TASK_INTERRUPTIBLE); | ||
82 | add_wait_queue(&kafstimod_sleepq, &myself); | ||
83 | |||
84 | for (;;) { | ||
85 | unsigned long jif; | ||
86 | signed long timeout; | ||
87 | |||
88 | /* deal with the server being asked to die */ | ||
89 | if (kafstimod_die) { | ||
90 | remove_wait_queue(&kafstimod_sleepq, &myself); | ||
91 | _leave(""); | ||
92 | complete_and_exit(&kafstimod_dead, 0); | ||
93 | } | ||
94 | |||
95 | try_to_freeze(); | ||
96 | |||
97 | /* discard pending signals */ | ||
98 | afs_discard_my_signals(); | ||
99 | |||
100 | /* work out the time to elapse before the next event */ | ||
101 | spin_lock(&kafstimod_lock); | ||
102 | if (list_empty(&kafstimod_list)) { | ||
103 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
104 | } | ||
105 | else { | ||
106 | timer = list_entry(kafstimod_list.next, | ||
107 | struct afs_timer, link); | ||
108 | timeout = timer->timo_jif; | ||
109 | jif = jiffies; | ||
110 | |||
111 | if (time_before_eq((unsigned long) timeout, jif)) | ||
112 | goto immediate; | ||
113 | |||
114 | else { | ||
115 | timeout = (long) timeout - (long) jiffies; | ||
116 | } | ||
117 | } | ||
118 | spin_unlock(&kafstimod_lock); | ||
119 | |||
120 | schedule_timeout(timeout); | ||
121 | |||
122 | set_current_state(TASK_INTERRUPTIBLE); | ||
123 | } | ||
124 | |||
125 | /* the thing on the front of the queue needs processing | ||
126 | * - we come here with the lock held and timer pointing to the expired | ||
127 | * entry | ||
128 | */ | ||
129 | immediate: | ||
130 | remove_wait_queue(&kafstimod_sleepq, &myself); | ||
131 | set_current_state(TASK_RUNNING); | ||
132 | |||
133 | _debug("@@@ Begin Timeout of %p", timer); | ||
134 | |||
135 | /* dequeue the timer */ | ||
136 | list_del_init(&timer->link); | ||
137 | spin_unlock(&kafstimod_lock); | ||
138 | |||
139 | /* call the timeout function */ | ||
140 | timer->ops->timed_out(timer); | ||
141 | |||
142 | _debug("@@@ End Timeout"); | ||
143 | goto loop; | ||
144 | |||
145 | } /* end kafstimod() */ | ||
146 | |||
147 | /*****************************************************************************/ | ||
148 | /* | ||
149 | * (re-)queue a timer | ||
150 | */ | ||
151 | void afs_kafstimod_add_timer(struct afs_timer *timer, unsigned long timeout) | ||
152 | { | ||
153 | struct afs_timer *ptimer; | ||
154 | struct list_head *_p; | ||
155 | |||
156 | _enter("%p,%lu", timer, timeout); | ||
157 | |||
158 | spin_lock(&kafstimod_lock); | ||
159 | |||
160 | list_del(&timer->link); | ||
161 | |||
162 | /* the timer was deferred or reset - put it back in the queue at the | ||
163 | * right place */ | ||
164 | timer->timo_jif = jiffies + timeout; | ||
165 | |||
166 | list_for_each(_p, &kafstimod_list) { | ||
167 | ptimer = list_entry(_p, struct afs_timer, link); | ||
168 | if (time_before(timer->timo_jif, ptimer->timo_jif)) | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | list_add_tail(&timer->link, _p); /* insert before stopping point */ | ||
173 | |||
174 | spin_unlock(&kafstimod_lock); | ||
175 | |||
176 | wake_up(&kafstimod_sleepq); | ||
177 | |||
178 | _leave(""); | ||
179 | } /* end afs_kafstimod_add_timer() */ | ||
180 | |||
181 | /*****************************************************************************/ | ||
182 | /* | ||
183 | * dequeue a timer | ||
184 | * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued | ||
185 | */ | ||
186 | int afs_kafstimod_del_timer(struct afs_timer *timer) | ||
187 | { | ||
188 | int ret = 0; | ||
189 | |||
190 | _enter("%p", timer); | ||
191 | |||
192 | spin_lock(&kafstimod_lock); | ||
193 | |||
194 | if (list_empty(&timer->link)) | ||
195 | ret = -ENOENT; | ||
196 | else | ||
197 | list_del_init(&timer->link); | ||
198 | |||
199 | spin_unlock(&kafstimod_lock); | ||
200 | |||
201 | wake_up(&kafstimod_sleepq); | ||
202 | |||
203 | _leave(" = %d", ret); | ||
204 | return ret; | ||
205 | } /* end afs_kafstimod_del_timer() */ | ||
diff --git a/fs/afs/kafstimod.h b/fs/afs/kafstimod.h deleted file mode 100644 index e312f1a61a7f..000000000000 --- a/fs/afs/kafstimod.h +++ /dev/null | |||
@@ -1,49 +0,0 @@ | |||
1 | /* kafstimod.h: AFS timeout daemon | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_KAFSTIMOD_H | ||
13 | #define _LINUX_AFS_KAFSTIMOD_H | ||
14 | |||
15 | #include "types.h" | ||
16 | |||
17 | struct afs_timer; | ||
18 | |||
19 | struct afs_timer_ops { | ||
20 | /* called when the front of the timer queue has timed out */ | ||
21 | void (*timed_out)(struct afs_timer *timer); | ||
22 | }; | ||
23 | |||
24 | /*****************************************************************************/ | ||
25 | /* | ||
26 | * AFS timer/timeout record | ||
27 | */ | ||
28 | struct afs_timer | ||
29 | { | ||
30 | struct list_head link; /* link in timer queue */ | ||
31 | unsigned long timo_jif; /* timeout time */ | ||
32 | const struct afs_timer_ops *ops; /* timeout expiry function */ | ||
33 | }; | ||
34 | |||
35 | static inline void afs_timer_init(struct afs_timer *timer, | ||
36 | const struct afs_timer_ops *ops) | ||
37 | { | ||
38 | INIT_LIST_HEAD(&timer->link); | ||
39 | timer->ops = ops; | ||
40 | } | ||
41 | |||
42 | extern int afs_kafstimod_start(void); | ||
43 | extern void afs_kafstimod_stop(void); | ||
44 | |||
45 | extern void afs_kafstimod_add_timer(struct afs_timer *timer, | ||
46 | unsigned long timeout); | ||
47 | extern int afs_kafstimod_del_timer(struct afs_timer *timer); | ||
48 | |||
49 | #endif /* _LINUX_AFS_KAFSTIMOD_H */ | ||
diff --git a/fs/afs/main.c b/fs/afs/main.c index f2704ba53857..40c2704e7557 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* main.c: AFS client file system | 1 | /* AFS client file system |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -13,43 +13,21 @@ | |||
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/completion.h> | 15 | #include <linux/completion.h> |
16 | #include <rxrpc/rxrpc.h> | ||
17 | #include <rxrpc/transport.h> | ||
18 | #include <rxrpc/call.h> | ||
19 | #include <rxrpc/peer.h> | ||
20 | #include "cache.h" | ||
21 | #include "cell.h" | ||
22 | #include "server.h" | ||
23 | #include "fsclient.h" | ||
24 | #include "cmservice.h" | ||
25 | #include "kafstimod.h" | ||
26 | #include "kafsasyncd.h" | ||
27 | #include "internal.h" | 16 | #include "internal.h" |
28 | 17 | ||
29 | struct rxrpc_transport *afs_transport; | ||
30 | |||
31 | static int afs_adding_peer(struct rxrpc_peer *peer); | ||
32 | static void afs_discarding_peer(struct rxrpc_peer *peer); | ||
33 | |||
34 | |||
35 | MODULE_DESCRIPTION("AFS Client File System"); | 18 | MODULE_DESCRIPTION("AFS Client File System"); |
36 | MODULE_AUTHOR("Red Hat, Inc."); | 19 | MODULE_AUTHOR("Red Hat, Inc."); |
37 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
38 | 21 | ||
22 | unsigned afs_debug; | ||
23 | module_param_named(debug, afs_debug, uint, S_IWUSR | S_IRUGO); | ||
24 | MODULE_PARM_DESC(afs_debug, "AFS debugging mask"); | ||
25 | |||
39 | static char *rootcell; | 26 | static char *rootcell; |
40 | 27 | ||
41 | module_param(rootcell, charp, 0); | 28 | module_param(rootcell, charp, 0); |
42 | MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); | 29 | MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); |
43 | 30 | ||
44 | |||
45 | static struct rxrpc_peer_ops afs_peer_ops = { | ||
46 | .adding = afs_adding_peer, | ||
47 | .discarding = afs_discarding_peer, | ||
48 | }; | ||
49 | |||
50 | struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT]; | ||
51 | DEFINE_SPINLOCK(afs_cb_hash_lock); | ||
52 | |||
53 | #ifdef AFS_CACHING_SUPPORT | 31 | #ifdef AFS_CACHING_SUPPORT |
54 | static struct cachefs_netfs_operations afs_cache_ops = { | 32 | static struct cachefs_netfs_operations afs_cache_ops = { |
55 | .get_page_cookie = afs_cache_get_page_cookie, | 33 | .get_page_cookie = afs_cache_get_page_cookie, |
@@ -62,20 +40,63 @@ struct cachefs_netfs afs_cache_netfs = { | |||
62 | }; | 40 | }; |
63 | #endif | 41 | #endif |
64 | 42 | ||
65 | /*****************************************************************************/ | 43 | struct afs_uuid afs_uuid; |
44 | |||
45 | /* | ||
46 | * get a client UUID | ||
47 | */ | ||
48 | static int __init afs_get_client_UUID(void) | ||
49 | { | ||
50 | struct timespec ts; | ||
51 | u64 uuidtime; | ||
52 | u16 clockseq; | ||
53 | int ret; | ||
54 | |||
55 | /* read the MAC address of one of the external interfaces and construct | ||
56 | * a UUID from it */ | ||
57 | ret = afs_get_MAC_address(afs_uuid.node); | ||
58 | if (ret < 0) | ||
59 | return ret; | ||
60 | |||
61 | getnstimeofday(&ts); | ||
62 | uuidtime = (u64) ts.tv_sec * 1000 * 1000 * 10; | ||
63 | uuidtime += ts.tv_nsec / 100; | ||
64 | uuidtime += AFS_UUID_TO_UNIX_TIME; | ||
65 | afs_uuid.time_low = uuidtime; | ||
66 | afs_uuid.time_mid = uuidtime >> 32; | ||
67 | afs_uuid.time_hi_and_version = (uuidtime >> 48) & AFS_UUID_TIMEHI_MASK; | ||
68 | afs_uuid.time_hi_and_version = AFS_UUID_VERSION_TIME; | ||
69 | |||
70 | get_random_bytes(&clockseq, 2); | ||
71 | afs_uuid.clock_seq_low = clockseq; | ||
72 | afs_uuid.clock_seq_hi_and_reserved = | ||
73 | (clockseq >> 8) & AFS_UUID_CLOCKHI_MASK; | ||
74 | afs_uuid.clock_seq_hi_and_reserved = AFS_UUID_VARIANT_STD; | ||
75 | |||
76 | _debug("AFS UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", | ||
77 | afs_uuid.time_low, | ||
78 | afs_uuid.time_mid, | ||
79 | afs_uuid.time_hi_and_version, | ||
80 | afs_uuid.clock_seq_hi_and_reserved, | ||
81 | afs_uuid.clock_seq_low, | ||
82 | afs_uuid.node[0], afs_uuid.node[1], afs_uuid.node[2], | ||
83 | afs_uuid.node[3], afs_uuid.node[4], afs_uuid.node[5]); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
66 | /* | 88 | /* |
67 | * initialise the AFS client FS module | 89 | * initialise the AFS client FS module |
68 | */ | 90 | */ |
69 | static int __init afs_init(void) | 91 | static int __init afs_init(void) |
70 | { | 92 | { |
71 | int loop, ret; | 93 | int ret; |
72 | 94 | ||
73 | printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n"); | 95 | printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n"); |
74 | 96 | ||
75 | /* initialise the callback hash table */ | 97 | ret = afs_get_client_UUID(); |
76 | spin_lock_init(&afs_cb_hash_lock); | 98 | if (ret < 0) |
77 | for (loop = AFS_CB_HASH_COUNT - 1; loop >= 0; loop--) | 99 | return ret; |
78 | INIT_LIST_HEAD(&afs_cb_hash_tbl[loop]); | ||
79 | 100 | ||
80 | /* register the /proc stuff */ | 101 | /* register the /proc stuff */ |
81 | ret = afs_proc_init(); | 102 | ret = afs_proc_init(); |
@@ -87,70 +108,56 @@ static int __init afs_init(void) | |||
87 | ret = cachefs_register_netfs(&afs_cache_netfs, | 108 | ret = cachefs_register_netfs(&afs_cache_netfs, |
88 | &afs_cache_cell_index_def); | 109 | &afs_cache_cell_index_def); |
89 | if (ret < 0) | 110 | if (ret < 0) |
90 | goto error; | ||
91 | #endif | ||
92 | |||
93 | #ifdef CONFIG_KEYS_TURNED_OFF | ||
94 | ret = afs_key_register(); | ||
95 | if (ret < 0) | ||
96 | goto error_cache; | 111 | goto error_cache; |
97 | #endif | 112 | #endif |
98 | 113 | ||
99 | /* initialise the cell DB */ | 114 | /* initialise the cell DB */ |
100 | ret = afs_cell_init(rootcell); | 115 | ret = afs_cell_init(rootcell); |
101 | if (ret < 0) | 116 | if (ret < 0) |
102 | goto error_keys; | 117 | goto error_cell_init; |
103 | 118 | ||
104 | /* start the timeout daemon */ | 119 | /* initialise the VL update process */ |
105 | ret = afs_kafstimod_start(); | 120 | ret = afs_vlocation_update_init(); |
106 | if (ret < 0) | 121 | if (ret < 0) |
107 | goto error_keys; | 122 | goto error_vl_update_init; |
108 | 123 | ||
109 | /* start the async operation daemon */ | 124 | /* initialise the callback update process */ |
110 | ret = afs_kafsasyncd_start(); | 125 | ret = afs_callback_update_init(); |
111 | if (ret < 0) | ||
112 | goto error_kafstimod; | ||
113 | 126 | ||
114 | /* create the RxRPC transport */ | 127 | /* create the RxRPC transport */ |
115 | ret = rxrpc_create_transport(7001, &afs_transport); | 128 | ret = afs_open_socket(); |
116 | if (ret < 0) | 129 | if (ret < 0) |
117 | goto error_kafsasyncd; | 130 | goto error_open_socket; |
118 | |||
119 | afs_transport->peer_ops = &afs_peer_ops; | ||
120 | 131 | ||
121 | /* register the filesystems */ | 132 | /* register the filesystems */ |
122 | ret = afs_fs_init(); | 133 | ret = afs_fs_init(); |
123 | if (ret < 0) | 134 | if (ret < 0) |
124 | goto error_transport; | 135 | goto error_fs; |
125 | 136 | ||
126 | return ret; | 137 | return ret; |
127 | 138 | ||
128 | error_transport: | 139 | error_fs: |
129 | rxrpc_put_transport(afs_transport); | 140 | afs_close_socket(); |
130 | error_kafsasyncd: | 141 | error_open_socket: |
131 | afs_kafsasyncd_stop(); | 142 | error_vl_update_init: |
132 | error_kafstimod: | 143 | error_cell_init: |
133 | afs_kafstimod_stop(); | ||
134 | error_keys: | ||
135 | #ifdef CONFIG_KEYS_TURNED_OFF | ||
136 | afs_key_unregister(); | ||
137 | error_cache: | ||
138 | #endif | ||
139 | #ifdef AFS_CACHING_SUPPORT | 144 | #ifdef AFS_CACHING_SUPPORT |
140 | cachefs_unregister_netfs(&afs_cache_netfs); | 145 | cachefs_unregister_netfs(&afs_cache_netfs); |
141 | error: | 146 | error_cache: |
142 | #endif | 147 | #endif |
148 | afs_callback_update_kill(); | ||
149 | afs_vlocation_purge(); | ||
143 | afs_cell_purge(); | 150 | afs_cell_purge(); |
144 | afs_proc_cleanup(); | 151 | afs_proc_cleanup(); |
145 | printk(KERN_ERR "kAFS: failed to register: %d\n", ret); | 152 | printk(KERN_ERR "kAFS: failed to register: %d\n", ret); |
146 | return ret; | 153 | return ret; |
147 | } /* end afs_init() */ | 154 | } |
148 | 155 | ||
149 | /* XXX late_initcall is kludgy, but the only alternative seems to create | 156 | /* XXX late_initcall is kludgy, but the only alternative seems to create |
150 | * a transport upon the first mount, which is worse. Or is it? | 157 | * a transport upon the first mount, which is worse. Or is it? |
151 | */ | 158 | */ |
152 | late_initcall(afs_init); /* must be called after net/ to create socket */ | 159 | late_initcall(afs_init); /* must be called after net/ to create socket */ |
153 | /*****************************************************************************/ | 160 | |
154 | /* | 161 | /* |
155 | * clean up on module removal | 162 | * clean up on module removal |
156 | */ | 163 | */ |
@@ -159,127 +166,16 @@ static void __exit afs_exit(void) | |||
159 | printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n"); | 166 | printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n"); |
160 | 167 | ||
161 | afs_fs_exit(); | 168 | afs_fs_exit(); |
162 | rxrpc_put_transport(afs_transport); | 169 | afs_close_socket(); |
163 | afs_kafstimod_stop(); | 170 | afs_purge_servers(); |
164 | afs_kafsasyncd_stop(); | 171 | afs_callback_update_kill(); |
172 | afs_vlocation_purge(); | ||
173 | flush_scheduled_work(); | ||
165 | afs_cell_purge(); | 174 | afs_cell_purge(); |
166 | #ifdef CONFIG_KEYS_TURNED_OFF | ||
167 | afs_key_unregister(); | ||
168 | #endif | ||
169 | #ifdef AFS_CACHING_SUPPORT | 175 | #ifdef AFS_CACHING_SUPPORT |
170 | cachefs_unregister_netfs(&afs_cache_netfs); | 176 | cachefs_unregister_netfs(&afs_cache_netfs); |
171 | #endif | 177 | #endif |
172 | afs_proc_cleanup(); | 178 | afs_proc_cleanup(); |
173 | |||
174 | } /* end afs_exit() */ | ||
175 | |||
176 | module_exit(afs_exit); | ||
177 | |||
178 | /*****************************************************************************/ | ||
179 | /* | ||
180 | * notification that new peer record is being added | ||
181 | * - called from krxsecd | ||
182 | * - return an error to induce an abort | ||
183 | * - mustn't sleep (caller holds an rwlock) | ||
184 | */ | ||
185 | static int afs_adding_peer(struct rxrpc_peer *peer) | ||
186 | { | ||
187 | struct afs_server *server; | ||
188 | int ret; | ||
189 | |||
190 | _debug("kAFS: Adding new peer %08x\n", ntohl(peer->addr.s_addr)); | ||
191 | |||
192 | /* determine which server the peer resides in (if any) */ | ||
193 | ret = afs_server_find_by_peer(peer, &server); | ||
194 | if (ret < 0) | ||
195 | return ret; /* none that we recognise, so abort */ | ||
196 | |||
197 | _debug("Server %p{u=%d}\n", server, atomic_read(&server->usage)); | ||
198 | |||
199 | _debug("Cell %p{u=%d}\n", | ||
200 | server->cell, atomic_read(&server->cell->usage)); | ||
201 | |||
202 | /* cross-point the structs under a global lock */ | ||
203 | spin_lock(&afs_server_peer_lock); | ||
204 | peer->user = server; | ||
205 | server->peer = peer; | ||
206 | spin_unlock(&afs_server_peer_lock); | ||
207 | |||
208 | afs_put_server(server); | ||
209 | |||
210 | return 0; | ||
211 | } /* end afs_adding_peer() */ | ||
212 | |||
213 | /*****************************************************************************/ | ||
214 | /* | ||
215 | * notification that a peer record is being discarded | ||
216 | * - called from krxiod or krxsecd | ||
217 | */ | ||
218 | static void afs_discarding_peer(struct rxrpc_peer *peer) | ||
219 | { | ||
220 | struct afs_server *server; | ||
221 | |||
222 | _enter("%p",peer); | ||
223 | |||
224 | _debug("Discarding peer %08x (rtt=%lu.%lumS)\n", | ||
225 | ntohl(peer->addr.s_addr), | ||
226 | (long) (peer->rtt / 1000), | ||
227 | (long) (peer->rtt % 1000)); | ||
228 | |||
229 | /* uncross-point the structs under a global lock */ | ||
230 | spin_lock(&afs_server_peer_lock); | ||
231 | server = peer->user; | ||
232 | if (server) { | ||
233 | peer->user = NULL; | ||
234 | server->peer = NULL; | ||
235 | } | ||
236 | spin_unlock(&afs_server_peer_lock); | ||
237 | |||
238 | _leave(""); | ||
239 | |||
240 | } /* end afs_discarding_peer() */ | ||
241 | |||
242 | /*****************************************************************************/ | ||
243 | /* | ||
244 | * clear the dead space between task_struct and kernel stack | ||
245 | * - called by supplying -finstrument-functions to gcc | ||
246 | */ | ||
247 | #if 0 | ||
248 | void __cyg_profile_func_enter (void *this_fn, void *call_site) | ||
249 | __attribute__((no_instrument_function)); | ||
250 | |||
251 | void __cyg_profile_func_enter (void *this_fn, void *call_site) | ||
252 | { | ||
253 | asm volatile(" movl %%esp,%%edi \n" | ||
254 | " andl %0,%%edi \n" | ||
255 | " addl %1,%%edi \n" | ||
256 | " movl %%esp,%%ecx \n" | ||
257 | " subl %%edi,%%ecx \n" | ||
258 | " shrl $2,%%ecx \n" | ||
259 | " movl $0xedededed,%%eax \n" | ||
260 | " rep stosl \n" | ||
261 | : | ||
262 | : "i"(~(THREAD_SIZE - 1)), "i"(sizeof(struct thread_info)) | ||
263 | : "eax", "ecx", "edi", "memory", "cc" | ||
264 | ); | ||
265 | } | 179 | } |
266 | 180 | ||
267 | void __cyg_profile_func_exit(void *this_fn, void *call_site) | 181 | module_exit(afs_exit); |
268 | __attribute__((no_instrument_function)); | ||
269 | |||
270 | void __cyg_profile_func_exit(void *this_fn, void *call_site) | ||
271 | { | ||
272 | asm volatile(" movl %%esp,%%edi \n" | ||
273 | " andl %0,%%edi \n" | ||
274 | " addl %1,%%edi \n" | ||
275 | " movl %%esp,%%ecx \n" | ||
276 | " subl %%edi,%%ecx \n" | ||
277 | " shrl $2,%%ecx \n" | ||
278 | " movl $0xdadadada,%%eax \n" | ||
279 | " rep stosl \n" | ||
280 | : | ||
281 | : "i"(~(THREAD_SIZE - 1)), "i"(sizeof(struct thread_info)) | ||
282 | : "eax", "ecx", "edi", "memory", "cc" | ||
283 | ); | ||
284 | } | ||
285 | #endif | ||
diff --git a/fs/afs/misc.c b/fs/afs/misc.c index e4fce66d76e0..cdb9792d8161 100644 --- a/fs/afs/misc.c +++ b/fs/afs/misc.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* misc.c: miscellaneous bits | 1 | /* miscellaneous bits |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -12,19 +12,20 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include "errors.h" | ||
16 | #include "internal.h" | 15 | #include "internal.h" |
16 | #include "afs_fs.h" | ||
17 | 17 | ||
18 | /*****************************************************************************/ | ||
19 | /* | 18 | /* |
20 | * convert an AFS abort code to a Linux error number | 19 | * convert an AFS abort code to a Linux error number |
21 | */ | 20 | */ |
22 | int afs_abort_to_error(int abortcode) | 21 | int afs_abort_to_error(u32 abort_code) |
23 | { | 22 | { |
24 | switch (abortcode) { | 23 | switch (abort_code) { |
24 | case 13: return -EACCES; | ||
25 | case 30: return -EROFS; | ||
25 | case VSALVAGE: return -EIO; | 26 | case VSALVAGE: return -EIO; |
26 | case VNOVNODE: return -ENOENT; | 27 | case VNOVNODE: return -ENOENT; |
27 | case VNOVOL: return -ENXIO; | 28 | case VNOVOL: return -ENOMEDIUM; |
28 | case VVOLEXISTS: return -EEXIST; | 29 | case VVOLEXISTS: return -EEXIST; |
29 | case VNOSERVICE: return -EIO; | 30 | case VNOSERVICE: return -EIO; |
30 | case VOFFLINE: return -ENOENT; | 31 | case VOFFLINE: return -ENOENT; |
@@ -33,7 +34,24 @@ int afs_abort_to_error(int abortcode) | |||
33 | case VOVERQUOTA: return -EDQUOT; | 34 | case VOVERQUOTA: return -EDQUOT; |
34 | case VBUSY: return -EBUSY; | 35 | case VBUSY: return -EBUSY; |
35 | case VMOVED: return -ENXIO; | 36 | case VMOVED: return -ENXIO; |
36 | default: return -EIO; | 37 | case 0x2f6df0c: return -EACCES; |
38 | case 0x2f6df0f: return -EBUSY; | ||
39 | case 0x2f6df10: return -EEXIST; | ||
40 | case 0x2f6df11: return -EXDEV; | ||
41 | case 0x2f6df13: return -ENOTDIR; | ||
42 | case 0x2f6df14: return -EISDIR; | ||
43 | case 0x2f6df15: return -EINVAL; | ||
44 | case 0x2f6df1a: return -EFBIG; | ||
45 | case 0x2f6df1b: return -ENOSPC; | ||
46 | case 0x2f6df1d: return -EROFS; | ||
47 | case 0x2f6df1e: return -EMLINK; | ||
48 | case 0x2f6df20: return -EDOM; | ||
49 | case 0x2f6df21: return -ERANGE; | ||
50 | case 0x2f6df22: return -EDEADLK; | ||
51 | case 0x2f6df23: return -ENAMETOOLONG; | ||
52 | case 0x2f6df24: return -ENOLCK; | ||
53 | case 0x2f6df26: return -ENOTEMPTY; | ||
54 | case 0x2f6df78: return -EDQUOT; | ||
55 | default: return -EREMOTEIO; | ||
37 | } | 56 | } |
38 | 57 | } | |
39 | } /* end afs_abort_to_error() */ | ||
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 68495f0de7b3..b905ae37f912 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* mntpt.c: mountpoint management | 1 | /* mountpoint management |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -18,10 +18,6 @@ | |||
18 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
19 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
20 | #include <linux/mnt_namespace.h> | 20 | #include <linux/mnt_namespace.h> |
21 | #include "super.h" | ||
22 | #include "cell.h" | ||
23 | #include "volume.h" | ||
24 | #include "vnode.h" | ||
25 | #include "internal.h" | 21 | #include "internal.h" |
26 | 22 | ||
27 | 23 | ||
@@ -30,6 +26,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, | |||
30 | struct nameidata *nd); | 26 | struct nameidata *nd); |
31 | static int afs_mntpt_open(struct inode *inode, struct file *file); | 27 | static int afs_mntpt_open(struct inode *inode, struct file *file); |
32 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); | 28 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); |
29 | static void afs_mntpt_expiry_timed_out(struct work_struct *work); | ||
33 | 30 | ||
34 | const struct file_operations afs_mntpt_file_operations = { | 31 | const struct file_operations afs_mntpt_file_operations = { |
35 | .open = afs_mntpt_open, | 32 | .open = afs_mntpt_open, |
@@ -43,24 +40,19 @@ const struct inode_operations afs_mntpt_inode_operations = { | |||
43 | }; | 40 | }; |
44 | 41 | ||
45 | static LIST_HEAD(afs_vfsmounts); | 42 | static LIST_HEAD(afs_vfsmounts); |
43 | static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); | ||
46 | 44 | ||
47 | static void afs_mntpt_expiry_timed_out(struct afs_timer *timer); | 45 | unsigned long afs_mntpt_expiry_timeout = 10 * 60; |
48 | 46 | ||
49 | struct afs_timer_ops afs_mntpt_expiry_timer_ops = { | ||
50 | .timed_out = afs_mntpt_expiry_timed_out, | ||
51 | }; | ||
52 | |||
53 | struct afs_timer afs_mntpt_expiry_timer; | ||
54 | |||
55 | unsigned long afs_mntpt_expiry_timeout = 20; | ||
56 | |||
57 | /*****************************************************************************/ | ||
58 | /* | 47 | /* |
59 | * 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 |
60 | * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately | 49 | * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately |
61 | */ | 50 | */ |
62 | int afs_mntpt_check_symlink(struct afs_vnode *vnode) | 51 | int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) |
63 | { | 52 | { |
53 | struct file file = { | ||
54 | .private_data = key, | ||
55 | }; | ||
64 | struct page *page; | 56 | struct page *page; |
65 | size_t size; | 57 | size_t size; |
66 | char *buf; | 58 | char *buf; |
@@ -69,7 +61,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) | |||
69 | _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); | 61 | _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); |
70 | 62 | ||
71 | /* read the contents of the symlink into the pagecache */ | 63 | /* read the contents of the symlink into the pagecache */ |
72 | 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); |
73 | if (IS_ERR(page)) { | 65 | if (IS_ERR(page)) { |
74 | ret = PTR_ERR(page); | 66 | ret = PTR_ERR(page); |
75 | goto out; | 67 | goto out; |
@@ -85,7 +77,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) | |||
85 | 77 | ||
86 | /* examine the symlink's contents */ | 78 | /* examine the symlink's contents */ |
87 | size = vnode->status.size; | 79 | size = vnode->status.size; |
88 | _debug("symlink to %*.*s", size, (int) size, buf); | 80 | _debug("symlink to %*.*s", (int) size, (int) size, buf); |
89 | 81 | ||
90 | if (size > 2 && | 82 | if (size > 2 && |
91 | (buf[0] == '%' || buf[0] == '#') && | 83 | (buf[0] == '%' || buf[0] == '#') && |
@@ -93,22 +85,20 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) | |||
93 | ) { | 85 | ) { |
94 | _debug("symlink is a mountpoint"); | 86 | _debug("symlink is a mountpoint"); |
95 | spin_lock(&vnode->lock); | 87 | spin_lock(&vnode->lock); |
96 | vnode->flags |= AFS_VNODE_MOUNTPOINT; | 88 | set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); |
97 | spin_unlock(&vnode->lock); | 89 | spin_unlock(&vnode->lock); |
98 | } | 90 | } |
99 | 91 | ||
100 | ret = 0; | 92 | ret = 0; |
101 | 93 | ||
102 | out_free: | 94 | out_free: |
103 | kunmap(page); | 95 | kunmap(page); |
104 | page_cache_release(page); | 96 | page_cache_release(page); |
105 | out: | 97 | out: |
106 | _leave(" = %d", ret); | 98 | _leave(" = %d", ret); |
107 | return ret; | 99 | return ret; |
100 | } | ||
108 | 101 | ||
109 | } /* end afs_mntpt_check_symlink() */ | ||
110 | |||
111 | /*****************************************************************************/ | ||
112 | /* | 102 | /* |
113 | * no valid lookup procedure on this sort of dir | 103 | * no valid lookup procedure on this sort of dir |
114 | */ | 104 | */ |
@@ -116,7 +106,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, | |||
116 | struct dentry *dentry, | 106 | struct dentry *dentry, |
117 | struct nameidata *nd) | 107 | struct nameidata *nd) |
118 | { | 108 | { |
119 | kenter("%p,%p{%p{%s},%s}", | 109 | _enter("%p,%p{%p{%s},%s}", |
120 | dir, | 110 | dir, |
121 | dentry, | 111 | dentry, |
122 | dentry->d_parent, | 112 | dentry->d_parent, |
@@ -125,15 +115,14 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, | |||
125 | dentry->d_name.name); | 115 | dentry->d_name.name); |
126 | 116 | ||
127 | return ERR_PTR(-EREMOTE); | 117 | return ERR_PTR(-EREMOTE); |
128 | } /* end afs_mntpt_lookup() */ | 118 | } |
129 | 119 | ||
130 | /*****************************************************************************/ | ||
131 | /* | 120 | /* |
132 | * no valid open procedure on this sort of dir | 121 | * no valid open procedure on this sort of dir |
133 | */ | 122 | */ |
134 | static int afs_mntpt_open(struct inode *inode, struct file *file) | 123 | static int afs_mntpt_open(struct inode *inode, struct file *file) |
135 | { | 124 | { |
136 | kenter("%p,%p{%p{%s},%s}", | 125 | _enter("%p,%p{%p{%s},%s}", |
137 | inode, file, | 126 | inode, file, |
138 | file->f_path.dentry->d_parent, | 127 | file->f_path.dentry->d_parent, |
139 | file->f_path.dentry->d_parent ? | 128 | file->f_path.dentry->d_parent ? |
@@ -142,9 +131,8 @@ static int afs_mntpt_open(struct inode *inode, struct file *file) | |||
142 | file->f_path.dentry->d_name.name); | 131 | file->f_path.dentry->d_name.name); |
143 | 132 | ||
144 | return -EREMOTE; | 133 | return -EREMOTE; |
145 | } /* end afs_mntpt_open() */ | 134 | } |
146 | 135 | ||
147 | /*****************************************************************************/ | ||
148 | /* | 136 | /* |
149 | * create a vfsmount to be automounted | 137 | * create a vfsmount to be automounted |
150 | */ | 138 | */ |
@@ -157,7 +145,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
157 | char *buf, *devname = NULL, *options = NULL; | 145 | char *buf, *devname = NULL, *options = NULL; |
158 | int ret; | 146 | int ret; |
159 | 147 | ||
160 | kenter("{%s}", mntpt->d_name.name); | 148 | _enter("{%s}", mntpt->d_name.name); |
161 | 149 | ||
162 | BUG_ON(!mntpt->d_inode); | 150 | BUG_ON(!mntpt->d_inode); |
163 | 151 | ||
@@ -201,79 +189,108 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
201 | strcat(options, ",rwpath"); | 189 | strcat(options, ",rwpath"); |
202 | 190 | ||
203 | /* try and do the mount */ | 191 | /* try and do the mount */ |
204 | kdebug("--- attempting mount %s -o %s ---", devname, options); | 192 | _debug("--- attempting mount %s -o %s ---", devname, options); |
205 | mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); | 193 | mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); |
206 | kdebug("--- mount result %p ---", mnt); | 194 | _debug("--- mount result %p ---", mnt); |
207 | 195 | ||
208 | free_page((unsigned long) devname); | 196 | free_page((unsigned long) devname); |
209 | free_page((unsigned long) options); | 197 | free_page((unsigned long) options); |
210 | kleave(" = %p", mnt); | 198 | _leave(" = %p", mnt); |
211 | return mnt; | 199 | return mnt; |
212 | 200 | ||
213 | error: | 201 | error: |
214 | if (page) | 202 | if (page) |
215 | page_cache_release(page); | 203 | page_cache_release(page); |
216 | if (devname) | 204 | if (devname) |
217 | free_page((unsigned long) devname); | 205 | free_page((unsigned long) devname); |
218 | if (options) | 206 | if (options) |
219 | free_page((unsigned long) options); | 207 | free_page((unsigned long) options); |
220 | kleave(" = %d", ret); | 208 | _leave(" = %d", ret); |
221 | return ERR_PTR(ret); | 209 | return ERR_PTR(ret); |
222 | } /* end afs_mntpt_do_automount() */ | 210 | } |
223 | 211 | ||
224 | /*****************************************************************************/ | ||
225 | /* | 212 | /* |
226 | * follow a link from a mountpoint directory, thus causing it to be mounted | 213 | * follow a link from a mountpoint directory, thus causing it to be mounted |
227 | */ | 214 | */ |
228 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | 215 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) |
229 | { | 216 | { |
230 | struct vfsmount *newmnt; | 217 | struct vfsmount *newmnt; |
231 | struct dentry *old_dentry; | ||
232 | int err; | 218 | int err; |
233 | 219 | ||
234 | kenter("%p{%s},{%s:%p{%s}}", | 220 | _enter("%p{%s},{%s:%p{%s},}", |
235 | dentry, | 221 | dentry, |
236 | dentry->d_name.name, | 222 | dentry->d_name.name, |
237 | nd->mnt->mnt_devname, | 223 | nd->mnt->mnt_devname, |
238 | dentry, | 224 | dentry, |
239 | nd->dentry->d_name.name); | 225 | nd->dentry->d_name.name); |
240 | 226 | ||
241 | newmnt = afs_mntpt_do_automount(dentry); | 227 | dput(nd->dentry); |
228 | nd->dentry = dget(dentry); | ||
229 | |||
230 | newmnt = afs_mntpt_do_automount(nd->dentry); | ||
242 | if (IS_ERR(newmnt)) { | 231 | if (IS_ERR(newmnt)) { |
243 | path_release(nd); | 232 | path_release(nd); |
244 | return (void *)newmnt; | 233 | return (void *)newmnt; |
245 | } | 234 | } |
246 | 235 | ||
247 | old_dentry = nd->dentry; | 236 | mntget(newmnt); |
248 | nd->dentry = dentry; | 237 | err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); |
249 | err = do_add_mount(newmnt, nd, 0, &afs_vfsmounts); | 238 | switch (err) { |
250 | nd->dentry = old_dentry; | 239 | case 0: |
251 | 240 | mntput(nd->mnt); | |
252 | path_release(nd); | 241 | dput(nd->dentry); |
253 | |||
254 | if (!err) { | ||
255 | mntget(newmnt); | ||
256 | nd->mnt = newmnt; | 242 | nd->mnt = newmnt; |
257 | dget(newmnt->mnt_root); | 243 | nd->dentry = dget(newmnt->mnt_root); |
258 | nd->dentry = newmnt->mnt_root; | 244 | schedule_delayed_work(&afs_mntpt_expiry_timer, |
245 | afs_mntpt_expiry_timeout * HZ); | ||
246 | break; | ||
247 | case -EBUSY: | ||
248 | /* someone else made a mount here whilst we were busy */ | ||
249 | while (d_mountpoint(nd->dentry) && | ||
250 | follow_down(&nd->mnt, &nd->dentry)) | ||
251 | ; | ||
252 | err = 0; | ||
253 | default: | ||
254 | mntput(newmnt); | ||
255 | break; | ||
259 | } | 256 | } |
260 | 257 | ||
261 | kleave(" = %d", err); | 258 | _leave(" = %d", err); |
262 | return ERR_PTR(err); | 259 | return ERR_PTR(err); |
263 | } /* end afs_mntpt_follow_link() */ | 260 | } |
264 | 261 | ||
265 | /*****************************************************************************/ | ||
266 | /* | 262 | /* |
267 | * handle mountpoint expiry timer going off | 263 | * handle mountpoint expiry timer going off |
268 | */ | 264 | */ |
269 | static void afs_mntpt_expiry_timed_out(struct afs_timer *timer) | 265 | static void afs_mntpt_expiry_timed_out(struct work_struct *work) |
270 | { | 266 | { |
271 | kenter(""); | 267 | _enter(""); |
272 | 268 | ||
273 | mark_mounts_for_expiry(&afs_vfsmounts); | 269 | if (!list_empty(&afs_vfsmounts)) { |
270 | mark_mounts_for_expiry(&afs_vfsmounts); | ||
271 | schedule_delayed_work(&afs_mntpt_expiry_timer, | ||
272 | afs_mntpt_expiry_timeout * HZ); | ||
273 | } | ||
274 | |||
275 | _leave(""); | ||
276 | } | ||
274 | 277 | ||
275 | afs_kafstimod_add_timer(&afs_mntpt_expiry_timer, | 278 | /* |
276 | afs_mntpt_expiry_timeout * HZ); | 279 | * kill the AFS mountpoint timer if it's still running |
280 | */ | ||
281 | void afs_mntpt_kill_timer(void) | ||
282 | { | ||
283 | _enter(""); | ||
277 | 284 | ||
278 | kleave(""); | 285 | ASSERT(list_empty(&afs_vfsmounts)); |
279 | } /* end afs_mntpt_expiry_timed_out() */ | 286 | cancel_delayed_work(&afs_mntpt_expiry_timer); |
287 | flush_scheduled_work(); | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * begin unmount by attempting to remove all automounted mountpoints we added | ||
292 | */ | ||
293 | void afs_umount_begin(struct vfsmount *vfsmnt, int flags) | ||
294 | { | ||
295 | shrink_submounts(vfsmnt, &afs_vfsmounts); | ||
296 | } | ||
diff --git a/fs/afs/mount.h b/fs/afs/mount.h deleted file mode 100644 index 9d2f46ec549f..000000000000 --- a/fs/afs/mount.h +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* mount.h: mount parameters | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_MOUNT_H | ||
13 | #define _LINUX_AFS_MOUNT_H | ||
14 | |||
15 | struct afs_mountdata { | ||
16 | const char *volume; /* name of volume */ | ||
17 | const char *cell; /* name of cell containing volume */ | ||
18 | const char *cache; /* name of cache block device */ | ||
19 | size_t nservers; /* number of server addresses listed */ | ||
20 | uint32_t servers[10]; /* IP addresses of servers in this cell */ | ||
21 | }; | ||
22 | |||
23 | #endif /* _LINUX_AFS_MOUNT_H */ | ||
diff --git a/fs/afs/proc.c b/fs/afs/proc.c index ae6b85b1e484..d5601f617cdb 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* proc.c: /proc interface for AFS | 1 | /* /proc interface for AFS |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -13,8 +13,6 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/proc_fs.h> | 14 | #include <linux/proc_fs.h> |
15 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
16 | #include "cell.h" | ||
17 | #include "volume.h" | ||
18 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
19 | #include "internal.h" | 17 | #include "internal.h" |
20 | 18 | ||
@@ -130,7 +128,6 @@ static const struct file_operations afs_proc_cell_servers_fops = { | |||
130 | .release = afs_proc_cell_servers_release, | 128 | .release = afs_proc_cell_servers_release, |
131 | }; | 129 | }; |
132 | 130 | ||
133 | /*****************************************************************************/ | ||
134 | /* | 131 | /* |
135 | * initialise the /proc/fs/afs/ directory | 132 | * initialise the /proc/fs/afs/ directory |
136 | */ | 133 | */ |
@@ -142,47 +139,43 @@ int afs_proc_init(void) | |||
142 | 139 | ||
143 | proc_afs = proc_mkdir("fs/afs", NULL); | 140 | proc_afs = proc_mkdir("fs/afs", NULL); |
144 | if (!proc_afs) | 141 | if (!proc_afs) |
145 | goto error; | 142 | goto error_dir; |
146 | proc_afs->owner = THIS_MODULE; | 143 | proc_afs->owner = THIS_MODULE; |
147 | 144 | ||
148 | p = create_proc_entry("cells", 0, proc_afs); | 145 | p = create_proc_entry("cells", 0, proc_afs); |
149 | if (!p) | 146 | if (!p) |
150 | goto error_proc; | 147 | goto error_cells; |
151 | p->proc_fops = &afs_proc_cells_fops; | 148 | p->proc_fops = &afs_proc_cells_fops; |
152 | p->owner = THIS_MODULE; | 149 | p->owner = THIS_MODULE; |
153 | 150 | ||
154 | p = create_proc_entry("rootcell", 0, proc_afs); | 151 | p = create_proc_entry("rootcell", 0, proc_afs); |
155 | if (!p) | 152 | if (!p) |
156 | goto error_cells; | 153 | goto error_rootcell; |
157 | p->proc_fops = &afs_proc_rootcell_fops; | 154 | p->proc_fops = &afs_proc_rootcell_fops; |
158 | p->owner = THIS_MODULE; | 155 | p->owner = THIS_MODULE; |
159 | 156 | ||
160 | _leave(" = 0"); | 157 | _leave(" = 0"); |
161 | return 0; | 158 | return 0; |
162 | 159 | ||
163 | error_cells: | 160 | error_rootcell: |
164 | remove_proc_entry("cells", proc_afs); | 161 | remove_proc_entry("cells", proc_afs); |
165 | error_proc: | 162 | error_cells: |
166 | remove_proc_entry("fs/afs", NULL); | 163 | remove_proc_entry("fs/afs", NULL); |
167 | error: | 164 | error_dir: |
168 | _leave(" = -ENOMEM"); | 165 | _leave(" = -ENOMEM"); |
169 | return -ENOMEM; | 166 | return -ENOMEM; |
167 | } | ||
170 | 168 | ||
171 | } /* end afs_proc_init() */ | ||
172 | |||
173 | /*****************************************************************************/ | ||
174 | /* | 169 | /* |
175 | * clean up the /proc/fs/afs/ directory | 170 | * clean up the /proc/fs/afs/ directory |
176 | */ | 171 | */ |
177 | void afs_proc_cleanup(void) | 172 | void afs_proc_cleanup(void) |
178 | { | 173 | { |
174 | remove_proc_entry("rootcell", proc_afs); | ||
179 | remove_proc_entry("cells", proc_afs); | 175 | remove_proc_entry("cells", proc_afs); |
180 | |||
181 | remove_proc_entry("fs/afs", NULL); | 176 | remove_proc_entry("fs/afs", NULL); |
177 | } | ||
182 | 178 | ||
183 | } /* end afs_proc_cleanup() */ | ||
184 | |||
185 | /*****************************************************************************/ | ||
186 | /* | 179 | /* |
187 | * open "/proc/fs/afs/cells" which provides a summary of extant cells | 180 | * open "/proc/fs/afs/cells" which provides a summary of extant cells |
188 | */ | 181 | */ |
@@ -199,9 +192,8 @@ static int afs_proc_cells_open(struct inode *inode, struct file *file) | |||
199 | m->private = PDE(inode)->data; | 192 | m->private = PDE(inode)->data; |
200 | 193 | ||
201 | return 0; | 194 | return 0; |
202 | } /* end afs_proc_cells_open() */ | 195 | } |
203 | 196 | ||
204 | /*****************************************************************************/ | ||
205 | /* | 197 | /* |
206 | * set up the iterator to start reading from the cells list and return the | 198 | * set up the iterator to start reading from the cells list and return the |
207 | * first item | 199 | * first item |
@@ -225,9 +217,8 @@ static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) | |||
225 | break; | 217 | break; |
226 | 218 | ||
227 | return _p != &afs_proc_cells ? _p : NULL; | 219 | return _p != &afs_proc_cells ? _p : NULL; |
228 | } /* end afs_proc_cells_start() */ | 220 | } |
229 | 221 | ||
230 | /*****************************************************************************/ | ||
231 | /* | 222 | /* |
232 | * move to next cell in cells list | 223 | * move to next cell in cells list |
233 | */ | 224 | */ |
@@ -241,19 +232,16 @@ static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos) | |||
241 | _p = v == (void *) 1 ? afs_proc_cells.next : _p->next; | 232 | _p = v == (void *) 1 ? afs_proc_cells.next : _p->next; |
242 | 233 | ||
243 | return _p != &afs_proc_cells ? _p : NULL; | 234 | return _p != &afs_proc_cells ? _p : NULL; |
244 | } /* end afs_proc_cells_next() */ | 235 | } |
245 | 236 | ||
246 | /*****************************************************************************/ | ||
247 | /* | 237 | /* |
248 | * clean up after reading from the cells list | 238 | * clean up after reading from the cells list |
249 | */ | 239 | */ |
250 | static void afs_proc_cells_stop(struct seq_file *p, void *v) | 240 | static void afs_proc_cells_stop(struct seq_file *p, void *v) |
251 | { | 241 | { |
252 | up_read(&afs_proc_cells_sem); | 242 | up_read(&afs_proc_cells_sem); |
243 | } | ||
253 | 244 | ||
254 | } /* end afs_proc_cells_stop() */ | ||
255 | |||
256 | /*****************************************************************************/ | ||
257 | /* | 245 | /* |
258 | * display a header line followed by a load of cell lines | 246 | * display a header line followed by a load of cell lines |
259 | */ | 247 | */ |
@@ -261,19 +249,18 @@ static int afs_proc_cells_show(struct seq_file *m, void *v) | |||
261 | { | 249 | { |
262 | struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); | 250 | struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); |
263 | 251 | ||
264 | /* display header on line 1 */ | ||
265 | if (v == (void *) 1) { | 252 | if (v == (void *) 1) { |
253 | /* display header on line 1 */ | ||
266 | seq_puts(m, "USE NAME\n"); | 254 | seq_puts(m, "USE NAME\n"); |
267 | return 0; | 255 | return 0; |
268 | } | 256 | } |
269 | 257 | ||
270 | /* display one cell per line on subsequent lines */ | 258 | /* display one cell per line on subsequent lines */ |
271 | seq_printf(m, "%3d %s\n", atomic_read(&cell->usage), cell->name); | 259 | seq_printf(m, "%3d %s\n", |
272 | 260 | atomic_read(&cell->usage), cell->name); | |
273 | return 0; | 261 | return 0; |
274 | } /* end afs_proc_cells_show() */ | 262 | } |
275 | 263 | ||
276 | /*****************************************************************************/ | ||
277 | /* | 264 | /* |
278 | * handle writes to /proc/fs/afs/cells | 265 | * handle writes to /proc/fs/afs/cells |
279 | * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" | 266 | * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" |
@@ -326,30 +313,32 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |||
326 | 313 | ||
327 | if (strcmp(kbuf, "add") == 0) { | 314 | if (strcmp(kbuf, "add") == 0) { |
328 | struct afs_cell *cell; | 315 | struct afs_cell *cell; |
329 | ret = afs_cell_create(name, args, &cell); | 316 | |
330 | if (ret < 0) | 317 | cell = afs_cell_create(name, args); |
318 | if (IS_ERR(cell)) { | ||
319 | ret = PTR_ERR(cell); | ||
331 | goto done; | 320 | goto done; |
321 | } | ||
332 | 322 | ||
323 | afs_put_cell(cell); | ||
333 | printk("kAFS: Added new cell '%s'\n", name); | 324 | printk("kAFS: Added new cell '%s'\n", name); |
334 | } | 325 | } else { |
335 | else { | ||
336 | goto inval; | 326 | goto inval; |
337 | } | 327 | } |
338 | 328 | ||
339 | ret = size; | 329 | ret = size; |
340 | 330 | ||
341 | done: | 331 | done: |
342 | kfree(kbuf); | 332 | kfree(kbuf); |
343 | _leave(" = %d", ret); | 333 | _leave(" = %d", ret); |
344 | return ret; | 334 | return ret; |
345 | 335 | ||
346 | inval: | 336 | inval: |
347 | ret = -EINVAL; | 337 | ret = -EINVAL; |
348 | printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n"); | 338 | printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n"); |
349 | goto done; | 339 | goto done; |
350 | } /* end afs_proc_cells_write() */ | 340 | } |
351 | 341 | ||
352 | /*****************************************************************************/ | ||
353 | /* | 342 | /* |
354 | * Stubs for /proc/fs/afs/rootcell | 343 | * Stubs for /proc/fs/afs/rootcell |
355 | */ | 344 | */ |
@@ -369,7 +358,6 @@ static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, | |||
369 | return 0; | 358 | return 0; |
370 | } | 359 | } |
371 | 360 | ||
372 | /*****************************************************************************/ | ||
373 | /* | 361 | /* |
374 | * handle writes to /proc/fs/afs/rootcell | 362 | * handle writes to /proc/fs/afs/rootcell |
375 | * - to initialize rootcell: echo "cell.name:192.168.231.14" | 363 | * - to initialize rootcell: echo "cell.name:192.168.231.14" |
@@ -407,14 +395,13 @@ static ssize_t afs_proc_rootcell_write(struct file *file, | |||
407 | if (ret >= 0) | 395 | if (ret >= 0) |
408 | ret = size; /* consume everything, always */ | 396 | ret = size; /* consume everything, always */ |
409 | 397 | ||
410 | infault: | 398 | infault: |
411 | kfree(kbuf); | 399 | kfree(kbuf); |
412 | nomem: | 400 | nomem: |
413 | _leave(" = %d", ret); | 401 | _leave(" = %d", ret); |
414 | return ret; | 402 | return ret; |
415 | } /* end afs_proc_rootcell_write() */ | 403 | } |
416 | 404 | ||
417 | /*****************************************************************************/ | ||
418 | /* | 405 | /* |
419 | * initialise /proc/fs/afs/<cell>/ | 406 | * initialise /proc/fs/afs/<cell>/ |
420 | */ | 407 | */ |
@@ -426,25 +413,25 @@ int afs_proc_cell_setup(struct afs_cell *cell) | |||
426 | 413 | ||
427 | cell->proc_dir = proc_mkdir(cell->name, proc_afs); | 414 | cell->proc_dir = proc_mkdir(cell->name, proc_afs); |
428 | if (!cell->proc_dir) | 415 | if (!cell->proc_dir) |
429 | return -ENOMEM; | 416 | goto error_dir; |
430 | 417 | ||
431 | p = create_proc_entry("servers", 0, cell->proc_dir); | 418 | p = create_proc_entry("servers", 0, cell->proc_dir); |
432 | if (!p) | 419 | if (!p) |
433 | goto error_proc; | 420 | goto error_servers; |
434 | p->proc_fops = &afs_proc_cell_servers_fops; | 421 | p->proc_fops = &afs_proc_cell_servers_fops; |
435 | p->owner = THIS_MODULE; | 422 | p->owner = THIS_MODULE; |
436 | p->data = cell; | 423 | p->data = cell; |
437 | 424 | ||
438 | p = create_proc_entry("vlservers", 0, cell->proc_dir); | 425 | p = create_proc_entry("vlservers", 0, cell->proc_dir); |
439 | if (!p) | 426 | if (!p) |
440 | goto error_servers; | 427 | goto error_vlservers; |
441 | p->proc_fops = &afs_proc_cell_vlservers_fops; | 428 | p->proc_fops = &afs_proc_cell_vlservers_fops; |
442 | p->owner = THIS_MODULE; | 429 | p->owner = THIS_MODULE; |
443 | p->data = cell; | 430 | p->data = cell; |
444 | 431 | ||
445 | p = create_proc_entry("volumes", 0, cell->proc_dir); | 432 | p = create_proc_entry("volumes", 0, cell->proc_dir); |
446 | if (!p) | 433 | if (!p) |
447 | goto error_vlservers; | 434 | goto error_volumes; |
448 | p->proc_fops = &afs_proc_cell_volumes_fops; | 435 | p->proc_fops = &afs_proc_cell_volumes_fops; |
449 | p->owner = THIS_MODULE; | 436 | p->owner = THIS_MODULE; |
450 | p->data = cell; | 437 | p->data = cell; |
@@ -452,17 +439,17 @@ int afs_proc_cell_setup(struct afs_cell *cell) | |||
452 | _leave(" = 0"); | 439 | _leave(" = 0"); |
453 | return 0; | 440 | return 0; |
454 | 441 | ||
455 | error_vlservers: | 442 | error_volumes: |
456 | remove_proc_entry("vlservers", cell->proc_dir); | 443 | remove_proc_entry("vlservers", cell->proc_dir); |
457 | error_servers: | 444 | error_vlservers: |
458 | remove_proc_entry("servers", cell->proc_dir); | 445 | remove_proc_entry("servers", cell->proc_dir); |
459 | error_proc: | 446 | error_servers: |
460 | remove_proc_entry(cell->name, proc_afs); | 447 | remove_proc_entry(cell->name, proc_afs); |
448 | error_dir: | ||
461 | _leave(" = -ENOMEM"); | 449 | _leave(" = -ENOMEM"); |
462 | return -ENOMEM; | 450 | return -ENOMEM; |
463 | } /* end afs_proc_cell_setup() */ | 451 | } |
464 | 452 | ||
465 | /*****************************************************************************/ | ||
466 | /* | 453 | /* |
467 | * remove /proc/fs/afs/<cell>/ | 454 | * remove /proc/fs/afs/<cell>/ |
468 | */ | 455 | */ |
@@ -476,9 +463,8 @@ void afs_proc_cell_remove(struct afs_cell *cell) | |||
476 | remove_proc_entry(cell->name, proc_afs); | 463 | remove_proc_entry(cell->name, proc_afs); |
477 | 464 | ||
478 | _leave(""); | 465 | _leave(""); |
479 | } /* end afs_proc_cell_remove() */ | 466 | } |
480 | 467 | ||
481 | /*****************************************************************************/ | ||
482 | /* | 468 | /* |
483 | * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells | 469 | * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells |
484 | */ | 470 | */ |
@@ -488,7 +474,7 @@ static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) | |||
488 | struct seq_file *m; | 474 | struct seq_file *m; |
489 | int ret; | 475 | int ret; |
490 | 476 | ||
491 | cell = afs_get_cell_maybe((struct afs_cell **) &PDE(inode)->data); | 477 | cell = PDE(inode)->data; |
492 | if (!cell) | 478 | if (!cell) |
493 | return -ENOENT; | 479 | return -ENOENT; |
494 | 480 | ||
@@ -500,25 +486,16 @@ static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) | |||
500 | m->private = cell; | 486 | m->private = cell; |
501 | 487 | ||
502 | return 0; | 488 | return 0; |
503 | } /* end afs_proc_cell_volumes_open() */ | 489 | } |
504 | 490 | ||
505 | /*****************************************************************************/ | ||
506 | /* | 491 | /* |
507 | * close the file and release the ref to the cell | 492 | * close the file and release the ref to the cell |
508 | */ | 493 | */ |
509 | static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file) | 494 | static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file) |
510 | { | 495 | { |
511 | struct afs_cell *cell = PDE(inode)->data; | 496 | return seq_release(inode, file); |
512 | int ret; | 497 | } |
513 | |||
514 | ret = seq_release(inode,file); | ||
515 | |||
516 | afs_put_cell(cell); | ||
517 | |||
518 | return ret; | ||
519 | } /* end afs_proc_cell_volumes_release() */ | ||
520 | 498 | ||
521 | /*****************************************************************************/ | ||
522 | /* | 499 | /* |
523 | * set up the iterator to start reading from the cells list and return the | 500 | * set up the iterator to start reading from the cells list and return the |
524 | * first item | 501 | * first item |
@@ -545,9 +522,8 @@ static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) | |||
545 | break; | 522 | break; |
546 | 523 | ||
547 | return _p != &cell->vl_list ? _p : NULL; | 524 | return _p != &cell->vl_list ? _p : NULL; |
548 | } /* end afs_proc_cell_volumes_start() */ | 525 | } |
549 | 526 | ||
550 | /*****************************************************************************/ | ||
551 | /* | 527 | /* |
552 | * move to next cell in cells list | 528 | * move to next cell in cells list |
553 | */ | 529 | */ |
@@ -562,12 +538,11 @@ static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, | |||
562 | (*_pos)++; | 538 | (*_pos)++; |
563 | 539 | ||
564 | _p = v; | 540 | _p = v; |
565 | _p = v == (void *) 1 ? cell->vl_list.next : _p->next; | 541 | _p = (v == (void *) 1) ? cell->vl_list.next : _p->next; |
566 | 542 | ||
567 | return _p != &cell->vl_list ? _p : NULL; | 543 | return (_p != &cell->vl_list) ? _p : NULL; |
568 | } /* end afs_proc_cell_volumes_next() */ | 544 | } |
569 | 545 | ||
570 | /*****************************************************************************/ | ||
571 | /* | 546 | /* |
572 | * clean up after reading from the cells list | 547 | * clean up after reading from the cells list |
573 | */ | 548 | */ |
@@ -576,10 +551,18 @@ static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) | |||
576 | struct afs_cell *cell = p->private; | 551 | struct afs_cell *cell = p->private; |
577 | 552 | ||
578 | up_read(&cell->vl_sem); | 553 | up_read(&cell->vl_sem); |
554 | } | ||
579 | 555 | ||
580 | } /* end afs_proc_cell_volumes_stop() */ | 556 | const char afs_vlocation_states[][4] = { |
557 | [AFS_VL_NEW] = "New", | ||
558 | [AFS_VL_CREATING] = "Crt", | ||
559 | [AFS_VL_VALID] = "Val", | ||
560 | [AFS_VL_NO_VOLUME] = "NoV", | ||
561 | [AFS_VL_UPDATING] = "Upd", | ||
562 | [AFS_VL_VOLUME_DELETED] = "Del", | ||
563 | [AFS_VL_UNCERTAIN] = "Unc", | ||
564 | }; | ||
581 | 565 | ||
582 | /*****************************************************************************/ | ||
583 | /* | 566 | /* |
584 | * display a header line followed by a load of volume lines | 567 | * display a header line followed by a load of volume lines |
585 | */ | 568 | */ |
@@ -590,23 +573,22 @@ static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) | |||
590 | 573 | ||
591 | /* display header on line 1 */ | 574 | /* display header on line 1 */ |
592 | if (v == (void *) 1) { | 575 | if (v == (void *) 1) { |
593 | seq_puts(m, "USE VLID[0] VLID[1] VLID[2] NAME\n"); | 576 | seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n"); |
594 | return 0; | 577 | return 0; |
595 | } | 578 | } |
596 | 579 | ||
597 | /* display one cell per line on subsequent lines */ | 580 | /* display one cell per line on subsequent lines */ |
598 | seq_printf(m, "%3d %08x %08x %08x %s\n", | 581 | seq_printf(m, "%3d %s %08x %08x %08x %s\n", |
599 | atomic_read(&vlocation->usage), | 582 | atomic_read(&vlocation->usage), |
583 | afs_vlocation_states[vlocation->state], | ||
600 | vlocation->vldb.vid[0], | 584 | vlocation->vldb.vid[0], |
601 | vlocation->vldb.vid[1], | 585 | vlocation->vldb.vid[1], |
602 | vlocation->vldb.vid[2], | 586 | vlocation->vldb.vid[2], |
603 | vlocation->vldb.name | 587 | vlocation->vldb.name); |
604 | ); | ||
605 | 588 | ||
606 | return 0; | 589 | return 0; |
607 | } /* end afs_proc_cell_volumes_show() */ | 590 | } |
608 | 591 | ||
609 | /*****************************************************************************/ | ||
610 | /* | 592 | /* |
611 | * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume | 593 | * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume |
612 | * location server | 594 | * location server |
@@ -617,11 +599,11 @@ static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) | |||
617 | struct seq_file *m; | 599 | struct seq_file *m; |
618 | int ret; | 600 | int ret; |
619 | 601 | ||
620 | cell = afs_get_cell_maybe((struct afs_cell**)&PDE(inode)->data); | 602 | cell = PDE(inode)->data; |
621 | if (!cell) | 603 | if (!cell) |
622 | return -ENOENT; | 604 | return -ENOENT; |
623 | 605 | ||
624 | ret = seq_open(file,&afs_proc_cell_vlservers_ops); | 606 | ret = seq_open(file, &afs_proc_cell_vlservers_ops); |
625 | if (ret<0) | 607 | if (ret<0) |
626 | return ret; | 608 | return ret; |
627 | 609 | ||
@@ -629,26 +611,17 @@ static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) | |||
629 | m->private = cell; | 611 | m->private = cell; |
630 | 612 | ||
631 | return 0; | 613 | return 0; |
632 | } /* end afs_proc_cell_vlservers_open() */ | 614 | } |
633 | 615 | ||
634 | /*****************************************************************************/ | ||
635 | /* | 616 | /* |
636 | * close the file and release the ref to the cell | 617 | * close the file and release the ref to the cell |
637 | */ | 618 | */ |
638 | static int afs_proc_cell_vlservers_release(struct inode *inode, | 619 | static int afs_proc_cell_vlservers_release(struct inode *inode, |
639 | struct file *file) | 620 | struct file *file) |
640 | { | 621 | { |
641 | struct afs_cell *cell = PDE(inode)->data; | 622 | return seq_release(inode, file); |
642 | int ret; | 623 | } |
643 | |||
644 | ret = seq_release(inode,file); | ||
645 | |||
646 | afs_put_cell(cell); | ||
647 | |||
648 | return ret; | ||
649 | } /* end afs_proc_cell_vlservers_release() */ | ||
650 | 624 | ||
651 | /*****************************************************************************/ | ||
652 | /* | 625 | /* |
653 | * set up the iterator to start reading from the cells list and return the | 626 | * set up the iterator to start reading from the cells list and return the |
654 | * first item | 627 | * first item |
@@ -672,9 +645,8 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) | |||
672 | return NULL; | 645 | return NULL; |
673 | 646 | ||
674 | return &cell->vl_addrs[pos]; | 647 | return &cell->vl_addrs[pos]; |
675 | } /* end afs_proc_cell_vlservers_start() */ | 648 | } |
676 | 649 | ||
677 | /*****************************************************************************/ | ||
678 | /* | 650 | /* |
679 | * move to next cell in cells list | 651 | * move to next cell in cells list |
680 | */ | 652 | */ |
@@ -692,9 +664,8 @@ static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, | |||
692 | return NULL; | 664 | return NULL; |
693 | 665 | ||
694 | return &cell->vl_addrs[pos]; | 666 | return &cell->vl_addrs[pos]; |
695 | } /* end afs_proc_cell_vlservers_next() */ | 667 | } |
696 | 668 | ||
697 | /*****************************************************************************/ | ||
698 | /* | 669 | /* |
699 | * clean up after reading from the cells list | 670 | * clean up after reading from the cells list |
700 | */ | 671 | */ |
@@ -703,10 +674,8 @@ static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) | |||
703 | struct afs_cell *cell = p->private; | 674 | struct afs_cell *cell = p->private; |
704 | 675 | ||
705 | up_read(&cell->vl_sem); | 676 | up_read(&cell->vl_sem); |
677 | } | ||
706 | 678 | ||
707 | } /* end afs_proc_cell_vlservers_stop() */ | ||
708 | |||
709 | /*****************************************************************************/ | ||
710 | /* | 679 | /* |
711 | * display a header line followed by a load of volume lines | 680 | * display a header line followed by a load of volume lines |
712 | */ | 681 | */ |
@@ -722,11 +691,9 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) | |||
722 | 691 | ||
723 | /* display one cell per line on subsequent lines */ | 692 | /* display one cell per line on subsequent lines */ |
724 | seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr)); | 693 | seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr)); |
725 | |||
726 | return 0; | 694 | return 0; |
727 | } /* end afs_proc_cell_vlservers_show() */ | 695 | } |
728 | 696 | ||
729 | /*****************************************************************************/ | ||
730 | /* | 697 | /* |
731 | * open "/proc/fs/afs/<cell>/servers" which provides a summary of active | 698 | * open "/proc/fs/afs/<cell>/servers" which provides a summary of active |
732 | * servers | 699 | * servers |
@@ -737,7 +704,7 @@ static int afs_proc_cell_servers_open(struct inode *inode, struct file *file) | |||
737 | struct seq_file *m; | 704 | struct seq_file *m; |
738 | int ret; | 705 | int ret; |
739 | 706 | ||
740 | cell = afs_get_cell_maybe((struct afs_cell **) &PDE(inode)->data); | 707 | cell = PDE(inode)->data; |
741 | if (!cell) | 708 | if (!cell) |
742 | return -ENOENT; | 709 | return -ENOENT; |
743 | 710 | ||
@@ -747,34 +714,24 @@ static int afs_proc_cell_servers_open(struct inode *inode, struct file *file) | |||
747 | 714 | ||
748 | m = file->private_data; | 715 | m = file->private_data; |
749 | m->private = cell; | 716 | m->private = cell; |
750 | |||
751 | return 0; | 717 | return 0; |
752 | } /* end afs_proc_cell_servers_open() */ | 718 | } |
753 | 719 | ||
754 | /*****************************************************************************/ | ||
755 | /* | 720 | /* |
756 | * close the file and release the ref to the cell | 721 | * close the file and release the ref to the cell |
757 | */ | 722 | */ |
758 | static int afs_proc_cell_servers_release(struct inode *inode, | 723 | static int afs_proc_cell_servers_release(struct inode *inode, |
759 | struct file *file) | 724 | struct file *file) |
760 | { | 725 | { |
761 | struct afs_cell *cell = PDE(inode)->data; | 726 | return seq_release(inode, file); |
762 | int ret; | 727 | } |
763 | |||
764 | ret = seq_release(inode, file); | ||
765 | |||
766 | afs_put_cell(cell); | ||
767 | |||
768 | return ret; | ||
769 | } /* end afs_proc_cell_servers_release() */ | ||
770 | 728 | ||
771 | /*****************************************************************************/ | ||
772 | /* | 729 | /* |
773 | * set up the iterator to start reading from the cells list and return the | 730 | * set up the iterator to start reading from the cells list and return the |
774 | * first item | 731 | * first item |
775 | */ | 732 | */ |
776 | static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos) | 733 | static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos) |
777 | __acquires(m->private->sv_lock) | 734 | __acquires(m->private->servers_lock) |
778 | { | 735 | { |
779 | struct list_head *_p; | 736 | struct list_head *_p; |
780 | struct afs_cell *cell = m->private; | 737 | struct afs_cell *cell = m->private; |
@@ -783,7 +740,7 @@ static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos) | |||
783 | _enter("cell=%p pos=%Ld", cell, *_pos); | 740 | _enter("cell=%p pos=%Ld", cell, *_pos); |
784 | 741 | ||
785 | /* lock the list against modification */ | 742 | /* lock the list against modification */ |
786 | read_lock(&cell->sv_lock); | 743 | read_lock(&cell->servers_lock); |
787 | 744 | ||
788 | /* allow for the header line */ | 745 | /* allow for the header line */ |
789 | if (!pos) | 746 | if (!pos) |
@@ -791,14 +748,13 @@ static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos) | |||
791 | pos--; | 748 | pos--; |
792 | 749 | ||
793 | /* find the n'th element in the list */ | 750 | /* find the n'th element in the list */ |
794 | list_for_each(_p, &cell->sv_list) | 751 | list_for_each(_p, &cell->servers) |
795 | if (!pos--) | 752 | if (!pos--) |
796 | break; | 753 | break; |
797 | 754 | ||
798 | return _p != &cell->sv_list ? _p : NULL; | 755 | return _p != &cell->servers ? _p : NULL; |
799 | } /* end afs_proc_cell_servers_start() */ | 756 | } |
800 | 757 | ||
801 | /*****************************************************************************/ | ||
802 | /* | 758 | /* |
803 | * move to next cell in cells list | 759 | * move to next cell in cells list |
804 | */ | 760 | */ |
@@ -813,25 +769,22 @@ static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, | |||
813 | (*_pos)++; | 769 | (*_pos)++; |
814 | 770 | ||
815 | _p = v; | 771 | _p = v; |
816 | _p = v == (void *) 1 ? cell->sv_list.next : _p->next; | 772 | _p = v == (void *) 1 ? cell->servers.next : _p->next; |
817 | 773 | ||
818 | return _p != &cell->sv_list ? _p : NULL; | 774 | return _p != &cell->servers ? _p : NULL; |
819 | } /* end afs_proc_cell_servers_next() */ | 775 | } |
820 | 776 | ||
821 | /*****************************************************************************/ | ||
822 | /* | 777 | /* |
823 | * clean up after reading from the cells list | 778 | * clean up after reading from the cells list |
824 | */ | 779 | */ |
825 | static void afs_proc_cell_servers_stop(struct seq_file *p, void *v) | 780 | static void afs_proc_cell_servers_stop(struct seq_file *p, void *v) |
826 | __releases(p->private->sv_lock) | 781 | __releases(p->private->servers_lock) |
827 | { | 782 | { |
828 | struct afs_cell *cell = p->private; | 783 | struct afs_cell *cell = p->private; |
829 | 784 | ||
830 | read_unlock(&cell->sv_lock); | 785 | read_unlock(&cell->servers_lock); |
831 | 786 | } | |
832 | } /* end afs_proc_cell_servers_stop() */ | ||
833 | 787 | ||
834 | /*****************************************************************************/ | ||
835 | /* | 788 | /* |
836 | * display a header line followed by a load of volume lines | 789 | * display a header line followed by a load of volume lines |
837 | */ | 790 | */ |
@@ -849,10 +802,7 @@ static int afs_proc_cell_servers_show(struct seq_file *m, void *v) | |||
849 | /* display one cell per line on subsequent lines */ | 802 | /* display one cell per line on subsequent lines */ |
850 | sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr)); | 803 | sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr)); |
851 | seq_printf(m, "%3d %-15.15s %5d\n", | 804 | seq_printf(m, "%3d %-15.15s %5d\n", |
852 | atomic_read(&server->usage), | 805 | atomic_read(&server->usage), ipaddr, server->fs_state); |
853 | ipaddr, | ||
854 | server->fs_state | ||
855 | ); | ||
856 | 806 | ||
857 | return 0; | 807 | return 0; |
858 | } /* end afs_proc_cell_servers_show() */ | 808 | } |
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c new file mode 100644 index 000000000000..e7b047328a39 --- /dev/null +++ b/fs/afs/rxrpc.c | |||
@@ -0,0 +1,782 @@ | |||
1 | /* Maintain an RxRPC server socket to do AFS communications through | ||
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 <net/sock.h> | ||
13 | #include <net/af_rxrpc.h> | ||
14 | #include <rxrpc/packet.h> | ||
15 | #include "internal.h" | ||
16 | #include "afs_cm.h" | ||
17 | |||
18 | static struct socket *afs_socket; /* my RxRPC socket */ | ||
19 | static struct workqueue_struct *afs_async_calls; | ||
20 | static atomic_t afs_outstanding_calls; | ||
21 | static atomic_t afs_outstanding_skbs; | ||
22 | |||
23 | static void afs_wake_up_call_waiter(struct afs_call *); | ||
24 | static int afs_wait_for_call_to_complete(struct afs_call *); | ||
25 | static void afs_wake_up_async_call(struct afs_call *); | ||
26 | static int afs_dont_wait_for_call_to_complete(struct afs_call *); | ||
27 | static void afs_process_async_call(struct work_struct *); | ||
28 | static void afs_rx_interceptor(struct sock *, unsigned long, struct sk_buff *); | ||
29 | static int afs_deliver_cm_op_id(struct afs_call *, struct sk_buff *, bool); | ||
30 | |||
31 | /* synchronous call management */ | ||
32 | const struct afs_wait_mode afs_sync_call = { | ||
33 | .rx_wakeup = afs_wake_up_call_waiter, | ||
34 | .wait = afs_wait_for_call_to_complete, | ||
35 | }; | ||
36 | |||
37 | /* asynchronous call management */ | ||
38 | const struct afs_wait_mode afs_async_call = { | ||
39 | .rx_wakeup = afs_wake_up_async_call, | ||
40 | .wait = afs_dont_wait_for_call_to_complete, | ||
41 | }; | ||
42 | |||
43 | /* asynchronous incoming call management */ | ||
44 | static const struct afs_wait_mode afs_async_incoming_call = { | ||
45 | .rx_wakeup = afs_wake_up_async_call, | ||
46 | }; | ||
47 | |||
48 | /* asynchronous incoming call initial processing */ | ||
49 | static const struct afs_call_type afs_RXCMxxxx = { | ||
50 | .name = "CB.xxxx", | ||
51 | .deliver = afs_deliver_cm_op_id, | ||
52 | .abort_to_error = afs_abort_to_error, | ||
53 | }; | ||
54 | |||
55 | static void afs_collect_incoming_call(struct work_struct *); | ||
56 | |||
57 | static struct sk_buff_head afs_incoming_calls; | ||
58 | static DECLARE_WORK(afs_collect_incoming_call_work, afs_collect_incoming_call); | ||
59 | |||
60 | /* | ||
61 | * open an RxRPC socket and bind it to be a server for callback notifications | ||
62 | * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT | ||
63 | */ | ||
64 | int afs_open_socket(void) | ||
65 | { | ||
66 | struct sockaddr_rxrpc srx; | ||
67 | struct socket *socket; | ||
68 | int ret; | ||
69 | |||
70 | _enter(""); | ||
71 | |||
72 | skb_queue_head_init(&afs_incoming_calls); | ||
73 | |||
74 | afs_async_calls = create_singlethread_workqueue("kafsd"); | ||
75 | if (!afs_async_calls) { | ||
76 | _leave(" = -ENOMEM [wq]"); | ||
77 | return -ENOMEM; | ||
78 | } | ||
79 | |||
80 | ret = sock_create_kern(AF_RXRPC, SOCK_DGRAM, PF_INET, &socket); | ||
81 | if (ret < 0) { | ||
82 | destroy_workqueue(afs_async_calls); | ||
83 | _leave(" = %d [socket]", ret); | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | socket->sk->sk_allocation = GFP_NOFS; | ||
88 | |||
89 | /* bind the callback manager's address to make this a server socket */ | ||
90 | srx.srx_family = AF_RXRPC; | ||
91 | srx.srx_service = CM_SERVICE; | ||
92 | srx.transport_type = SOCK_DGRAM; | ||
93 | srx.transport_len = sizeof(srx.transport.sin); | ||
94 | srx.transport.sin.sin_family = AF_INET; | ||
95 | srx.transport.sin.sin_port = htons(AFS_CM_PORT); | ||
96 | memset(&srx.transport.sin.sin_addr, 0, | ||
97 | sizeof(srx.transport.sin.sin_addr)); | ||
98 | |||
99 | ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); | ||
100 | if (ret < 0) { | ||
101 | sock_release(socket); | ||
102 | _leave(" = %d [bind]", ret); | ||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | rxrpc_kernel_intercept_rx_messages(socket, afs_rx_interceptor); | ||
107 | |||
108 | afs_socket = socket; | ||
109 | _leave(" = 0"); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * close the RxRPC socket AFS was using | ||
115 | */ | ||
116 | void afs_close_socket(void) | ||
117 | { | ||
118 | _enter(""); | ||
119 | |||
120 | sock_release(afs_socket); | ||
121 | |||
122 | _debug("dework"); | ||
123 | destroy_workqueue(afs_async_calls); | ||
124 | |||
125 | ASSERTCMP(atomic_read(&afs_outstanding_skbs), ==, 0); | ||
126 | ASSERTCMP(atomic_read(&afs_outstanding_calls), ==, 0); | ||
127 | _leave(""); | ||
128 | } | ||
129 | |||
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 | /* | ||
185 | * allocate a call with flat request and reply buffers | ||
186 | */ | ||
187 | struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, | ||
188 | size_t request_size, size_t reply_size) | ||
189 | { | ||
190 | struct afs_call *call; | ||
191 | |||
192 | call = kzalloc(sizeof(*call), GFP_NOFS); | ||
193 | if (!call) | ||
194 | goto nomem_call; | ||
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 | |||
204 | if (request_size) { | ||
205 | call->request = kmalloc(request_size, GFP_NOFS); | ||
206 | if (!call->request) | ||
207 | goto nomem_free; | ||
208 | } | ||
209 | |||
210 | if (reply_size) { | ||
211 | call->buffer = kmalloc(reply_size, GFP_NOFS); | ||
212 | if (!call->buffer) | ||
213 | goto nomem_free; | ||
214 | } | ||
215 | |||
216 | init_waitqueue_head(&call->waitq); | ||
217 | skb_queue_head_init(&call->rx_queue); | ||
218 | return call; | ||
219 | |||
220 | nomem_free: | ||
221 | afs_free_call(call); | ||
222 | nomem_call: | ||
223 | return NULL; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * clean up a call with flat buffer | ||
228 | */ | ||
229 | void afs_flat_call_destructor(struct afs_call *call) | ||
230 | { | ||
231 | _enter(""); | ||
232 | |||
233 | kfree(call->request); | ||
234 | call->request = NULL; | ||
235 | kfree(call->buffer); | ||
236 | call->buffer = NULL; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * initiate a call | ||
241 | */ | ||
242 | int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | ||
243 | const struct afs_wait_mode *wait_mode) | ||
244 | { | ||
245 | struct sockaddr_rxrpc srx; | ||
246 | struct rxrpc_call *rxcall; | ||
247 | struct msghdr msg; | ||
248 | struct kvec iov[1]; | ||
249 | int ret; | ||
250 | |||
251 | _enter("%x,{%d},", addr->s_addr, ntohs(call->port)); | ||
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 | |||
259 | call->wait_mode = wait_mode; | ||
260 | INIT_WORK(&call->async_work, afs_process_async_call); | ||
261 | |||
262 | memset(&srx, 0, sizeof(srx)); | ||
263 | srx.srx_family = AF_RXRPC; | ||
264 | srx.srx_service = call->service_id; | ||
265 | srx.transport_type = SOCK_DGRAM; | ||
266 | srx.transport_len = sizeof(srx.transport.sin); | ||
267 | srx.transport.sin.sin_family = AF_INET; | ||
268 | srx.transport.sin.sin_port = call->port; | ||
269 | memcpy(&srx.transport.sin.sin_addr, addr, 4); | ||
270 | |||
271 | /* create a call */ | ||
272 | rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, | ||
273 | (unsigned long) call, gfp); | ||
274 | call->key = NULL; | ||
275 | if (IS_ERR(rxcall)) { | ||
276 | ret = PTR_ERR(rxcall); | ||
277 | goto error_kill_call; | ||
278 | } | ||
279 | |||
280 | call->rxcall = rxcall; | ||
281 | |||
282 | /* send the request */ | ||
283 | iov[0].iov_base = call->request; | ||
284 | iov[0].iov_len = call->request_size; | ||
285 | |||
286 | msg.msg_name = NULL; | ||
287 | msg.msg_namelen = 0; | ||
288 | msg.msg_iov = (struct iovec *) iov; | ||
289 | msg.msg_iovlen = 1; | ||
290 | msg.msg_control = NULL; | ||
291 | msg.msg_controllen = 0; | ||
292 | msg.msg_flags = 0; | ||
293 | |||
294 | /* have to change the state *before* sending the last packet as RxRPC | ||
295 | * might give us the reply before it returns from sending the | ||
296 | * request */ | ||
297 | call->state = AFS_CALL_AWAIT_REPLY; | ||
298 | ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size); | ||
299 | if (ret < 0) | ||
300 | goto error_do_abort; | ||
301 | |||
302 | /* at this point, an async call may no longer exist as it may have | ||
303 | * already completed */ | ||
304 | return wait_mode->wait(call); | ||
305 | |||
306 | error_do_abort: | ||
307 | rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT); | ||
308 | rxrpc_kernel_end_call(rxcall); | ||
309 | call->rxcall = NULL; | ||
310 | error_kill_call: | ||
311 | call->type->destructor(call); | ||
312 | afs_free_call(call); | ||
313 | _leave(" = %d", ret); | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * handles intercepted messages that were arriving in the socket's Rx queue | ||
319 | * - called with the socket receive queue lock held to ensure message ordering | ||
320 | * - called with softirqs disabled | ||
321 | */ | ||
322 | static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID, | ||
323 | struct sk_buff *skb) | ||
324 | { | ||
325 | struct afs_call *call = (struct afs_call *) user_call_ID; | ||
326 | |||
327 | _enter("%p,,%u", call, skb->mark); | ||
328 | |||
329 | _debug("ICPT %p{%u} [%d]", | ||
330 | skb, skb->mark, atomic_read(&afs_outstanding_skbs)); | ||
331 | |||
332 | ASSERTCMP(sk, ==, afs_socket->sk); | ||
333 | atomic_inc(&afs_outstanding_skbs); | ||
334 | |||
335 | if (!call) { | ||
336 | /* its an incoming call for our callback service */ | ||
337 | skb_queue_tail(&afs_incoming_calls, skb); | ||
338 | schedule_work(&afs_collect_incoming_call_work); | ||
339 | } else { | ||
340 | /* route the messages directly to the appropriate call */ | ||
341 | skb_queue_tail(&call->rx_queue, skb); | ||
342 | call->wait_mode->rx_wakeup(call); | ||
343 | } | ||
344 | |||
345 | _leave(""); | ||
346 | } | ||
347 | |||
348 | /* | ||
349 | * deliver messages to a call | ||
350 | */ | ||
351 | static void afs_deliver_to_call(struct afs_call *call) | ||
352 | { | ||
353 | struct sk_buff *skb; | ||
354 | bool last; | ||
355 | u32 abort_code; | ||
356 | int ret; | ||
357 | |||
358 | _enter(""); | ||
359 | |||
360 | while ((call->state == AFS_CALL_AWAIT_REPLY || | ||
361 | call->state == AFS_CALL_AWAIT_OP_ID || | ||
362 | call->state == AFS_CALL_AWAIT_REQUEST || | ||
363 | call->state == AFS_CALL_AWAIT_ACK) && | ||
364 | (skb = skb_dequeue(&call->rx_queue))) { | ||
365 | switch (skb->mark) { | ||
366 | case RXRPC_SKB_MARK_DATA: | ||
367 | _debug("Rcv DATA"); | ||
368 | last = rxrpc_kernel_is_data_last(skb); | ||
369 | ret = call->type->deliver(call, skb, last); | ||
370 | switch (ret) { | ||
371 | case 0: | ||
372 | if (last && | ||
373 | call->state == AFS_CALL_AWAIT_REPLY) | ||
374 | call->state = AFS_CALL_COMPLETE; | ||
375 | break; | ||
376 | case -ENOTCONN: | ||
377 | abort_code = RX_CALL_DEAD; | ||
378 | goto do_abort; | ||
379 | case -ENOTSUPP: | ||
380 | abort_code = RX_INVALID_OPERATION; | ||
381 | goto do_abort; | ||
382 | default: | ||
383 | abort_code = RXGEN_CC_UNMARSHAL; | ||
384 | if (call->state != AFS_CALL_AWAIT_REPLY) | ||
385 | abort_code = RXGEN_SS_UNMARSHAL; | ||
386 | do_abort: | ||
387 | rxrpc_kernel_abort_call(call->rxcall, | ||
388 | abort_code); | ||
389 | call->error = ret; | ||
390 | call->state = AFS_CALL_ERROR; | ||
391 | break; | ||
392 | } | ||
393 | afs_data_delivered(skb); | ||
394 | skb = NULL; | ||
395 | continue; | ||
396 | case RXRPC_SKB_MARK_FINAL_ACK: | ||
397 | _debug("Rcv ACK"); | ||
398 | call->state = AFS_CALL_COMPLETE; | ||
399 | break; | ||
400 | case RXRPC_SKB_MARK_BUSY: | ||
401 | _debug("Rcv BUSY"); | ||
402 | call->error = -EBUSY; | ||
403 | call->state = AFS_CALL_BUSY; | ||
404 | break; | ||
405 | case RXRPC_SKB_MARK_REMOTE_ABORT: | ||
406 | abort_code = rxrpc_kernel_get_abort_code(skb); | ||
407 | call->error = call->type->abort_to_error(abort_code); | ||
408 | call->state = AFS_CALL_ABORTED; | ||
409 | _debug("Rcv ABORT %u -> %d", abort_code, call->error); | ||
410 | break; | ||
411 | case RXRPC_SKB_MARK_NET_ERROR: | ||
412 | call->error = -rxrpc_kernel_get_error_number(skb); | ||
413 | call->state = AFS_CALL_ERROR; | ||
414 | _debug("Rcv NET ERROR %d", call->error); | ||
415 | break; | ||
416 | case RXRPC_SKB_MARK_LOCAL_ERROR: | ||
417 | call->error = -rxrpc_kernel_get_error_number(skb); | ||
418 | call->state = AFS_CALL_ERROR; | ||
419 | _debug("Rcv LOCAL ERROR %d", call->error); | ||
420 | break; | ||
421 | default: | ||
422 | BUG(); | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | afs_free_skb(skb); | ||
427 | } | ||
428 | |||
429 | /* make sure the queue is empty if the call is done with (we might have | ||
430 | * aborted the call early because of an unmarshalling error) */ | ||
431 | if (call->state >= AFS_CALL_COMPLETE) { | ||
432 | while ((skb = skb_dequeue(&call->rx_queue))) | ||
433 | afs_free_skb(skb); | ||
434 | if (call->incoming) { | ||
435 | rxrpc_kernel_end_call(call->rxcall); | ||
436 | call->rxcall = NULL; | ||
437 | call->type->destructor(call); | ||
438 | afs_free_call(call); | ||
439 | } | ||
440 | } | ||
441 | |||
442 | _leave(""); | ||
443 | } | ||
444 | |||
445 | /* | ||
446 | * wait synchronously for a call to complete | ||
447 | */ | ||
448 | static int afs_wait_for_call_to_complete(struct afs_call *call) | ||
449 | { | ||
450 | struct sk_buff *skb; | ||
451 | int ret; | ||
452 | |||
453 | DECLARE_WAITQUEUE(myself, current); | ||
454 | |||
455 | _enter(""); | ||
456 | |||
457 | add_wait_queue(&call->waitq, &myself); | ||
458 | for (;;) { | ||
459 | set_current_state(TASK_INTERRUPTIBLE); | ||
460 | |||
461 | /* deliver any messages that are in the queue */ | ||
462 | if (!skb_queue_empty(&call->rx_queue)) { | ||
463 | __set_current_state(TASK_RUNNING); | ||
464 | afs_deliver_to_call(call); | ||
465 | continue; | ||
466 | } | ||
467 | |||
468 | ret = call->error; | ||
469 | if (call->state >= AFS_CALL_COMPLETE) | ||
470 | break; | ||
471 | ret = -EINTR; | ||
472 | if (signal_pending(current)) | ||
473 | break; | ||
474 | schedule(); | ||
475 | } | ||
476 | |||
477 | remove_wait_queue(&call->waitq, &myself); | ||
478 | __set_current_state(TASK_RUNNING); | ||
479 | |||
480 | /* kill the call */ | ||
481 | if (call->state < AFS_CALL_COMPLETE) { | ||
482 | _debug("call incomplete"); | ||
483 | rxrpc_kernel_abort_call(call->rxcall, RX_CALL_DEAD); | ||
484 | while ((skb = skb_dequeue(&call->rx_queue))) | ||
485 | afs_free_skb(skb); | ||
486 | } | ||
487 | |||
488 | _debug("call complete"); | ||
489 | rxrpc_kernel_end_call(call->rxcall); | ||
490 | call->rxcall = NULL; | ||
491 | call->type->destructor(call); | ||
492 | afs_free_call(call); | ||
493 | _leave(" = %d", ret); | ||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * wake up a waiting call | ||
499 | */ | ||
500 | static void afs_wake_up_call_waiter(struct afs_call *call) | ||
501 | { | ||
502 | wake_up(&call->waitq); | ||
503 | } | ||
504 | |||
505 | /* | ||
506 | * wake up an asynchronous call | ||
507 | */ | ||
508 | static void afs_wake_up_async_call(struct afs_call *call) | ||
509 | { | ||
510 | _enter(""); | ||
511 | queue_work(afs_async_calls, &call->async_work); | ||
512 | } | ||
513 | |||
514 | /* | ||
515 | * put a call into asynchronous mode | ||
516 | * - mustn't touch the call descriptor as the call my have completed by the | ||
517 | * time we get here | ||
518 | */ | ||
519 | static int afs_dont_wait_for_call_to_complete(struct afs_call *call) | ||
520 | { | ||
521 | _enter(""); | ||
522 | return -EINPROGRESS; | ||
523 | } | ||
524 | |||
525 | /* | ||
526 | * delete an asynchronous call | ||
527 | */ | ||
528 | static void afs_delete_async_call(struct work_struct *work) | ||
529 | { | ||
530 | struct afs_call *call = | ||
531 | container_of(work, struct afs_call, async_work); | ||
532 | |||
533 | _enter(""); | ||
534 | |||
535 | afs_free_call(call); | ||
536 | |||
537 | _leave(""); | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * perform processing on an asynchronous call | ||
542 | * - on a multiple-thread workqueue this work item may try to run on several | ||
543 | * CPUs at the same time | ||
544 | */ | ||
545 | static void afs_process_async_call(struct work_struct *work) | ||
546 | { | ||
547 | struct afs_call *call = | ||
548 | container_of(work, struct afs_call, async_work); | ||
549 | |||
550 | _enter(""); | ||
551 | |||
552 | if (!skb_queue_empty(&call->rx_queue)) | ||
553 | afs_deliver_to_call(call); | ||
554 | |||
555 | if (call->state >= AFS_CALL_COMPLETE && call->wait_mode) { | ||
556 | if (call->wait_mode->async_complete) | ||
557 | call->wait_mode->async_complete(call->reply, | ||
558 | call->error); | ||
559 | call->reply = NULL; | ||
560 | |||
561 | /* kill the call */ | ||
562 | rxrpc_kernel_end_call(call->rxcall); | ||
563 | call->rxcall = NULL; | ||
564 | if (call->type->destructor) | ||
565 | call->type->destructor(call); | ||
566 | |||
567 | /* we can't just delete the call because the work item may be | ||
568 | * queued */ | ||
569 | PREPARE_WORK(&call->async_work, afs_delete_async_call); | ||
570 | queue_work(afs_async_calls, &call->async_work); | ||
571 | } | ||
572 | |||
573 | _leave(""); | ||
574 | } | ||
575 | |||
576 | /* | ||
577 | * empty a socket buffer into a flat reply buffer | ||
578 | */ | ||
579 | void afs_transfer_reply(struct afs_call *call, struct sk_buff *skb) | ||
580 | { | ||
581 | size_t len = skb->len; | ||
582 | |||
583 | if (skb_copy_bits(skb, 0, call->buffer + call->reply_size, len) < 0) | ||
584 | BUG(); | ||
585 | call->reply_size += len; | ||
586 | } | ||
587 | |||
588 | /* | ||
589 | * accept the backlog of incoming calls | ||
590 | */ | ||
591 | static void afs_collect_incoming_call(struct work_struct *work) | ||
592 | { | ||
593 | struct rxrpc_call *rxcall; | ||
594 | struct afs_call *call = NULL; | ||
595 | struct sk_buff *skb; | ||
596 | |||
597 | while ((skb = skb_dequeue(&afs_incoming_calls))) { | ||
598 | _debug("new call"); | ||
599 | |||
600 | /* don't need the notification */ | ||
601 | afs_free_skb(skb); | ||
602 | |||
603 | if (!call) { | ||
604 | call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); | ||
605 | if (!call) { | ||
606 | rxrpc_kernel_reject_call(afs_socket); | ||
607 | return; | ||
608 | } | ||
609 | |||
610 | INIT_WORK(&call->async_work, afs_process_async_call); | ||
611 | call->wait_mode = &afs_async_incoming_call; | ||
612 | call->type = &afs_RXCMxxxx; | ||
613 | init_waitqueue_head(&call->waitq); | ||
614 | skb_queue_head_init(&call->rx_queue); | ||
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); | ||
621 | } | ||
622 | |||
623 | rxcall = rxrpc_kernel_accept_call(afs_socket, | ||
624 | (unsigned long) call); | ||
625 | if (!IS_ERR(rxcall)) { | ||
626 | call->rxcall = rxcall; | ||
627 | call = NULL; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | if (call) | ||
632 | afs_free_call(call); | ||
633 | } | ||
634 | |||
635 | /* | ||
636 | * grab the operation ID from an incoming cache manager call | ||
637 | */ | ||
638 | static int afs_deliver_cm_op_id(struct afs_call *call, struct sk_buff *skb, | ||
639 | bool last) | ||
640 | { | ||
641 | size_t len = skb->len; | ||
642 | void *oibuf = (void *) &call->operation_ID; | ||
643 | |||
644 | _enter("{%u},{%zu},%d", call->offset, len, last); | ||
645 | |||
646 | ASSERTCMP(call->offset, <, 4); | ||
647 | |||
648 | /* the operation ID forms the first four bytes of the request data */ | ||
649 | len = min_t(size_t, len, 4 - call->offset); | ||
650 | if (skb_copy_bits(skb, 0, oibuf + call->offset, len) < 0) | ||
651 | BUG(); | ||
652 | if (!pskb_pull(skb, len)) | ||
653 | BUG(); | ||
654 | call->offset += len; | ||
655 | |||
656 | if (call->offset < 4) { | ||
657 | if (last) { | ||
658 | _leave(" = -EBADMSG [op ID short]"); | ||
659 | return -EBADMSG; | ||
660 | } | ||
661 | _leave(" = 0 [incomplete]"); | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | call->state = AFS_CALL_AWAIT_REQUEST; | ||
666 | |||
667 | /* ask the cache manager to route the call (it'll change the call type | ||
668 | * if successful) */ | ||
669 | if (!afs_cm_incoming_call(call)) | ||
670 | return -ENOTSUPP; | ||
671 | |||
672 | /* pass responsibility for the remainer of this message off to the | ||
673 | * cache manager op */ | ||
674 | return call->type->deliver(call, skb, last); | ||
675 | } | ||
676 | |||
677 | /* | ||
678 | * send an empty reply | ||
679 | */ | ||
680 | void afs_send_empty_reply(struct afs_call *call) | ||
681 | { | ||
682 | struct msghdr msg; | ||
683 | struct iovec iov[1]; | ||
684 | |||
685 | _enter(""); | ||
686 | |||
687 | iov[0].iov_base = NULL; | ||
688 | iov[0].iov_len = 0; | ||
689 | msg.msg_name = NULL; | ||
690 | msg.msg_namelen = 0; | ||
691 | msg.msg_iov = iov; | ||
692 | msg.msg_iovlen = 0; | ||
693 | msg.msg_control = NULL; | ||
694 | msg.msg_controllen = 0; | ||
695 | msg.msg_flags = 0; | ||
696 | |||
697 | call->state = AFS_CALL_AWAIT_ACK; | ||
698 | switch (rxrpc_kernel_send_data(call->rxcall, &msg, 0)) { | ||
699 | case 0: | ||
700 | _leave(" [replied]"); | ||
701 | return; | ||
702 | |||
703 | case -ENOMEM: | ||
704 | _debug("oom"); | ||
705 | rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT); | ||
706 | default: | ||
707 | rxrpc_kernel_end_call(call->rxcall); | ||
708 | call->rxcall = NULL; | ||
709 | call->type->destructor(call); | ||
710 | afs_free_call(call); | ||
711 | _leave(" [error]"); | ||
712 | return; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | /* | ||
717 | * send a simple reply | ||
718 | */ | ||
719 | void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) | ||
720 | { | ||
721 | struct msghdr msg; | ||
722 | struct iovec iov[1]; | ||
723 | |||
724 | _enter(""); | ||
725 | |||
726 | iov[0].iov_base = (void *) buf; | ||
727 | iov[0].iov_len = len; | ||
728 | msg.msg_name = NULL; | ||
729 | msg.msg_namelen = 0; | ||
730 | msg.msg_iov = iov; | ||
731 | msg.msg_iovlen = 1; | ||
732 | msg.msg_control = NULL; | ||
733 | msg.msg_controllen = 0; | ||
734 | msg.msg_flags = 0; | ||
735 | |||
736 | call->state = AFS_CALL_AWAIT_ACK; | ||
737 | switch (rxrpc_kernel_send_data(call->rxcall, &msg, len)) { | ||
738 | case 0: | ||
739 | _leave(" [replied]"); | ||
740 | return; | ||
741 | |||
742 | case -ENOMEM: | ||
743 | _debug("oom"); | ||
744 | rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT); | ||
745 | default: | ||
746 | rxrpc_kernel_end_call(call->rxcall); | ||
747 | call->rxcall = NULL; | ||
748 | call->type->destructor(call); | ||
749 | afs_free_call(call); | ||
750 | _leave(" [error]"); | ||
751 | return; | ||
752 | } | ||
753 | } | ||
754 | |||
755 | /* | ||
756 | * extract a piece of data from the received data socket buffers | ||
757 | */ | ||
758 | int afs_extract_data(struct afs_call *call, struct sk_buff *skb, | ||
759 | bool last, void *buf, size_t count) | ||
760 | { | ||
761 | size_t len = skb->len; | ||
762 | |||
763 | _enter("{%u},{%zu},%d,,%zu", call->offset, len, last, count); | ||
764 | |||
765 | ASSERTCMP(call->offset, <, count); | ||
766 | |||
767 | len = min_t(size_t, len, count - call->offset); | ||
768 | if (skb_copy_bits(skb, 0, buf + call->offset, len) < 0 || | ||
769 | !pskb_pull(skb, len)) | ||
770 | BUG(); | ||
771 | call->offset += len; | ||
772 | |||
773 | if (call->offset < count) { | ||
774 | if (last) { | ||
775 | _leave(" = -EBADMSG [%d < %lu]", call->offset, count); | ||
776 | return -EBADMSG; | ||
777 | } | ||
778 | _leave(" = -EAGAIN"); | ||
779 | return -EAGAIN; | ||
780 | } | ||
781 | return 0; | ||
782 | } | ||
diff --git a/fs/afs/security.c b/fs/afs/security.c new file mode 100644 index 000000000000..f9f424d80458 --- /dev/null +++ b/fs/afs/security.c | |||
@@ -0,0 +1,356 @@ | |||
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, NULL, NULL); | ||
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},%lx},%x,", | ||
292 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); | ||
293 | |||
294 | key = afs_request_key(vnode->volume->cell); | ||
295 | if (IS_ERR(key)) { | ||
296 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
297 | return PTR_ERR(key); | ||
298 | } | ||
299 | |||
300 | /* if the promise has expired, we need to check the server again */ | ||
301 | if (!vnode->cb_promised) { | ||
302 | _debug("not promised"); | ||
303 | ret = afs_vnode_fetch_status(vnode, NULL, key); | ||
304 | if (ret < 0) | ||
305 | goto error; | ||
306 | _debug("new promise [fl=%lx]", vnode->flags); | ||
307 | } | ||
308 | |||
309 | /* check the permits to see if we've got one yet */ | ||
310 | ret = afs_check_permit(vnode, key, &access); | ||
311 | if (ret < 0) | ||
312 | goto error; | ||
313 | |||
314 | /* interpret the access mask */ | ||
315 | _debug("REQ %x ACC %x on %s", | ||
316 | mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file"); | ||
317 | |||
318 | if (S_ISDIR(inode->i_mode)) { | ||
319 | if (mask & MAY_EXEC) { | ||
320 | if (!(access & AFS_ACE_LOOKUP)) | ||
321 | goto permission_denied; | ||
322 | } else if (mask & MAY_READ) { | ||
323 | if (!(access & AFS_ACE_READ)) | ||
324 | goto permission_denied; | ||
325 | } else if (mask & MAY_WRITE) { | ||
326 | if (!(access & (AFS_ACE_DELETE | /* rmdir, unlink, rename from */ | ||
327 | AFS_ACE_INSERT | /* create, mkdir, symlink, rename to */ | ||
328 | AFS_ACE_WRITE))) /* chmod */ | ||
329 | goto permission_denied; | ||
330 | } else { | ||
331 | BUG(); | ||
332 | } | ||
333 | } else { | ||
334 | if (!(access & AFS_ACE_LOOKUP)) | ||
335 | goto permission_denied; | ||
336 | if (mask & (MAY_EXEC | MAY_READ)) { | ||
337 | if (!(access & AFS_ACE_READ)) | ||
338 | goto permission_denied; | ||
339 | } else if (mask & MAY_WRITE) { | ||
340 | if (!(access & AFS_ACE_WRITE)) | ||
341 | goto permission_denied; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | key_put(key); | ||
346 | ret = generic_permission(inode, mask, NULL); | ||
347 | _leave(" = %d", ret); | ||
348 | return ret; | ||
349 | |||
350 | permission_denied: | ||
351 | ret = -EACCES; | ||
352 | error: | ||
353 | key_put(key); | ||
354 | _leave(" = %d", ret); | ||
355 | return ret; | ||
356 | } | ||
diff --git a/fs/afs/server.c b/fs/afs/server.c index 44aff81dc6a7..96bb23b476a2 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* server.c: AFS server record management | 1 | /* AFS server record management |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -11,489 +11,314 @@ | |||
11 | 11 | ||
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <rxrpc/peer.h> | ||
15 | #include <rxrpc/connection.h> | ||
16 | #include "volume.h" | ||
17 | #include "cell.h" | ||
18 | #include "server.h" | ||
19 | #include "transport.h" | ||
20 | #include "vlclient.h" | ||
21 | #include "kafstimod.h" | ||
22 | #include "internal.h" | 14 | #include "internal.h" |
23 | 15 | ||
24 | DEFINE_SPINLOCK(afs_server_peer_lock); | 16 | unsigned afs_server_timeout = 10; /* server timeout in seconds */ |
25 | 17 | ||
26 | #define FS_SERVICE_ID 1 /* AFS Volume Location Service ID */ | 18 | static void afs_reap_server(struct work_struct *); |
27 | #define VL_SERVICE_ID 52 /* AFS Volume Location Service ID */ | ||
28 | 19 | ||
29 | static void __afs_server_timeout(struct afs_timer *timer) | 20 | /* tree of all the servers, indexed by IP address */ |
21 | static struct rb_root afs_servers = RB_ROOT; | ||
22 | static DEFINE_RWLOCK(afs_servers_lock); | ||
23 | |||
24 | /* LRU list of all the servers not currently in use */ | ||
25 | static LIST_HEAD(afs_server_graveyard); | ||
26 | static DEFINE_SPINLOCK(afs_server_graveyard_lock); | ||
27 | static DECLARE_DELAYED_WORK(afs_server_reaper, afs_reap_server); | ||
28 | |||
29 | /* | ||
30 | * install a server record in the master tree | ||
31 | */ | ||
32 | static int afs_install_server(struct afs_server *server) | ||
30 | { | 33 | { |
31 | struct afs_server *server = | 34 | struct afs_server *xserver; |
32 | list_entry(timer, struct afs_server, timeout); | 35 | struct rb_node **pp, *p; |
36 | int ret; | ||
33 | 37 | ||
34 | _debug("SERVER TIMEOUT [%p{u=%d}]", | 38 | _enter("%p", server); |
35 | server, atomic_read(&server->usage)); | ||
36 | 39 | ||
37 | afs_server_do_timeout(server); | 40 | write_lock(&afs_servers_lock); |
38 | } | 41 | |
42 | ret = -EEXIST; | ||
43 | pp = &afs_servers.rb_node; | ||
44 | p = NULL; | ||
45 | while (*pp) { | ||
46 | p = *pp; | ||
47 | _debug("- consider %p", p); | ||
48 | xserver = rb_entry(p, struct afs_server, master_rb); | ||
49 | if (server->addr.s_addr < xserver->addr.s_addr) | ||
50 | pp = &(*pp)->rb_left; | ||
51 | else if (server->addr.s_addr > xserver->addr.s_addr) | ||
52 | pp = &(*pp)->rb_right; | ||
53 | else | ||
54 | goto error; | ||
55 | } | ||
39 | 56 | ||
40 | static const struct afs_timer_ops afs_server_timer_ops = { | 57 | rb_link_node(&server->master_rb, p, pp); |
41 | .timed_out = __afs_server_timeout, | 58 | rb_insert_color(&server->master_rb, &afs_servers); |
42 | }; | 59 | ret = 0; |
60 | |||
61 | error: | ||
62 | write_unlock(&afs_servers_lock); | ||
63 | return ret; | ||
64 | } | ||
43 | 65 | ||
44 | /*****************************************************************************/ | ||
45 | /* | 66 | /* |
46 | * lookup a server record in a cell | 67 | * allocate a new server record |
47 | * - TODO: search the cell's server list | ||
48 | */ | 68 | */ |
49 | int afs_server_lookup(struct afs_cell *cell, const struct in_addr *addr, | 69 | static struct afs_server *afs_alloc_server(struct afs_cell *cell, |
50 | struct afs_server **_server) | 70 | const struct in_addr *addr) |
51 | { | 71 | { |
52 | struct afs_server *server, *active, *zombie; | 72 | struct afs_server *server; |
53 | int loop; | ||
54 | 73 | ||
55 | _enter("%p,%08x,", cell, ntohl(addr->s_addr)); | 74 | _enter(""); |
56 | 75 | ||
57 | /* allocate and initialise a server record */ | ||
58 | server = kzalloc(sizeof(struct afs_server), GFP_KERNEL); | 76 | server = kzalloc(sizeof(struct afs_server), GFP_KERNEL); |
59 | if (!server) { | 77 | if (server) { |
60 | _leave(" = -ENOMEM"); | 78 | atomic_set(&server->usage, 1); |
61 | return -ENOMEM; | 79 | server->cell = cell; |
80 | |||
81 | INIT_LIST_HEAD(&server->link); | ||
82 | INIT_LIST_HEAD(&server->grave); | ||
83 | init_rwsem(&server->sem); | ||
84 | spin_lock_init(&server->fs_lock); | ||
85 | server->fs_vnodes = RB_ROOT; | ||
86 | server->cb_promises = RB_ROOT; | ||
87 | spin_lock_init(&server->cb_lock); | ||
88 | init_waitqueue_head(&server->cb_break_waitq); | ||
89 | INIT_DELAYED_WORK(&server->cb_break_work, | ||
90 | afs_dispatch_give_up_callbacks); | ||
91 | |||
92 | memcpy(&server->addr, addr, sizeof(struct in_addr)); | ||
93 | server->addr.s_addr = addr->s_addr; | ||
62 | } | 94 | } |
63 | 95 | ||
64 | atomic_set(&server->usage, 1); | 96 | _leave(" = %p{%d}", server, atomic_read(&server->usage)); |
65 | 97 | return server; | |
66 | INIT_LIST_HEAD(&server->link); | 98 | } |
67 | init_rwsem(&server->sem); | ||
68 | INIT_LIST_HEAD(&server->fs_callq); | ||
69 | spin_lock_init(&server->fs_lock); | ||
70 | INIT_LIST_HEAD(&server->cb_promises); | ||
71 | spin_lock_init(&server->cb_lock); | ||
72 | |||
73 | for (loop = 0; loop < AFS_SERVER_CONN_LIST_SIZE; loop++) | ||
74 | server->fs_conn_cnt[loop] = 4; | ||
75 | 99 | ||
76 | memcpy(&server->addr, addr, sizeof(struct in_addr)); | 100 | /* |
77 | server->addr.s_addr = addr->s_addr; | 101 | * get an FS-server record for a cell |
102 | */ | ||
103 | struct afs_server *afs_lookup_server(struct afs_cell *cell, | ||
104 | const struct in_addr *addr) | ||
105 | { | ||
106 | struct afs_server *server, *candidate; | ||
78 | 107 | ||
79 | afs_timer_init(&server->timeout, &afs_server_timer_ops); | 108 | _enter("%p,"NIPQUAD_FMT, cell, NIPQUAD(addr->s_addr)); |
80 | 109 | ||
81 | /* add to the cell */ | 110 | /* quick scan of the list to see if we already have the server */ |
82 | write_lock(&cell->sv_lock); | 111 | read_lock(&cell->servers_lock); |
83 | 112 | ||
84 | /* check the active list */ | 113 | list_for_each_entry(server, &cell->servers, link) { |
85 | list_for_each_entry(active, &cell->sv_list, link) { | 114 | if (server->addr.s_addr == addr->s_addr) |
86 | if (active->addr.s_addr == addr->s_addr) | 115 | goto found_server_quickly; |
87 | goto use_active_server; | ||
88 | } | 116 | } |
117 | read_unlock(&cell->servers_lock); | ||
89 | 118 | ||
90 | /* check the inactive list */ | 119 | candidate = afs_alloc_server(cell, addr); |
91 | spin_lock(&cell->sv_gylock); | 120 | if (!candidate) { |
92 | list_for_each_entry(zombie, &cell->sv_graveyard, link) { | 121 | _leave(" = -ENOMEM"); |
93 | if (zombie->addr.s_addr == addr->s_addr) | 122 | return ERR_PTR(-ENOMEM); |
94 | goto resurrect_server; | ||
95 | } | 123 | } |
96 | spin_unlock(&cell->sv_gylock); | ||
97 | 124 | ||
98 | afs_get_cell(cell); | 125 | write_lock(&cell->servers_lock); |
99 | server->cell = cell; | ||
100 | list_add_tail(&server->link, &cell->sv_list); | ||
101 | 126 | ||
102 | write_unlock(&cell->sv_lock); | 127 | /* check the cell's server list again */ |
128 | list_for_each_entry(server, &cell->servers, link) { | ||
129 | if (server->addr.s_addr == addr->s_addr) | ||
130 | goto found_server; | ||
131 | } | ||
103 | 132 | ||
104 | *_server = server; | 133 | _debug("new"); |
105 | _leave(" = 0 (%p)", server); | 134 | server = candidate; |
106 | return 0; | 135 | if (afs_install_server(server) < 0) |
136 | goto server_in_two_cells; | ||
107 | 137 | ||
108 | /* found a matching active server */ | 138 | afs_get_cell(cell); |
109 | use_active_server: | 139 | list_add_tail(&server->link, &cell->servers); |
110 | _debug("active server"); | 140 | |
111 | afs_get_server(active); | 141 | write_unlock(&cell->servers_lock); |
112 | write_unlock(&cell->sv_lock); | 142 | _leave(" = %p{%d}", server, atomic_read(&server->usage)); |
143 | return server; | ||
144 | |||
145 | /* found a matching server quickly */ | ||
146 | found_server_quickly: | ||
147 | _debug("found quickly"); | ||
148 | afs_get_server(server); | ||
149 | read_unlock(&cell->servers_lock); | ||
150 | no_longer_unused: | ||
151 | if (!list_empty(&server->grave)) { | ||
152 | spin_lock(&afs_server_graveyard_lock); | ||
153 | list_del_init(&server->grave); | ||
154 | spin_unlock(&afs_server_graveyard_lock); | ||
155 | } | ||
156 | _leave(" = %p{%d}", server, atomic_read(&server->usage)); | ||
157 | return server; | ||
158 | |||
159 | /* found a matching server on the second pass */ | ||
160 | found_server: | ||
161 | _debug("found"); | ||
162 | afs_get_server(server); | ||
163 | write_unlock(&cell->servers_lock); | ||
164 | kfree(candidate); | ||
165 | goto no_longer_unused; | ||
166 | |||
167 | /* found a server that seems to be in two cells */ | ||
168 | server_in_two_cells: | ||
169 | write_unlock(&cell->servers_lock); | ||
170 | kfree(candidate); | ||
171 | printk(KERN_NOTICE "kAFS:" | ||
172 | " Server "NIPQUAD_FMT" appears to be in two cells\n", | ||
173 | NIPQUAD(*addr)); | ||
174 | _leave(" = -EEXIST"); | ||
175 | return ERR_PTR(-EEXIST); | ||
176 | } | ||
113 | 177 | ||
114 | kfree(server); | 178 | /* |
179 | * look up a server by its IP address | ||
180 | */ | ||
181 | struct afs_server *afs_find_server(const struct in_addr *_addr) | ||
182 | { | ||
183 | struct afs_server *server = NULL; | ||
184 | struct rb_node *p; | ||
185 | struct in_addr addr = *_addr; | ||
115 | 186 | ||
116 | *_server = active; | 187 | _enter(NIPQUAD_FMT, NIPQUAD(addr.s_addr)); |
117 | _leave(" = 0 (%p)", active); | ||
118 | return 0; | ||
119 | 188 | ||
120 | /* found a matching server in the graveyard, so resurrect it and | 189 | read_lock(&afs_servers_lock); |
121 | * dispose of the new record */ | ||
122 | resurrect_server: | ||
123 | _debug("resurrecting server"); | ||
124 | 190 | ||
125 | list_move_tail(&zombie->link, &cell->sv_list); | 191 | p = afs_servers.rb_node; |
126 | afs_get_server(zombie); | 192 | while (p) { |
127 | afs_kafstimod_del_timer(&zombie->timeout); | 193 | server = rb_entry(p, struct afs_server, master_rb); |
128 | spin_unlock(&cell->sv_gylock); | ||
129 | write_unlock(&cell->sv_lock); | ||
130 | 194 | ||
131 | kfree(server); | 195 | _debug("- consider %p", p); |
132 | 196 | ||
133 | *_server = zombie; | 197 | if (addr.s_addr < server->addr.s_addr) { |
134 | _leave(" = 0 (%p)", zombie); | 198 | p = p->rb_left; |
135 | return 0; | 199 | } else if (addr.s_addr > server->addr.s_addr) { |
200 | p = p->rb_right; | ||
201 | } else { | ||
202 | afs_get_server(server); | ||
203 | goto found; | ||
204 | } | ||
205 | } | ||
136 | 206 | ||
137 | } /* end afs_server_lookup() */ | 207 | server = NULL; |
208 | found: | ||
209 | read_unlock(&afs_servers_lock); | ||
210 | ASSERTIFCMP(server, server->addr.s_addr, ==, addr.s_addr); | ||
211 | _leave(" = %p", server); | ||
212 | return server; | ||
213 | } | ||
138 | 214 | ||
139 | /*****************************************************************************/ | ||
140 | /* | 215 | /* |
141 | * destroy a server record | 216 | * destroy a server record |
142 | * - removes from the cell list | 217 | * - removes from the cell list |
143 | */ | 218 | */ |
144 | void afs_put_server(struct afs_server *server) | 219 | void afs_put_server(struct afs_server *server) |
145 | { | 220 | { |
146 | struct afs_cell *cell; | ||
147 | |||
148 | if (!server) | 221 | if (!server) |
149 | return; | 222 | return; |
150 | 223 | ||
151 | _enter("%p", server); | 224 | _enter("%p{%d}", server, atomic_read(&server->usage)); |
152 | |||
153 | cell = server->cell; | ||
154 | 225 | ||
155 | /* sanity check */ | 226 | _debug("PUT SERVER %d", atomic_read(&server->usage)); |
156 | BUG_ON(atomic_read(&server->usage) <= 0); | ||
157 | 227 | ||
158 | /* to prevent a race, the decrement and the dequeue must be effectively | 228 | ASSERTCMP(atomic_read(&server->usage), >, 0); |
159 | * atomic */ | ||
160 | write_lock(&cell->sv_lock); | ||
161 | 229 | ||
162 | if (likely(!atomic_dec_and_test(&server->usage))) { | 230 | if (likely(!atomic_dec_and_test(&server->usage))) { |
163 | write_unlock(&cell->sv_lock); | ||
164 | _leave(""); | 231 | _leave(""); |
165 | return; | 232 | return; |
166 | } | 233 | } |
167 | 234 | ||
168 | spin_lock(&cell->sv_gylock); | 235 | afs_flush_callback_breaks(server); |
169 | list_move_tail(&server->link, &cell->sv_graveyard); | ||
170 | 236 | ||
171 | /* time out in 10 secs */ | 237 | spin_lock(&afs_server_graveyard_lock); |
172 | afs_kafstimod_add_timer(&server->timeout, 10 * HZ); | 238 | if (atomic_read(&server->usage) == 0) { |
173 | 239 | list_move_tail(&server->grave, &afs_server_graveyard); | |
174 | spin_unlock(&cell->sv_gylock); | 240 | server->time_of_death = get_seconds(); |
175 | write_unlock(&cell->sv_lock); | 241 | schedule_delayed_work(&afs_server_reaper, |
176 | 242 | afs_server_timeout * HZ); | |
177 | _leave(" [killed]"); | 243 | } |
178 | } /* end afs_put_server() */ | 244 | spin_unlock(&afs_server_graveyard_lock); |
245 | _leave(" [dead]"); | ||
246 | } | ||
179 | 247 | ||
180 | /*****************************************************************************/ | ||
181 | /* | 248 | /* |
182 | * timeout server record | 249 | * destroy a dead server |
183 | * - removes from the cell's graveyard if the usage count is zero | ||
184 | */ | 250 | */ |
185 | void afs_server_do_timeout(struct afs_server *server) | 251 | static void afs_destroy_server(struct afs_server *server) |
186 | { | 252 | { |
187 | struct rxrpc_peer *peer; | ||
188 | struct afs_cell *cell; | ||
189 | int loop; | ||
190 | |||
191 | _enter("%p", server); | 253 | _enter("%p", server); |
192 | 254 | ||
193 | cell = server->cell; | 255 | ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL); |
194 | 256 | ASSERTCMP(server->cb_promises.rb_node, ==, NULL); | |
195 | BUG_ON(atomic_read(&server->usage) < 0); | 257 | ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail); |
196 | 258 | ASSERTCMP(atomic_read(&server->cb_break_n), ==, 0); | |
197 | /* remove from graveyard if still dead */ | ||
198 | spin_lock(&cell->vl_gylock); | ||
199 | if (atomic_read(&server->usage) == 0) | ||
200 | list_del_init(&server->link); | ||
201 | else | ||
202 | server = NULL; | ||
203 | spin_unlock(&cell->vl_gylock); | ||
204 | |||
205 | if (!server) { | ||
206 | _leave(""); | ||
207 | return; /* resurrected */ | ||
208 | } | ||
209 | |||
210 | /* we can now destroy it properly */ | ||
211 | afs_put_cell(cell); | ||
212 | |||
213 | /* uncross-point the structs under a global lock */ | ||
214 | spin_lock(&afs_server_peer_lock); | ||
215 | peer = server->peer; | ||
216 | if (peer) { | ||
217 | server->peer = NULL; | ||
218 | peer->user = NULL; | ||
219 | } | ||
220 | spin_unlock(&afs_server_peer_lock); | ||
221 | |||
222 | /* finish cleaning up the server */ | ||
223 | for (loop = AFS_SERVER_CONN_LIST_SIZE - 1; loop >= 0; loop--) | ||
224 | if (server->fs_conn[loop]) | ||
225 | rxrpc_put_connection(server->fs_conn[loop]); | ||
226 | |||
227 | if (server->vlserver) | ||
228 | rxrpc_put_connection(server->vlserver); | ||
229 | 259 | ||
260 | afs_put_cell(server->cell); | ||
230 | kfree(server); | 261 | kfree(server); |
262 | } | ||
231 | 263 | ||
232 | _leave(" [destroyed]"); | ||
233 | } /* end afs_server_do_timeout() */ | ||
234 | |||
235 | /*****************************************************************************/ | ||
236 | /* | 264 | /* |
237 | * get a callslot on a connection to the fileserver on the specified server | 265 | * reap dead server records |
238 | */ | 266 | */ |
239 | int afs_server_request_callslot(struct afs_server *server, | 267 | static void afs_reap_server(struct work_struct *work) |
240 | struct afs_server_callslot *callslot) | ||
241 | { | 268 | { |
242 | struct afs_server_callslot *pcallslot; | 269 | LIST_HEAD(corpses); |
243 | struct rxrpc_connection *conn; | 270 | struct afs_server *server; |
244 | int nconn, ret; | 271 | unsigned long delay, expiry; |
245 | 272 | time_t now; | |
246 | _enter("%p,",server); | 273 | |
247 | 274 | now = get_seconds(); | |
248 | INIT_LIST_HEAD(&callslot->link); | 275 | spin_lock(&afs_server_graveyard_lock); |
249 | callslot->task = current; | 276 | |
250 | callslot->conn = NULL; | 277 | while (!list_empty(&afs_server_graveyard)) { |
251 | callslot->nconn = -1; | 278 | server = list_entry(afs_server_graveyard.next, |
252 | callslot->ready = 0; | 279 | struct afs_server, grave); |
253 | 280 | ||
254 | ret = 0; | 281 | /* the queue is ordered most dead first */ |
255 | conn = NULL; | 282 | expiry = server->time_of_death + afs_server_timeout; |
256 | 283 | if (expiry > now) { | |
257 | /* get hold of a callslot first */ | 284 | delay = (expiry - now) * HZ; |
258 | spin_lock(&server->fs_lock); | 285 | if (!schedule_delayed_work(&afs_server_reaper, delay)) { |
259 | 286 | cancel_delayed_work(&afs_server_reaper); | |
260 | /* resurrect the server if it's death timeout has expired */ | 287 | schedule_delayed_work(&afs_server_reaper, |
261 | if (server->fs_state) { | 288 | delay); |
262 | if (time_before(jiffies, server->fs_dead_jif)) { | 289 | } |
263 | ret = server->fs_state; | 290 | break; |
264 | spin_unlock(&server->fs_lock); | ||
265 | _leave(" = %d [still dead]", ret); | ||
266 | return ret; | ||
267 | } | 291 | } |
268 | 292 | ||
269 | server->fs_state = 0; | 293 | write_lock(&server->cell->servers_lock); |
270 | } | 294 | write_lock(&afs_servers_lock); |
271 | 295 | if (atomic_read(&server->usage) > 0) { | |
272 | /* try and find a connection that has spare callslots */ | 296 | list_del_init(&server->grave); |
273 | for (nconn = 0; nconn < AFS_SERVER_CONN_LIST_SIZE; nconn++) { | 297 | } else { |
274 | if (server->fs_conn_cnt[nconn] > 0) { | 298 | list_move_tail(&server->grave, &corpses); |
275 | server->fs_conn_cnt[nconn]--; | 299 | list_del_init(&server->link); |
276 | spin_unlock(&server->fs_lock); | 300 | rb_erase(&server->master_rb, &afs_servers); |
277 | callslot->nconn = nconn; | ||
278 | goto obtained_slot; | ||
279 | } | 301 | } |
302 | write_unlock(&afs_servers_lock); | ||
303 | write_unlock(&server->cell->servers_lock); | ||
280 | } | 304 | } |
281 | 305 | ||
282 | /* none were available - wait interruptibly for one to become | 306 | spin_unlock(&afs_server_graveyard_lock); |
283 | * available */ | ||
284 | set_current_state(TASK_INTERRUPTIBLE); | ||
285 | list_add_tail(&callslot->link, &server->fs_callq); | ||
286 | spin_unlock(&server->fs_lock); | ||
287 | |||
288 | while (!callslot->ready && !signal_pending(current)) { | ||
289 | schedule(); | ||
290 | set_current_state(TASK_INTERRUPTIBLE); | ||
291 | } | ||
292 | |||
293 | set_current_state(TASK_RUNNING); | ||
294 | |||
295 | /* even if we were interrupted we may still be queued */ | ||
296 | if (!callslot->ready) { | ||
297 | spin_lock(&server->fs_lock); | ||
298 | list_del_init(&callslot->link); | ||
299 | spin_unlock(&server->fs_lock); | ||
300 | } | ||
301 | |||
302 | nconn = callslot->nconn; | ||
303 | 307 | ||
304 | /* if interrupted, we must release any slot we also got before | 308 | /* now reap the corpses we've extracted */ |
305 | * returning an error */ | 309 | while (!list_empty(&corpses)) { |
306 | if (signal_pending(current)) { | 310 | server = list_entry(corpses.next, struct afs_server, grave); |
307 | ret = -EINTR; | 311 | list_del(&server->grave); |
308 | goto error_release; | 312 | afs_destroy_server(server); |
309 | } | 313 | } |
314 | } | ||
310 | 315 | ||
311 | /* if we were woken up with an error, then pass that error back to the | ||
312 | * called */ | ||
313 | if (nconn < 0) { | ||
314 | _leave(" = %d", callslot->errno); | ||
315 | return callslot->errno; | ||
316 | } | ||
317 | |||
318 | /* were we given a connection directly? */ | ||
319 | if (callslot->conn) { | ||
320 | /* yes - use it */ | ||
321 | _leave(" = 0 (nc=%d)", nconn); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /* got a callslot, but no connection */ | ||
326 | obtained_slot: | ||
327 | |||
328 | /* need to get hold of the RxRPC connection */ | ||
329 | down_write(&server->sem); | ||
330 | |||
331 | /* quick check to see if there's an outstanding error */ | ||
332 | ret = server->fs_state; | ||
333 | if (ret) | ||
334 | goto error_release_upw; | ||
335 | |||
336 | if (server->fs_conn[nconn]) { | ||
337 | /* reuse an existing connection */ | ||
338 | rxrpc_get_connection(server->fs_conn[nconn]); | ||
339 | callslot->conn = server->fs_conn[nconn]; | ||
340 | } | ||
341 | else { | ||
342 | /* create a new connection */ | ||
343 | ret = rxrpc_create_connection(afs_transport, | ||
344 | htons(7000), | ||
345 | server->addr.s_addr, | ||
346 | FS_SERVICE_ID, | ||
347 | NULL, | ||
348 | &server->fs_conn[nconn]); | ||
349 | |||
350 | if (ret < 0) | ||
351 | goto error_release_upw; | ||
352 | |||
353 | callslot->conn = server->fs_conn[0]; | ||
354 | rxrpc_get_connection(callslot->conn); | ||
355 | } | ||
356 | |||
357 | up_write(&server->sem); | ||
358 | |||
359 | _leave(" = 0"); | ||
360 | return 0; | ||
361 | |||
362 | /* handle an error occurring */ | ||
363 | error_release_upw: | ||
364 | up_write(&server->sem); | ||
365 | |||
366 | error_release: | ||
367 | /* either release the callslot or pass it along to another deserving | ||
368 | * task */ | ||
369 | spin_lock(&server->fs_lock); | ||
370 | |||
371 | if (nconn < 0) { | ||
372 | /* no callslot allocated */ | ||
373 | } | ||
374 | else if (list_empty(&server->fs_callq)) { | ||
375 | /* no one waiting */ | ||
376 | server->fs_conn_cnt[nconn]++; | ||
377 | spin_unlock(&server->fs_lock); | ||
378 | } | ||
379 | else { | ||
380 | /* someone's waiting - dequeue them and wake them up */ | ||
381 | pcallslot = list_entry(server->fs_callq.next, | ||
382 | struct afs_server_callslot, link); | ||
383 | list_del_init(&pcallslot->link); | ||
384 | |||
385 | pcallslot->errno = server->fs_state; | ||
386 | if (!pcallslot->errno) { | ||
387 | /* pass them out callslot details */ | ||
388 | callslot->conn = xchg(&pcallslot->conn, | ||
389 | callslot->conn); | ||
390 | pcallslot->nconn = nconn; | ||
391 | callslot->nconn = nconn = -1; | ||
392 | } | ||
393 | pcallslot->ready = 1; | ||
394 | wake_up_process(pcallslot->task); | ||
395 | spin_unlock(&server->fs_lock); | ||
396 | } | ||
397 | |||
398 | rxrpc_put_connection(callslot->conn); | ||
399 | callslot->conn = NULL; | ||
400 | |||
401 | _leave(" = %d", ret); | ||
402 | return ret; | ||
403 | |||
404 | } /* end afs_server_request_callslot() */ | ||
405 | |||
406 | /*****************************************************************************/ | ||
407 | /* | ||
408 | * release a callslot back to the server | ||
409 | * - transfers the RxRPC connection to the next pending callslot if possible | ||
410 | */ | ||
411 | void afs_server_release_callslot(struct afs_server *server, | ||
412 | struct afs_server_callslot *callslot) | ||
413 | { | ||
414 | struct afs_server_callslot *pcallslot; | ||
415 | |||
416 | _enter("{ad=%08x,cnt=%u},{%d}", | ||
417 | ntohl(server->addr.s_addr), | ||
418 | server->fs_conn_cnt[callslot->nconn], | ||
419 | callslot->nconn); | ||
420 | |||
421 | BUG_ON(callslot->nconn < 0); | ||
422 | |||
423 | spin_lock(&server->fs_lock); | ||
424 | |||
425 | if (list_empty(&server->fs_callq)) { | ||
426 | /* no one waiting */ | ||
427 | server->fs_conn_cnt[callslot->nconn]++; | ||
428 | spin_unlock(&server->fs_lock); | ||
429 | } | ||
430 | else { | ||
431 | /* someone's waiting - dequeue them and wake them up */ | ||
432 | pcallslot = list_entry(server->fs_callq.next, | ||
433 | struct afs_server_callslot, link); | ||
434 | list_del_init(&pcallslot->link); | ||
435 | |||
436 | pcallslot->errno = server->fs_state; | ||
437 | if (!pcallslot->errno) { | ||
438 | /* pass them out callslot details */ | ||
439 | callslot->conn = xchg(&pcallslot->conn, callslot->conn); | ||
440 | pcallslot->nconn = callslot->nconn; | ||
441 | callslot->nconn = -1; | ||
442 | } | ||
443 | |||
444 | pcallslot->ready = 1; | ||
445 | wake_up_process(pcallslot->task); | ||
446 | spin_unlock(&server->fs_lock); | ||
447 | } | ||
448 | |||
449 | rxrpc_put_connection(callslot->conn); | ||
450 | |||
451 | _leave(""); | ||
452 | } /* end afs_server_release_callslot() */ | ||
453 | |||
454 | /*****************************************************************************/ | ||
455 | /* | 316 | /* |
456 | * get a handle to a connection to the vlserver (volume location) on the | 317 | * discard all the server records for rmmod |
457 | * specified server | ||
458 | */ | 318 | */ |
459 | int afs_server_get_vlconn(struct afs_server *server, | 319 | void __exit afs_purge_servers(void) |
460 | struct rxrpc_connection **_conn) | ||
461 | { | 320 | { |
462 | struct rxrpc_connection *conn; | 321 | afs_server_timeout = 0; |
463 | int ret; | 322 | cancel_delayed_work(&afs_server_reaper); |
464 | 323 | schedule_delayed_work(&afs_server_reaper, 0); | |
465 | _enter("%p,", server); | 324 | } |
466 | |||
467 | ret = 0; | ||
468 | conn = NULL; | ||
469 | down_read(&server->sem); | ||
470 | |||
471 | if (server->vlserver) { | ||
472 | /* reuse an existing connection */ | ||
473 | rxrpc_get_connection(server->vlserver); | ||
474 | conn = server->vlserver; | ||
475 | up_read(&server->sem); | ||
476 | } | ||
477 | else { | ||
478 | /* create a new connection */ | ||
479 | up_read(&server->sem); | ||
480 | down_write(&server->sem); | ||
481 | if (!server->vlserver) { | ||
482 | ret = rxrpc_create_connection(afs_transport, | ||
483 | htons(7003), | ||
484 | server->addr.s_addr, | ||
485 | VL_SERVICE_ID, | ||
486 | NULL, | ||
487 | &server->vlserver); | ||
488 | } | ||
489 | if (ret == 0) { | ||
490 | rxrpc_get_connection(server->vlserver); | ||
491 | conn = server->vlserver; | ||
492 | } | ||
493 | up_write(&server->sem); | ||
494 | } | ||
495 | |||
496 | *_conn = conn; | ||
497 | _leave(" = %d", ret); | ||
498 | return ret; | ||
499 | } /* end afs_server_get_vlconn() */ | ||
diff --git a/fs/afs/server.h b/fs/afs/server.h deleted file mode 100644 index c3d24115578f..000000000000 --- a/fs/afs/server.h +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | /* server.h: AFS server record | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_SERVER_H | ||
13 | #define _LINUX_AFS_SERVER_H | ||
14 | |||
15 | #include "types.h" | ||
16 | #include "kafstimod.h" | ||
17 | #include <rxrpc/peer.h> | ||
18 | #include <linux/rwsem.h> | ||
19 | |||
20 | extern spinlock_t afs_server_peer_lock; | ||
21 | |||
22 | /*****************************************************************************/ | ||
23 | /* | ||
24 | * AFS server record | ||
25 | */ | ||
26 | struct afs_server | ||
27 | { | ||
28 | atomic_t usage; | ||
29 | struct afs_cell *cell; /* cell in which server resides */ | ||
30 | struct list_head link; /* link in cell's server list */ | ||
31 | struct rw_semaphore sem; /* access lock */ | ||
32 | struct afs_timer timeout; /* graveyard timeout */ | ||
33 | struct in_addr addr; /* server address */ | ||
34 | struct rxrpc_peer *peer; /* peer record for this server */ | ||
35 | struct rxrpc_connection *vlserver; /* connection to the volume location service */ | ||
36 | |||
37 | /* file service access */ | ||
38 | #define AFS_SERVER_CONN_LIST_SIZE 2 | ||
39 | struct rxrpc_connection *fs_conn[AFS_SERVER_CONN_LIST_SIZE]; /* FS connections */ | ||
40 | unsigned fs_conn_cnt[AFS_SERVER_CONN_LIST_SIZE]; /* per conn call count */ | ||
41 | struct list_head fs_callq; /* queue of processes waiting to make a call */ | ||
42 | spinlock_t fs_lock; /* access lock */ | ||
43 | int fs_state; /* 0 or reason FS currently marked dead (-errno) */ | ||
44 | unsigned fs_rtt; /* FS round trip time */ | ||
45 | unsigned long fs_act_jif; /* time at which last activity occurred */ | ||
46 | unsigned long fs_dead_jif; /* time at which no longer to be considered dead */ | ||
47 | |||
48 | /* callback promise management */ | ||
49 | struct list_head cb_promises; /* as yet unbroken promises from this server */ | ||
50 | spinlock_t cb_lock; /* access lock */ | ||
51 | }; | ||
52 | |||
53 | extern int afs_server_lookup(struct afs_cell *cell, | ||
54 | const struct in_addr *addr, | ||
55 | struct afs_server **_server); | ||
56 | |||
57 | #define afs_get_server(S) do { atomic_inc(&(S)->usage); } while(0) | ||
58 | |||
59 | extern void afs_put_server(struct afs_server *server); | ||
60 | extern void afs_server_do_timeout(struct afs_server *server); | ||
61 | |||
62 | extern int afs_server_find_by_peer(const struct rxrpc_peer *peer, | ||
63 | struct afs_server **_server); | ||
64 | |||
65 | extern int afs_server_get_vlconn(struct afs_server *server, | ||
66 | struct rxrpc_connection **_conn); | ||
67 | |||
68 | static inline | ||
69 | struct afs_server *afs_server_get_from_peer(struct rxrpc_peer *peer) | ||
70 | { | ||
71 | struct afs_server *server; | ||
72 | |||
73 | spin_lock(&afs_server_peer_lock); | ||
74 | server = peer->user; | ||
75 | if (server) | ||
76 | afs_get_server(server); | ||
77 | spin_unlock(&afs_server_peer_lock); | ||
78 | |||
79 | return server; | ||
80 | } | ||
81 | |||
82 | /*****************************************************************************/ | ||
83 | /* | ||
84 | * AFS server callslot grant record | ||
85 | */ | ||
86 | struct afs_server_callslot | ||
87 | { | ||
88 | struct list_head link; /* link in server's list */ | ||
89 | struct task_struct *task; /* process waiting to make call */ | ||
90 | struct rxrpc_connection *conn; /* connection to use (or NULL on error) */ | ||
91 | short nconn; /* connection slot number (-1 on error) */ | ||
92 | char ready; /* T when ready */ | ||
93 | int errno; /* error number if nconn==-1 */ | ||
94 | }; | ||
95 | |||
96 | extern int afs_server_request_callslot(struct afs_server *server, | ||
97 | struct afs_server_callslot *callslot); | ||
98 | |||
99 | extern void afs_server_release_callslot(struct afs_server *server, | ||
100 | struct afs_server_callslot *callslot); | ||
101 | |||
102 | #endif /* _LINUX_AFS_SERVER_H */ | ||
diff --git a/fs/afs/super.c b/fs/afs/super.c index eb7e32349da3..cebd03c91f57 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* AFS superblock handling |
2 | * Copyright (c) 2002 Red Hat, Inc. All rights reserved. | 2 | * |
3 | * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved. | ||
3 | * | 4 | * |
4 | * This software may be freely redistributed under the terms of the | 5 | * This software may be freely redistributed under the terms of the |
5 | * GNU General Public License. | 6 | * GNU General Public License. |
@@ -9,7 +10,7 @@ | |||
9 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 10 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
10 | * | 11 | * |
11 | * Authors: David Howells <dhowells@redhat.com> | 12 | * Authors: David Howells <dhowells@redhat.com> |
12 | * David Woodhouse <dwmw2@cambridge.redhat.com> | 13 | * David Woodhouse <dwmw2@redhat.com> |
13 | * | 14 | * |
14 | */ | 15 | */ |
15 | 16 | ||
@@ -19,22 +20,10 @@ | |||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
21 | #include <linux/pagemap.h> | 22 | #include <linux/pagemap.h> |
22 | #include "vnode.h" | ||
23 | #include "volume.h" | ||
24 | #include "cell.h" | ||
25 | #include "cmservice.h" | ||
26 | #include "fsclient.h" | ||
27 | #include "super.h" | ||
28 | #include "internal.h" | 23 | #include "internal.h" |
29 | 24 | ||
30 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ | 25 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ |
31 | 26 | ||
32 | struct afs_mount_params { | ||
33 | int rwpath; | ||
34 | struct afs_cell *default_cell; | ||
35 | struct afs_volume *volume; | ||
36 | }; | ||
37 | |||
38 | 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, |
39 | unsigned long flags); | 28 | unsigned long flags); |
40 | 29 | ||
@@ -62,13 +51,13 @@ static const struct super_operations afs_super_ops = { | |||
62 | .drop_inode = generic_delete_inode, | 51 | .drop_inode = generic_delete_inode, |
63 | .destroy_inode = afs_destroy_inode, | 52 | .destroy_inode = afs_destroy_inode, |
64 | .clear_inode = afs_clear_inode, | 53 | .clear_inode = afs_clear_inode, |
54 | .umount_begin = afs_umount_begin, | ||
65 | .put_super = afs_put_super, | 55 | .put_super = afs_put_super, |
66 | }; | 56 | }; |
67 | 57 | ||
68 | static struct kmem_cache *afs_inode_cachep; | 58 | static struct kmem_cache *afs_inode_cachep; |
69 | static atomic_t afs_count_active_inodes; | 59 | static atomic_t afs_count_active_inodes; |
70 | 60 | ||
71 | /*****************************************************************************/ | ||
72 | /* | 61 | /* |
73 | * initialise the filesystem | 62 | * initialise the filesystem |
74 | */ | 63 | */ |
@@ -78,8 +67,6 @@ int __init afs_fs_init(void) | |||
78 | 67 | ||
79 | _enter(""); | 68 | _enter(""); |
80 | 69 | ||
81 | afs_timer_init(&afs_mntpt_expiry_timer, &afs_mntpt_expiry_timer_ops); | ||
82 | |||
83 | /* create ourselves an inode cache */ | 70 | /* create ourselves an inode cache */ |
84 | atomic_set(&afs_count_active_inodes, 0); | 71 | atomic_set(&afs_count_active_inodes, 0); |
85 | 72 | ||
@@ -99,20 +86,22 @@ int __init afs_fs_init(void) | |||
99 | ret = register_filesystem(&afs_fs_type); | 86 | ret = register_filesystem(&afs_fs_type); |
100 | if (ret < 0) { | 87 | if (ret < 0) { |
101 | kmem_cache_destroy(afs_inode_cachep); | 88 | kmem_cache_destroy(afs_inode_cachep); |
102 | kleave(" = %d", ret); | 89 | _leave(" = %d", ret); |
103 | return ret; | 90 | return ret; |
104 | } | 91 | } |
105 | 92 | ||
106 | kleave(" = 0"); | 93 | _leave(" = 0"); |
107 | return 0; | 94 | return 0; |
108 | } /* end afs_fs_init() */ | 95 | } |
109 | 96 | ||
110 | /*****************************************************************************/ | ||
111 | /* | 97 | /* |
112 | * clean up the filesystem | 98 | * clean up the filesystem |
113 | */ | 99 | */ |
114 | void __exit afs_fs_exit(void) | 100 | void __exit afs_fs_exit(void) |
115 | { | 101 | { |
102 | _enter(""); | ||
103 | |||
104 | afs_mntpt_kill_timer(); | ||
116 | unregister_filesystem(&afs_fs_type); | 105 | unregister_filesystem(&afs_fs_type); |
117 | 106 | ||
118 | if (atomic_read(&afs_count_active_inodes) != 0) { | 107 | if (atomic_read(&afs_count_active_inodes) != 0) { |
@@ -122,10 +111,9 @@ void __exit afs_fs_exit(void) | |||
122 | } | 111 | } |
123 | 112 | ||
124 | kmem_cache_destroy(afs_inode_cachep); | 113 | kmem_cache_destroy(afs_inode_cachep); |
114 | _leave(""); | ||
115 | } | ||
125 | 116 | ||
126 | } /* end afs_fs_exit() */ | ||
127 | |||
128 | /*****************************************************************************/ | ||
129 | /* | 117 | /* |
130 | * check that an argument has a value | 118 | * check that an argument has a value |
131 | */ | 119 | */ |
@@ -136,9 +124,8 @@ static int want_arg(char **_value, const char *option) | |||
136 | return 0; | 124 | return 0; |
137 | } | 125 | } |
138 | return 1; | 126 | return 1; |
139 | } /* end want_arg() */ | 127 | } |
140 | 128 | ||
141 | /*****************************************************************************/ | ||
142 | /* | 129 | /* |
143 | * check that there's no subsequent value | 130 | * check that there's no subsequent value |
144 | */ | 131 | */ |
@@ -150,18 +137,17 @@ static int want_no_value(char *const *_value, const char *option) | |||
150 | return 0; | 137 | return 0; |
151 | } | 138 | } |
152 | return 1; | 139 | return 1; |
153 | } /* end want_no_value() */ | 140 | } |
154 | 141 | ||
155 | /*****************************************************************************/ | ||
156 | /* | 142 | /* |
157 | * parse the mount options | 143 | * parse the mount options |
158 | * - this function has been shamelessly adapted from the ext3 fs which | 144 | * - this function has been shamelessly adapted from the ext3 fs which |
159 | * shamelessly adapted it from the msdos fs | 145 | * shamelessly adapted it from the msdos fs |
160 | */ | 146 | */ |
161 | static int afs_super_parse_options(struct afs_mount_params *params, | 147 | static int afs_parse_options(struct afs_mount_params *params, |
162 | char *options, | 148 | char *options, const char **devname) |
163 | const char **devname) | ||
164 | { | 149 | { |
150 | struct afs_cell *cell; | ||
165 | char *key, *value; | 151 | char *key, *value; |
166 | int ret; | 152 | int ret; |
167 | 153 | ||
@@ -170,51 +156,135 @@ static int afs_super_parse_options(struct afs_mount_params *params, | |||
170 | options[PAGE_SIZE - 1] = 0; | 156 | options[PAGE_SIZE - 1] = 0; |
171 | 157 | ||
172 | ret = 0; | 158 | ret = 0; |
173 | while ((key = strsep(&options, ",")) != 0) | 159 | while ((key = strsep(&options, ","))) { |
174 | { | ||
175 | value = strchr(key, '='); | 160 | value = strchr(key, '='); |
176 | if (value) | 161 | if (value) |
177 | *value++ = 0; | 162 | *value++ = 0; |
178 | 163 | ||
179 | printk("kAFS: KEY: %s, VAL:%s\n", key, value ?: "-"); | 164 | _debug("kAFS: KEY: %s, VAL:%s", key, value ?: "-"); |
180 | 165 | ||
181 | if (strcmp(key, "rwpath") == 0) { | 166 | if (strcmp(key, "rwpath") == 0) { |
182 | if (!want_no_value(&value, "rwpath")) | 167 | if (!want_no_value(&value, "rwpath")) |
183 | return -EINVAL; | 168 | return -EINVAL; |
184 | params->rwpath = 1; | 169 | params->rwpath = 1; |
185 | continue; | 170 | } else if (strcmp(key, "vol") == 0) { |
186 | } | ||
187 | else if (strcmp(key, "vol") == 0) { | ||
188 | if (!want_arg(&value, "vol")) | 171 | if (!want_arg(&value, "vol")) |
189 | return -EINVAL; | 172 | return -EINVAL; |
190 | *devname = value; | 173 | *devname = value; |
191 | continue; | 174 | } else if (strcmp(key, "cell") == 0) { |
192 | } | ||
193 | else if (strcmp(key, "cell") == 0) { | ||
194 | if (!want_arg(&value, "cell")) | 175 | if (!want_arg(&value, "cell")) |
195 | return -EINVAL; | 176 | return -EINVAL; |
196 | afs_put_cell(params->default_cell); | 177 | cell = afs_cell_lookup(value, strlen(value)); |
197 | ret = afs_cell_lookup(value, | 178 | if (IS_ERR(cell)) |
198 | strlen(value), | 179 | return PTR_ERR(cell); |
199 | ¶ms->default_cell); | 180 | afs_put_cell(params->cell); |
200 | if (ret < 0) | 181 | params->cell = cell; |
201 | return -EINVAL; | 182 | } else { |
202 | continue; | 183 | printk("kAFS: Unknown mount option: '%s'\n", key); |
184 | ret = -EINVAL; | ||
185 | goto error; | ||
203 | } | 186 | } |
204 | |||
205 | printk("kAFS: Unknown mount option: '%s'\n", key); | ||
206 | ret = -EINVAL; | ||
207 | goto error; | ||
208 | } | 187 | } |
209 | 188 | ||
210 | ret = 0; | 189 | ret = 0; |
211 | 190 | error: | |
212 | error: | ||
213 | _leave(" = %d", ret); | 191 | _leave(" = %d", ret); |
214 | return ret; | 192 | return ret; |
215 | } /* end afs_super_parse_options() */ | 193 | } |
194 | |||
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 | } | ||
216 | 287 | ||
217 | /*****************************************************************************/ | ||
218 | /* | 288 | /* |
219 | * 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 |
220 | */ | 290 | */ |
@@ -224,13 +294,12 @@ static int afs_test_super(struct super_block *sb, void *data) | |||
224 | struct afs_super_info *as = sb->s_fs_info; | 294 | struct afs_super_info *as = sb->s_fs_info; |
225 | 295 | ||
226 | return as->volume == params->volume; | 296 | return as->volume == params->volume; |
227 | } /* end afs_test_super() */ | 297 | } |
228 | 298 | ||
229 | /*****************************************************************************/ | ||
230 | /* | 299 | /* |
231 | * fill in the superblock | 300 | * fill in the superblock |
232 | */ | 301 | */ |
233 | static int afs_fill_super(struct super_block *sb, void *data, int silent) | 302 | static int afs_fill_super(struct super_block *sb, void *data) |
234 | { | 303 | { |
235 | struct afs_mount_params *params = data; | 304 | struct afs_mount_params *params = data; |
236 | struct afs_super_info *as = NULL; | 305 | struct afs_super_info *as = NULL; |
@@ -239,7 +308,7 @@ static int afs_fill_super(struct super_block *sb, void *data, int silent) | |||
239 | struct inode *inode = NULL; | 308 | struct inode *inode = NULL; |
240 | int ret; | 309 | int ret; |
241 | 310 | ||
242 | kenter(""); | 311 | _enter(""); |
243 | 312 | ||
244 | /* allocate a superblock info record */ | 313 | /* allocate a superblock info record */ |
245 | as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); | 314 | as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); |
@@ -262,9 +331,9 @@ static int afs_fill_super(struct super_block *sb, void *data, int silent) | |||
262 | fid.vid = as->volume->vid; | 331 | fid.vid = as->volume->vid; |
263 | fid.vnode = 1; | 332 | fid.vnode = 1; |
264 | fid.unique = 1; | 333 | fid.unique = 1; |
265 | ret = afs_iget(sb, &fid, &inode); | 334 | inode = afs_iget(sb, params->key, &fid, NULL, NULL); |
266 | if (ret < 0) | 335 | if (IS_ERR(inode)) |
267 | goto error; | 336 | goto error_inode; |
268 | 337 | ||
269 | ret = -ENOMEM; | 338 | ret = -ENOMEM; |
270 | root = d_alloc_root(inode); | 339 | root = d_alloc_root(inode); |
@@ -273,21 +342,23 @@ static int afs_fill_super(struct super_block *sb, void *data, int silent) | |||
273 | 342 | ||
274 | sb->s_root = root; | 343 | sb->s_root = root; |
275 | 344 | ||
276 | kleave(" = 0"); | 345 | _leave(" = 0"); |
277 | return 0; | 346 | return 0; |
278 | 347 | ||
279 | error: | 348 | error_inode: |
349 | ret = PTR_ERR(inode); | ||
350 | inode = NULL; | ||
351 | error: | ||
280 | iput(inode); | 352 | iput(inode); |
281 | afs_put_volume(as->volume); | 353 | afs_put_volume(as->volume); |
282 | kfree(as); | 354 | kfree(as); |
283 | 355 | ||
284 | sb->s_fs_info = NULL; | 356 | sb->s_fs_info = NULL; |
285 | 357 | ||
286 | kleave(" = %d", ret); | 358 | _leave(" = %d", ret); |
287 | return ret; | 359 | return ret; |
288 | } /* end afs_fill_super() */ | 360 | } |
289 | 361 | ||
290 | /*****************************************************************************/ | ||
291 | /* | 362 | /* |
292 | * get an AFS superblock | 363 | * get an AFS superblock |
293 | * - TODO: don't use get_sb_nodev(), but rather call sget() directly | 364 | * - TODO: don't use get_sb_nodev(), but rather call sget() directly |
@@ -300,69 +371,80 @@ static int afs_get_sb(struct file_system_type *fs_type, | |||
300 | { | 371 | { |
301 | struct afs_mount_params params; | 372 | struct afs_mount_params params; |
302 | struct super_block *sb; | 373 | struct super_block *sb; |
374 | struct afs_volume *vol; | ||
375 | struct key *key; | ||
303 | int ret; | 376 | int ret; |
304 | 377 | ||
305 | _enter(",,%s,%p", dev_name, options); | 378 | _enter(",,%s,%p", dev_name, options); |
306 | 379 | ||
307 | memset(¶ms, 0, sizeof(params)); | 380 | memset(¶ms, 0, sizeof(params)); |
308 | 381 | ||
309 | /* start the cache manager */ | 382 | /* parse the options and device name */ |
310 | ret = afscm_start(); | ||
311 | if (ret < 0) { | ||
312 | _leave(" = %d", ret); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | /* parse the options */ | ||
317 | if (options) { | 383 | if (options) { |
318 | ret = afs_super_parse_options(¶ms, options, &dev_name); | 384 | ret = afs_parse_options(¶ms, options, &dev_name); |
319 | if (ret < 0) | 385 | if (ret < 0) |
320 | goto error; | 386 | goto error; |
321 | if (!dev_name) { | ||
322 | printk("kAFS: no volume name specified\n"); | ||
323 | ret = -EINVAL; | ||
324 | goto error; | ||
325 | } | ||
326 | } | 387 | } |
327 | 388 | ||
328 | /* parse the device name */ | 389 | |
329 | ret = afs_volume_lookup(dev_name, | 390 | ret = afs_parse_device_name(¶ms, dev_name); |
330 | params.default_cell, | ||
331 | params.rwpath, | ||
332 | ¶ms.volume); | ||
333 | if (ret < 0) | 391 | if (ret < 0) |
334 | goto error; | 392 | goto error; |
335 | 393 | ||
336 | /* allocate a deviceless superblock */ | 394 | /* try and do the mount securely */ |
337 | sb = sget(fs_type, afs_test_super, set_anon_super, ¶ms); | 395 | key = afs_request_key(params.cell); |
338 | if (IS_ERR(sb)) | 396 | if (IS_ERR(key)) { |
397 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
398 | ret = PTR_ERR(key); | ||
339 | goto error; | 399 | goto error; |
400 | } | ||
401 | params.key = key; | ||
340 | 402 | ||
341 | sb->s_flags = flags; | 403 | /* parse the device name */ |
404 | vol = afs_volume_lookup(¶ms); | ||
405 | if (IS_ERR(vol)) { | ||
406 | ret = PTR_ERR(vol); | ||
407 | goto error; | ||
408 | } | ||
409 | params.volume = vol; | ||
342 | 410 | ||
343 | ret = afs_fill_super(sb, ¶ms, flags & MS_SILENT ? 1 : 0); | 411 | /* allocate a deviceless superblock */ |
344 | if (ret < 0) { | 412 | sb = sget(fs_type, afs_test_super, set_anon_super, ¶ms); |
345 | up_write(&sb->s_umount); | 413 | if (IS_ERR(sb)) { |
346 | deactivate_super(sb); | 414 | ret = PTR_ERR(sb); |
347 | goto error; | 415 | goto error; |
348 | } | 416 | } |
349 | sb->s_flags |= MS_ACTIVE; | ||
350 | simple_set_mnt(mnt, sb); | ||
351 | 417 | ||
418 | if (!sb->s_root) { | ||
419 | /* initial superblock/root creation */ | ||
420 | _debug("create"); | ||
421 | sb->s_flags = flags; | ||
422 | ret = afs_fill_super(sb, ¶ms); | ||
423 | if (ret < 0) { | ||
424 | up_write(&sb->s_umount); | ||
425 | deactivate_super(sb); | ||
426 | goto error; | ||
427 | } | ||
428 | sb->s_flags |= MS_ACTIVE; | ||
429 | } else { | ||
430 | _debug("reuse"); | ||
431 | ASSERTCMP(sb->s_flags, &, MS_ACTIVE); | ||
432 | } | ||
433 | |||
434 | simple_set_mnt(mnt, sb); | ||
352 | afs_put_volume(params.volume); | 435 | afs_put_volume(params.volume); |
353 | afs_put_cell(params.default_cell); | 436 | afs_put_cell(params.cell); |
354 | _leave(" = 0 [%p]", 0, sb); | 437 | _leave(" = 0 [%p]", sb); |
355 | return 0; | 438 | return 0; |
356 | 439 | ||
357 | error: | 440 | error: |
358 | afs_put_volume(params.volume); | 441 | afs_put_volume(params.volume); |
359 | afs_put_cell(params.default_cell); | 442 | afs_put_cell(params.cell); |
360 | afscm_stop(); | 443 | key_put(params.key); |
361 | _leave(" = %d", ret); | 444 | _leave(" = %d", ret); |
362 | return ret; | 445 | return ret; |
363 | } /* end afs_get_sb() */ | 446 | } |
364 | 447 | ||
365 | /*****************************************************************************/ | ||
366 | /* | 448 | /* |
367 | * finish the unmounting process on the superblock | 449 | * finish the unmounting process on the superblock |
368 | */ | 450 | */ |
@@ -373,35 +455,30 @@ static void afs_put_super(struct super_block *sb) | |||
373 | _enter(""); | 455 | _enter(""); |
374 | 456 | ||
375 | afs_put_volume(as->volume); | 457 | afs_put_volume(as->volume); |
376 | afscm_stop(); | ||
377 | 458 | ||
378 | _leave(""); | 459 | _leave(""); |
379 | } /* end afs_put_super() */ | 460 | } |
380 | 461 | ||
381 | /*****************************************************************************/ | ||
382 | /* | 462 | /* |
383 | * initialise an inode cache slab element prior to any use | 463 | * initialise an inode cache slab element prior to any use |
384 | */ | 464 | */ |
385 | static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, | 465 | static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, |
386 | unsigned long flags) | 466 | unsigned long flags) |
387 | { | 467 | { |
388 | struct afs_vnode *vnode = (struct afs_vnode *) _vnode; | 468 | struct afs_vnode *vnode = _vnode; |
389 | 469 | ||
390 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | 470 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == |
391 | SLAB_CTOR_CONSTRUCTOR) { | 471 | SLAB_CTOR_CONSTRUCTOR) { |
392 | memset(vnode, 0, sizeof(*vnode)); | 472 | memset(vnode, 0, sizeof(*vnode)); |
393 | inode_init_once(&vnode->vfs_inode); | 473 | inode_init_once(&vnode->vfs_inode); |
394 | init_waitqueue_head(&vnode->update_waitq); | 474 | init_waitqueue_head(&vnode->update_waitq); |
475 | mutex_init(&vnode->permits_lock); | ||
476 | mutex_init(&vnode->validate_lock); | ||
395 | spin_lock_init(&vnode->lock); | 477 | spin_lock_init(&vnode->lock); |
396 | INIT_LIST_HEAD(&vnode->cb_link); | 478 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); |
397 | INIT_LIST_HEAD(&vnode->cb_hash_link); | ||
398 | afs_timer_init(&vnode->cb_timeout, | ||
399 | &afs_vnode_cb_timed_out_ops); | ||
400 | } | 479 | } |
480 | } | ||
401 | 481 | ||
402 | } /* end afs_i_init_once() */ | ||
403 | |||
404 | /*****************************************************************************/ | ||
405 | /* | 482 | /* |
406 | * allocate an AFS inode struct from our slab cache | 483 | * allocate an AFS inode struct from our slab cache |
407 | */ | 484 | */ |
@@ -409,8 +486,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb) | |||
409 | { | 486 | { |
410 | struct afs_vnode *vnode; | 487 | struct afs_vnode *vnode; |
411 | 488 | ||
412 | vnode = (struct afs_vnode *) | 489 | vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); |
413 | kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); | ||
414 | if (!vnode) | 490 | if (!vnode) |
415 | return NULL; | 491 | return NULL; |
416 | 492 | ||
@@ -421,21 +497,25 @@ static struct inode *afs_alloc_inode(struct super_block *sb) | |||
421 | 497 | ||
422 | vnode->volume = NULL; | 498 | vnode->volume = NULL; |
423 | vnode->update_cnt = 0; | 499 | vnode->update_cnt = 0; |
424 | vnode->flags = 0; | 500 | vnode->flags = 1 << AFS_VNODE_UNSET; |
501 | vnode->cb_promised = false; | ||
425 | 502 | ||
426 | return &vnode->vfs_inode; | 503 | return &vnode->vfs_inode; |
427 | } /* end afs_alloc_inode() */ | 504 | } |
428 | 505 | ||
429 | /*****************************************************************************/ | ||
430 | /* | 506 | /* |
431 | * destroy an AFS inode struct | 507 | * destroy an AFS inode struct |
432 | */ | 508 | */ |
433 | static void afs_destroy_inode(struct inode *inode) | 509 | static void afs_destroy_inode(struct inode *inode) |
434 | { | 510 | { |
511 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
512 | |||
435 | _enter("{%lu}", inode->i_ino); | 513 | _enter("{%lu}", inode->i_ino); |
436 | 514 | ||
437 | kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode)); | 515 | _debug("DESTROY INODE %p", inode); |
438 | 516 | ||
439 | atomic_dec(&afs_count_active_inodes); | 517 | ASSERTCMP(vnode->server, ==, NULL); |
440 | 518 | ||
441 | } /* end afs_destroy_inode() */ | 519 | kmem_cache_free(afs_inode_cachep, vnode); |
520 | atomic_dec(&afs_count_active_inodes); | ||
521 | } | ||
diff --git a/fs/afs/super.h b/fs/afs/super.h deleted file mode 100644 index 32de8cc6fae8..000000000000 --- a/fs/afs/super.h +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | /* super.h: AFS filesystem internal private data | ||
2 | * | ||
3 | * Copyright (c) 2002 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This software may be freely redistributed under the terms of the | ||
6 | * GNU General Public License. | ||
7 | * | ||
8 | * You should have received a copy of the GNU General Public License | ||
9 | * along with this program; if not, write to the Free Software | ||
10 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
11 | * | ||
12 | * Authors: David Woodhouse <dwmw2@cambridge.redhat.com> | ||
13 | * David Howells <dhowells@redhat.com> | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef _LINUX_AFS_SUPER_H | ||
18 | #define _LINUX_AFS_SUPER_H | ||
19 | |||
20 | #include <linux/fs.h> | ||
21 | #include "server.h" | ||
22 | |||
23 | #ifdef __KERNEL__ | ||
24 | |||
25 | /*****************************************************************************/ | ||
26 | /* | ||
27 | * AFS superblock private data | ||
28 | * - there's one superblock per volume | ||
29 | */ | ||
30 | struct afs_super_info | ||
31 | { | ||
32 | struct afs_volume *volume; /* volume record */ | ||
33 | char rwparent; /* T if parent is R/W AFS volume */ | ||
34 | }; | ||
35 | |||
36 | static inline struct afs_super_info *AFS_FS_S(struct super_block *sb) | ||
37 | { | ||
38 | return sb->s_fs_info; | ||
39 | } | ||
40 | |||
41 | extern struct file_system_type afs_fs_type; | ||
42 | |||
43 | #endif /* __KERNEL__ */ | ||
44 | |||
45 | #endif /* _LINUX_AFS_SUPER_H */ | ||
diff --git a/fs/afs/transport.h b/fs/afs/transport.h deleted file mode 100644 index 7013ae6ccc8c..000000000000 --- a/fs/afs/transport.h +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* transport.h: AFS transport management | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_TRANSPORT_H | ||
13 | #define _LINUX_AFS_TRANSPORT_H | ||
14 | |||
15 | #include "types.h" | ||
16 | #include <rxrpc/transport.h> | ||
17 | |||
18 | /* the cache manager transport endpoint */ | ||
19 | extern struct rxrpc_transport *afs_transport; | ||
20 | |||
21 | #endif /* _LINUX_AFS_TRANSPORT_H */ | ||
diff --git a/fs/afs/types.h b/fs/afs/types.h deleted file mode 100644 index b1a2367c7587..000000000000 --- a/fs/afs/types.h +++ /dev/null | |||
@@ -1,125 +0,0 @@ | |||
1 | /* types.h: AFS types | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_TYPES_H | ||
13 | #define _LINUX_AFS_TYPES_H | ||
14 | |||
15 | #ifdef __KERNEL__ | ||
16 | #include <rxrpc/types.h> | ||
17 | #endif /* __KERNEL__ */ | ||
18 | |||
19 | typedef unsigned afs_volid_t; | ||
20 | typedef unsigned afs_vnodeid_t; | ||
21 | typedef unsigned long long afs_dataversion_t; | ||
22 | |||
23 | typedef enum { | ||
24 | AFSVL_RWVOL, /* read/write volume */ | ||
25 | AFSVL_ROVOL, /* read-only volume */ | ||
26 | AFSVL_BACKVOL, /* backup volume */ | ||
27 | } __attribute__((packed)) afs_voltype_t; | ||
28 | |||
29 | typedef enum { | ||
30 | AFS_FTYPE_INVALID = 0, | ||
31 | AFS_FTYPE_FILE = 1, | ||
32 | AFS_FTYPE_DIR = 2, | ||
33 | AFS_FTYPE_SYMLINK = 3, | ||
34 | } afs_file_type_t; | ||
35 | |||
36 | #ifdef __KERNEL__ | ||
37 | |||
38 | struct afs_cell; | ||
39 | struct afs_vnode; | ||
40 | |||
41 | /*****************************************************************************/ | ||
42 | /* | ||
43 | * AFS file identifier | ||
44 | */ | ||
45 | struct afs_fid | ||
46 | { | ||
47 | afs_volid_t vid; /* volume ID */ | ||
48 | afs_vnodeid_t vnode; /* file index within volume */ | ||
49 | unsigned unique; /* unique ID number (file index version) */ | ||
50 | }; | ||
51 | |||
52 | /*****************************************************************************/ | ||
53 | /* | ||
54 | * AFS callback notification | ||
55 | */ | ||
56 | typedef enum { | ||
57 | AFSCM_CB_UNTYPED = 0, /* no type set on CB break */ | ||
58 | AFSCM_CB_EXCLUSIVE = 1, /* CB exclusive to CM [not implemented] */ | ||
59 | AFSCM_CB_SHARED = 2, /* CB shared by other CM's */ | ||
60 | AFSCM_CB_DROPPED = 3, /* CB promise cancelled by file server */ | ||
61 | } afs_callback_type_t; | ||
62 | |||
63 | struct afs_callback | ||
64 | { | ||
65 | struct afs_server *server; /* server that made the promise */ | ||
66 | struct afs_fid fid; /* file identifier */ | ||
67 | unsigned version; /* callback version */ | ||
68 | unsigned expiry; /* time at which expires */ | ||
69 | afs_callback_type_t type; /* type of callback */ | ||
70 | }; | ||
71 | |||
72 | #define AFSCBMAX 50 | ||
73 | |||
74 | /*****************************************************************************/ | ||
75 | /* | ||
76 | * AFS volume information | ||
77 | */ | ||
78 | struct afs_volume_info | ||
79 | { | ||
80 | afs_volid_t vid; /* volume ID */ | ||
81 | afs_voltype_t type; /* type of this volume */ | ||
82 | afs_volid_t type_vids[5]; /* volume ID's for possible types for this vol */ | ||
83 | |||
84 | /* list of fileservers serving this volume */ | ||
85 | size_t nservers; /* number of entries used in servers[] */ | ||
86 | struct { | ||
87 | struct in_addr addr; /* fileserver address */ | ||
88 | } servers[8]; | ||
89 | }; | ||
90 | |||
91 | /*****************************************************************************/ | ||
92 | /* | ||
93 | * AFS file status information | ||
94 | */ | ||
95 | struct afs_file_status | ||
96 | { | ||
97 | unsigned if_version; /* interface version */ | ||
98 | #define AFS_FSTATUS_VERSION 1 | ||
99 | |||
100 | afs_file_type_t type; /* file type */ | ||
101 | unsigned nlink; /* link count */ | ||
102 | size_t size; /* file size */ | ||
103 | afs_dataversion_t version; /* current data version */ | ||
104 | unsigned author; /* author ID */ | ||
105 | unsigned owner; /* owner ID */ | ||
106 | unsigned caller_access; /* access rights for authenticated caller */ | ||
107 | unsigned anon_access; /* access rights for unauthenticated caller */ | ||
108 | umode_t mode; /* UNIX mode */ | ||
109 | struct afs_fid parent; /* parent file ID */ | ||
110 | time_t mtime_client; /* last time client changed data */ | ||
111 | time_t mtime_server; /* last time server changed data */ | ||
112 | }; | ||
113 | |||
114 | /*****************************************************************************/ | ||
115 | /* | ||
116 | * AFS volume synchronisation information | ||
117 | */ | ||
118 | struct afs_volsync | ||
119 | { | ||
120 | time_t creation; /* volume creation time */ | ||
121 | }; | ||
122 | |||
123 | #endif /* __KERNEL__ */ | ||
124 | |||
125 | #endif /* _LINUX_AFS_TYPES_H */ | ||
diff --git a/fs/afs/use-rtnetlink.c b/fs/afs/use-rtnetlink.c new file mode 100644 index 000000000000..82f0daa28970 --- /dev/null +++ b/fs/afs/use-rtnetlink.c | |||
@@ -0,0 +1,473 @@ | |||
1 | /* RTNETLINK client | ||
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 | #include <linux/netlink.h> | ||
12 | #include <linux/rtnetlink.h> | ||
13 | #include <linux/if_addr.h> | ||
14 | #include <linux/if_arp.h> | ||
15 | #include <linux/inetdevice.h> | ||
16 | #include <net/netlink.h> | ||
17 | #include "internal.h" | ||
18 | |||
19 | struct afs_rtm_desc { | ||
20 | struct socket *nlsock; | ||
21 | struct afs_interface *bufs; | ||
22 | u8 *mac; | ||
23 | size_t nbufs; | ||
24 | size_t maxbufs; | ||
25 | void *data; | ||
26 | ssize_t datalen; | ||
27 | size_t datamax; | ||
28 | int msg_seq; | ||
29 | unsigned mac_index; | ||
30 | bool wantloopback; | ||
31 | int (*parse)(struct afs_rtm_desc *, struct nlmsghdr *); | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * parse an RTM_GETADDR response | ||
36 | */ | ||
37 | static int afs_rtm_getaddr_parse(struct afs_rtm_desc *desc, | ||
38 | struct nlmsghdr *nlhdr) | ||
39 | { | ||
40 | struct afs_interface *this; | ||
41 | struct ifaddrmsg *ifa; | ||
42 | struct rtattr *rtattr; | ||
43 | const char *name; | ||
44 | size_t len; | ||
45 | |||
46 | ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr); | ||
47 | |||
48 | _enter("{ix=%d,af=%d}", ifa->ifa_index, ifa->ifa_family); | ||
49 | |||
50 | if (ifa->ifa_family != AF_INET) { | ||
51 | _leave(" = 0 [family %d]", ifa->ifa_family); | ||
52 | return 0; | ||
53 | } | ||
54 | if (desc->nbufs >= desc->maxbufs) { | ||
55 | _leave(" = 0 [max %zu/%zu]", desc->nbufs, desc->maxbufs); | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | this = &desc->bufs[desc->nbufs]; | ||
60 | |||
61 | this->index = ifa->ifa_index; | ||
62 | this->netmask.s_addr = inet_make_mask(ifa->ifa_prefixlen); | ||
63 | this->mtu = 0; | ||
64 | |||
65 | rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)); | ||
66 | len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifaddrmsg)); | ||
67 | |||
68 | name = "unknown"; | ||
69 | for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) { | ||
70 | switch (rtattr->rta_type) { | ||
71 | case IFA_ADDRESS: | ||
72 | memcpy(&this->address, RTA_DATA(rtattr), 4); | ||
73 | break; | ||
74 | case IFA_LABEL: | ||
75 | name = RTA_DATA(rtattr); | ||
76 | break; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | _debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT, | ||
81 | name, NIPQUAD(this->address), NIPQUAD(this->netmask)); | ||
82 | |||
83 | desc->nbufs++; | ||
84 | _leave(" = 0"); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * parse an RTM_GETLINK response for MTUs | ||
90 | */ | ||
91 | static int afs_rtm_getlink_if_parse(struct afs_rtm_desc *desc, | ||
92 | struct nlmsghdr *nlhdr) | ||
93 | { | ||
94 | struct afs_interface *this; | ||
95 | struct ifinfomsg *ifi; | ||
96 | struct rtattr *rtattr; | ||
97 | const char *name; | ||
98 | size_t len, loop; | ||
99 | |||
100 | ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr); | ||
101 | |||
102 | _enter("{ix=%d}", ifi->ifi_index); | ||
103 | |||
104 | for (loop = 0; loop < desc->nbufs; loop++) { | ||
105 | this = &desc->bufs[loop]; | ||
106 | if (this->index == ifi->ifi_index) | ||
107 | goto found; | ||
108 | } | ||
109 | |||
110 | _leave(" = 0 [no match]"); | ||
111 | return 0; | ||
112 | |||
113 | found: | ||
114 | if (ifi->ifi_type == ARPHRD_LOOPBACK && !desc->wantloopback) { | ||
115 | _leave(" = 0 [loopback]"); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg)); | ||
120 | len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg)); | ||
121 | |||
122 | name = "unknown"; | ||
123 | for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) { | ||
124 | switch (rtattr->rta_type) { | ||
125 | case IFLA_MTU: | ||
126 | memcpy(&this->mtu, RTA_DATA(rtattr), 4); | ||
127 | break; | ||
128 | case IFLA_IFNAME: | ||
129 | name = RTA_DATA(rtattr); | ||
130 | break; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | _debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u", | ||
135 | name, NIPQUAD(this->address), NIPQUAD(this->netmask), | ||
136 | this->mtu); | ||
137 | |||
138 | _leave(" = 0"); | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * parse an RTM_GETLINK response for the MAC address belonging to the lowest | ||
144 | * non-internal interface | ||
145 | */ | ||
146 | static int afs_rtm_getlink_mac_parse(struct afs_rtm_desc *desc, | ||
147 | struct nlmsghdr *nlhdr) | ||
148 | { | ||
149 | struct ifinfomsg *ifi; | ||
150 | struct rtattr *rtattr; | ||
151 | const char *name; | ||
152 | size_t remain, len; | ||
153 | bool set; | ||
154 | |||
155 | ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr); | ||
156 | |||
157 | _enter("{ix=%d}", ifi->ifi_index); | ||
158 | |||
159 | if (ifi->ifi_index >= desc->mac_index) { | ||
160 | _leave(" = 0 [high]"); | ||
161 | return 0; | ||
162 | } | ||
163 | if (ifi->ifi_type == ARPHRD_LOOPBACK) { | ||
164 | _leave(" = 0 [loopback]"); | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg)); | ||
169 | remain = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg)); | ||
170 | |||
171 | name = "unknown"; | ||
172 | set = false; | ||
173 | for (; RTA_OK(rtattr, remain); rtattr = RTA_NEXT(rtattr, remain)) { | ||
174 | switch (rtattr->rta_type) { | ||
175 | case IFLA_ADDRESS: | ||
176 | len = RTA_PAYLOAD(rtattr); | ||
177 | memcpy(desc->mac, RTA_DATA(rtattr), | ||
178 | min_t(size_t, len, 6)); | ||
179 | desc->mac_index = ifi->ifi_index; | ||
180 | set = true; | ||
181 | break; | ||
182 | case IFLA_IFNAME: | ||
183 | name = RTA_DATA(rtattr); | ||
184 | break; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | if (set) | ||
189 | _debug("%s: %02x:%02x:%02x:%02x:%02x:%02x", | ||
190 | name, | ||
191 | desc->mac[0], desc->mac[1], desc->mac[2], | ||
192 | desc->mac[3], desc->mac[4], desc->mac[5]); | ||
193 | |||
194 | _leave(" = 0"); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * read the rtnetlink response and pass to parsing routine | ||
200 | */ | ||
201 | static int afs_read_rtm(struct afs_rtm_desc *desc) | ||
202 | { | ||
203 | struct nlmsghdr *nlhdr, tmphdr; | ||
204 | struct msghdr msg; | ||
205 | struct kvec iov[1]; | ||
206 | void *data; | ||
207 | bool last = false; | ||
208 | int len, ret, remain; | ||
209 | |||
210 | _enter(""); | ||
211 | |||
212 | do { | ||
213 | /* first of all peek to see how big the packet is */ | ||
214 | memset(&msg, 0, sizeof(msg)); | ||
215 | iov[0].iov_base = &tmphdr; | ||
216 | iov[0].iov_len = sizeof(tmphdr); | ||
217 | len = kernel_recvmsg(desc->nlsock, &msg, iov, 1, | ||
218 | sizeof(tmphdr), MSG_PEEK | MSG_TRUNC); | ||
219 | if (len < 0) { | ||
220 | _leave(" = %d [peek]", len); | ||
221 | return len; | ||
222 | } | ||
223 | if (len == 0) | ||
224 | continue; | ||
225 | if (len < sizeof(tmphdr) || len < NLMSG_PAYLOAD(&tmphdr, 0)) { | ||
226 | _leave(" = -EMSGSIZE"); | ||
227 | return -EMSGSIZE; | ||
228 | } | ||
229 | |||
230 | if (desc->datamax < len) { | ||
231 | kfree(desc->data); | ||
232 | desc->data = NULL; | ||
233 | data = kmalloc(len, GFP_KERNEL); | ||
234 | if (!data) | ||
235 | return -ENOMEM; | ||
236 | desc->data = data; | ||
237 | } | ||
238 | desc->datamax = len; | ||
239 | |||
240 | /* read all the data from this packet */ | ||
241 | iov[0].iov_base = desc->data; | ||
242 | iov[0].iov_len = desc->datamax; | ||
243 | desc->datalen = kernel_recvmsg(desc->nlsock, &msg, iov, 1, | ||
244 | desc->datamax, 0); | ||
245 | if (desc->datalen < 0) { | ||
246 | _leave(" = %ld [recv]", desc->datalen); | ||
247 | return desc->datalen; | ||
248 | } | ||
249 | |||
250 | nlhdr = desc->data; | ||
251 | |||
252 | /* check if the header is valid */ | ||
253 | if (!NLMSG_OK(nlhdr, desc->datalen) || | ||
254 | nlhdr->nlmsg_type == NLMSG_ERROR) { | ||
255 | _leave(" = -EIO"); | ||
256 | return -EIO; | ||
257 | } | ||
258 | |||
259 | /* see if this is the last message */ | ||
260 | if (nlhdr->nlmsg_type == NLMSG_DONE || | ||
261 | !(nlhdr->nlmsg_flags & NLM_F_MULTI)) | ||
262 | last = true; | ||
263 | |||
264 | /* parse the bits we got this time */ | ||
265 | nlmsg_for_each_msg(nlhdr, desc->data, desc->datalen, remain) { | ||
266 | ret = desc->parse(desc, nlhdr); | ||
267 | if (ret < 0) { | ||
268 | _leave(" = %d [parse]", ret); | ||
269 | return ret; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | } while (!last); | ||
274 | |||
275 | _leave(" = 0"); | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * list the interface bound addresses to get the address and netmask | ||
281 | */ | ||
282 | static int afs_rtm_getaddr(struct afs_rtm_desc *desc) | ||
283 | { | ||
284 | struct msghdr msg; | ||
285 | struct kvec iov[1]; | ||
286 | int ret; | ||
287 | |||
288 | struct { | ||
289 | struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO))); | ||
290 | struct ifaddrmsg addr_msg __attribute__((aligned(NLMSG_ALIGNTO))); | ||
291 | } request; | ||
292 | |||
293 | _enter(""); | ||
294 | |||
295 | memset(&request, 0, sizeof(request)); | ||
296 | |||
297 | request.nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); | ||
298 | request.nl_msg.nlmsg_type = RTM_GETADDR; | ||
299 | request.nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; | ||
300 | request.nl_msg.nlmsg_seq = desc->msg_seq++; | ||
301 | request.nl_msg.nlmsg_pid = 0; | ||
302 | |||
303 | memset(&msg, 0, sizeof(msg)); | ||
304 | iov[0].iov_base = &request; | ||
305 | iov[0].iov_len = sizeof(request); | ||
306 | |||
307 | ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len); | ||
308 | _leave(" = %d", ret); | ||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * list the interface link statuses to get the MTUs | ||
314 | */ | ||
315 | static int afs_rtm_getlink(struct afs_rtm_desc *desc) | ||
316 | { | ||
317 | struct msghdr msg; | ||
318 | struct kvec iov[1]; | ||
319 | int ret; | ||
320 | |||
321 | struct { | ||
322 | struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO))); | ||
323 | struct ifinfomsg link_msg __attribute__((aligned(NLMSG_ALIGNTO))); | ||
324 | } request; | ||
325 | |||
326 | _enter(""); | ||
327 | |||
328 | memset(&request, 0, sizeof(request)); | ||
329 | |||
330 | request.nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | ||
331 | request.nl_msg.nlmsg_type = RTM_GETLINK; | ||
332 | request.nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; | ||
333 | request.nl_msg.nlmsg_seq = desc->msg_seq++; | ||
334 | request.nl_msg.nlmsg_pid = 0; | ||
335 | |||
336 | memset(&msg, 0, sizeof(msg)); | ||
337 | iov[0].iov_base = &request; | ||
338 | iov[0].iov_len = sizeof(request); | ||
339 | |||
340 | ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len); | ||
341 | _leave(" = %d", ret); | ||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * cull any interface records for which there isn't an MTU value | ||
347 | */ | ||
348 | static void afs_cull_interfaces(struct afs_rtm_desc *desc) | ||
349 | { | ||
350 | struct afs_interface *bufs = desc->bufs; | ||
351 | size_t nbufs = desc->nbufs; | ||
352 | int loop, point = 0; | ||
353 | |||
354 | _enter("{%zu}", nbufs); | ||
355 | |||
356 | for (loop = 0; loop < nbufs; loop++) { | ||
357 | if (desc->bufs[loop].mtu != 0) { | ||
358 | if (loop != point) { | ||
359 | ASSERTCMP(loop, >, point); | ||
360 | bufs[point] = bufs[loop]; | ||
361 | } | ||
362 | point++; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | desc->nbufs = point; | ||
367 | _leave(" [%zu/%zu]", desc->nbufs, nbufs); | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * get a list of this system's interface IPv4 addresses, netmasks and MTUs | ||
372 | * - returns the number of interface records in the buffer | ||
373 | */ | ||
374 | int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs, | ||
375 | bool wantloopback) | ||
376 | { | ||
377 | struct afs_rtm_desc desc; | ||
378 | int ret, loop; | ||
379 | |||
380 | _enter(""); | ||
381 | |||
382 | memset(&desc, 0, sizeof(desc)); | ||
383 | desc.bufs = bufs; | ||
384 | desc.maxbufs = maxbufs; | ||
385 | desc.wantloopback = wantloopback; | ||
386 | |||
387 | ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, | ||
388 | &desc.nlsock); | ||
389 | if (ret < 0) { | ||
390 | _leave(" = %d [sock]", ret); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | /* issue RTM_GETADDR */ | ||
395 | desc.parse = afs_rtm_getaddr_parse; | ||
396 | ret = afs_rtm_getaddr(&desc); | ||
397 | if (ret < 0) | ||
398 | goto error; | ||
399 | ret = afs_read_rtm(&desc); | ||
400 | if (ret < 0) | ||
401 | goto error; | ||
402 | |||
403 | /* issue RTM_GETLINK */ | ||
404 | desc.parse = afs_rtm_getlink_if_parse; | ||
405 | ret = afs_rtm_getlink(&desc); | ||
406 | if (ret < 0) | ||
407 | goto error; | ||
408 | ret = afs_read_rtm(&desc); | ||
409 | if (ret < 0) | ||
410 | goto error; | ||
411 | |||
412 | afs_cull_interfaces(&desc); | ||
413 | ret = desc.nbufs; | ||
414 | |||
415 | for (loop = 0; loop < ret; loop++) | ||
416 | _debug("[%d] "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u", | ||
417 | bufs[loop].index, | ||
418 | NIPQUAD(bufs[loop].address), | ||
419 | NIPQUAD(bufs[loop].netmask), | ||
420 | bufs[loop].mtu); | ||
421 | |||
422 | error: | ||
423 | kfree(desc.data); | ||
424 | sock_release(desc.nlsock); | ||
425 | _leave(" = %d", ret); | ||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * get a MAC address from a random ethernet interface that has a real one | ||
431 | * - the buffer should be 6 bytes in size | ||
432 | */ | ||
433 | int afs_get_MAC_address(u8 mac[6]) | ||
434 | { | ||
435 | struct afs_rtm_desc desc; | ||
436 | int ret; | ||
437 | |||
438 | _enter(""); | ||
439 | |||
440 | memset(&desc, 0, sizeof(desc)); | ||
441 | desc.mac = mac; | ||
442 | desc.mac_index = UINT_MAX; | ||
443 | |||
444 | ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, | ||
445 | &desc.nlsock); | ||
446 | if (ret < 0) { | ||
447 | _leave(" = %d [sock]", ret); | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | /* issue RTM_GETLINK */ | ||
452 | desc.parse = afs_rtm_getlink_mac_parse; | ||
453 | ret = afs_rtm_getlink(&desc); | ||
454 | if (ret < 0) | ||
455 | goto error; | ||
456 | ret = afs_read_rtm(&desc); | ||
457 | if (ret < 0) | ||
458 | goto error; | ||
459 | |||
460 | if (desc.mac_index < UINT_MAX) { | ||
461 | /* got a MAC address */ | ||
462 | _debug("[%d] %02x:%02x:%02x:%02x:%02x:%02x", | ||
463 | desc.mac_index, | ||
464 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | ||
465 | } else { | ||
466 | ret = -ENONET; | ||
467 | } | ||
468 | |||
469 | error: | ||
470 | sock_release(desc.nlsock); | ||
471 | _leave(" = %d", ret); | ||
472 | return ret; | ||
473 | } | ||
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c index 7b0e3192ee39..36c1306e09e0 100644 --- a/fs/afs/vlclient.c +++ b/fs/afs/vlclient.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* vlclient.c: AFS Volume Location Service client | 1 | /* AFS Volume Location Service client |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -11,247 +11,76 @@ | |||
11 | 11 | ||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <rxrpc/rxrpc.h> | ||
15 | #include <rxrpc/transport.h> | ||
16 | #include <rxrpc/connection.h> | ||
17 | #include <rxrpc/call.h> | ||
18 | #include "server.h" | ||
19 | #include "volume.h" | ||
20 | #include "vlclient.h" | ||
21 | #include "kafsasyncd.h" | ||
22 | #include "kafstimod.h" | ||
23 | #include "errors.h" | ||
24 | #include "internal.h" | 14 | #include "internal.h" |
25 | 15 | ||
26 | #define VLGETENTRYBYID 503 /* AFS Get Cache Entry By ID operation ID */ | ||
27 | #define VLGETENTRYBYNAME 504 /* AFS Get Cache Entry By Name operation ID */ | ||
28 | #define VLPROBE 514 /* AFS Probe Volume Location Service operation ID */ | ||
29 | |||
30 | static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call); | ||
31 | static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call); | ||
32 | |||
33 | /*****************************************************************************/ | ||
34 | /* | 16 | /* |
35 | * map afs VL abort codes to/from Linux error codes | 17 | * map volume locator abort codes to error codes |
36 | * - called with call->lock held | ||
37 | */ | 18 | */ |
38 | static void afs_rxvl_aemap(struct rxrpc_call *call) | 19 | static int afs_vl_abort_to_error(u32 abort_code) |
39 | { | 20 | { |
40 | int err; | 21 | _enter("%u", abort_code); |
41 | 22 | ||
42 | _enter("{%u,%u,%d}", | 23 | switch (abort_code) { |
43 | call->app_err_state, call->app_abort_code, call->app_errno); | 24 | case AFSVL_IDEXIST: return -EEXIST; |
44 | 25 | case AFSVL_IO: return -EREMOTEIO; | |
45 | switch (call->app_err_state) { | 26 | case AFSVL_NAMEEXIST: return -EEXIST; |
46 | case RXRPC_ESTATE_LOCAL_ABORT: | 27 | case AFSVL_CREATEFAIL: return -EREMOTEIO; |
47 | call->app_abort_code = -call->app_errno; | 28 | case AFSVL_NOENT: return -ENOMEDIUM; |
48 | return; | 29 | case AFSVL_EMPTY: return -ENOMEDIUM; |
49 | 30 | case AFSVL_ENTDELETED: return -ENOMEDIUM; | |
50 | case RXRPC_ESTATE_PEER_ABORT: | 31 | case AFSVL_BADNAME: return -EINVAL; |
51 | switch (call->app_abort_code) { | 32 | case AFSVL_BADINDEX: return -EINVAL; |
52 | case AFSVL_IDEXIST: err = -EEXIST; break; | 33 | case AFSVL_BADVOLTYPE: return -EINVAL; |
53 | case AFSVL_IO: err = -EREMOTEIO; break; | 34 | case AFSVL_BADSERVER: return -EINVAL; |
54 | case AFSVL_NAMEEXIST: err = -EEXIST; break; | 35 | case AFSVL_BADPARTITION: return -EINVAL; |
55 | case AFSVL_CREATEFAIL: err = -EREMOTEIO; break; | 36 | case AFSVL_REPSFULL: return -EFBIG; |
56 | case AFSVL_NOENT: err = -ENOMEDIUM; break; | 37 | case AFSVL_NOREPSERVER: return -ENOENT; |
57 | case AFSVL_EMPTY: err = -ENOMEDIUM; break; | 38 | case AFSVL_DUPREPSERVER: return -EEXIST; |
58 | case AFSVL_ENTDELETED: err = -ENOMEDIUM; break; | 39 | case AFSVL_RWNOTFOUND: return -ENOENT; |
59 | case AFSVL_BADNAME: err = -EINVAL; break; | 40 | case AFSVL_BADREFCOUNT: return -EINVAL; |
60 | case AFSVL_BADINDEX: err = -EINVAL; break; | 41 | case AFSVL_SIZEEXCEEDED: return -EINVAL; |
61 | case AFSVL_BADVOLTYPE: err = -EINVAL; break; | 42 | case AFSVL_BADENTRY: return -EINVAL; |
62 | case AFSVL_BADSERVER: err = -EINVAL; break; | 43 | case AFSVL_BADVOLIDBUMP: return -EINVAL; |
63 | case AFSVL_BADPARTITION: err = -EINVAL; break; | 44 | case AFSVL_IDALREADYHASHED: return -EINVAL; |
64 | case AFSVL_REPSFULL: err = -EFBIG; break; | 45 | case AFSVL_ENTRYLOCKED: return -EBUSY; |
65 | case AFSVL_NOREPSERVER: err = -ENOENT; break; | 46 | case AFSVL_BADVOLOPER: return -EBADRQC; |
66 | case AFSVL_DUPREPSERVER: err = -EEXIST; break; | 47 | case AFSVL_BADRELLOCKTYPE: return -EINVAL; |
67 | case AFSVL_RWNOTFOUND: err = -ENOENT; break; | 48 | case AFSVL_RERELEASE: return -EREMOTEIO; |
68 | case AFSVL_BADREFCOUNT: err = -EINVAL; break; | 49 | case AFSVL_BADSERVERFLAG: return -EINVAL; |
69 | case AFSVL_SIZEEXCEEDED: err = -EINVAL; break; | 50 | case AFSVL_PERM: return -EACCES; |
70 | case AFSVL_BADENTRY: err = -EINVAL; break; | 51 | case AFSVL_NOMEM: return -EREMOTEIO; |
71 | case AFSVL_BADVOLIDBUMP: err = -EINVAL; break; | ||
72 | case AFSVL_IDALREADYHASHED: err = -EINVAL; break; | ||
73 | case AFSVL_ENTRYLOCKED: err = -EBUSY; break; | ||
74 | case AFSVL_BADVOLOPER: err = -EBADRQC; break; | ||
75 | case AFSVL_BADRELLOCKTYPE: err = -EINVAL; break; | ||
76 | case AFSVL_RERELEASE: err = -EREMOTEIO; break; | ||
77 | case AFSVL_BADSERVERFLAG: err = -EINVAL; break; | ||
78 | case AFSVL_PERM: err = -EACCES; break; | ||
79 | case AFSVL_NOMEM: err = -EREMOTEIO; break; | ||
80 | default: | ||
81 | err = afs_abort_to_error(call->app_abort_code); | ||
82 | break; | ||
83 | } | ||
84 | call->app_errno = err; | ||
85 | return; | ||
86 | |||
87 | default: | 52 | default: |
88 | return; | 53 | return afs_abort_to_error(abort_code); |
89 | } | 54 | } |
90 | } /* end afs_rxvl_aemap() */ | 55 | } |
91 | 56 | ||
92 | #if 0 | ||
93 | /*****************************************************************************/ | ||
94 | /* | 57 | /* |
95 | * probe a volume location server to see if it is still alive -- unused | 58 | * deliver reply data to a VL.GetEntryByXXX call |
96 | */ | 59 | */ |
97 | static int afs_rxvl_probe(struct afs_server *server, int alloc_flags) | 60 | static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call, |
61 | struct sk_buff *skb, bool last) | ||
98 | { | 62 | { |
99 | struct rxrpc_connection *conn; | 63 | struct afs_cache_vlocation *entry; |
100 | struct rxrpc_call *call; | 64 | __be32 *bp; |
101 | struct kvec piov[1]; | 65 | u32 tmp; |
102 | size_t sent; | 66 | int loop; |
103 | int ret; | ||
104 | __be32 param[1]; | ||
105 | |||
106 | DECLARE_WAITQUEUE(myself, current); | ||
107 | |||
108 | /* get hold of the vlserver connection */ | ||
109 | ret = afs_server_get_vlconn(server, &conn); | ||
110 | if (ret < 0) | ||
111 | goto out; | ||
112 | |||
113 | /* create a call through that connection */ | ||
114 | ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call); | ||
115 | if (ret < 0) { | ||
116 | printk("kAFS: Unable to create call: %d\n", ret); | ||
117 | goto out_put_conn; | ||
118 | } | ||
119 | call->app_opcode = VLPROBE; | ||
120 | |||
121 | /* we want to get event notifications from the call */ | ||
122 | add_wait_queue(&call->waitq, &myself); | ||
123 | |||
124 | /* marshall the parameters */ | ||
125 | param[0] = htonl(VLPROBE); | ||
126 | piov[0].iov_len = sizeof(param); | ||
127 | piov[0].iov_base = param; | ||
128 | |||
129 | /* send the parameters to the server */ | ||
130 | ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, | ||
131 | alloc_flags, 0, &sent); | ||
132 | if (ret < 0) | ||
133 | goto abort; | ||
134 | |||
135 | /* wait for the reply to completely arrive */ | ||
136 | for (;;) { | ||
137 | set_current_state(TASK_INTERRUPTIBLE); | ||
138 | if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY || | ||
139 | signal_pending(current)) | ||
140 | break; | ||
141 | schedule(); | ||
142 | } | ||
143 | set_current_state(TASK_RUNNING); | ||
144 | |||
145 | ret = -EINTR; | ||
146 | if (signal_pending(current)) | ||
147 | goto abort; | ||
148 | |||
149 | switch (call->app_call_state) { | ||
150 | case RXRPC_CSTATE_ERROR: | ||
151 | ret = call->app_errno; | ||
152 | goto out_unwait; | ||
153 | |||
154 | case RXRPC_CSTATE_CLNT_GOT_REPLY: | ||
155 | ret = 0; | ||
156 | goto out_unwait; | ||
157 | |||
158 | default: | ||
159 | BUG(); | ||
160 | } | ||
161 | |||
162 | abort: | ||
163 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
164 | rxrpc_call_abort(call, ret); | ||
165 | schedule(); | ||
166 | |||
167 | out_unwait: | ||
168 | set_current_state(TASK_RUNNING); | ||
169 | remove_wait_queue(&call->waitq, &myself); | ||
170 | rxrpc_put_call(call); | ||
171 | out_put_conn: | ||
172 | rxrpc_put_connection(conn); | ||
173 | out: | ||
174 | return ret; | ||
175 | 67 | ||
176 | } /* end afs_rxvl_probe() */ | 68 | _enter(",,%u", last); |
177 | #endif | ||
178 | 69 | ||
179 | /*****************************************************************************/ | 70 | afs_transfer_reply(call, skb); |
180 | /* | 71 | if (!last) |
181 | * look up a volume location database entry by name | 72 | return 0; |
182 | */ | ||
183 | int afs_rxvl_get_entry_by_name(struct afs_server *server, | ||
184 | const char *volname, | ||
185 | unsigned volnamesz, | ||
186 | struct afs_cache_vlocation *entry) | ||
187 | { | ||
188 | DECLARE_WAITQUEUE(myself, current); | ||
189 | |||
190 | struct rxrpc_connection *conn; | ||
191 | struct rxrpc_call *call; | ||
192 | struct kvec piov[3]; | ||
193 | unsigned tmp; | ||
194 | size_t sent; | ||
195 | int ret, loop; | ||
196 | __be32 *bp, param[2], zero; | ||
197 | |||
198 | _enter(",%*.*s,%u,", volnamesz, volnamesz, volname, volnamesz); | ||
199 | |||
200 | memset(entry, 0, sizeof(*entry)); | ||
201 | |||
202 | /* get hold of the vlserver connection */ | ||
203 | ret = afs_server_get_vlconn(server, &conn); | ||
204 | if (ret < 0) | ||
205 | goto out; | ||
206 | |||
207 | /* create a call through that connection */ | ||
208 | ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call); | ||
209 | if (ret < 0) { | ||
210 | printk("kAFS: Unable to create call: %d\n", ret); | ||
211 | goto out_put_conn; | ||
212 | } | ||
213 | call->app_opcode = VLGETENTRYBYNAME; | ||
214 | 73 | ||
215 | /* we want to get event notifications from the call */ | 74 | if (call->reply_size != call->reply_max) |
216 | add_wait_queue(&call->waitq, &myself); | 75 | return -EBADMSG; |
217 | 76 | ||
218 | /* marshall the parameters */ | 77 | /* unmarshall the reply once we've received all of it */ |
219 | piov[1].iov_len = volnamesz; | 78 | entry = call->reply; |
220 | piov[1].iov_base = (char *) volname; | 79 | bp = call->buffer; |
221 | |||
222 | zero = 0; | ||
223 | piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3; | ||
224 | piov[2].iov_base = &zero; | ||
225 | |||
226 | param[0] = htonl(VLGETENTRYBYNAME); | ||
227 | param[1] = htonl(piov[1].iov_len); | ||
228 | |||
229 | piov[0].iov_len = sizeof(param); | ||
230 | piov[0].iov_base = param; | ||
231 | |||
232 | /* send the parameters to the server */ | ||
233 | ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS, | ||
234 | 0, &sent); | ||
235 | if (ret < 0) | ||
236 | goto abort; | ||
237 | |||
238 | /* wait for the reply to completely arrive */ | ||
239 | bp = rxrpc_call_alloc_scratch(call, 384); | ||
240 | |||
241 | ret = rxrpc_call_read_data(call, bp, 384, | ||
242 | RXRPC_CALL_READ_BLOCK | | ||
243 | RXRPC_CALL_READ_ALL); | ||
244 | if (ret < 0) { | ||
245 | if (ret == -ECONNABORTED) { | ||
246 | ret = call->app_errno; | ||
247 | goto out_unwait; | ||
248 | } | ||
249 | goto abort; | ||
250 | } | ||
251 | 80 | ||
252 | /* unmarshall the reply */ | ||
253 | for (loop = 0; loop < 64; loop++) | 81 | for (loop = 0; loop < 64; loop++) |
254 | entry->name[loop] = ntohl(*bp++); | 82 | entry->name[loop] = ntohl(*bp++); |
83 | entry->name[loop] = 0; | ||
255 | bp++; /* final NUL */ | 84 | bp++; /* final NUL */ |
256 | 85 | ||
257 | bp++; /* type */ | 86 | bp++; /* type */ |
@@ -264,6 +93,7 @@ int afs_rxvl_get_entry_by_name(struct afs_server *server, | |||
264 | 93 | ||
265 | for (loop = 0; loop < 8; loop++) { | 94 | for (loop = 0; loop < 8; loop++) { |
266 | tmp = ntohl(*bp++); | 95 | tmp = ntohl(*bp++); |
96 | entry->srvtmask[loop] = 0; | ||
267 | if (tmp & AFS_VLSF_RWVOL) | 97 | if (tmp & AFS_VLSF_RWVOL) |
268 | entry->srvtmask[loop] |= AFS_VOL_VTM_RW; | 98 | entry->srvtmask[loop] |= AFS_VOL_VTM_RW; |
269 | if (tmp & AFS_VLSF_ROVOL) | 99 | if (tmp & AFS_VLSF_ROVOL) |
@@ -279,417 +109,110 @@ int afs_rxvl_get_entry_by_name(struct afs_server *server, | |||
279 | bp++; /* clone ID */ | 109 | bp++; /* clone ID */ |
280 | 110 | ||
281 | tmp = ntohl(*bp++); /* flags */ | 111 | tmp = ntohl(*bp++); /* flags */ |
112 | entry->vidmask = 0; | ||
282 | if (tmp & AFS_VLF_RWEXISTS) | 113 | if (tmp & AFS_VLF_RWEXISTS) |
283 | entry->vidmask |= AFS_VOL_VTM_RW; | 114 | entry->vidmask |= AFS_VOL_VTM_RW; |
284 | if (tmp & AFS_VLF_ROEXISTS) | 115 | if (tmp & AFS_VLF_ROEXISTS) |
285 | entry->vidmask |= AFS_VOL_VTM_RO; | 116 | entry->vidmask |= AFS_VOL_VTM_RO; |
286 | if (tmp & AFS_VLF_BACKEXISTS) | 117 | if (tmp & AFS_VLF_BACKEXISTS) |
287 | entry->vidmask |= AFS_VOL_VTM_BAK; | 118 | entry->vidmask |= AFS_VOL_VTM_BAK; |
288 | |||
289 | ret = -ENOMEDIUM; | ||
290 | if (!entry->vidmask) | 119 | if (!entry->vidmask) |
291 | goto abort; | 120 | return -EBADMSG; |
292 | |||
293 | /* success */ | ||
294 | entry->rtime = get_seconds(); | ||
295 | ret = 0; | ||
296 | |||
297 | out_unwait: | ||
298 | set_current_state(TASK_RUNNING); | ||
299 | remove_wait_queue(&call->waitq, &myself); | ||
300 | rxrpc_put_call(call); | ||
301 | out_put_conn: | ||
302 | rxrpc_put_connection(conn); | ||
303 | out: | ||
304 | _leave(" = %d", ret); | ||
305 | return ret; | ||
306 | |||
307 | abort: | ||
308 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
309 | rxrpc_call_abort(call, ret); | ||
310 | schedule(); | ||
311 | goto out_unwait; | ||
312 | } /* end afs_rxvl_get_entry_by_name() */ | ||
313 | |||
314 | /*****************************************************************************/ | ||
315 | /* | ||
316 | * look up a volume location database entry by ID | ||
317 | */ | ||
318 | int afs_rxvl_get_entry_by_id(struct afs_server *server, | ||
319 | afs_volid_t volid, | ||
320 | afs_voltype_t voltype, | ||
321 | struct afs_cache_vlocation *entry) | ||
322 | { | ||
323 | DECLARE_WAITQUEUE(myself, current); | ||
324 | |||
325 | struct rxrpc_connection *conn; | ||
326 | struct rxrpc_call *call; | ||
327 | struct kvec piov[1]; | ||
328 | unsigned tmp; | ||
329 | size_t sent; | ||
330 | int ret, loop; | ||
331 | __be32 *bp, param[3]; | ||
332 | |||
333 | _enter(",%x,%d,", volid, voltype); | ||
334 | |||
335 | memset(entry, 0, sizeof(*entry)); | ||
336 | |||
337 | /* get hold of the vlserver connection */ | ||
338 | ret = afs_server_get_vlconn(server, &conn); | ||
339 | if (ret < 0) | ||
340 | goto out; | ||
341 | |||
342 | /* create a call through that connection */ | ||
343 | ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call); | ||
344 | if (ret < 0) { | ||
345 | printk("kAFS: Unable to create call: %d\n", ret); | ||
346 | goto out_put_conn; | ||
347 | } | ||
348 | call->app_opcode = VLGETENTRYBYID; | ||
349 | |||
350 | /* we want to get event notifications from the call */ | ||
351 | add_wait_queue(&call->waitq, &myself); | ||
352 | |||
353 | /* marshall the parameters */ | ||
354 | param[0] = htonl(VLGETENTRYBYID); | ||
355 | param[1] = htonl(volid); | ||
356 | param[2] = htonl(voltype); | ||
357 | |||
358 | piov[0].iov_len = sizeof(param); | ||
359 | piov[0].iov_base = param; | ||
360 | |||
361 | /* send the parameters to the server */ | ||
362 | ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS, | ||
363 | 0, &sent); | ||
364 | if (ret < 0) | ||
365 | goto abort; | ||
366 | |||
367 | /* wait for the reply to completely arrive */ | ||
368 | bp = rxrpc_call_alloc_scratch(call, 384); | ||
369 | |||
370 | ret = rxrpc_call_read_data(call, bp, 384, | ||
371 | RXRPC_CALL_READ_BLOCK | | ||
372 | RXRPC_CALL_READ_ALL); | ||
373 | if (ret < 0) { | ||
374 | if (ret == -ECONNABORTED) { | ||
375 | ret = call->app_errno; | ||
376 | goto out_unwait; | ||
377 | } | ||
378 | goto abort; | ||
379 | } | ||
380 | |||
381 | /* unmarshall the reply */ | ||
382 | for (loop = 0; loop < 64; loop++) | ||
383 | entry->name[loop] = ntohl(*bp++); | ||
384 | bp++; /* final NUL */ | ||
385 | 121 | ||
386 | bp++; /* type */ | 122 | _leave(" = 0 [done]"); |
387 | entry->nservers = ntohl(*bp++); | 123 | return 0; |
388 | 124 | } | |
389 | for (loop = 0; loop < 8; loop++) | ||
390 | entry->servers[loop].s_addr = *bp++; | ||
391 | |||
392 | bp += 8; /* partition IDs */ | ||
393 | 125 | ||
394 | for (loop = 0; loop < 8; loop++) { | ||
395 | tmp = ntohl(*bp++); | ||
396 | if (tmp & AFS_VLSF_RWVOL) | ||
397 | entry->srvtmask[loop] |= AFS_VOL_VTM_RW; | ||
398 | if (tmp & AFS_VLSF_ROVOL) | ||
399 | entry->srvtmask[loop] |= AFS_VOL_VTM_RO; | ||
400 | if (tmp & AFS_VLSF_BACKVOL) | ||
401 | entry->srvtmask[loop] |= AFS_VOL_VTM_BAK; | ||
402 | } | ||
403 | |||
404 | entry->vid[0] = ntohl(*bp++); | ||
405 | entry->vid[1] = ntohl(*bp++); | ||
406 | entry->vid[2] = ntohl(*bp++); | ||
407 | |||
408 | bp++; /* clone ID */ | ||
409 | |||
410 | tmp = ntohl(*bp++); /* flags */ | ||
411 | if (tmp & AFS_VLF_RWEXISTS) | ||
412 | entry->vidmask |= AFS_VOL_VTM_RW; | ||
413 | if (tmp & AFS_VLF_ROEXISTS) | ||
414 | entry->vidmask |= AFS_VOL_VTM_RO; | ||
415 | if (tmp & AFS_VLF_BACKEXISTS) | ||
416 | entry->vidmask |= AFS_VOL_VTM_BAK; | ||
417 | |||
418 | ret = -ENOMEDIUM; | ||
419 | if (!entry->vidmask) | ||
420 | goto abort; | ||
421 | |||
422 | #if 0 /* TODO: remove */ | ||
423 | entry->nservers = 3; | ||
424 | entry->servers[0].s_addr = htonl(0xac101249); | ||
425 | entry->servers[1].s_addr = htonl(0xac101243); | ||
426 | entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/); | ||
427 | |||
428 | entry->srvtmask[0] = AFS_VOL_VTM_RO; | ||
429 | entry->srvtmask[1] = AFS_VOL_VTM_RO; | ||
430 | entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW; | ||
431 | #endif | ||
432 | |||
433 | /* success */ | ||
434 | entry->rtime = get_seconds(); | ||
435 | ret = 0; | ||
436 | |||
437 | out_unwait: | ||
438 | set_current_state(TASK_RUNNING); | ||
439 | remove_wait_queue(&call->waitq, &myself); | ||
440 | rxrpc_put_call(call); | ||
441 | out_put_conn: | ||
442 | rxrpc_put_connection(conn); | ||
443 | out: | ||
444 | _leave(" = %d", ret); | ||
445 | return ret; | ||
446 | |||
447 | abort: | ||
448 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
449 | rxrpc_call_abort(call, ret); | ||
450 | schedule(); | ||
451 | goto out_unwait; | ||
452 | } /* end afs_rxvl_get_entry_by_id() */ | ||
453 | |||
454 | /*****************************************************************************/ | ||
455 | /* | 126 | /* |
456 | * look up a volume location database entry by ID asynchronously | 127 | * VL.GetEntryByName operation type |
457 | */ | 128 | */ |
458 | int afs_rxvl_get_entry_by_id_async(struct afs_async_op *op, | 129 | static const struct afs_call_type afs_RXVLGetEntryByName = { |
459 | afs_volid_t volid, | 130 | .name = "VL.GetEntryByName", |
460 | afs_voltype_t voltype) | 131 | .deliver = afs_deliver_vl_get_entry_by_xxx, |
461 | { | 132 | .abort_to_error = afs_vl_abort_to_error, |
462 | struct rxrpc_connection *conn; | 133 | .destructor = afs_flat_call_destructor, |
463 | struct rxrpc_call *call; | 134 | }; |
464 | struct kvec piov[1]; | ||
465 | size_t sent; | ||
466 | int ret; | ||
467 | __be32 param[3]; | ||
468 | |||
469 | _enter(",%x,%d,", volid, voltype); | ||
470 | |||
471 | /* get hold of the vlserver connection */ | ||
472 | ret = afs_server_get_vlconn(op->server, &conn); | ||
473 | if (ret < 0) { | ||
474 | _leave(" = %d", ret); | ||
475 | return ret; | ||
476 | } | ||
477 | |||
478 | /* create a call through that connection */ | ||
479 | ret = rxrpc_create_call(conn, | ||
480 | afs_rxvl_get_entry_by_id_attn, | ||
481 | afs_rxvl_get_entry_by_id_error, | ||
482 | afs_rxvl_aemap, | ||
483 | &op->call); | ||
484 | rxrpc_put_connection(conn); | ||
485 | |||
486 | if (ret < 0) { | ||
487 | printk("kAFS: Unable to create call: %d\n", ret); | ||
488 | _leave(" = %d", ret); | ||
489 | return ret; | ||
490 | } | ||
491 | 135 | ||
492 | op->call->app_opcode = VLGETENTRYBYID; | 136 | /* |
493 | op->call->app_user = op; | 137 | * VL.GetEntryById operation type |
494 | 138 | */ | |
495 | call = op->call; | 139 | static const struct afs_call_type afs_RXVLGetEntryById = { |
496 | rxrpc_get_call(call); | 140 | .name = "VL.GetEntryById", |
497 | 141 | .deliver = afs_deliver_vl_get_entry_by_xxx, | |
498 | /* send event notifications from the call to kafsasyncd */ | 142 | .abort_to_error = afs_vl_abort_to_error, |
499 | afs_kafsasyncd_begin_op(op); | 143 | .destructor = afs_flat_call_destructor, |
500 | 144 | }; | |
501 | /* marshall the parameters */ | ||
502 | param[0] = htonl(VLGETENTRYBYID); | ||
503 | param[1] = htonl(volid); | ||
504 | param[2] = htonl(voltype); | ||
505 | |||
506 | piov[0].iov_len = sizeof(param); | ||
507 | piov[0].iov_base = param; | ||
508 | |||
509 | /* allocate result read buffer in scratch space */ | ||
510 | call->app_scr_ptr = rxrpc_call_alloc_scratch(op->call, 384); | ||
511 | |||
512 | /* send the parameters to the server */ | ||
513 | ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS, | ||
514 | 0, &sent); | ||
515 | if (ret < 0) { | ||
516 | rxrpc_call_abort(call, ret); /* handle from kafsasyncd */ | ||
517 | ret = 0; | ||
518 | goto out; | ||
519 | } | ||
520 | |||
521 | /* wait for the reply to completely arrive */ | ||
522 | ret = rxrpc_call_read_data(call, call->app_scr_ptr, 384, 0); | ||
523 | switch (ret) { | ||
524 | case 0: | ||
525 | case -EAGAIN: | ||
526 | case -ECONNABORTED: | ||
527 | ret = 0; | ||
528 | break; /* all handled by kafsasyncd */ | ||
529 | |||
530 | default: | ||
531 | rxrpc_call_abort(call, ret); /* make kafsasyncd handle it */ | ||
532 | ret = 0; | ||
533 | break; | ||
534 | } | ||
535 | |||
536 | out: | ||
537 | rxrpc_put_call(call); | ||
538 | _leave(" = %d", ret); | ||
539 | return ret; | ||
540 | |||
541 | } /* end afs_rxvl_get_entry_by_id_async() */ | ||
542 | 145 | ||
543 | /*****************************************************************************/ | ||
544 | /* | 146 | /* |
545 | * attend to the asynchronous get VLDB entry by ID | 147 | * dispatch a get volume entry by name operation |
546 | */ | 148 | */ |
547 | int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *op, | 149 | int afs_vl_get_entry_by_name(struct in_addr *addr, |
548 | struct afs_cache_vlocation *entry) | 150 | struct key *key, |
151 | const char *volname, | ||
152 | struct afs_cache_vlocation *entry, | ||
153 | const struct afs_wait_mode *wait_mode) | ||
549 | { | 154 | { |
155 | struct afs_call *call; | ||
156 | size_t volnamesz, reqsz, padsz; | ||
550 | __be32 *bp; | 157 | __be32 *bp; |
551 | __u32 tmp; | ||
552 | int loop, ret; | ||
553 | |||
554 | _enter("{op=%p cst=%u}", op, op->call->app_call_state); | ||
555 | |||
556 | memset(entry, 0, sizeof(*entry)); | ||
557 | |||
558 | if (op->call->app_call_state == RXRPC_CSTATE_COMPLETE) { | ||
559 | /* operation finished */ | ||
560 | afs_kafsasyncd_terminate_op(op); | ||
561 | |||
562 | bp = op->call->app_scr_ptr; | ||
563 | |||
564 | /* unmarshall the reply */ | ||
565 | for (loop = 0; loop < 64; loop++) | ||
566 | entry->name[loop] = ntohl(*bp++); | ||
567 | bp++; /* final NUL */ | ||
568 | |||
569 | bp++; /* type */ | ||
570 | entry->nservers = ntohl(*bp++); | ||
571 | |||
572 | for (loop = 0; loop < 8; loop++) | ||
573 | entry->servers[loop].s_addr = *bp++; | ||
574 | |||
575 | bp += 8; /* partition IDs */ | ||
576 | |||
577 | for (loop = 0; loop < 8; loop++) { | ||
578 | tmp = ntohl(*bp++); | ||
579 | if (tmp & AFS_VLSF_RWVOL) | ||
580 | entry->srvtmask[loop] |= AFS_VOL_VTM_RW; | ||
581 | if (tmp & AFS_VLSF_ROVOL) | ||
582 | entry->srvtmask[loop] |= AFS_VOL_VTM_RO; | ||
583 | if (tmp & AFS_VLSF_BACKVOL) | ||
584 | entry->srvtmask[loop] |= AFS_VOL_VTM_BAK; | ||
585 | } | ||
586 | |||
587 | entry->vid[0] = ntohl(*bp++); | ||
588 | entry->vid[1] = ntohl(*bp++); | ||
589 | entry->vid[2] = ntohl(*bp++); | ||
590 | |||
591 | bp++; /* clone ID */ | ||
592 | |||
593 | tmp = ntohl(*bp++); /* flags */ | ||
594 | if (tmp & AFS_VLF_RWEXISTS) | ||
595 | entry->vidmask |= AFS_VOL_VTM_RW; | ||
596 | if (tmp & AFS_VLF_ROEXISTS) | ||
597 | entry->vidmask |= AFS_VOL_VTM_RO; | ||
598 | if (tmp & AFS_VLF_BACKEXISTS) | ||
599 | entry->vidmask |= AFS_VOL_VTM_BAK; | ||
600 | |||
601 | ret = -ENOMEDIUM; | ||
602 | if (!entry->vidmask) { | ||
603 | rxrpc_call_abort(op->call, ret); | ||
604 | goto done; | ||
605 | } | ||
606 | |||
607 | #if 0 /* TODO: remove */ | ||
608 | entry->nservers = 3; | ||
609 | entry->servers[0].s_addr = htonl(0xac101249); | ||
610 | entry->servers[1].s_addr = htonl(0xac101243); | ||
611 | entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/); | ||
612 | |||
613 | entry->srvtmask[0] = AFS_VOL_VTM_RO; | ||
614 | entry->srvtmask[1] = AFS_VOL_VTM_RO; | ||
615 | entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW; | ||
616 | #endif | ||
617 | |||
618 | /* success */ | ||
619 | entry->rtime = get_seconds(); | ||
620 | ret = 0; | ||
621 | goto done; | ||
622 | } | ||
623 | 158 | ||
624 | if (op->call->app_call_state == RXRPC_CSTATE_ERROR) { | 159 | _enter(""); |
625 | /* operation error */ | ||
626 | ret = op->call->app_errno; | ||
627 | goto done; | ||
628 | } | ||
629 | 160 | ||
630 | _leave(" = -EAGAIN"); | 161 | volnamesz = strlen(volname); |
631 | return -EAGAIN; | 162 | padsz = (4 - (volnamesz & 3)) & 3; |
163 | reqsz = 8 + volnamesz + padsz; | ||
632 | 164 | ||
633 | done: | 165 | call = afs_alloc_flat_call(&afs_RXVLGetEntryByName, reqsz, 384); |
634 | rxrpc_put_call(op->call); | 166 | if (!call) |
635 | op->call = NULL; | 167 | return -ENOMEM; |
636 | _leave(" = %d", ret); | ||
637 | return ret; | ||
638 | } /* end afs_rxvl_get_entry_by_id_async2() */ | ||
639 | 168 | ||
640 | /*****************************************************************************/ | 169 | call->key = key; |
641 | /* | 170 | call->reply = entry; |
642 | * handle attention events on an async get-entry-by-ID op | 171 | call->service_id = VL_SERVICE; |
643 | * - called from krxiod | 172 | call->port = htons(AFS_VL_PORT); |
644 | */ | ||
645 | static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call) | ||
646 | { | ||
647 | struct afs_async_op *op = call->app_user; | ||
648 | |||
649 | _enter("{op=%p cst=%u}", op, call->app_call_state); | ||
650 | |||
651 | switch (call->app_call_state) { | ||
652 | case RXRPC_CSTATE_COMPLETE: | ||
653 | afs_kafsasyncd_attend_op(op); | ||
654 | break; | ||
655 | case RXRPC_CSTATE_CLNT_RCV_REPLY: | ||
656 | if (call->app_async_read) | ||
657 | break; | ||
658 | case RXRPC_CSTATE_CLNT_GOT_REPLY: | ||
659 | if (call->app_read_count == 0) | ||
660 | break; | ||
661 | printk("kAFS: Reply bigger than expected" | ||
662 | " {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}", | ||
663 | call->app_call_state, | ||
664 | call->app_async_read, | ||
665 | call->app_mark, | ||
666 | call->app_ready_qty, | ||
667 | call->pkt_rcv_count, | ||
668 | call->app_last_rcv ? " last" : ""); | ||
669 | |||
670 | rxrpc_call_abort(call, -EBADMSG); | ||
671 | break; | ||
672 | default: | ||
673 | BUG(); | ||
674 | } | ||
675 | 173 | ||
676 | _leave(""); | 174 | /* marshall the parameters */ |
175 | bp = call->request; | ||
176 | *bp++ = htonl(VLGETENTRYBYNAME); | ||
177 | *bp++ = htonl(volnamesz); | ||
178 | memcpy(bp, volname, volnamesz); | ||
179 | if (padsz > 0) | ||
180 | memset((void *) bp + volnamesz, 0, padsz); | ||
677 | 181 | ||
678 | } /* end afs_rxvl_get_entry_by_id_attn() */ | 182 | /* initiate the call */ |
183 | return afs_make_call(addr, call, GFP_KERNEL, wait_mode); | ||
184 | } | ||
679 | 185 | ||
680 | /*****************************************************************************/ | ||
681 | /* | 186 | /* |
682 | * handle error events on an async get-entry-by-ID op | 187 | * dispatch a get volume entry by ID operation |
683 | * - called from krxiod | ||
684 | */ | 188 | */ |
685 | static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call) | 189 | int afs_vl_get_entry_by_id(struct in_addr *addr, |
190 | struct key *key, | ||
191 | afs_volid_t volid, | ||
192 | afs_voltype_t voltype, | ||
193 | struct afs_cache_vlocation *entry, | ||
194 | const struct afs_wait_mode *wait_mode) | ||
686 | { | 195 | { |
687 | struct afs_async_op *op = call->app_user; | 196 | struct afs_call *call; |
197 | __be32 *bp; | ||
688 | 198 | ||
689 | _enter("{op=%p cst=%u}", op, call->app_call_state); | 199 | _enter(""); |
690 | 200 | ||
691 | afs_kafsasyncd_attend_op(op); | 201 | call = afs_alloc_flat_call(&afs_RXVLGetEntryById, 12, 384); |
202 | if (!call) | ||
203 | return -ENOMEM; | ||
692 | 204 | ||
693 | _leave(""); | 205 | call->key = key; |
206 | call->reply = entry; | ||
207 | call->service_id = VL_SERVICE; | ||
208 | call->port = htons(AFS_VL_PORT); | ||
694 | 209 | ||
695 | } /* end afs_rxvl_get_entry_by_id_error() */ | 210 | /* marshall the parameters */ |
211 | bp = call->request; | ||
212 | *bp++ = htonl(VLGETENTRYBYID); | ||
213 | *bp++ = htonl(volid); | ||
214 | *bp = htonl(voltype); | ||
215 | |||
216 | /* initiate the call */ | ||
217 | return afs_make_call(addr, call, GFP_KERNEL, wait_mode); | ||
218 | } | ||
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index 782ee7c600ca..74cce174882a 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* vlocation.c: volume location management | 1 | /* AFS volume location management |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -12,131 +12,61 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/slab.h> | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/pagemap.h> | ||
18 | #include "volume.h" | ||
19 | #include "cell.h" | ||
20 | #include "cmservice.h" | ||
21 | #include "fsclient.h" | ||
22 | #include "vlclient.h" | ||
23 | #include "kafstimod.h" | ||
24 | #include <rxrpc/connection.h> | ||
25 | #include "internal.h" | 15 | #include "internal.h" |
26 | 16 | ||
27 | #define AFS_VLDB_TIMEOUT HZ*1000 | 17 | unsigned afs_vlocation_timeout = 10; /* volume location timeout in seconds */ |
18 | unsigned afs_vlocation_update_timeout = 10 * 60; | ||
28 | 19 | ||
29 | static void afs_vlocation_update_timer(struct afs_timer *timer); | 20 | static void afs_vlocation_reaper(struct work_struct *); |
30 | static void afs_vlocation_update_attend(struct afs_async_op *op); | 21 | static void afs_vlocation_updater(struct work_struct *); |
31 | static void afs_vlocation_update_discard(struct afs_async_op *op); | ||
32 | static void __afs_put_vlocation(struct afs_vlocation *vlocation); | ||
33 | 22 | ||
34 | static void __afs_vlocation_timeout(struct afs_timer *timer) | 23 | static LIST_HEAD(afs_vlocation_updates); |
35 | { | 24 | static LIST_HEAD(afs_vlocation_graveyard); |
36 | struct afs_vlocation *vlocation = | 25 | static DEFINE_SPINLOCK(afs_vlocation_updates_lock); |
37 | list_entry(timer, struct afs_vlocation, timeout); | 26 | static DEFINE_SPINLOCK(afs_vlocation_graveyard_lock); |
38 | 27 | static DECLARE_DELAYED_WORK(afs_vlocation_reap, afs_vlocation_reaper); | |
39 | _debug("VL TIMEOUT [%s{u=%d}]", | 28 | static DECLARE_DELAYED_WORK(afs_vlocation_update, afs_vlocation_updater); |
40 | vlocation->vldb.name, atomic_read(&vlocation->usage)); | 29 | static struct workqueue_struct *afs_vlocation_update_worker; |
41 | |||
42 | afs_vlocation_do_timeout(vlocation); | ||
43 | } | ||
44 | |||
45 | static const struct afs_timer_ops afs_vlocation_timer_ops = { | ||
46 | .timed_out = __afs_vlocation_timeout, | ||
47 | }; | ||
48 | 30 | ||
49 | static const struct afs_timer_ops afs_vlocation_update_timer_ops = { | ||
50 | .timed_out = afs_vlocation_update_timer, | ||
51 | }; | ||
52 | |||
53 | static const struct afs_async_op_ops afs_vlocation_update_op_ops = { | ||
54 | .attend = afs_vlocation_update_attend, | ||
55 | .discard = afs_vlocation_update_discard, | ||
56 | }; | ||
57 | |||
58 | static LIST_HEAD(afs_vlocation_update_pendq); /* queue of VLs awaiting update */ | ||
59 | static struct afs_vlocation *afs_vlocation_update; /* VL currently being updated */ | ||
60 | static DEFINE_SPINLOCK(afs_vlocation_update_lock); /* lock guarding update queue */ | ||
61 | |||
62 | #ifdef AFS_CACHING_SUPPORT | ||
63 | static cachefs_match_val_t afs_vlocation_cache_match(void *target, | ||
64 | const void *entry); | ||
65 | static void afs_vlocation_cache_update(void *source, void *entry); | ||
66 | |||
67 | struct cachefs_index_def afs_vlocation_cache_index_def = { | ||
68 | .name = "vldb", | ||
69 | .data_size = sizeof(struct afs_cache_vlocation), | ||
70 | .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 }, | ||
71 | .match = afs_vlocation_cache_match, | ||
72 | .update = afs_vlocation_cache_update, | ||
73 | }; | ||
74 | #endif | ||
75 | |||
76 | /*****************************************************************************/ | ||
77 | /* | 31 | /* |
78 | * iterate through the VL servers in a cell until one of them admits knowing | 32 | * iterate through the VL servers in a cell until one of them admits knowing |
79 | * about the volume in question | 33 | * about the volume in question |
80 | * - caller must have cell->vl_sem write-locked | ||
81 | */ | 34 | */ |
82 | static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vlocation, | 35 | static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, |
83 | const char *name, | 36 | struct key *key, |
84 | unsigned namesz, | ||
85 | struct afs_cache_vlocation *vldb) | 37 | struct afs_cache_vlocation *vldb) |
86 | { | 38 | { |
87 | struct afs_server *server = NULL; | 39 | struct afs_cell *cell = vl->cell; |
88 | struct afs_cell *cell = vlocation->cell; | 40 | struct in_addr addr; |
89 | int count, ret; | 41 | int count, ret; |
90 | 42 | ||
91 | _enter("%s,%*.*s,%u", cell->name, namesz, namesz, name, namesz); | 43 | _enter("%s,%s", cell->name, vl->vldb.name); |
92 | 44 | ||
45 | down_write(&vl->cell->vl_sem); | ||
93 | ret = -ENOMEDIUM; | 46 | ret = -ENOMEDIUM; |
94 | for (count = cell->vl_naddrs; count > 0; count--) { | 47 | for (count = cell->vl_naddrs; count > 0; count--) { |
95 | _debug("CellServ[%hu]: %08x", | 48 | addr = cell->vl_addrs[cell->vl_curr_svix]; |
96 | cell->vl_curr_svix, | 49 | |
97 | cell->vl_addrs[cell->vl_curr_svix].s_addr); | 50 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); |
98 | |||
99 | /* try and create a server */ | ||
100 | ret = afs_server_lookup(cell, | ||
101 | &cell->vl_addrs[cell->vl_curr_svix], | ||
102 | &server); | ||
103 | switch (ret) { | ||
104 | case 0: | ||
105 | break; | ||
106 | case -ENOMEM: | ||
107 | case -ENONET: | ||
108 | goto out; | ||
109 | default: | ||
110 | goto rotate; | ||
111 | } | ||
112 | 51 | ||
113 | /* attempt to access the VL server */ | 52 | /* attempt to access the VL server */ |
114 | ret = afs_rxvl_get_entry_by_name(server, name, namesz, vldb); | 53 | ret = afs_vl_get_entry_by_name(&addr, key, vl->vldb.name, vldb, |
54 | &afs_sync_call); | ||
115 | switch (ret) { | 55 | switch (ret) { |
116 | case 0: | 56 | case 0: |
117 | afs_put_server(server); | ||
118 | goto out; | 57 | goto out; |
119 | case -ENOMEM: | 58 | case -ENOMEM: |
120 | case -ENONET: | 59 | case -ENONET: |
121 | case -ENETUNREACH: | 60 | case -ENETUNREACH: |
122 | case -EHOSTUNREACH: | 61 | case -EHOSTUNREACH: |
123 | case -ECONNREFUSED: | 62 | case -ECONNREFUSED: |
124 | down_write(&server->sem); | ||
125 | if (server->vlserver) { | ||
126 | rxrpc_put_connection(server->vlserver); | ||
127 | server->vlserver = NULL; | ||
128 | } | ||
129 | up_write(&server->sem); | ||
130 | afs_put_server(server); | ||
131 | if (ret == -ENOMEM || ret == -ENONET) | 63 | if (ret == -ENOMEM || ret == -ENONET) |
132 | goto out; | 64 | goto out; |
133 | goto rotate; | 65 | goto rotate; |
134 | case -ENOMEDIUM: | 66 | case -ENOMEDIUM: |
135 | afs_put_server(server); | ||
136 | goto out; | 67 | goto out; |
137 | default: | 68 | default: |
138 | afs_put_server(server); | 69 | ret = -EIO; |
139 | ret = -ENOMEDIUM; | ||
140 | goto rotate; | 70 | goto rotate; |
141 | } | 71 | } |
142 | 72 | ||
@@ -146,76 +76,66 @@ static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vlocation, | |||
146 | cell->vl_curr_svix %= cell->vl_naddrs; | 76 | cell->vl_curr_svix %= cell->vl_naddrs; |
147 | } | 77 | } |
148 | 78 | ||
149 | out: | 79 | out: |
80 | up_write(&vl->cell->vl_sem); | ||
150 | _leave(" = %d", ret); | 81 | _leave(" = %d", ret); |
151 | return ret; | 82 | return ret; |
83 | } | ||
152 | 84 | ||
153 | } /* end afs_vlocation_access_vl_by_name() */ | ||
154 | |||
155 | /*****************************************************************************/ | ||
156 | /* | 85 | /* |
157 | * iterate through the VL servers in a cell until one of them admits knowing | 86 | * iterate through the VL servers in a cell until one of them admits knowing |
158 | * about the volume in question | 87 | * about the volume in question |
159 | * - caller must have cell->vl_sem write-locked | ||
160 | */ | 88 | */ |
161 | static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vlocation, | 89 | static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl, |
90 | struct key *key, | ||
162 | afs_volid_t volid, | 91 | afs_volid_t volid, |
163 | afs_voltype_t voltype, | 92 | afs_voltype_t voltype, |
164 | struct afs_cache_vlocation *vldb) | 93 | struct afs_cache_vlocation *vldb) |
165 | { | 94 | { |
166 | struct afs_server *server = NULL; | 95 | struct afs_cell *cell = vl->cell; |
167 | struct afs_cell *cell = vlocation->cell; | 96 | struct in_addr addr; |
168 | int count, ret; | 97 | int count, ret; |
169 | 98 | ||
170 | _enter("%s,%x,%d,", cell->name, volid, voltype); | 99 | _enter("%s,%x,%d,", cell->name, volid, voltype); |
171 | 100 | ||
101 | down_write(&vl->cell->vl_sem); | ||
172 | ret = -ENOMEDIUM; | 102 | ret = -ENOMEDIUM; |
173 | for (count = cell->vl_naddrs; count > 0; count--) { | 103 | for (count = cell->vl_naddrs; count > 0; count--) { |
174 | _debug("CellServ[%hu]: %08x", | 104 | addr = cell->vl_addrs[cell->vl_curr_svix]; |
175 | cell->vl_curr_svix, | 105 | |
176 | cell->vl_addrs[cell->vl_curr_svix].s_addr); | 106 | _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr); |
177 | |||
178 | /* try and create a server */ | ||
179 | ret = afs_server_lookup(cell, | ||
180 | &cell->vl_addrs[cell->vl_curr_svix], | ||
181 | &server); | ||
182 | switch (ret) { | ||
183 | case 0: | ||
184 | break; | ||
185 | case -ENOMEM: | ||
186 | case -ENONET: | ||
187 | goto out; | ||
188 | default: | ||
189 | goto rotate; | ||
190 | } | ||
191 | 107 | ||
192 | /* attempt to access the VL server */ | 108 | /* attempt to access the VL server */ |
193 | ret = afs_rxvl_get_entry_by_id(server, volid, voltype, vldb); | 109 | ret = afs_vl_get_entry_by_id(&addr, key, volid, voltype, vldb, |
110 | &afs_sync_call); | ||
194 | switch (ret) { | 111 | switch (ret) { |
195 | case 0: | 112 | case 0: |
196 | afs_put_server(server); | ||
197 | goto out; | 113 | goto out; |
198 | case -ENOMEM: | 114 | case -ENOMEM: |
199 | case -ENONET: | 115 | case -ENONET: |
200 | case -ENETUNREACH: | 116 | case -ENETUNREACH: |
201 | case -EHOSTUNREACH: | 117 | case -EHOSTUNREACH: |
202 | case -ECONNREFUSED: | 118 | case -ECONNREFUSED: |
203 | down_write(&server->sem); | ||
204 | if (server->vlserver) { | ||
205 | rxrpc_put_connection(server->vlserver); | ||
206 | server->vlserver = NULL; | ||
207 | } | ||
208 | up_write(&server->sem); | ||
209 | afs_put_server(server); | ||
210 | if (ret == -ENOMEM || ret == -ENONET) | 119 | if (ret == -ENOMEM || ret == -ENONET) |
211 | goto out; | 120 | goto out; |
212 | goto rotate; | 121 | goto rotate; |
122 | case -EBUSY: | ||
123 | vl->upd_busy_cnt++; | ||
124 | if (vl->upd_busy_cnt <= 3) { | ||
125 | if (vl->upd_busy_cnt > 1) { | ||
126 | /* second+ BUSY - sleep a little bit */ | ||
127 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
128 | schedule_timeout(1); | ||
129 | __set_current_state(TASK_RUNNING); | ||
130 | } | ||
131 | continue; | ||
132 | } | ||
133 | break; | ||
213 | case -ENOMEDIUM: | 134 | case -ENOMEDIUM: |
214 | afs_put_server(server); | 135 | vl->upd_rej_cnt++; |
215 | goto out; | 136 | goto rotate; |
216 | default: | 137 | default: |
217 | afs_put_server(server); | 138 | ret = -EIO; |
218 | ret = -ENOMEDIUM; | ||
219 | goto rotate; | 139 | goto rotate; |
220 | } | 140 | } |
221 | 141 | ||
@@ -223,729 +143,580 @@ static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vlocation, | |||
223 | rotate: | 143 | rotate: |
224 | cell->vl_curr_svix++; | 144 | cell->vl_curr_svix++; |
225 | cell->vl_curr_svix %= cell->vl_naddrs; | 145 | cell->vl_curr_svix %= cell->vl_naddrs; |
146 | vl->upd_busy_cnt = 0; | ||
226 | } | 147 | } |
227 | 148 | ||
228 | out: | 149 | out: |
150 | if (ret < 0 && vl->upd_rej_cnt > 0) { | ||
151 | printk(KERN_NOTICE "kAFS:" | ||
152 | " Active volume no longer valid '%s'\n", | ||
153 | vl->vldb.name); | ||
154 | vl->valid = 0; | ||
155 | ret = -ENOMEDIUM; | ||
156 | } | ||
157 | |||
158 | up_write(&vl->cell->vl_sem); | ||
229 | _leave(" = %d", ret); | 159 | _leave(" = %d", ret); |
230 | return ret; | 160 | return ret; |
161 | } | ||
231 | 162 | ||
232 | } /* end afs_vlocation_access_vl_by_id() */ | ||
233 | |||
234 | /*****************************************************************************/ | ||
235 | /* | 163 | /* |
236 | * lookup volume location | 164 | * allocate a volume location record |
237 | * - caller must have cell->vol_sem write-locked | ||
238 | * - iterate through the VL servers in a cell until one of them admits knowing | ||
239 | * about the volume in question | ||
240 | * - lookup in the local cache if not able to find on the VL server | ||
241 | * - insert/update in the local cache if did get a VL response | ||
242 | */ | 165 | */ |
243 | int afs_vlocation_lookup(struct afs_cell *cell, | 166 | static struct afs_vlocation *afs_vlocation_alloc(struct afs_cell *cell, |
244 | const char *name, | 167 | const char *name, |
245 | unsigned namesz, | 168 | size_t namesz) |
246 | struct afs_vlocation **_vlocation) | ||
247 | { | 169 | { |
248 | struct afs_cache_vlocation vldb; | 170 | struct afs_vlocation *vl; |
249 | struct afs_vlocation *vlocation; | 171 | |
250 | afs_voltype_t voltype; | 172 | vl = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL); |
251 | afs_volid_t vid; | 173 | if (vl) { |
252 | int active = 0, ret; | 174 | vl->cell = cell; |
253 | 175 | vl->state = AFS_VL_NEW; | |
254 | _enter("{%s},%*.*s,%u,", cell->name, namesz, namesz, name, namesz); | 176 | atomic_set(&vl->usage, 1); |
255 | 177 | INIT_LIST_HEAD(&vl->link); | |
256 | if (namesz > sizeof(vlocation->vldb.name)) { | 178 | INIT_LIST_HEAD(&vl->grave); |
257 | _leave(" = -ENAMETOOLONG"); | 179 | INIT_LIST_HEAD(&vl->update); |
258 | return -ENAMETOOLONG; | 180 | init_waitqueue_head(&vl->waitq); |
259 | } | 181 | spin_lock_init(&vl->lock); |
260 | 182 | memcpy(vl->vldb.name, name, namesz); | |
261 | /* search the cell's active list first */ | ||
262 | list_for_each_entry(vlocation, &cell->vl_list, link) { | ||
263 | if (namesz < sizeof(vlocation->vldb.name) && | ||
264 | vlocation->vldb.name[namesz] != '\0') | ||
265 | continue; | ||
266 | |||
267 | if (memcmp(vlocation->vldb.name, name, namesz) == 0) | ||
268 | goto found_in_memory; | ||
269 | } | ||
270 | |||
271 | /* search the cell's graveyard list second */ | ||
272 | spin_lock(&cell->vl_gylock); | ||
273 | list_for_each_entry(vlocation, &cell->vl_graveyard, link) { | ||
274 | if (namesz < sizeof(vlocation->vldb.name) && | ||
275 | vlocation->vldb.name[namesz] != '\0') | ||
276 | continue; | ||
277 | |||
278 | if (memcmp(vlocation->vldb.name, name, namesz) == 0) | ||
279 | goto found_in_graveyard; | ||
280 | } | ||
281 | spin_unlock(&cell->vl_gylock); | ||
282 | |||
283 | /* not in the cell's in-memory lists - create a new record */ | ||
284 | vlocation = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL); | ||
285 | if (!vlocation) | ||
286 | return -ENOMEM; | ||
287 | |||
288 | atomic_set(&vlocation->usage, 1); | ||
289 | INIT_LIST_HEAD(&vlocation->link); | ||
290 | rwlock_init(&vlocation->lock); | ||
291 | memcpy(vlocation->vldb.name, name, namesz); | ||
292 | |||
293 | afs_timer_init(&vlocation->timeout, &afs_vlocation_timer_ops); | ||
294 | afs_timer_init(&vlocation->upd_timer, &afs_vlocation_update_timer_ops); | ||
295 | afs_async_op_init(&vlocation->upd_op, &afs_vlocation_update_op_ops); | ||
296 | |||
297 | afs_get_cell(cell); | ||
298 | vlocation->cell = cell; | ||
299 | |||
300 | list_add_tail(&vlocation->link, &cell->vl_list); | ||
301 | |||
302 | #ifdef AFS_CACHING_SUPPORT | ||
303 | /* we want to store it in the cache, plus it might already be | ||
304 | * encached */ | ||
305 | cachefs_acquire_cookie(cell->cache, | ||
306 | &afs_volume_cache_index_def, | ||
307 | vlocation, | ||
308 | &vlocation->cache); | ||
309 | |||
310 | if (vlocation->valid) | ||
311 | goto found_in_cache; | ||
312 | #endif | ||
313 | |||
314 | /* try to look up an unknown volume in the cell VL databases by name */ | ||
315 | ret = afs_vlocation_access_vl_by_name(vlocation, name, namesz, &vldb); | ||
316 | if (ret < 0) { | ||
317 | printk("kAFS: failed to locate '%*.*s' in cell '%s'\n", | ||
318 | namesz, namesz, name, cell->name); | ||
319 | goto error; | ||
320 | } | 183 | } |
321 | 184 | ||
322 | goto found_on_vlserver; | 185 | _leave(" = %p", vl); |
323 | 186 | return vl; | |
324 | found_in_graveyard: | 187 | } |
325 | /* found in the graveyard - resurrect */ | ||
326 | _debug("found in graveyard"); | ||
327 | atomic_inc(&vlocation->usage); | ||
328 | list_move_tail(&vlocation->link, &cell->vl_list); | ||
329 | spin_unlock(&cell->vl_gylock); | ||
330 | |||
331 | afs_kafstimod_del_timer(&vlocation->timeout); | ||
332 | goto active; | ||
333 | |||
334 | found_in_memory: | ||
335 | /* found in memory - check to see if it's active */ | ||
336 | _debug("found in memory"); | ||
337 | atomic_inc(&vlocation->usage); | ||
338 | 188 | ||
339 | active: | 189 | /* |
340 | active = 1; | 190 | * update record if we found it in the cache |
191 | */ | ||
192 | static int afs_vlocation_update_record(struct afs_vlocation *vl, | ||
193 | struct key *key, | ||
194 | struct afs_cache_vlocation *vldb) | ||
195 | { | ||
196 | afs_voltype_t voltype; | ||
197 | afs_volid_t vid; | ||
198 | int ret; | ||
341 | 199 | ||
342 | #ifdef AFS_CACHING_SUPPORT | ||
343 | found_in_cache: | ||
344 | #endif | ||
345 | /* try to look up a cached volume in the cell VL databases by ID */ | 200 | /* try to look up a cached volume in the cell VL databases by ID */ |
346 | _debug("found in cache"); | ||
347 | |||
348 | _debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }", | 201 | _debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }", |
349 | vlocation->vldb.name, | 202 | vl->vldb.name, |
350 | vlocation->vldb.vidmask, | 203 | vl->vldb.vidmask, |
351 | ntohl(vlocation->vldb.servers[0].s_addr), | 204 | ntohl(vl->vldb.servers[0].s_addr), |
352 | vlocation->vldb.srvtmask[0], | 205 | vl->vldb.srvtmask[0], |
353 | ntohl(vlocation->vldb.servers[1].s_addr), | 206 | ntohl(vl->vldb.servers[1].s_addr), |
354 | vlocation->vldb.srvtmask[1], | 207 | vl->vldb.srvtmask[1], |
355 | ntohl(vlocation->vldb.servers[2].s_addr), | 208 | ntohl(vl->vldb.servers[2].s_addr), |
356 | vlocation->vldb.srvtmask[2] | 209 | vl->vldb.srvtmask[2]); |
357 | ); | ||
358 | 210 | ||
359 | _debug("Vids: %08x %08x %08x", | 211 | _debug("Vids: %08x %08x %08x", |
360 | vlocation->vldb.vid[0], | 212 | vl->vldb.vid[0], |
361 | vlocation->vldb.vid[1], | 213 | vl->vldb.vid[1], |
362 | vlocation->vldb.vid[2]); | 214 | vl->vldb.vid[2]); |
363 | 215 | ||
364 | if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) { | 216 | if (vl->vldb.vidmask & AFS_VOL_VTM_RW) { |
365 | vid = vlocation->vldb.vid[0]; | 217 | vid = vl->vldb.vid[0]; |
366 | voltype = AFSVL_RWVOL; | 218 | voltype = AFSVL_RWVOL; |
367 | } | 219 | } else if (vl->vldb.vidmask & AFS_VOL_VTM_RO) { |
368 | else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) { | 220 | vid = vl->vldb.vid[1]; |
369 | vid = vlocation->vldb.vid[1]; | ||
370 | voltype = AFSVL_ROVOL; | 221 | voltype = AFSVL_ROVOL; |
371 | } | 222 | } else if (vl->vldb.vidmask & AFS_VOL_VTM_BAK) { |
372 | else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) { | 223 | vid = vl->vldb.vid[2]; |
373 | vid = vlocation->vldb.vid[2]; | ||
374 | voltype = AFSVL_BACKVOL; | 224 | voltype = AFSVL_BACKVOL; |
375 | } | 225 | } else { |
376 | else { | ||
377 | BUG(); | 226 | BUG(); |
378 | vid = 0; | 227 | vid = 0; |
379 | voltype = 0; | 228 | voltype = 0; |
380 | } | 229 | } |
381 | 230 | ||
382 | ret = afs_vlocation_access_vl_by_id(vlocation, vid, voltype, &vldb); | 231 | /* contact the server to make sure the volume is still available |
232 | * - TODO: need to handle disconnected operation here | ||
233 | */ | ||
234 | ret = afs_vlocation_access_vl_by_id(vl, key, vid, voltype, vldb); | ||
383 | switch (ret) { | 235 | switch (ret) { |
384 | /* net error */ | 236 | /* net error */ |
385 | default: | 237 | default: |
386 | printk("kAFS: failed to volume '%*.*s' (%x) up in '%s': %d\n", | 238 | printk(KERN_WARNING "kAFS:" |
387 | namesz, namesz, name, vid, cell->name, ret); | 239 | " failed to update volume '%s' (%x) up in '%s': %d\n", |
388 | goto error; | 240 | vl->vldb.name, vid, vl->cell->name, ret); |
241 | _leave(" = %d", ret); | ||
242 | return ret; | ||
389 | 243 | ||
390 | /* pulled from local cache into memory */ | 244 | /* pulled from local cache into memory */ |
391 | case 0: | 245 | case 0: |
392 | goto found_on_vlserver; | 246 | _leave(" = 0"); |
247 | return 0; | ||
393 | 248 | ||
394 | /* uh oh... looks like the volume got deleted */ | 249 | /* uh oh... looks like the volume got deleted */ |
395 | case -ENOMEDIUM: | 250 | case -ENOMEDIUM: |
396 | printk("kAFS: volume '%*.*s' (%x) does not exist '%s'\n", | 251 | printk(KERN_ERR "kAFS:" |
397 | namesz, namesz, name, vid, cell->name); | 252 | " volume '%s' (%x) does not exist '%s'\n", |
253 | vl->vldb.name, vid, vl->cell->name); | ||
398 | 254 | ||
399 | /* TODO: make existing record unavailable */ | 255 | /* TODO: make existing record unavailable */ |
400 | goto error; | 256 | _leave(" = %d", ret); |
257 | return ret; | ||
401 | } | 258 | } |
259 | } | ||
402 | 260 | ||
403 | found_on_vlserver: | 261 | /* |
404 | _debug("Done VL Lookup: %*.*s %02x { %08x(%x) %08x(%x) %08x(%x) }", | 262 | * apply the update to a VL record |
405 | namesz, namesz, name, | 263 | */ |
406 | vldb.vidmask, | 264 | static void afs_vlocation_apply_update(struct afs_vlocation *vl, |
407 | ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0], | 265 | struct afs_cache_vlocation *vldb) |
408 | ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1], | 266 | { |
409 | ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2] | 267 | _debug("Done VL Lookup: %s %02x { %08x(%x) %08x(%x) %08x(%x) }", |
410 | ); | 268 | vldb->name, vldb->vidmask, |
411 | 269 | ntohl(vldb->servers[0].s_addr), vldb->srvtmask[0], | |
412 | _debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]); | 270 | ntohl(vldb->servers[1].s_addr), vldb->srvtmask[1], |
271 | ntohl(vldb->servers[2].s_addr), vldb->srvtmask[2]); | ||
413 | 272 | ||
414 | if ((namesz < sizeof(vlocation->vldb.name) && | 273 | _debug("Vids: %08x %08x %08x", |
415 | vlocation->vldb.name[namesz] != '\0') || | 274 | vldb->vid[0], vldb->vid[1], vldb->vid[2]); |
416 | memcmp(vldb.name, name, namesz) != 0) | ||
417 | printk("kAFS: name of volume '%*.*s' changed to '%s' on server\n", | ||
418 | namesz, namesz, name, vldb.name); | ||
419 | 275 | ||
420 | memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb)); | 276 | if (strcmp(vldb->name, vl->vldb.name) != 0) |
277 | printk(KERN_NOTICE "kAFS:" | ||
278 | " name of volume '%s' changed to '%s' on server\n", | ||
279 | vl->vldb.name, vldb->name); | ||
421 | 280 | ||
422 | afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ); | 281 | vl->vldb = *vldb; |
423 | 282 | ||
424 | #ifdef AFS_CACHING_SUPPORT | 283 | #ifdef AFS_CACHING_SUPPORT |
425 | /* update volume entry in local cache */ | 284 | /* update volume entry in local cache */ |
426 | cachefs_update_cookie(vlocation->cache); | 285 | cachefs_update_cookie(vl->cache); |
427 | #endif | ||
428 | |||
429 | *_vlocation = vlocation; | ||
430 | _leave(" = 0 (%p)",vlocation); | ||
431 | return 0; | ||
432 | |||
433 | error: | ||
434 | if (vlocation) { | ||
435 | if (active) { | ||
436 | __afs_put_vlocation(vlocation); | ||
437 | } | ||
438 | else { | ||
439 | list_del(&vlocation->link); | ||
440 | #ifdef AFS_CACHING_SUPPORT | ||
441 | cachefs_relinquish_cookie(vlocation->cache, 0); | ||
442 | #endif | 286 | #endif |
443 | afs_put_cell(vlocation->cell); | 287 | } |
444 | kfree(vlocation); | ||
445 | } | ||
446 | } | ||
447 | |||
448 | _leave(" = %d", ret); | ||
449 | return ret; | ||
450 | } /* end afs_vlocation_lookup() */ | ||
451 | 288 | ||
452 | /*****************************************************************************/ | ||
453 | /* | 289 | /* |
454 | * finish using a volume location record | 290 | * fill in a volume location record, consulting the cache and the VL server |
455 | * - caller must have cell->vol_sem write-locked | 291 | * both |
456 | */ | 292 | */ |
457 | static void __afs_put_vlocation(struct afs_vlocation *vlocation) | 293 | static int afs_vlocation_fill_in_record(struct afs_vlocation *vl, |
294 | struct key *key) | ||
458 | { | 295 | { |
459 | struct afs_cell *cell; | 296 | struct afs_cache_vlocation vldb; |
297 | int ret; | ||
460 | 298 | ||
461 | if (!vlocation) | 299 | _enter(""); |
462 | return; | ||
463 | 300 | ||
464 | _enter("%s", vlocation->vldb.name); | 301 | ASSERTCMP(vl->valid, ==, 0); |
465 | 302 | ||
466 | cell = vlocation->cell; | 303 | memset(&vldb, 0, sizeof(vldb)); |
467 | 304 | ||
468 | /* sanity check */ | 305 | /* see if we have an in-cache copy (will set vl->valid if there is) */ |
469 | BUG_ON(atomic_read(&vlocation->usage) <= 0); | 306 | #ifdef AFS_CACHING_SUPPORT |
307 | cachefs_acquire_cookie(cell->cache, | ||
308 | &afs_volume_cache_index_def, | ||
309 | vlocation, | ||
310 | &vl->cache); | ||
311 | #endif | ||
470 | 312 | ||
471 | spin_lock(&cell->vl_gylock); | 313 | if (vl->valid) { |
472 | if (likely(!atomic_dec_and_test(&vlocation->usage))) { | 314 | /* try to update a known volume in the cell VL databases by |
473 | spin_unlock(&cell->vl_gylock); | 315 | * ID as the name may have changed */ |
474 | _leave(""); | 316 | _debug("found in cache"); |
475 | return; | 317 | ret = afs_vlocation_update_record(vl, key, &vldb); |
318 | } else { | ||
319 | /* try to look up an unknown volume in the cell VL databases by | ||
320 | * name */ | ||
321 | ret = afs_vlocation_access_vl_by_name(vl, key, &vldb); | ||
322 | if (ret < 0) { | ||
323 | printk("kAFS: failed to locate '%s' in cell '%s'\n", | ||
324 | vl->vldb.name, vl->cell->name); | ||
325 | return ret; | ||
326 | } | ||
476 | } | 327 | } |
477 | 328 | ||
478 | /* move to graveyard queue */ | 329 | afs_vlocation_apply_update(vl, &vldb); |
479 | list_move_tail(&vlocation->link,&cell->vl_graveyard); | 330 | _leave(" = 0"); |
480 | 331 | return 0; | |
481 | /* remove from pending timeout queue (refcounted if actually being | 332 | } |
482 | * updated) */ | ||
483 | list_del_init(&vlocation->upd_op.link); | ||
484 | |||
485 | /* time out in 10 secs */ | ||
486 | afs_kafstimod_del_timer(&vlocation->upd_timer); | ||
487 | afs_kafstimod_add_timer(&vlocation->timeout, 10 * HZ); | ||
488 | |||
489 | spin_unlock(&cell->vl_gylock); | ||
490 | |||
491 | _leave(" [killed]"); | ||
492 | } /* end __afs_put_vlocation() */ | ||
493 | |||
494 | /*****************************************************************************/ | ||
495 | /* | ||
496 | * finish using a volume location record | ||
497 | */ | ||
498 | void afs_put_vlocation(struct afs_vlocation *vlocation) | ||
499 | { | ||
500 | if (vlocation) { | ||
501 | struct afs_cell *cell = vlocation->cell; | ||
502 | |||
503 | down_write(&cell->vl_sem); | ||
504 | __afs_put_vlocation(vlocation); | ||
505 | up_write(&cell->vl_sem); | ||
506 | } | ||
507 | } /* end afs_put_vlocation() */ | ||
508 | 333 | ||
509 | /*****************************************************************************/ | ||
510 | /* | 334 | /* |
511 | * timeout vlocation record | 335 | * queue a vlocation record for updates |
512 | * - removes from the cell's graveyard if the usage count is zero | ||
513 | */ | 336 | */ |
514 | void afs_vlocation_do_timeout(struct afs_vlocation *vlocation) | 337 | void afs_vlocation_queue_for_updates(struct afs_vlocation *vl) |
515 | { | 338 | { |
516 | struct afs_cell *cell; | 339 | struct afs_vlocation *xvl; |
517 | 340 | ||
518 | _enter("%s", vlocation->vldb.name); | 341 | /* wait at least 10 minutes before updating... */ |
342 | vl->update_at = get_seconds() + afs_vlocation_update_timeout; | ||
519 | 343 | ||
520 | cell = vlocation->cell; | 344 | spin_lock(&afs_vlocation_updates_lock); |
521 | 345 | ||
522 | BUG_ON(atomic_read(&vlocation->usage) < 0); | 346 | if (!list_empty(&afs_vlocation_updates)) { |
523 | 347 | /* ... but wait at least 1 second more than the newest record | |
524 | /* remove from graveyard if still dead */ | 348 | * already queued so that we don't spam the VL server suddenly |
525 | spin_lock(&cell->vl_gylock); | 349 | * with lots of requests |
526 | if (atomic_read(&vlocation->usage) == 0) | 350 | */ |
527 | list_del_init(&vlocation->link); | 351 | xvl = list_entry(afs_vlocation_updates.prev, |
528 | else | 352 | struct afs_vlocation, update); |
529 | vlocation = NULL; | 353 | if (vl->update_at <= xvl->update_at) |
530 | spin_unlock(&cell->vl_gylock); | 354 | vl->update_at = xvl->update_at + 1; |
531 | 355 | } else { | |
532 | if (!vlocation) { | 356 | queue_delayed_work(afs_vlocation_update_worker, |
533 | _leave(""); | 357 | &afs_vlocation_update, |
534 | return; /* resurrected */ | 358 | afs_vlocation_update_timeout * HZ); |
535 | } | 359 | } |
536 | 360 | ||
537 | /* we can now destroy it properly */ | 361 | list_add_tail(&vl->update, &afs_vlocation_updates); |
538 | #ifdef AFS_CACHING_SUPPORT | 362 | spin_unlock(&afs_vlocation_updates_lock); |
539 | cachefs_relinquish_cookie(vlocation->cache, 0); | 363 | } |
540 | #endif | ||
541 | afs_put_cell(cell); | ||
542 | |||
543 | kfree(vlocation); | ||
544 | |||
545 | _leave(" [destroyed]"); | ||
546 | } /* end afs_vlocation_do_timeout() */ | ||
547 | 364 | ||
548 | /*****************************************************************************/ | ||
549 | /* | 365 | /* |
550 | * send an update operation to the currently selected server | 366 | * lookup volume location |
367 | * - iterate through the VL servers in a cell until one of them admits knowing | ||
368 | * about the volume in question | ||
369 | * - lookup in the local cache if not able to find on the VL server | ||
370 | * - insert/update in the local cache if did get a VL response | ||
551 | */ | 371 | */ |
552 | static int afs_vlocation_update_begin(struct afs_vlocation *vlocation) | 372 | struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, |
373 | struct key *key, | ||
374 | const char *name, | ||
375 | size_t namesz) | ||
553 | { | 376 | { |
554 | afs_voltype_t voltype; | 377 | struct afs_vlocation *vl; |
555 | afs_volid_t vid; | ||
556 | int ret; | 378 | int ret; |
557 | 379 | ||
558 | _enter("%s{ufs=%u ucs=%u}", | 380 | _enter("{%s},{%x},%*.*s,%zu", |
559 | vlocation->vldb.name, | 381 | cell->name, key_serial(key), |
560 | vlocation->upd_first_svix, | 382 | (int) namesz, (int) namesz, name, namesz); |
561 | vlocation->upd_curr_svix); | ||
562 | 383 | ||
563 | /* try to look up a cached volume in the cell VL databases by ID */ | 384 | if (namesz > sizeof(vl->vldb.name)) { |
564 | if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) { | 385 | _leave(" = -ENAMETOOLONG"); |
565 | vid = vlocation->vldb.vid[0]; | 386 | return ERR_PTR(-ENAMETOOLONG); |
566 | voltype = AFSVL_RWVOL; | ||
567 | } | ||
568 | else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) { | ||
569 | vid = vlocation->vldb.vid[1]; | ||
570 | voltype = AFSVL_ROVOL; | ||
571 | } | 387 | } |
572 | else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) { | 388 | |
573 | vid = vlocation->vldb.vid[2]; | 389 | /* see if we have an in-memory copy first */ |
574 | voltype = AFSVL_BACKVOL; | 390 | down_write(&cell->vl_sem); |
391 | spin_lock(&cell->vl_lock); | ||
392 | list_for_each_entry(vl, &cell->vl_list, link) { | ||
393 | if (vl->vldb.name[namesz] != '\0') | ||
394 | continue; | ||
395 | if (memcmp(vl->vldb.name, name, namesz) == 0) | ||
396 | goto found_in_memory; | ||
575 | } | 397 | } |
576 | else { | 398 | spin_unlock(&cell->vl_lock); |
577 | BUG(); | 399 | |
578 | vid = 0; | 400 | /* not in the cell's in-memory lists - create a new record */ |
579 | voltype = 0; | 401 | vl = afs_vlocation_alloc(cell, name, namesz); |
402 | if (!vl) { | ||
403 | up_write(&cell->vl_sem); | ||
404 | return ERR_PTR(-ENOMEM); | ||
580 | } | 405 | } |
581 | 406 | ||
582 | /* contact the chosen server */ | 407 | afs_get_cell(cell); |
583 | ret = afs_server_lookup( | ||
584 | vlocation->cell, | ||
585 | &vlocation->cell->vl_addrs[vlocation->upd_curr_svix], | ||
586 | &vlocation->upd_op.server); | ||
587 | 408 | ||
588 | switch (ret) { | 409 | list_add_tail(&vl->link, &cell->vl_list); |
589 | case 0: | 410 | vl->state = AFS_VL_CREATING; |
590 | break; | 411 | up_write(&cell->vl_sem); |
591 | case -ENOMEM: | ||
592 | case -ENONET: | ||
593 | default: | ||
594 | _leave(" = %d", ret); | ||
595 | return ret; | ||
596 | } | ||
597 | 412 | ||
598 | /* initiate the update operation */ | 413 | fill_in_record: |
599 | ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op, vid, voltype); | 414 | ret = afs_vlocation_fill_in_record(vl, key); |
600 | if (ret < 0) { | 415 | if (ret < 0) |
601 | _leave(" = %d", ret); | 416 | goto error_abandon; |
602 | return ret; | 417 | spin_lock(&vl->lock); |
418 | vl->state = AFS_VL_VALID; | ||
419 | wake_up(&vl->waitq); | ||
420 | spin_unlock(&vl->lock); | ||
421 | |||
422 | /* schedule for regular updates */ | ||
423 | afs_vlocation_queue_for_updates(vl); | ||
424 | goto success; | ||
425 | |||
426 | found_in_memory: | ||
427 | /* found in memory */ | ||
428 | _debug("found in memory"); | ||
429 | atomic_inc(&vl->usage); | ||
430 | spin_unlock(&cell->vl_lock); | ||
431 | if (!list_empty(&vl->grave)) { | ||
432 | spin_lock(&afs_vlocation_graveyard_lock); | ||
433 | list_del_init(&vl->grave); | ||
434 | spin_unlock(&afs_vlocation_graveyard_lock); | ||
603 | } | 435 | } |
436 | up_write(&cell->vl_sem); | ||
437 | |||
438 | /* see if it was an abandoned record that we might try filling in */ | ||
439 | spin_lock(&vl->lock); | ||
440 | while (vl->state != AFS_VL_VALID) { | ||
441 | afs_vlocation_state_t state = vl->state; | ||
442 | |||
443 | _debug("invalid [state %d]", state); | ||
444 | |||
445 | if ((state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME)) { | ||
446 | vl->state = AFS_VL_CREATING; | ||
447 | spin_unlock(&vl->lock); | ||
448 | goto fill_in_record; | ||
449 | } | ||
450 | |||
451 | /* must now wait for creation or update by someone else to | ||
452 | * complete */ | ||
453 | _debug("wait"); | ||
604 | 454 | ||
455 | spin_unlock(&vl->lock); | ||
456 | ret = wait_event_interruptible( | ||
457 | vl->waitq, | ||
458 | vl->state == AFS_VL_NEW || | ||
459 | vl->state == AFS_VL_VALID || | ||
460 | vl->state == AFS_VL_NO_VOLUME); | ||
461 | if (ret < 0) | ||
462 | goto error; | ||
463 | spin_lock(&vl->lock); | ||
464 | } | ||
465 | spin_unlock(&vl->lock); | ||
466 | |||
467 | success: | ||
468 | _leave(" = %p",vl); | ||
469 | return vl; | ||
470 | |||
471 | error_abandon: | ||
472 | spin_lock(&vl->lock); | ||
473 | vl->state = AFS_VL_NEW; | ||
474 | wake_up(&vl->waitq); | ||
475 | spin_unlock(&vl->lock); | ||
476 | error: | ||
477 | ASSERT(vl != NULL); | ||
478 | afs_put_vlocation(vl); | ||
605 | _leave(" = %d", ret); | 479 | _leave(" = %d", ret); |
606 | return ret; | 480 | return ERR_PTR(ret); |
607 | } /* end afs_vlocation_update_begin() */ | 481 | } |
608 | 482 | ||
609 | /*****************************************************************************/ | ||
610 | /* | 483 | /* |
611 | * abandon updating a VL record | 484 | * finish using a volume location record |
612 | * - does not restart the update timer | ||
613 | */ | 485 | */ |
614 | static void afs_vlocation_update_abandon(struct afs_vlocation *vlocation, | 486 | void afs_put_vlocation(struct afs_vlocation *vl) |
615 | afs_vlocation_upd_t state, | ||
616 | int ret) | ||
617 | { | 487 | { |
618 | _enter("%s,%u", vlocation->vldb.name, state); | 488 | if (!vl) |
619 | 489 | return; | |
620 | if (ret < 0) | ||
621 | printk("kAFS: Abandoning VL update '%s': %d\n", | ||
622 | vlocation->vldb.name, ret); | ||
623 | |||
624 | /* discard the server record */ | ||
625 | afs_put_server(vlocation->upd_op.server); | ||
626 | vlocation->upd_op.server = NULL; | ||
627 | 490 | ||
628 | spin_lock(&afs_vlocation_update_lock); | 491 | _enter("%s", vl->vldb.name); |
629 | afs_vlocation_update = NULL; | ||
630 | vlocation->upd_state = state; | ||
631 | 492 | ||
632 | /* TODO: start updating next VL record on pending list */ | 493 | ASSERTCMP(atomic_read(&vl->usage), >, 0); |
633 | 494 | ||
634 | spin_unlock(&afs_vlocation_update_lock); | 495 | if (likely(!atomic_dec_and_test(&vl->usage))) { |
496 | _leave(""); | ||
497 | return; | ||
498 | } | ||
635 | 499 | ||
636 | _leave(""); | 500 | spin_lock(&afs_vlocation_graveyard_lock); |
637 | } /* end afs_vlocation_update_abandon() */ | 501 | if (atomic_read(&vl->usage) == 0) { |
502 | _debug("buried"); | ||
503 | list_move_tail(&vl->grave, &afs_vlocation_graveyard); | ||
504 | vl->time_of_death = get_seconds(); | ||
505 | schedule_delayed_work(&afs_vlocation_reap, | ||
506 | afs_vlocation_timeout * HZ); | ||
507 | |||
508 | /* suspend updates on this record */ | ||
509 | if (!list_empty(&vl->update)) { | ||
510 | spin_lock(&afs_vlocation_updates_lock); | ||
511 | list_del_init(&vl->update); | ||
512 | spin_unlock(&afs_vlocation_updates_lock); | ||
513 | } | ||
514 | } | ||
515 | spin_unlock(&afs_vlocation_graveyard_lock); | ||
516 | _leave(" [killed?]"); | ||
517 | } | ||
638 | 518 | ||
639 | /*****************************************************************************/ | ||
640 | /* | 519 | /* |
641 | * handle periodic update timeouts and busy retry timeouts | 520 | * destroy a dead volume location record |
642 | * - called from kafstimod | ||
643 | */ | 521 | */ |
644 | static void afs_vlocation_update_timer(struct afs_timer *timer) | 522 | static void afs_vlocation_destroy(struct afs_vlocation *vl) |
645 | { | 523 | { |
646 | struct afs_vlocation *vlocation = | 524 | _enter("%p", vl); |
647 | list_entry(timer, struct afs_vlocation, upd_timer); | ||
648 | int ret; | ||
649 | 525 | ||
650 | _enter("%s", vlocation->vldb.name); | 526 | #ifdef AFS_CACHING_SUPPORT |
527 | cachefs_relinquish_cookie(vl->cache, 0); | ||
528 | #endif | ||
651 | 529 | ||
652 | /* only update if not in the graveyard (defend against putting too) */ | 530 | afs_put_cell(vl->cell); |
653 | spin_lock(&vlocation->cell->vl_gylock); | 531 | kfree(vl); |
532 | } | ||
654 | 533 | ||
655 | if (!atomic_read(&vlocation->usage)) | 534 | /* |
656 | goto out_unlock1; | 535 | * reap dead volume location records |
536 | */ | ||
537 | static void afs_vlocation_reaper(struct work_struct *work) | ||
538 | { | ||
539 | LIST_HEAD(corpses); | ||
540 | struct afs_vlocation *vl; | ||
541 | unsigned long delay, expiry; | ||
542 | time_t now; | ||
657 | 543 | ||
658 | spin_lock(&afs_vlocation_update_lock); | 544 | _enter(""); |
659 | 545 | ||
660 | /* if we were woken up due to EBUSY sleep then restart immediately if | 546 | now = get_seconds(); |
661 | * possible or else jump to front of pending queue */ | 547 | spin_lock(&afs_vlocation_graveyard_lock); |
662 | if (vlocation->upd_state == AFS_VLUPD_BUSYSLEEP) { | 548 | |
663 | if (afs_vlocation_update) { | 549 | while (!list_empty(&afs_vlocation_graveyard)) { |
664 | list_add(&vlocation->upd_op.link, | 550 | vl = list_entry(afs_vlocation_graveyard.next, |
665 | &afs_vlocation_update_pendq); | 551 | struct afs_vlocation, grave); |
552 | |||
553 | _debug("check %p", vl); | ||
554 | |||
555 | /* the queue is ordered most dead first */ | ||
556 | expiry = vl->time_of_death + afs_vlocation_timeout; | ||
557 | if (expiry > now) { | ||
558 | delay = (expiry - now) * HZ; | ||
559 | _debug("delay %lu", delay); | ||
560 | if (!schedule_delayed_work(&afs_vlocation_reap, | ||
561 | delay)) { | ||
562 | cancel_delayed_work(&afs_vlocation_reap); | ||
563 | schedule_delayed_work(&afs_vlocation_reap, | ||
564 | delay); | ||
565 | } | ||
566 | break; | ||
666 | } | 567 | } |
667 | else { | 568 | |
668 | afs_get_vlocation(vlocation); | 569 | spin_lock(&vl->cell->vl_lock); |
669 | afs_vlocation_update = vlocation; | 570 | if (atomic_read(&vl->usage) > 0) { |
670 | vlocation->upd_state = AFS_VLUPD_INPROGRESS; | 571 | _debug("no reap"); |
572 | list_del_init(&vl->grave); | ||
573 | } else { | ||
574 | _debug("reap"); | ||
575 | list_move_tail(&vl->grave, &corpses); | ||
576 | list_del_init(&vl->link); | ||
671 | } | 577 | } |
672 | goto out_unlock2; | 578 | spin_unlock(&vl->cell->vl_lock); |
673 | } | 579 | } |
674 | 580 | ||
675 | /* put on pending queue if there's already another update in progress */ | 581 | spin_unlock(&afs_vlocation_graveyard_lock); |
676 | if (afs_vlocation_update) { | ||
677 | vlocation->upd_state = AFS_VLUPD_PENDING; | ||
678 | list_add_tail(&vlocation->upd_op.link, | ||
679 | &afs_vlocation_update_pendq); | ||
680 | goto out_unlock2; | ||
681 | } | ||
682 | 582 | ||
683 | /* hold a ref on it while actually updating */ | 583 | /* now reap the corpses we've extracted */ |
684 | afs_get_vlocation(vlocation); | 584 | while (!list_empty(&corpses)) { |
685 | afs_vlocation_update = vlocation; | 585 | vl = list_entry(corpses.next, struct afs_vlocation, grave); |
686 | vlocation->upd_state = AFS_VLUPD_INPROGRESS; | 586 | list_del(&vl->grave); |
687 | 587 | afs_vlocation_destroy(vl); | |
688 | spin_unlock(&afs_vlocation_update_lock); | ||
689 | spin_unlock(&vlocation->cell->vl_gylock); | ||
690 | |||
691 | /* okay... we can start the update */ | ||
692 | _debug("BEGIN VL UPDATE [%s]", vlocation->vldb.name); | ||
693 | vlocation->upd_first_svix = vlocation->cell->vl_curr_svix; | ||
694 | vlocation->upd_curr_svix = vlocation->upd_first_svix; | ||
695 | vlocation->upd_rej_cnt = 0; | ||
696 | vlocation->upd_busy_cnt = 0; | ||
697 | |||
698 | ret = afs_vlocation_update_begin(vlocation); | ||
699 | if (ret < 0) { | ||
700 | afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret); | ||
701 | afs_kafstimod_add_timer(&vlocation->upd_timer, | ||
702 | AFS_VLDB_TIMEOUT); | ||
703 | afs_put_vlocation(vlocation); | ||
704 | } | 588 | } |
705 | 589 | ||
706 | _leave(""); | 590 | _leave(""); |
707 | return; | 591 | } |
708 | 592 | ||
709 | out_unlock2: | 593 | /* |
710 | spin_unlock(&afs_vlocation_update_lock); | 594 | * initialise the VL update process |
711 | out_unlock1: | 595 | */ |
712 | spin_unlock(&vlocation->cell->vl_gylock); | 596 | int __init afs_vlocation_update_init(void) |
713 | _leave(""); | 597 | { |
714 | return; | 598 | afs_vlocation_update_worker = |
599 | create_singlethread_workqueue("kafs_vlupdated"); | ||
600 | return afs_vlocation_update_worker ? 0 : -ENOMEM; | ||
601 | } | ||
715 | 602 | ||
716 | } /* end afs_vlocation_update_timer() */ | 603 | /* |
604 | * discard all the volume location records for rmmod | ||
605 | */ | ||
606 | void __exit afs_vlocation_purge(void) | ||
607 | { | ||
608 | afs_vlocation_timeout = 0; | ||
609 | |||
610 | spin_lock(&afs_vlocation_updates_lock); | ||
611 | list_del_init(&afs_vlocation_updates); | ||
612 | spin_unlock(&afs_vlocation_updates_lock); | ||
613 | cancel_delayed_work(&afs_vlocation_update); | ||
614 | queue_delayed_work(afs_vlocation_update_worker, | ||
615 | &afs_vlocation_update, 0); | ||
616 | destroy_workqueue(afs_vlocation_update_worker); | ||
617 | |||
618 | cancel_delayed_work(&afs_vlocation_reap); | ||
619 | schedule_delayed_work(&afs_vlocation_reap, 0); | ||
620 | } | ||
717 | 621 | ||
718 | /*****************************************************************************/ | ||
719 | /* | 622 | /* |
720 | * attend to an update operation upon which an event happened | 623 | * update a volume location |
721 | * - called in kafsasyncd context | ||
722 | */ | 624 | */ |
723 | static void afs_vlocation_update_attend(struct afs_async_op *op) | 625 | static void afs_vlocation_updater(struct work_struct *work) |
724 | { | 626 | { |
725 | struct afs_cache_vlocation vldb; | 627 | struct afs_cache_vlocation vldb; |
726 | struct afs_vlocation *vlocation = | 628 | struct afs_vlocation *vl, *xvl; |
727 | list_entry(op, struct afs_vlocation, upd_op); | 629 | time_t now; |
728 | unsigned tmp; | 630 | long timeout; |
729 | int ret; | 631 | int ret; |
730 | 632 | ||
731 | _enter("%s", vlocation->vldb.name); | 633 | _enter(""); |
732 | |||
733 | ret = afs_rxvl_get_entry_by_id_async2(op, &vldb); | ||
734 | switch (ret) { | ||
735 | case -EAGAIN: | ||
736 | _leave(" [unfinished]"); | ||
737 | return; | ||
738 | |||
739 | case 0: | ||
740 | _debug("END VL UPDATE: %d\n", ret); | ||
741 | vlocation->valid = 1; | ||
742 | |||
743 | _debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }", | ||
744 | vldb.vidmask, | ||
745 | ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0], | ||
746 | ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1], | ||
747 | ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2] | ||
748 | ); | ||
749 | |||
750 | _debug("Vids: %08x %08x %08x", | ||
751 | vldb.vid[0], vldb.vid[1], vldb.vid[2]); | ||
752 | |||
753 | afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0); | ||
754 | |||
755 | down_write(&vlocation->cell->vl_sem); | ||
756 | |||
757 | /* actually update the cache */ | ||
758 | if (strncmp(vldb.name, vlocation->vldb.name, | ||
759 | sizeof(vlocation->vldb.name)) != 0) | ||
760 | printk("kAFS: name of volume '%s'" | ||
761 | " changed to '%s' on server\n", | ||
762 | vlocation->vldb.name, vldb.name); | ||
763 | |||
764 | memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb)); | ||
765 | |||
766 | #if 0 | ||
767 | /* TODO update volume entry in local cache */ | ||
768 | #endif | ||
769 | |||
770 | up_write(&vlocation->cell->vl_sem); | ||
771 | |||
772 | if (ret < 0) | ||
773 | printk("kAFS: failed to update local cache: %d\n", ret); | ||
774 | |||
775 | afs_kafstimod_add_timer(&vlocation->upd_timer, | ||
776 | AFS_VLDB_TIMEOUT); | ||
777 | afs_put_vlocation(vlocation); | ||
778 | _leave(" [found]"); | ||
779 | return; | ||
780 | |||
781 | case -ENOMEDIUM: | ||
782 | vlocation->upd_rej_cnt++; | ||
783 | goto try_next; | ||
784 | |||
785 | /* the server is locked - retry in a very short while */ | ||
786 | case -EBUSY: | ||
787 | vlocation->upd_busy_cnt++; | ||
788 | if (vlocation->upd_busy_cnt > 3) | ||
789 | goto try_next; /* too many retries */ | ||
790 | |||
791 | afs_vlocation_update_abandon(vlocation, | ||
792 | AFS_VLUPD_BUSYSLEEP, 0); | ||
793 | afs_kafstimod_add_timer(&vlocation->upd_timer, HZ / 2); | ||
794 | afs_put_vlocation(vlocation); | ||
795 | _leave(" [busy]"); | ||
796 | return; | ||
797 | |||
798 | case -ENETUNREACH: | ||
799 | case -EHOSTUNREACH: | ||
800 | case -ECONNREFUSED: | ||
801 | case -EREMOTEIO: | ||
802 | /* record bad vlserver info in the cell too | ||
803 | * - TODO: use down_write_trylock() if available | ||
804 | */ | ||
805 | if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix) | ||
806 | vlocation->cell->vl_curr_svix = | ||
807 | vlocation->cell->vl_curr_svix % | ||
808 | vlocation->cell->vl_naddrs; | ||
809 | |||
810 | case -EBADRQC: | ||
811 | case -EINVAL: | ||
812 | case -EACCES: | ||
813 | case -EBADMSG: | ||
814 | goto try_next; | ||
815 | |||
816 | default: | ||
817 | goto abandon; | ||
818 | } | ||
819 | |||
820 | /* try contacting the next server */ | ||
821 | try_next: | ||
822 | vlocation->upd_busy_cnt = 0; | ||
823 | |||
824 | /* discard the server record */ | ||
825 | afs_put_server(vlocation->upd_op.server); | ||
826 | vlocation->upd_op.server = NULL; | ||
827 | 634 | ||
828 | tmp = vlocation->cell->vl_naddrs; | 635 | now = get_seconds(); |
829 | if (tmp == 0) | ||
830 | goto abandon; | ||
831 | 636 | ||
832 | vlocation->upd_curr_svix++; | 637 | /* find a record to update */ |
833 | if (vlocation->upd_curr_svix >= tmp) | 638 | spin_lock(&afs_vlocation_updates_lock); |
834 | vlocation->upd_curr_svix = 0; | 639 | for (;;) { |
835 | if (vlocation->upd_first_svix >= tmp) | 640 | if (list_empty(&afs_vlocation_updates)) { |
836 | vlocation->upd_first_svix = tmp - 1; | 641 | spin_unlock(&afs_vlocation_updates_lock); |
642 | _leave(" [nothing]"); | ||
643 | return; | ||
644 | } | ||
837 | 645 | ||
838 | /* move to the next server */ | 646 | vl = list_entry(afs_vlocation_updates.next, |
839 | if (vlocation->upd_curr_svix != vlocation->upd_first_svix) { | 647 | struct afs_vlocation, update); |
840 | afs_vlocation_update_begin(vlocation); | 648 | if (atomic_read(&vl->usage) > 0) |
841 | _leave(" [next]"); | 649 | break; |
842 | return; | 650 | list_del_init(&vl->update); |
843 | } | 651 | } |
844 | 652 | ||
845 | /* run out of servers to try - was the volume rejected? */ | 653 | timeout = vl->update_at - now; |
846 | if (vlocation->upd_rej_cnt > 0) { | 654 | if (timeout > 0) { |
847 | printk("kAFS: Active volume no longer valid '%s'\n", | 655 | queue_delayed_work(afs_vlocation_update_worker, |
848 | vlocation->vldb.name); | 656 | &afs_vlocation_update, timeout * HZ); |
849 | vlocation->valid = 0; | 657 | spin_unlock(&afs_vlocation_updates_lock); |
850 | afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0); | 658 | _leave(" [nothing]"); |
851 | afs_kafstimod_add_timer(&vlocation->upd_timer, | ||
852 | AFS_VLDB_TIMEOUT); | ||
853 | afs_put_vlocation(vlocation); | ||
854 | _leave(" [invalidated]"); | ||
855 | return; | 659 | return; |
856 | } | 660 | } |
857 | 661 | ||
858 | /* abandon the update */ | 662 | list_del_init(&vl->update); |
859 | abandon: | 663 | atomic_inc(&vl->usage); |
860 | afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret); | 664 | spin_unlock(&afs_vlocation_updates_lock); |
861 | afs_kafstimod_add_timer(&vlocation->upd_timer, HZ * 10); | ||
862 | afs_put_vlocation(vlocation); | ||
863 | _leave(" [abandoned]"); | ||
864 | |||
865 | } /* end afs_vlocation_update_attend() */ | ||
866 | |||
867 | /*****************************************************************************/ | ||
868 | /* | ||
869 | * deal with an update operation being discarded | ||
870 | * - called in kafsasyncd context when it's dying due to rmmod | ||
871 | * - the call has already been aborted and put()'d | ||
872 | */ | ||
873 | static void afs_vlocation_update_discard(struct afs_async_op *op) | ||
874 | { | ||
875 | struct afs_vlocation *vlocation = | ||
876 | list_entry(op, struct afs_vlocation, upd_op); | ||
877 | 665 | ||
878 | _enter("%s", vlocation->vldb.name); | 666 | /* we can now perform the update */ |
667 | _debug("update %s", vl->vldb.name); | ||
668 | vl->state = AFS_VL_UPDATING; | ||
669 | vl->upd_rej_cnt = 0; | ||
670 | vl->upd_busy_cnt = 0; | ||
879 | 671 | ||
880 | afs_put_server(op->server); | 672 | ret = afs_vlocation_update_record(vl, NULL, &vldb); |
881 | op->server = NULL; | 673 | spin_lock(&vl->lock); |
674 | switch (ret) { | ||
675 | case 0: | ||
676 | afs_vlocation_apply_update(vl, &vldb); | ||
677 | vl->state = AFS_VL_VALID; | ||
678 | wake_up(&vl->waitq); | ||
679 | break; | ||
680 | case -ENOMEDIUM: | ||
681 | vl->state = AFS_VL_VOLUME_DELETED; | ||
682 | break; | ||
683 | default: | ||
684 | vl->state = AFS_VL_UNCERTAIN; | ||
685 | break; | ||
686 | } | ||
687 | spin_unlock(&vl->lock); | ||
882 | 688 | ||
883 | afs_put_vlocation(vlocation); | 689 | /* and then reschedule */ |
690 | _debug("reschedule"); | ||
691 | vl->update_at = get_seconds() + afs_vlocation_update_timeout; | ||
884 | 692 | ||
885 | _leave(""); | 693 | spin_lock(&afs_vlocation_updates_lock); |
886 | } /* end afs_vlocation_update_discard() */ | ||
887 | 694 | ||
888 | /*****************************************************************************/ | 695 | if (!list_empty(&afs_vlocation_updates)) { |
889 | /* | 696 | /* next update in 10 minutes, but wait at least 1 second more |
890 | * match a VLDB record stored in the cache | 697 | * than the newest record already queued so that we don't spam |
891 | * - may also load target from entry | 698 | * the VL server suddenly with lots of requests |
892 | */ | 699 | */ |
893 | #ifdef AFS_CACHING_SUPPORT | 700 | xvl = list_entry(afs_vlocation_updates.prev, |
894 | static cachefs_match_val_t afs_vlocation_cache_match(void *target, | 701 | struct afs_vlocation, update); |
895 | const void *entry) | 702 | if (vl->update_at <= xvl->update_at) |
896 | { | 703 | vl->update_at = xvl->update_at + 1; |
897 | const struct afs_cache_vlocation *vldb = entry; | 704 | xvl = list_entry(afs_vlocation_updates.next, |
898 | struct afs_vlocation *vlocation = target; | 705 | struct afs_vlocation, update); |
899 | 706 | timeout = xvl->update_at - now; | |
900 | _enter("{%s},{%s}", vlocation->vldb.name, vldb->name); | 707 | if (timeout < 0) |
901 | 708 | timeout = 0; | |
902 | if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0 | 709 | } else { |
903 | ) { | 710 | timeout = afs_vlocation_update_timeout; |
904 | if (!vlocation->valid || | ||
905 | vlocation->vldb.rtime == vldb->rtime | ||
906 | ) { | ||
907 | vlocation->vldb = *vldb; | ||
908 | vlocation->valid = 1; | ||
909 | _leave(" = SUCCESS [c->m]"); | ||
910 | return CACHEFS_MATCH_SUCCESS; | ||
911 | } | ||
912 | /* need to update cache if cached info differs */ | ||
913 | else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) { | ||
914 | /* delete if VIDs for this name differ */ | ||
915 | if (memcmp(&vlocation->vldb.vid, | ||
916 | &vldb->vid, | ||
917 | sizeof(vldb->vid)) != 0) { | ||
918 | _leave(" = DELETE"); | ||
919 | return CACHEFS_MATCH_SUCCESS_DELETE; | ||
920 | } | ||
921 | |||
922 | _leave(" = UPDATE"); | ||
923 | return CACHEFS_MATCH_SUCCESS_UPDATE; | ||
924 | } | ||
925 | else { | ||
926 | _leave(" = SUCCESS"); | ||
927 | return CACHEFS_MATCH_SUCCESS; | ||
928 | } | ||
929 | } | 711 | } |
930 | 712 | ||
931 | _leave(" = FAILED"); | 713 | ASSERT(list_empty(&vl->update)); |
932 | return CACHEFS_MATCH_FAILED; | ||
933 | } /* end afs_vlocation_cache_match() */ | ||
934 | #endif | ||
935 | |||
936 | /*****************************************************************************/ | ||
937 | /* | ||
938 | * update a VLDB record stored in the cache | ||
939 | */ | ||
940 | #ifdef AFS_CACHING_SUPPORT | ||
941 | static void afs_vlocation_cache_update(void *source, void *entry) | ||
942 | { | ||
943 | struct afs_cache_vlocation *vldb = entry; | ||
944 | struct afs_vlocation *vlocation = source; | ||
945 | 714 | ||
946 | _enter(""); | 715 | list_add_tail(&vl->update, &afs_vlocation_updates); |
947 | |||
948 | *vldb = vlocation->vldb; | ||
949 | 716 | ||
950 | } /* end afs_vlocation_cache_update() */ | 717 | _debug("timeout %ld", timeout); |
951 | #endif | 718 | queue_delayed_work(afs_vlocation_update_worker, |
719 | &afs_vlocation_update, timeout * HZ); | ||
720 | spin_unlock(&afs_vlocation_updates_lock); | ||
721 | afs_put_vlocation(vl); | ||
722 | } | ||
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index cf62da5d7825..a1904ab8426a 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* vnode.c: AFS vnode management | 1 | /* AFS vnode management |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -14,142 +14,237 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
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> | ||
18 | #include "volume.h" | ||
19 | #include "cell.h" | ||
20 | #include "cmservice.h" | ||
21 | #include "fsclient.h" | ||
22 | #include "vlclient.h" | ||
23 | #include "vnode.h" | ||
24 | #include "internal.h" | 17 | #include "internal.h" |
25 | 18 | ||
26 | static void afs_vnode_cb_timed_out(struct afs_timer *timer); | 19 | #if 0 |
20 | static noinline bool dump_tree_aux(struct rb_node *node, struct rb_node *parent, | ||
21 | int depth, char lr) | ||
22 | { | ||
23 | struct afs_vnode *vnode; | ||
24 | bool bad = false; | ||
25 | |||
26 | if (!node) | ||
27 | return false; | ||
28 | |||
29 | if (node->rb_left) | ||
30 | bad = dump_tree_aux(node->rb_left, node, depth + 2, '/'); | ||
31 | |||
32 | vnode = rb_entry(node, struct afs_vnode, cb_promise); | ||
33 | _debug("%c %*.*s%c%p {%d}", | ||
34 | rb_is_red(node) ? 'R' : 'B', | ||
35 | depth, depth, "", lr, | ||
36 | vnode, vnode->cb_expires_at); | ||
37 | if (rb_parent(node) != parent) { | ||
38 | printk("BAD: %p != %p\n", rb_parent(node), parent); | ||
39 | bad = true; | ||
40 | } | ||
27 | 41 | ||
28 | struct afs_timer_ops afs_vnode_cb_timed_out_ops = { | 42 | if (node->rb_right) |
29 | .timed_out = afs_vnode_cb_timed_out, | 43 | bad |= dump_tree_aux(node->rb_right, node, depth + 2, '\\'); |
30 | }; | ||
31 | 44 | ||
32 | #ifdef AFS_CACHING_SUPPORT | 45 | return bad; |
33 | static cachefs_match_val_t afs_vnode_cache_match(void *target, | 46 | } |
34 | const void *entry); | ||
35 | static void afs_vnode_cache_update(void *source, void *entry); | ||
36 | 47 | ||
37 | struct cachefs_index_def afs_vnode_cache_index_def = { | 48 | static noinline void dump_tree(const char *name, struct afs_server *server) |
38 | .name = "vnode", | 49 | { |
39 | .data_size = sizeof(struct afs_cache_vnode), | 50 | _enter("%s", name); |
40 | .keys[0] = { CACHEFS_INDEX_KEYS_BIN, 4 }, | 51 | if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-')) |
41 | .match = afs_vnode_cache_match, | 52 | BUG(); |
42 | .update = afs_vnode_cache_update, | 53 | } |
43 | }; | ||
44 | #endif | 54 | #endif |
45 | 55 | ||
46 | /*****************************************************************************/ | ||
47 | /* | 56 | /* |
48 | * handle a callback timing out | 57 | * insert a vnode into the backing server's vnode tree |
49 | * TODO: retain a ref to vnode struct for an outstanding callback timeout | ||
50 | */ | 58 | */ |
51 | static void afs_vnode_cb_timed_out(struct afs_timer *timer) | 59 | static void afs_install_vnode(struct afs_vnode *vnode, |
60 | struct afs_server *server) | ||
52 | { | 61 | { |
53 | struct afs_server *oldserver; | 62 | struct afs_server *old_server = vnode->server; |
54 | struct afs_vnode *vnode; | 63 | struct afs_vnode *xvnode; |
64 | struct rb_node *parent, **p; | ||
55 | 65 | ||
56 | vnode = list_entry(timer, struct afs_vnode, cb_timeout); | 66 | _enter("%p,%p", vnode, server); |
57 | 67 | ||
58 | _enter("%p", vnode); | 68 | if (old_server) { |
69 | spin_lock(&old_server->fs_lock); | ||
70 | rb_erase(&vnode->server_rb, &old_server->fs_vnodes); | ||
71 | spin_unlock(&old_server->fs_lock); | ||
72 | } | ||
59 | 73 | ||
60 | /* set the changed flag in the vnode and release the server */ | 74 | afs_get_server(server); |
61 | spin_lock(&vnode->lock); | 75 | vnode->server = server; |
76 | afs_put_server(old_server); | ||
77 | |||
78 | /* insert into the server's vnode tree in FID order */ | ||
79 | spin_lock(&server->fs_lock); | ||
80 | |||
81 | parent = NULL; | ||
82 | p = &server->fs_vnodes.rb_node; | ||
83 | while (*p) { | ||
84 | parent = *p; | ||
85 | xvnode = rb_entry(parent, struct afs_vnode, server_rb); | ||
86 | if (vnode->fid.vid < xvnode->fid.vid) | ||
87 | p = &(*p)->rb_left; | ||
88 | else if (vnode->fid.vid > xvnode->fid.vid) | ||
89 | p = &(*p)->rb_right; | ||
90 | else if (vnode->fid.vnode < xvnode->fid.vnode) | ||
91 | p = &(*p)->rb_left; | ||
92 | else if (vnode->fid.vnode > xvnode->fid.vnode) | ||
93 | p = &(*p)->rb_right; | ||
94 | else if (vnode->fid.unique < xvnode->fid.unique) | ||
95 | p = &(*p)->rb_left; | ||
96 | else if (vnode->fid.unique > xvnode->fid.unique) | ||
97 | p = &(*p)->rb_right; | ||
98 | else | ||
99 | BUG(); /* can't happen unless afs_iget() malfunctions */ | ||
100 | } | ||
101 | |||
102 | rb_link_node(&vnode->server_rb, parent, p); | ||
103 | rb_insert_color(&vnode->server_rb, &server->fs_vnodes); | ||
62 | 104 | ||
63 | oldserver = xchg(&vnode->cb_server, NULL); | 105 | spin_unlock(&server->fs_lock); |
64 | if (oldserver) { | 106 | _leave(""); |
65 | vnode->flags |= AFS_VNODE_CHANGED; | 107 | } |
66 | 108 | ||
67 | spin_lock(&afs_cb_hash_lock); | 109 | /* |
68 | list_del_init(&vnode->cb_hash_link); | 110 | * insert a vnode into the promising server's update/expiration tree |
69 | spin_unlock(&afs_cb_hash_lock); | 111 | * - caller must hold vnode->lock |
112 | */ | ||
113 | static void afs_vnode_note_promise(struct afs_vnode *vnode, | ||
114 | struct afs_server *server) | ||
115 | { | ||
116 | struct afs_server *old_server; | ||
117 | struct afs_vnode *xvnode; | ||
118 | struct rb_node *parent, **p; | ||
70 | 119 | ||
71 | spin_lock(&oldserver->cb_lock); | 120 | _enter("%p,%p", vnode, server); |
72 | list_del_init(&vnode->cb_link); | 121 | |
73 | spin_unlock(&oldserver->cb_lock); | 122 | ASSERT(server != NULL); |
123 | |||
124 | old_server = vnode->server; | ||
125 | if (vnode->cb_promised) { | ||
126 | if (server == old_server && | ||
127 | vnode->cb_expires == vnode->cb_expires_at) { | ||
128 | _leave(" [no change]"); | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | spin_lock(&old_server->cb_lock); | ||
133 | if (vnode->cb_promised) { | ||
134 | _debug("delete"); | ||
135 | rb_erase(&vnode->cb_promise, &old_server->cb_promises); | ||
136 | vnode->cb_promised = false; | ||
137 | } | ||
138 | spin_unlock(&old_server->cb_lock); | ||
74 | } | 139 | } |
75 | 140 | ||
76 | spin_unlock(&vnode->lock); | 141 | if (vnode->server != server) |
142 | afs_install_vnode(vnode, server); | ||
143 | |||
144 | vnode->cb_expires_at = vnode->cb_expires; | ||
145 | _debug("PROMISE on %p {%lu}", | ||
146 | vnode, (unsigned long) vnode->cb_expires_at); | ||
147 | |||
148 | /* abuse an RB-tree to hold the expiration order (we may have multiple | ||
149 | * items with the same expiration time) */ | ||
150 | spin_lock(&server->cb_lock); | ||
151 | |||
152 | parent = NULL; | ||
153 | p = &server->cb_promises.rb_node; | ||
154 | while (*p) { | ||
155 | parent = *p; | ||
156 | xvnode = rb_entry(parent, struct afs_vnode, cb_promise); | ||
157 | if (vnode->cb_expires_at < xvnode->cb_expires_at) | ||
158 | p = &(*p)->rb_left; | ||
159 | else | ||
160 | p = &(*p)->rb_right; | ||
161 | } | ||
77 | 162 | ||
78 | afs_put_server(oldserver); | 163 | rb_link_node(&vnode->cb_promise, parent, p); |
164 | rb_insert_color(&vnode->cb_promise, &server->cb_promises); | ||
165 | vnode->cb_promised = true; | ||
79 | 166 | ||
167 | spin_unlock(&server->cb_lock); | ||
80 | _leave(""); | 168 | _leave(""); |
81 | } /* end afs_vnode_cb_timed_out() */ | 169 | } |
82 | 170 | ||
83 | /*****************************************************************************/ | ||
84 | /* | 171 | /* |
85 | * finish off updating the recorded status of a file | 172 | * handle remote file deletion by discarding the callback promise |
173 | */ | ||
174 | static void afs_vnode_deleted_remotely(struct afs_vnode *vnode) | ||
175 | { | ||
176 | struct afs_server *server; | ||
177 | |||
178 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | ||
179 | |||
180 | server = vnode->server; | ||
181 | if (vnode->cb_promised) { | ||
182 | spin_lock(&server->cb_lock); | ||
183 | if (vnode->cb_promised) { | ||
184 | rb_erase(&vnode->cb_promise, &server->cb_promises); | ||
185 | vnode->cb_promised = false; | ||
186 | } | ||
187 | spin_unlock(&server->cb_lock); | ||
188 | } | ||
189 | |||
190 | spin_lock(&vnode->server->fs_lock); | ||
191 | rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes); | ||
192 | spin_unlock(&vnode->server->fs_lock); | ||
193 | |||
194 | vnode->server = NULL; | ||
195 | afs_put_server(server); | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * finish off updating the recorded status of a file after a successful | ||
200 | * operation completion | ||
86 | * - starts callback expiry timer | 201 | * - starts callback expiry timer |
87 | * - adds to server's callback list | 202 | * - adds to server's callback list |
88 | */ | 203 | */ |
89 | static void afs_vnode_finalise_status_update(struct afs_vnode *vnode, | 204 | void afs_vnode_finalise_status_update(struct afs_vnode *vnode, |
90 | struct afs_server *server, | 205 | struct afs_server *server) |
91 | int ret) | ||
92 | { | 206 | { |
93 | struct afs_server *oldserver = NULL; | 207 | struct afs_server *oldserver = NULL; |
94 | 208 | ||
95 | _enter("%p,%p,%d", vnode, server, ret); | 209 | _enter("%p,%p", vnode, server); |
96 | 210 | ||
97 | spin_lock(&vnode->lock); | 211 | spin_lock(&vnode->lock); |
212 | clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | ||
213 | afs_vnode_note_promise(vnode, server); | ||
214 | vnode->update_cnt--; | ||
215 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
216 | spin_unlock(&vnode->lock); | ||
217 | |||
218 | wake_up_all(&vnode->update_waitq); | ||
219 | afs_put_server(oldserver); | ||
220 | _leave(""); | ||
221 | } | ||
98 | 222 | ||
99 | vnode->flags &= ~AFS_VNODE_CHANGED; | 223 | /* |
224 | * finish off updating the recorded status of a file after an operation failed | ||
225 | */ | ||
226 | static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret) | ||
227 | { | ||
228 | _enter("%p,%d", vnode, ret); | ||
100 | 229 | ||
101 | if (ret == 0) { | 230 | spin_lock(&vnode->lock); |
102 | /* adjust the callback timeout appropriately */ | ||
103 | afs_kafstimod_add_timer(&vnode->cb_timeout, | ||
104 | vnode->cb_expiry * HZ); | ||
105 | |||
106 | spin_lock(&afs_cb_hash_lock); | ||
107 | list_move_tail(&vnode->cb_hash_link, | ||
108 | &afs_cb_hash(server, &vnode->fid)); | ||
109 | spin_unlock(&afs_cb_hash_lock); | ||
110 | |||
111 | /* swap ref to old callback server with that for new callback | ||
112 | * server */ | ||
113 | oldserver = xchg(&vnode->cb_server, server); | ||
114 | if (oldserver != server) { | ||
115 | if (oldserver) { | ||
116 | spin_lock(&oldserver->cb_lock); | ||
117 | list_del_init(&vnode->cb_link); | ||
118 | spin_unlock(&oldserver->cb_lock); | ||
119 | } | ||
120 | 231 | ||
121 | afs_get_server(server); | 232 | clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
122 | spin_lock(&server->cb_lock); | ||
123 | list_add_tail(&vnode->cb_link, &server->cb_promises); | ||
124 | spin_unlock(&server->cb_lock); | ||
125 | } | ||
126 | else { | ||
127 | /* same server */ | ||
128 | oldserver = NULL; | ||
129 | } | ||
130 | } | ||
131 | else if (ret == -ENOENT) { | ||
132 | /* the file was deleted - clear the callback timeout */ | ||
133 | oldserver = xchg(&vnode->cb_server, NULL); | ||
134 | afs_kafstimod_del_timer(&vnode->cb_timeout); | ||
135 | 233 | ||
234 | if (ret == -ENOENT) { | ||
235 | /* the file was deleted on the server */ | ||
136 | _debug("got NOENT from server - marking file deleted"); | 236 | _debug("got NOENT from server - marking file deleted"); |
137 | vnode->flags |= AFS_VNODE_DELETED; | 237 | afs_vnode_deleted_remotely(vnode); |
138 | } | 238 | } |
139 | 239 | ||
140 | vnode->update_cnt--; | 240 | vnode->update_cnt--; |
141 | 241 | ASSERTCMP(vnode->update_cnt, >=, 0); | |
142 | spin_unlock(&vnode->lock); | 242 | spin_unlock(&vnode->lock); |
143 | 243 | ||
144 | wake_up_all(&vnode->update_waitq); | 244 | wake_up_all(&vnode->update_waitq); |
145 | |||
146 | afs_put_server(oldserver); | ||
147 | |||
148 | _leave(""); | 245 | _leave(""); |
246 | } | ||
149 | 247 | ||
150 | } /* end afs_vnode_finalise_status_update() */ | ||
151 | |||
152 | /*****************************************************************************/ | ||
153 | /* | 248 | /* |
154 | * fetch file status from the volume | 249 | * fetch file status from the volume |
155 | * - don't issue a fetch if: | 250 | * - don't issue a fetch if: |
@@ -157,9 +252,11 @@ static void afs_vnode_finalise_status_update(struct afs_vnode *vnode, | |||
157 | * - there are any outstanding ops that will fetch the status | 252 | * - there are any outstanding ops that will fetch the status |
158 | * - TODO implement local caching | 253 | * - TODO implement local caching |
159 | */ | 254 | */ |
160 | int afs_vnode_fetch_status(struct afs_vnode *vnode) | 255 | int afs_vnode_fetch_status(struct afs_vnode *vnode, |
256 | struct afs_vnode *auth_vnode, struct key *key) | ||
161 | { | 257 | { |
162 | struct afs_server *server; | 258 | struct afs_server *server; |
259 | unsigned long acl_order; | ||
163 | int ret; | 260 | int ret; |
164 | 261 | ||
165 | DECLARE_WAITQUEUE(myself, current); | 262 | DECLARE_WAITQUEUE(myself, current); |
@@ -168,38 +265,49 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode) | |||
168 | vnode->volume->vlocation->vldb.name, | 265 | vnode->volume->vlocation->vldb.name, |
169 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | 266 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); |
170 | 267 | ||
171 | if (!(vnode->flags & AFS_VNODE_CHANGED) && vnode->cb_server) { | 268 | if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && |
269 | vnode->cb_promised) { | ||
172 | _leave(" [unchanged]"); | 270 | _leave(" [unchanged]"); |
173 | return 0; | 271 | return 0; |
174 | } | 272 | } |
175 | 273 | ||
176 | if (vnode->flags & AFS_VNODE_DELETED) { | 274 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { |
177 | _leave(" [deleted]"); | 275 | _leave(" [deleted]"); |
178 | return -ENOENT; | 276 | return -ENOENT; |
179 | } | 277 | } |
180 | 278 | ||
279 | acl_order = 0; | ||
280 | if (auth_vnode) | ||
281 | acl_order = auth_vnode->acl_order; | ||
282 | |||
181 | spin_lock(&vnode->lock); | 283 | spin_lock(&vnode->lock); |
182 | 284 | ||
183 | if (!(vnode->flags & AFS_VNODE_CHANGED)) { | 285 | if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && |
286 | vnode->cb_promised) { | ||
184 | spin_unlock(&vnode->lock); | 287 | spin_unlock(&vnode->lock); |
185 | _leave(" [unchanged]"); | 288 | _leave(" [unchanged]"); |
186 | return 0; | 289 | return 0; |
187 | } | 290 | } |
188 | 291 | ||
292 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
293 | |||
189 | if (vnode->update_cnt > 0) { | 294 | if (vnode->update_cnt > 0) { |
190 | /* someone else started a fetch */ | 295 | /* someone else started a fetch */ |
296 | _debug("wait on fetch %d", vnode->update_cnt); | ||
297 | |||
191 | set_current_state(TASK_UNINTERRUPTIBLE); | 298 | set_current_state(TASK_UNINTERRUPTIBLE); |
299 | ASSERT(myself.func != NULL); | ||
192 | add_wait_queue(&vnode->update_waitq, &myself); | 300 | add_wait_queue(&vnode->update_waitq, &myself); |
193 | 301 | ||
194 | /* wait for the status to be updated */ | 302 | /* wait for the status to be updated */ |
195 | for (;;) { | 303 | for (;;) { |
196 | if (!(vnode->flags & AFS_VNODE_CHANGED)) | 304 | if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) |
197 | break; | 305 | break; |
198 | if (vnode->flags & AFS_VNODE_DELETED) | 306 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
199 | break; | 307 | break; |
200 | 308 | ||
201 | /* it got updated and invalidated all before we saw | 309 | /* check to see if it got updated and invalidated all |
202 | * it */ | 310 | * before we saw it */ |
203 | if (vnode->update_cnt == 0) { | 311 | if (vnode->update_cnt == 0) { |
204 | remove_wait_queue(&vnode->update_waitq, | 312 | remove_wait_queue(&vnode->update_waitq, |
205 | &myself); | 313 | &myself); |
@@ -219,10 +327,11 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode) | |||
219 | spin_unlock(&vnode->lock); | 327 | spin_unlock(&vnode->lock); |
220 | set_current_state(TASK_RUNNING); | 328 | set_current_state(TASK_RUNNING); |
221 | 329 | ||
222 | return vnode->flags & AFS_VNODE_DELETED ? -ENOENT : 0; | 330 | return test_bit(AFS_VNODE_DELETED, &vnode->flags) ? |
331 | -ENOENT : 0; | ||
223 | } | 332 | } |
224 | 333 | ||
225 | get_anyway: | 334 | get_anyway: |
226 | /* okay... we're going to have to initiate the op */ | 335 | /* okay... we're going to have to initiate the op */ |
227 | vnode->update_cnt++; | 336 | vnode->update_cnt++; |
228 | 337 | ||
@@ -232,39 +341,60 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode) | |||
232 | * vnode */ | 341 | * vnode */ |
233 | do { | 342 | do { |
234 | /* pick a server to query */ | 343 | /* pick a server to query */ |
235 | ret = afs_volume_pick_fileserver(vnode->volume, &server); | 344 | server = afs_volume_pick_fileserver(vnode); |
236 | if (ret<0) | 345 | if (IS_ERR(server)) |
237 | return ret; | 346 | goto no_server; |
238 | 347 | ||
239 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | 348 | _debug("USING SERVER: %p{%08x}", |
349 | server, ntohl(server->addr.s_addr)); | ||
240 | 350 | ||
241 | ret = afs_rxfs_fetch_file_status(server, vnode, NULL); | 351 | ret = afs_fs_fetch_file_status(server, key, vnode, NULL, |
352 | &afs_sync_call); | ||
242 | 353 | ||
243 | } while (!afs_volume_release_fileserver(vnode->volume, server, ret)); | 354 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
244 | 355 | ||
245 | /* adjust the flags */ | 356 | /* adjust the flags */ |
246 | afs_vnode_finalise_status_update(vnode, server, ret); | 357 | if (ret == 0) { |
358 | _debug("adjust"); | ||
359 | if (auth_vnode) | ||
360 | afs_cache_permit(vnode, key, acl_order); | ||
361 | afs_vnode_finalise_status_update(vnode, server); | ||
362 | afs_put_server(server); | ||
363 | } else { | ||
364 | _debug("failed [%d]", ret); | ||
365 | afs_vnode_status_update_failed(vnode, ret); | ||
366 | } | ||
247 | 367 | ||
248 | _leave(" = %d", ret); | 368 | ASSERTCMP(vnode->update_cnt, >=, 0); |
369 | |||
370 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); | ||
249 | return ret; | 371 | return ret; |
250 | } /* end afs_vnode_fetch_status() */ | ||
251 | 372 | ||
252 | /*****************************************************************************/ | 373 | no_server: |
374 | spin_lock(&vnode->lock); | ||
375 | vnode->update_cnt--; | ||
376 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
377 | spin_unlock(&vnode->lock); | ||
378 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
379 | return PTR_ERR(server); | ||
380 | } | ||
381 | |||
253 | /* | 382 | /* |
254 | * fetch file data from the volume | 383 | * fetch file data from the volume |
255 | * - TODO implement caching and server failover | 384 | * - TODO implement caching |
256 | */ | 385 | */ |
257 | int afs_vnode_fetch_data(struct afs_vnode *vnode, | 386 | int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, |
258 | struct afs_rxfs_fetch_descriptor *desc) | 387 | off_t offset, size_t length, struct page *page) |
259 | { | 388 | { |
260 | struct afs_server *server; | 389 | struct afs_server *server; |
261 | int ret; | 390 | int ret; |
262 | 391 | ||
263 | _enter("%s,{%u,%u,%u}", | 392 | _enter("%s{%u,%u,%u},%x,,,", |
264 | vnode->volume->vlocation->vldb.name, | 393 | vnode->volume->vlocation->vldb.name, |
265 | vnode->fid.vid, | 394 | vnode->fid.vid, |
266 | vnode->fid.vnode, | 395 | vnode->fid.vnode, |
267 | vnode->fid.unique); | 396 | vnode->fid.unique, |
397 | key_serial(key)); | ||
268 | 398 | ||
269 | /* this op will fetch the status */ | 399 | /* this op will fetch the status */ |
270 | spin_lock(&vnode->lock); | 400 | spin_lock(&vnode->lock); |
@@ -275,120 +405,351 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, | |||
275 | * vnode */ | 405 | * vnode */ |
276 | do { | 406 | do { |
277 | /* pick a server to query */ | 407 | /* pick a server to query */ |
278 | ret = afs_volume_pick_fileserver(vnode->volume, &server); | 408 | server = afs_volume_pick_fileserver(vnode); |
279 | if (ret < 0) | 409 | if (IS_ERR(server)) |
280 | return ret; | 410 | goto no_server; |
281 | 411 | ||
282 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | 412 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); |
283 | 413 | ||
284 | ret = afs_rxfs_fetch_file_data(server, vnode, desc, NULL); | 414 | ret = afs_fs_fetch_data(server, key, vnode, offset, length, |
415 | page, &afs_sync_call); | ||
285 | 416 | ||
286 | } while (!afs_volume_release_fileserver(vnode->volume, server, ret)); | 417 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
287 | 418 | ||
288 | /* adjust the flags */ | 419 | /* adjust the flags */ |
289 | afs_vnode_finalise_status_update(vnode, server, ret); | 420 | if (ret == 0) { |
421 | afs_vnode_finalise_status_update(vnode, server); | ||
422 | afs_put_server(server); | ||
423 | } else { | ||
424 | afs_vnode_status_update_failed(vnode, ret); | ||
425 | } | ||
290 | 426 | ||
291 | _leave(" = %d", ret); | 427 | _leave(" = %d", ret); |
292 | return ret; | 428 | return ret; |
293 | 429 | ||
294 | } /* end afs_vnode_fetch_data() */ | 430 | no_server: |
431 | spin_lock(&vnode->lock); | ||
432 | vnode->update_cnt--; | ||
433 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
434 | spin_unlock(&vnode->lock); | ||
435 | return PTR_ERR(server); | ||
436 | } | ||
295 | 437 | ||
296 | /*****************************************************************************/ | ||
297 | /* | 438 | /* |
298 | * break any outstanding callback on a vnode | 439 | * make a file or a directory |
299 | * - only relevent to server that issued it | ||
300 | */ | 440 | */ |
301 | int afs_vnode_give_up_callback(struct afs_vnode *vnode) | 441 | int afs_vnode_create(struct afs_vnode *vnode, struct key *key, |
442 | const char *name, umode_t mode, struct afs_fid *newfid, | ||
443 | struct afs_file_status *newstatus, | ||
444 | struct afs_callback *newcb, struct afs_server **_server) | ||
302 | { | 445 | { |
303 | struct afs_server *server; | 446 | struct afs_server *server; |
304 | int ret; | 447 | int ret; |
305 | 448 | ||
306 | _enter("%s,{%u,%u,%u}", | 449 | _enter("%s{%u,%u,%u},%x,%s,,", |
307 | vnode->volume->vlocation->vldb.name, | 450 | vnode->volume->vlocation->vldb.name, |
308 | vnode->fid.vid, | 451 | vnode->fid.vid, |
309 | vnode->fid.vnode, | 452 | vnode->fid.vnode, |
310 | vnode->fid.unique); | 453 | vnode->fid.unique, |
311 | 454 | key_serial(key), | |
312 | spin_lock(&afs_cb_hash_lock); | 455 | name); |
313 | list_del_init(&vnode->cb_hash_link); | ||
314 | spin_unlock(&afs_cb_hash_lock); | ||
315 | 456 | ||
316 | /* set the changed flag in the vnode and release the server */ | 457 | /* this op will fetch the status on the directory we're creating in */ |
317 | spin_lock(&vnode->lock); | 458 | spin_lock(&vnode->lock); |
459 | vnode->update_cnt++; | ||
460 | spin_unlock(&vnode->lock); | ||
318 | 461 | ||
319 | afs_kafstimod_del_timer(&vnode->cb_timeout); | 462 | do { |
463 | /* pick a server to query */ | ||
464 | server = afs_volume_pick_fileserver(vnode); | ||
465 | if (IS_ERR(server)) | ||
466 | goto no_server; | ||
467 | |||
468 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
320 | 469 | ||
321 | server = xchg(&vnode->cb_server, NULL); | 470 | ret = afs_fs_create(server, key, vnode, name, mode, newfid, |
322 | if (server) { | 471 | newstatus, newcb, &afs_sync_call); |
323 | vnode->flags |= AFS_VNODE_CHANGED; | ||
324 | 472 | ||
325 | spin_lock(&server->cb_lock); | 473 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
326 | list_del_init(&vnode->cb_link); | 474 | |
327 | spin_unlock(&server->cb_lock); | 475 | /* adjust the flags */ |
476 | if (ret == 0) { | ||
477 | afs_vnode_finalise_status_update(vnode, server); | ||
478 | *_server = server; | ||
479 | } else { | ||
480 | afs_vnode_status_update_failed(vnode, ret); | ||
481 | *_server = NULL; | ||
328 | } | 482 | } |
329 | 483 | ||
484 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); | ||
485 | return ret; | ||
486 | |||
487 | no_server: | ||
488 | spin_lock(&vnode->lock); | ||
489 | vnode->update_cnt--; | ||
490 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
330 | spin_unlock(&vnode->lock); | 491 | spin_unlock(&vnode->lock); |
492 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
493 | return PTR_ERR(server); | ||
494 | } | ||
331 | 495 | ||
332 | ret = 0; | 496 | /* |
333 | if (server) { | 497 | * remove a file or directory |
334 | ret = afs_rxfs_give_up_callback(server, vnode); | 498 | */ |
499 | int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name, | ||
500 | bool isdir) | ||
501 | { | ||
502 | struct afs_server *server; | ||
503 | int ret; | ||
504 | |||
505 | _enter("%s{%u,%u,%u},%x,%s", | ||
506 | vnode->volume->vlocation->vldb.name, | ||
507 | vnode->fid.vid, | ||
508 | vnode->fid.vnode, | ||
509 | vnode->fid.unique, | ||
510 | key_serial(key), | ||
511 | name); | ||
512 | |||
513 | /* this op will fetch the status on the directory we're removing from */ | ||
514 | spin_lock(&vnode->lock); | ||
515 | vnode->update_cnt++; | ||
516 | spin_unlock(&vnode->lock); | ||
517 | |||
518 | do { | ||
519 | /* pick a server to query */ | ||
520 | server = afs_volume_pick_fileserver(vnode); | ||
521 | if (IS_ERR(server)) | ||
522 | goto no_server; | ||
523 | |||
524 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
525 | |||
526 | ret = afs_fs_remove(server, key, vnode, name, isdir, | ||
527 | &afs_sync_call); | ||
528 | |||
529 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
530 | |||
531 | /* adjust the flags */ | ||
532 | if (ret == 0) { | ||
533 | afs_vnode_finalise_status_update(vnode, server); | ||
335 | afs_put_server(server); | 534 | afs_put_server(server); |
535 | } else { | ||
536 | afs_vnode_status_update_failed(vnode, ret); | ||
336 | } | 537 | } |
337 | 538 | ||
338 | _leave(" = %d", ret); | 539 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); |
339 | return ret; | 540 | return ret; |
340 | } /* end afs_vnode_give_up_callback() */ | ||
341 | 541 | ||
342 | /*****************************************************************************/ | 542 | no_server: |
543 | spin_lock(&vnode->lock); | ||
544 | vnode->update_cnt--; | ||
545 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
546 | spin_unlock(&vnode->lock); | ||
547 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
548 | return PTR_ERR(server); | ||
549 | } | ||
550 | |||
343 | /* | 551 | /* |
344 | * match a vnode record stored in the cache | 552 | * create a hard link |
345 | */ | 553 | */ |
346 | #ifdef AFS_CACHING_SUPPORT | 554 | extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode, |
347 | static cachefs_match_val_t afs_vnode_cache_match(void *target, | 555 | struct key *key, const char *name) |
348 | const void *entry) | ||
349 | { | 556 | { |
350 | const struct afs_cache_vnode *cvnode = entry; | 557 | struct afs_server *server; |
351 | struct afs_vnode *vnode = target; | 558 | int ret; |
352 | 559 | ||
353 | _enter("{%x,%x,%Lx},{%x,%x,%Lx}", | 560 | _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s", |
561 | dvnode->volume->vlocation->vldb.name, | ||
562 | dvnode->fid.vid, | ||
563 | dvnode->fid.vnode, | ||
564 | dvnode->fid.unique, | ||
565 | vnode->volume->vlocation->vldb.name, | ||
566 | vnode->fid.vid, | ||
354 | vnode->fid.vnode, | 567 | vnode->fid.vnode, |
355 | vnode->fid.unique, | 568 | vnode->fid.unique, |
356 | vnode->status.version, | 569 | key_serial(key), |
357 | cvnode->vnode_id, | 570 | name); |
358 | cvnode->vnode_unique, | 571 | |
359 | cvnode->data_version); | 572 | /* this op will fetch the status on the directory we're removing from */ |
360 | 573 | spin_lock(&vnode->lock); | |
361 | if (vnode->fid.vnode != cvnode->vnode_id) { | 574 | vnode->update_cnt++; |
362 | _leave(" = FAILED"); | 575 | spin_unlock(&vnode->lock); |
363 | return CACHEFS_MATCH_FAILED; | 576 | spin_lock(&dvnode->lock); |
577 | dvnode->update_cnt++; | ||
578 | spin_unlock(&dvnode->lock); | ||
579 | |||
580 | do { | ||
581 | /* pick a server to query */ | ||
582 | server = afs_volume_pick_fileserver(dvnode); | ||
583 | if (IS_ERR(server)) | ||
584 | goto no_server; | ||
585 | |||
586 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
587 | |||
588 | ret = afs_fs_link(server, key, dvnode, vnode, name, | ||
589 | &afs_sync_call); | ||
590 | |||
591 | } while (!afs_volume_release_fileserver(dvnode, server, ret)); | ||
592 | |||
593 | /* adjust the flags */ | ||
594 | if (ret == 0) { | ||
595 | afs_vnode_finalise_status_update(vnode, server); | ||
596 | afs_vnode_finalise_status_update(dvnode, server); | ||
597 | afs_put_server(server); | ||
598 | } else { | ||
599 | afs_vnode_status_update_failed(vnode, ret); | ||
600 | afs_vnode_status_update_failed(dvnode, ret); | ||
364 | } | 601 | } |
365 | 602 | ||
366 | if (vnode->fid.unique != cvnode->vnode_unique || | 603 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); |
367 | vnode->status.version != cvnode->data_version) { | 604 | return ret; |
368 | _leave(" = DELETE"); | 605 | |
369 | return CACHEFS_MATCH_SUCCESS_DELETE; | 606 | no_server: |
607 | spin_lock(&vnode->lock); | ||
608 | vnode->update_cnt--; | ||
609 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
610 | spin_unlock(&vnode->lock); | ||
611 | spin_lock(&dvnode->lock); | ||
612 | dvnode->update_cnt--; | ||
613 | ASSERTCMP(dvnode->update_cnt, >=, 0); | ||
614 | spin_unlock(&dvnode->lock); | ||
615 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
616 | return PTR_ERR(server); | ||
617 | } | ||
618 | |||
619 | /* | ||
620 | * create a symbolic link | ||
621 | */ | ||
622 | int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key, | ||
623 | const char *name, const char *content, | ||
624 | struct afs_fid *newfid, | ||
625 | struct afs_file_status *newstatus, | ||
626 | struct afs_server **_server) | ||
627 | { | ||
628 | struct afs_server *server; | ||
629 | int ret; | ||
630 | |||
631 | _enter("%s{%u,%u,%u},%x,%s,%s,,,", | ||
632 | vnode->volume->vlocation->vldb.name, | ||
633 | vnode->fid.vid, | ||
634 | vnode->fid.vnode, | ||
635 | vnode->fid.unique, | ||
636 | key_serial(key), | ||
637 | name, content); | ||
638 | |||
639 | /* this op will fetch the status on the directory we're creating in */ | ||
640 | spin_lock(&vnode->lock); | ||
641 | vnode->update_cnt++; | ||
642 | spin_unlock(&vnode->lock); | ||
643 | |||
644 | do { | ||
645 | /* pick a server to query */ | ||
646 | server = afs_volume_pick_fileserver(vnode); | ||
647 | if (IS_ERR(server)) | ||
648 | goto no_server; | ||
649 | |||
650 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
651 | |||
652 | ret = afs_fs_symlink(server, key, vnode, name, content, | ||
653 | newfid, newstatus, &afs_sync_call); | ||
654 | |||
655 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
656 | |||
657 | /* adjust the flags */ | ||
658 | if (ret == 0) { | ||
659 | afs_vnode_finalise_status_update(vnode, server); | ||
660 | *_server = server; | ||
661 | } else { | ||
662 | afs_vnode_status_update_failed(vnode, ret); | ||
663 | *_server = NULL; | ||
370 | } | 664 | } |
371 | 665 | ||
372 | _leave(" = SUCCESS"); | 666 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); |
373 | return CACHEFS_MATCH_SUCCESS; | 667 | return ret; |
374 | } /* end afs_vnode_cache_match() */ | 668 | |
375 | #endif | 669 | no_server: |
670 | spin_lock(&vnode->lock); | ||
671 | vnode->update_cnt--; | ||
672 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
673 | spin_unlock(&vnode->lock); | ||
674 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
675 | return PTR_ERR(server); | ||
676 | } | ||
376 | 677 | ||
377 | /*****************************************************************************/ | ||
378 | /* | 678 | /* |
379 | * update a vnode record stored in the cache | 679 | * rename a file |
380 | */ | 680 | */ |
381 | #ifdef AFS_CACHING_SUPPORT | 681 | int afs_vnode_rename(struct afs_vnode *orig_dvnode, |
382 | static void afs_vnode_cache_update(void *source, void *entry) | 682 | struct afs_vnode *new_dvnode, |
683 | struct key *key, | ||
684 | const char *orig_name, | ||
685 | const char *new_name) | ||
383 | { | 686 | { |
384 | struct afs_cache_vnode *cvnode = entry; | 687 | struct afs_server *server; |
385 | struct afs_vnode *vnode = source; | 688 | int ret; |
386 | 689 | ||
387 | _enter(""); | 690 | _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s", |
691 | orig_dvnode->volume->vlocation->vldb.name, | ||
692 | orig_dvnode->fid.vid, | ||
693 | orig_dvnode->fid.vnode, | ||
694 | orig_dvnode->fid.unique, | ||
695 | new_dvnode->volume->vlocation->vldb.name, | ||
696 | new_dvnode->fid.vid, | ||
697 | new_dvnode->fid.vnode, | ||
698 | new_dvnode->fid.unique, | ||
699 | key_serial(key), | ||
700 | orig_name, | ||
701 | new_name); | ||
702 | |||
703 | /* this op will fetch the status on both the directories we're dealing | ||
704 | * with */ | ||
705 | spin_lock(&orig_dvnode->lock); | ||
706 | orig_dvnode->update_cnt++; | ||
707 | spin_unlock(&orig_dvnode->lock); | ||
708 | if (new_dvnode != orig_dvnode) { | ||
709 | spin_lock(&new_dvnode->lock); | ||
710 | new_dvnode->update_cnt++; | ||
711 | spin_unlock(&new_dvnode->lock); | ||
712 | } | ||
388 | 713 | ||
389 | cvnode->vnode_id = vnode->fid.vnode; | 714 | do { |
390 | cvnode->vnode_unique = vnode->fid.unique; | 715 | /* pick a server to query */ |
391 | cvnode->data_version = vnode->status.version; | 716 | server = afs_volume_pick_fileserver(orig_dvnode); |
717 | if (IS_ERR(server)) | ||
718 | goto no_server; | ||
392 | 719 | ||
393 | } /* end afs_vnode_cache_update() */ | 720 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); |
394 | #endif | 721 | |
722 | ret = afs_fs_rename(server, key, orig_dvnode, orig_name, | ||
723 | new_dvnode, new_name, &afs_sync_call); | ||
724 | |||
725 | } while (!afs_volume_release_fileserver(orig_dvnode, server, ret)); | ||
726 | |||
727 | /* adjust the flags */ | ||
728 | if (ret == 0) { | ||
729 | afs_vnode_finalise_status_update(orig_dvnode, server); | ||
730 | if (new_dvnode != orig_dvnode) | ||
731 | afs_vnode_finalise_status_update(new_dvnode, server); | ||
732 | afs_put_server(server); | ||
733 | } else { | ||
734 | afs_vnode_status_update_failed(orig_dvnode, ret); | ||
735 | if (new_dvnode != orig_dvnode) | ||
736 | afs_vnode_status_update_failed(new_dvnode, ret); | ||
737 | } | ||
738 | |||
739 | _leave(" = %d [cnt %d]", ret, orig_dvnode->update_cnt); | ||
740 | return ret; | ||
741 | |||
742 | no_server: | ||
743 | spin_lock(&orig_dvnode->lock); | ||
744 | orig_dvnode->update_cnt--; | ||
745 | ASSERTCMP(orig_dvnode->update_cnt, >=, 0); | ||
746 | spin_unlock(&orig_dvnode->lock); | ||
747 | if (new_dvnode != orig_dvnode) { | ||
748 | spin_lock(&new_dvnode->lock); | ||
749 | new_dvnode->update_cnt--; | ||
750 | ASSERTCMP(new_dvnode->update_cnt, >=, 0); | ||
751 | spin_unlock(&new_dvnode->lock); | ||
752 | } | ||
753 | _leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt); | ||
754 | return PTR_ERR(server); | ||
755 | } | ||
diff --git a/fs/afs/vnode.h b/fs/afs/vnode.h deleted file mode 100644 index b86a97102e8b..000000000000 --- a/fs/afs/vnode.h +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | /* vnode.h: AFS vnode record | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_VNODE_H | ||
13 | #define _LINUX_AFS_VNODE_H | ||
14 | |||
15 | #include <linux/fs.h> | ||
16 | #include "server.h" | ||
17 | #include "kafstimod.h" | ||
18 | #include "cache.h" | ||
19 | |||
20 | #ifdef __KERNEL__ | ||
21 | |||
22 | struct afs_rxfs_fetch_descriptor; | ||
23 | |||
24 | /*****************************************************************************/ | ||
25 | /* | ||
26 | * vnode catalogue entry | ||
27 | */ | ||
28 | struct afs_cache_vnode | ||
29 | { | ||
30 | afs_vnodeid_t vnode_id; /* vnode ID */ | ||
31 | unsigned vnode_unique; /* vnode ID uniquifier */ | ||
32 | afs_dataversion_t data_version; /* data version */ | ||
33 | }; | ||
34 | |||
35 | #ifdef AFS_CACHING_SUPPORT | ||
36 | extern struct cachefs_index_def afs_vnode_cache_index_def; | ||
37 | #endif | ||
38 | |||
39 | /*****************************************************************************/ | ||
40 | /* | ||
41 | * AFS inode private data | ||
42 | */ | ||
43 | struct afs_vnode | ||
44 | { | ||
45 | struct inode vfs_inode; /* the VFS's inode record */ | ||
46 | |||
47 | struct afs_volume *volume; /* volume on which vnode resides */ | ||
48 | struct afs_fid fid; /* the file identifier for this inode */ | ||
49 | struct afs_file_status status; /* AFS status info for this file */ | ||
50 | #ifdef AFS_CACHING_SUPPORT | ||
51 | struct cachefs_cookie *cache; /* caching cookie */ | ||
52 | #endif | ||
53 | |||
54 | wait_queue_head_t update_waitq; /* status fetch waitqueue */ | ||
55 | unsigned update_cnt; /* number of outstanding ops that will update the | ||
56 | * status */ | ||
57 | spinlock_t lock; /* waitqueue/flags lock */ | ||
58 | unsigned flags; | ||
59 | #define AFS_VNODE_CHANGED 0x00000001 /* set if vnode reported changed by callback */ | ||
60 | #define AFS_VNODE_DELETED 0x00000002 /* set if vnode deleted on server */ | ||
61 | #define AFS_VNODE_MOUNTPOINT 0x00000004 /* set if vnode is a mountpoint symlink */ | ||
62 | |||
63 | /* outstanding callback notification on this file */ | ||
64 | struct afs_server *cb_server; /* server that made the current promise */ | ||
65 | struct list_head cb_link; /* link in server's promises list */ | ||
66 | struct list_head cb_hash_link; /* link in master callback hash */ | ||
67 | struct afs_timer cb_timeout; /* timeout on promise */ | ||
68 | unsigned cb_version; /* callback version */ | ||
69 | unsigned cb_expiry; /* callback expiry time */ | ||
70 | afs_callback_type_t cb_type; /* type of callback */ | ||
71 | }; | ||
72 | |||
73 | static inline struct afs_vnode *AFS_FS_I(struct inode *inode) | ||
74 | { | ||
75 | return container_of(inode,struct afs_vnode,vfs_inode); | ||
76 | } | ||
77 | |||
78 | static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode) | ||
79 | { | ||
80 | return &vnode->vfs_inode; | ||
81 | } | ||
82 | |||
83 | extern int afs_vnode_fetch_status(struct afs_vnode *vnode); | ||
84 | |||
85 | extern int afs_vnode_fetch_data(struct afs_vnode *vnode, | ||
86 | struct afs_rxfs_fetch_descriptor *desc); | ||
87 | |||
88 | extern int afs_vnode_give_up_callback(struct afs_vnode *vnode); | ||
89 | |||
90 | extern struct afs_timer_ops afs_vnode_cb_timed_out_ops; | ||
91 | |||
92 | #endif /* __KERNEL__ */ | ||
93 | |||
94 | #endif /* _LINUX_AFS_VNODE_H */ | ||
diff --git a/fs/afs/volume.c b/fs/afs/volume.c index 768c6dbd323a..dd160cada45d 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* volume.c: AFS volume management | 1 | /* AFS volume management |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -15,35 +15,10 @@ | |||
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 "volume.h" | ||
19 | #include "vnode.h" | ||
20 | #include "cell.h" | ||
21 | #include "cache.h" | ||
22 | #include "cmservice.h" | ||
23 | #include "fsclient.h" | ||
24 | #include "vlclient.h" | ||
25 | #include "internal.h" | 18 | #include "internal.h" |
26 | 19 | ||
27 | #ifdef __KDEBUG | ||
28 | static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; | 20 | static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; |
29 | #endif | ||
30 | |||
31 | #ifdef AFS_CACHING_SUPPORT | ||
32 | static cachefs_match_val_t afs_volume_cache_match(void *target, | ||
33 | const void *entry); | ||
34 | static void afs_volume_cache_update(void *source, void *entry); | ||
35 | |||
36 | struct cachefs_index_def afs_volume_cache_index_def = { | ||
37 | .name = "volume", | ||
38 | .data_size = sizeof(struct afs_cache_vhash), | ||
39 | .keys[0] = { CACHEFS_INDEX_KEYS_BIN, 1 }, | ||
40 | .keys[1] = { CACHEFS_INDEX_KEYS_BIN, 1 }, | ||
41 | .match = afs_volume_cache_match, | ||
42 | .update = afs_volume_cache_update, | ||
43 | }; | ||
44 | #endif | ||
45 | 21 | ||
46 | /*****************************************************************************/ | ||
47 | /* | 22 | /* |
48 | * lookup a volume by name | 23 | * lookup a volume by name |
49 | * - this can be one of the following: | 24 | * - this can be one of the following: |
@@ -66,118 +41,52 @@ struct cachefs_index_def afs_volume_cache_index_def = { | |||
66 | * - 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 |
67 | * explicitly told otherwise | 42 | * explicitly told otherwise |
68 | */ | 43 | */ |
69 | int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | 44 | struct afs_volume *afs_volume_lookup(struct afs_mount_params *params) |
70 | struct afs_volume **_volume) | ||
71 | { | 45 | { |
72 | struct afs_vlocation *vlocation = NULL; | 46 | struct afs_vlocation *vlocation = NULL; |
73 | struct afs_volume *volume = NULL; | 47 | struct afs_volume *volume = NULL; |
74 | afs_voltype_t type; | 48 | struct afs_server *server = NULL; |
75 | const char *cellname, *volname, *suffix; | ||
76 | char srvtmask; | 49 | char srvtmask; |
77 | int force, ret, loop, cellnamesz, volnamesz; | 50 | int ret, loop; |
78 | |||
79 | _enter("%s,,%d,", name, rwpath); | ||
80 | |||
81 | if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) { | ||
82 | printk("kAFS: unparsable volume name\n"); | ||
83 | return -EINVAL; | ||
84 | } | ||
85 | |||
86 | /* determine the type of volume we're looking for */ | ||
87 | force = 0; | ||
88 | type = AFSVL_ROVOL; | ||
89 | |||
90 | if (rwpath || name[0] == '%') { | ||
91 | type = AFSVL_RWVOL; | ||
92 | force = 1; | ||
93 | } | ||
94 | |||
95 | suffix = strrchr(name, '.'); | ||
96 | if (suffix) { | ||
97 | if (strcmp(suffix, ".readonly") == 0) { | ||
98 | type = AFSVL_ROVOL; | ||
99 | force = 1; | ||
100 | } | ||
101 | else if (strcmp(suffix, ".backup") == 0) { | ||
102 | type = AFSVL_BACKVOL; | ||
103 | force = 1; | ||
104 | } | ||
105 | else if (suffix[1] == 0) { | ||
106 | } | ||
107 | else { | ||
108 | suffix = NULL; | ||
109 | } | ||
110 | } | ||
111 | 51 | ||
112 | /* split the cell and volume names */ | 52 | _enter("{%*.*s,%d}", |
113 | name++; | 53 | params->volnamesz, params->volnamesz, params->volname, params->rwpath); |
114 | volname = strchr(name, ':'); | ||
115 | if (volname) { | ||
116 | cellname = name; | ||
117 | cellnamesz = volname - name; | ||
118 | volname++; | ||
119 | } | ||
120 | else { | ||
121 | volname = name; | ||
122 | cellname = NULL; | ||
123 | cellnamesz = 0; | ||
124 | } | ||
125 | |||
126 | volnamesz = suffix ? suffix - volname : strlen(volname); | ||
127 | |||
128 | _debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", | ||
129 | cellnamesz, cellnamesz, cellname ?: "", cell, | ||
130 | volnamesz, volnamesz, volname, suffix ?: "-", | ||
131 | type, | ||
132 | force ? " FORCE" : ""); | ||
133 | |||
134 | /* lookup the cell record */ | ||
135 | if (cellname || !cell) { | ||
136 | ret = afs_cell_lookup(cellname, cellnamesz, &cell); | ||
137 | if (ret<0) { | ||
138 | printk("kAFS: unable to lookup cell '%s'\n", | ||
139 | cellname ?: ""); | ||
140 | goto error; | ||
141 | } | ||
142 | } | ||
143 | else { | ||
144 | afs_get_cell(cell); | ||
145 | } | ||
146 | 54 | ||
147 | /* lookup the volume location record */ | 55 | /* lookup the volume location record */ |
148 | ret = afs_vlocation_lookup(cell, volname, volnamesz, &vlocation); | 56 | vlocation = afs_vlocation_lookup(params->cell, params->key, |
149 | if (ret < 0) | 57 | params->volname, params->volnamesz); |
58 | if (IS_ERR(vlocation)) { | ||
59 | ret = PTR_ERR(vlocation); | ||
60 | vlocation = NULL; | ||
150 | goto error; | 61 | goto error; |
62 | } | ||
151 | 63 | ||
152 | /* make the final decision on the type we want */ | 64 | /* make the final decision on the type we want */ |
153 | ret = -ENOMEDIUM; | 65 | ret = -ENOMEDIUM; |
154 | if (force && !(vlocation->vldb.vidmask & (1 << type))) | 66 | if (params->force && !(vlocation->vldb.vidmask & (1 << params->type))) |
155 | goto error; | 67 | goto error; |
156 | 68 | ||
157 | srvtmask = 0; | 69 | srvtmask = 0; |
158 | for (loop = 0; loop < vlocation->vldb.nservers; loop++) | 70 | for (loop = 0; loop < vlocation->vldb.nservers; loop++) |
159 | srvtmask |= vlocation->vldb.srvtmask[loop]; | 71 | srvtmask |= vlocation->vldb.srvtmask[loop]; |
160 | 72 | ||
161 | if (force) { | 73 | if (params->force) { |
162 | if (!(srvtmask & (1 << type))) | 74 | if (!(srvtmask & (1 << params->type))) |
163 | goto error; | 75 | goto error; |
164 | } | 76 | } else if (srvtmask & AFS_VOL_VTM_RO) { |
165 | else if (srvtmask & AFS_VOL_VTM_RO) { | 77 | params->type = AFSVL_ROVOL; |
166 | type = AFSVL_ROVOL; | 78 | } else if (srvtmask & AFS_VOL_VTM_RW) { |
167 | } | 79 | params->type = AFSVL_RWVOL; |
168 | else if (srvtmask & AFS_VOL_VTM_RW) { | 80 | } else { |
169 | type = AFSVL_RWVOL; | ||
170 | } | ||
171 | else { | ||
172 | goto error; | 81 | goto error; |
173 | } | 82 | } |
174 | 83 | ||
175 | down_write(&cell->vl_sem); | 84 | down_write(¶ms->cell->vl_sem); |
176 | 85 | ||
177 | /* is the volume already active? */ | 86 | /* is the volume already active? */ |
178 | if (vlocation->vols[type]) { | 87 | if (vlocation->vols[params->type]) { |
179 | /* yes - re-use it */ | 88 | /* yes - re-use it */ |
180 | volume = vlocation->vols[type]; | 89 | volume = vlocation->vols[params->type]; |
181 | afs_get_volume(volume); | 90 | afs_get_volume(volume); |
182 | goto success; | 91 | goto success; |
183 | } | 92 | } |
@@ -191,23 +100,24 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | |||
191 | goto error_up; | 100 | goto error_up; |
192 | 101 | ||
193 | atomic_set(&volume->usage, 1); | 102 | atomic_set(&volume->usage, 1); |
194 | volume->type = type; | 103 | volume->type = params->type; |
195 | volume->type_force = force; | 104 | volume->type_force = params->force; |
196 | volume->cell = cell; | 105 | volume->cell = params->cell; |
197 | volume->vid = vlocation->vldb.vid[type]; | 106 | volume->vid = vlocation->vldb.vid[params->type]; |
198 | 107 | ||
199 | init_rwsem(&volume->server_sem); | 108 | init_rwsem(&volume->server_sem); |
200 | 109 | ||
201 | /* look up all the applicable server records */ | 110 | /* look up all the applicable server records */ |
202 | for (loop = 0; loop < 8; loop++) { | 111 | for (loop = 0; loop < 8; loop++) { |
203 | if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) { | 112 | if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) { |
204 | ret = afs_server_lookup( | 113 | server = afs_lookup_server( |
205 | volume->cell, | 114 | volume->cell, &vlocation->vldb.servers[loop]); |
206 | &vlocation->vldb.servers[loop], | 115 | if (IS_ERR(server)) { |
207 | &volume->servers[volume->nservers]); | 116 | ret = PTR_ERR(server); |
208 | if (ret < 0) | ||
209 | goto error_discard; | 117 | goto error_discard; |
118 | } | ||
210 | 119 | ||
120 | volume->servers[volume->nservers] = server; | ||
211 | volume->nservers++; | 121 | volume->nservers++; |
212 | } | 122 | } |
213 | } | 123 | } |
@@ -223,35 +133,34 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath, | |||
223 | afs_get_vlocation(vlocation); | 133 | afs_get_vlocation(vlocation); |
224 | volume->vlocation = vlocation; | 134 | volume->vlocation = vlocation; |
225 | 135 | ||
226 | vlocation->vols[type] = volume; | 136 | vlocation->vols[volume->type] = volume; |
227 | 137 | ||
228 | success: | 138 | success: |
229 | _debug("kAFS selected %s volume %08x", | 139 | _debug("kAFS selected %s volume %08x", |
230 | afs_voltypes[volume->type], volume->vid); | 140 | afs_voltypes[volume->type], volume->vid); |
231 | *_volume = volume; | 141 | up_write(¶ms->cell->vl_sem); |
232 | ret = 0; | 142 | afs_put_vlocation(vlocation); |
143 | _leave(" = %p", volume); | ||
144 | return volume; | ||
233 | 145 | ||
234 | /* clean up */ | 146 | /* clean up */ |
235 | error_up: | 147 | error_up: |
236 | up_write(&cell->vl_sem); | 148 | up_write(¶ms->cell->vl_sem); |
237 | error: | 149 | error: |
238 | afs_put_vlocation(vlocation); | 150 | afs_put_vlocation(vlocation); |
239 | afs_put_cell(cell); | 151 | _leave(" = %d", ret); |
240 | 152 | return ERR_PTR(ret); | |
241 | _leave(" = %d (%p)", ret, volume); | ||
242 | return ret; | ||
243 | 153 | ||
244 | error_discard: | 154 | error_discard: |
245 | up_write(&cell->vl_sem); | 155 | up_write(¶ms->cell->vl_sem); |
246 | 156 | ||
247 | for (loop = volume->nservers - 1; loop >= 0; loop--) | 157 | for (loop = volume->nservers - 1; loop >= 0; loop--) |
248 | afs_put_server(volume->servers[loop]); | 158 | afs_put_server(volume->servers[loop]); |
249 | 159 | ||
250 | kfree(volume); | 160 | kfree(volume); |
251 | goto error; | 161 | goto error; |
252 | } /* end afs_volume_lookup() */ | 162 | } |
253 | 163 | ||
254 | /*****************************************************************************/ | ||
255 | /* | 164 | /* |
256 | * destroy a volume record | 165 | * destroy a volume record |
257 | */ | 166 | */ |
@@ -265,10 +174,9 @@ void afs_put_volume(struct afs_volume *volume) | |||
265 | 174 | ||
266 | _enter("%p", volume); | 175 | _enter("%p", volume); |
267 | 176 | ||
268 | vlocation = volume->vlocation; | 177 | ASSERTCMP(atomic_read(&volume->usage), >, 0); |
269 | 178 | ||
270 | /* sanity check */ | 179 | vlocation = volume->vlocation; |
271 | BUG_ON(atomic_read(&volume->usage) <= 0); | ||
272 | 180 | ||
273 | /* to prevent a race, the decrement and the dequeue must be effectively | 181 | /* to prevent a race, the decrement and the dequeue must be effectively |
274 | * atomic */ | 182 | * atomic */ |
@@ -296,21 +204,27 @@ void afs_put_volume(struct afs_volume *volume) | |||
296 | kfree(volume); | 204 | kfree(volume); |
297 | 205 | ||
298 | _leave(" [destroyed]"); | 206 | _leave(" [destroyed]"); |
299 | } /* end afs_put_volume() */ | 207 | } |
300 | 208 | ||
301 | /*****************************************************************************/ | ||
302 | /* | 209 | /* |
303 | * pick a server to use to try accessing this volume | 210 | * pick a server to use to try accessing this volume |
304 | * - returns with an elevated usage count on the server chosen | 211 | * - returns with an elevated usage count on the server chosen |
305 | */ | 212 | */ |
306 | int afs_volume_pick_fileserver(struct afs_volume *volume, | 213 | struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode) |
307 | struct afs_server **_server) | ||
308 | { | 214 | { |
215 | struct afs_volume *volume = vnode->volume; | ||
309 | struct afs_server *server; | 216 | struct afs_server *server; |
310 | int ret, state, loop; | 217 | int ret, state, loop; |
311 | 218 | ||
312 | _enter("%s", volume->vlocation->vldb.name); | 219 | _enter("%s", volume->vlocation->vldb.name); |
313 | 220 | ||
221 | /* stick with the server we're already using if we can */ | ||
222 | if (vnode->server && vnode->server->fs_state == 0) { | ||
223 | afs_get_server(vnode->server); | ||
224 | _leave(" = %p [current]", vnode->server); | ||
225 | return vnode->server; | ||
226 | } | ||
227 | |||
314 | down_read(&volume->server_sem); | 228 | down_read(&volume->server_sem); |
315 | 229 | ||
316 | /* handle the no-server case */ | 230 | /* handle the no-server case */ |
@@ -318,7 +232,7 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, | |||
318 | ret = volume->rjservers ? -ENOMEDIUM : -ESTALE; | 232 | ret = volume->rjservers ? -ENOMEDIUM : -ESTALE; |
319 | up_read(&volume->server_sem); | 233 | up_read(&volume->server_sem); |
320 | _leave(" = %d [no servers]", ret); | 234 | _leave(" = %d [no servers]", ret); |
321 | return ret; | 235 | return ERR_PTR(ret); |
322 | } | 236 | } |
323 | 237 | ||
324 | /* basically, just search the list for the first live server and use | 238 | /* basically, just search the list for the first live server and use |
@@ -328,15 +242,16 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, | |||
328 | server = volume->servers[loop]; | 242 | server = volume->servers[loop]; |
329 | state = server->fs_state; | 243 | state = server->fs_state; |
330 | 244 | ||
245 | _debug("consider %d [%d]", loop, state); | ||
246 | |||
331 | switch (state) { | 247 | switch (state) { |
332 | /* found an apparently healthy server */ | 248 | /* found an apparently healthy server */ |
333 | case 0: | 249 | case 0: |
334 | afs_get_server(server); | 250 | afs_get_server(server); |
335 | up_read(&volume->server_sem); | 251 | up_read(&volume->server_sem); |
336 | *_server = server; | 252 | _leave(" = %p (picked %08x)", |
337 | _leave(" = 0 (picked %08x)", | 253 | server, ntohl(server->addr.s_addr)); |
338 | ntohl(server->addr.s_addr)); | 254 | return server; |
339 | return 0; | ||
340 | 255 | ||
341 | case -ENETUNREACH: | 256 | case -ENETUNREACH: |
342 | if (ret == 0) | 257 | if (ret == 0) |
@@ -372,20 +287,21 @@ int afs_volume_pick_fileserver(struct afs_volume *volume, | |||
372 | */ | 287 | */ |
373 | up_read(&volume->server_sem); | 288 | up_read(&volume->server_sem); |
374 | _leave(" = %d", ret); | 289 | _leave(" = %d", ret); |
375 | return ret; | 290 | return ERR_PTR(ret); |
376 | } /* end afs_volume_pick_fileserver() */ | 291 | } |
377 | 292 | ||
378 | /*****************************************************************************/ | ||
379 | /* | 293 | /* |
380 | * release a server after use | 294 | * release a server after use |
381 | * - releases the ref on the server struct that was acquired by picking | 295 | * - releases the ref on the server struct that was acquired by picking |
382 | * - records result of using a particular server to access a volume | 296 | * - records result of using a particular server to access a volume |
383 | * - return 0 to try again, 1 if okay or to issue error | 297 | * - return 0 to try again, 1 if okay or to issue error |
298 | * - the caller must release the server struct if result was 0 | ||
384 | */ | 299 | */ |
385 | int afs_volume_release_fileserver(struct afs_volume *volume, | 300 | int afs_volume_release_fileserver(struct afs_vnode *vnode, |
386 | struct afs_server *server, | 301 | struct afs_server *server, |
387 | int result) | 302 | int result) |
388 | { | 303 | { |
304 | struct afs_volume *volume = vnode->volume; | ||
389 | unsigned loop; | 305 | unsigned loop; |
390 | 306 | ||
391 | _enter("%s,%08x,%d", | 307 | _enter("%s,%08x,%d", |
@@ -396,14 +312,16 @@ int afs_volume_release_fileserver(struct afs_volume *volume, | |||
396 | /* success */ | 312 | /* success */ |
397 | case 0: | 313 | case 0: |
398 | server->fs_act_jif = jiffies; | 314 | server->fs_act_jif = jiffies; |
399 | break; | 315 | server->fs_state = 0; |
316 | _leave(""); | ||
317 | return 1; | ||
400 | 318 | ||
401 | /* the fileserver denied all knowledge of the volume */ | 319 | /* the fileserver denied all knowledge of the volume */ |
402 | case -ENOMEDIUM: | 320 | case -ENOMEDIUM: |
403 | server->fs_act_jif = jiffies; | 321 | server->fs_act_jif = jiffies; |
404 | down_write(&volume->server_sem); | 322 | down_write(&volume->server_sem); |
405 | 323 | ||
406 | /* first, find where the server is in the active list (if it | 324 | /* firstly, find where the server is in the active list (if it |
407 | * is) */ | 325 | * is) */ |
408 | for (loop = 0; loop < volume->nservers; loop++) | 326 | for (loop = 0; loop < volume->nservers; loop++) |
409 | if (volume->servers[loop] == server) | 327 | if (volume->servers[loop] == server) |
@@ -441,6 +359,7 @@ int afs_volume_release_fileserver(struct afs_volume *volume, | |||
441 | case -ENETUNREACH: | 359 | case -ENETUNREACH: |
442 | case -EHOSTUNREACH: | 360 | case -EHOSTUNREACH: |
443 | case -ECONNREFUSED: | 361 | case -ECONNREFUSED: |
362 | case -ETIME: | ||
444 | case -ETIMEDOUT: | 363 | case -ETIMEDOUT: |
445 | case -EREMOTEIO: | 364 | case -EREMOTEIO: |
446 | /* mark the server as dead | 365 | /* mark the server as dead |
@@ -460,60 +379,17 @@ int afs_volume_release_fileserver(struct afs_volume *volume, | |||
460 | server->fs_act_jif = jiffies; | 379 | server->fs_act_jif = jiffies; |
461 | case -ENOMEM: | 380 | case -ENOMEM: |
462 | case -ENONET: | 381 | case -ENONET: |
463 | break; | 382 | /* tell the caller to accept the result */ |
383 | afs_put_server(server); | ||
384 | _leave(" [local failure]"); | ||
385 | return 1; | ||
464 | } | 386 | } |
465 | 387 | ||
466 | /* tell the caller to accept the result */ | ||
467 | afs_put_server(server); | ||
468 | _leave(""); | ||
469 | return 1; | ||
470 | |||
471 | /* tell the caller to loop around and try the next server */ | 388 | /* tell the caller to loop around and try the next server */ |
472 | try_next_server_upw: | 389 | try_next_server_upw: |
473 | up_write(&volume->server_sem); | 390 | up_write(&volume->server_sem); |
474 | try_next_server: | 391 | try_next_server: |
475 | afs_put_server(server); | 392 | afs_put_server(server); |
476 | _leave(" [try next server]"); | 393 | _leave(" [try next server]"); |
477 | return 0; | 394 | return 0; |
478 | 395 | } | |
479 | } /* end afs_volume_release_fileserver() */ | ||
480 | |||
481 | /*****************************************************************************/ | ||
482 | /* | ||
483 | * match a volume hash record stored in the cache | ||
484 | */ | ||
485 | #ifdef AFS_CACHING_SUPPORT | ||
486 | static cachefs_match_val_t afs_volume_cache_match(void *target, | ||
487 | const void *entry) | ||
488 | { | ||
489 | const struct afs_cache_vhash *vhash = entry; | ||
490 | struct afs_volume *volume = target; | ||
491 | |||
492 | _enter("{%u},{%u}", volume->type, vhash->vtype); | ||
493 | |||
494 | if (volume->type == vhash->vtype) { | ||
495 | _leave(" = SUCCESS"); | ||
496 | return CACHEFS_MATCH_SUCCESS; | ||
497 | } | ||
498 | |||
499 | _leave(" = FAILED"); | ||
500 | return CACHEFS_MATCH_FAILED; | ||
501 | } /* end afs_volume_cache_match() */ | ||
502 | #endif | ||
503 | |||
504 | /*****************************************************************************/ | ||
505 | /* | ||
506 | * update a volume hash record stored in the cache | ||
507 | */ | ||
508 | #ifdef AFS_CACHING_SUPPORT | ||
509 | static void afs_volume_cache_update(void *source, void *entry) | ||
510 | { | ||
511 | struct afs_cache_vhash *vhash = entry; | ||
512 | struct afs_volume *volume = source; | ||
513 | |||
514 | _enter(""); | ||
515 | |||
516 | vhash->vtype = volume->type; | ||
517 | |||
518 | } /* end afs_volume_cache_update() */ | ||
519 | #endif | ||
diff --git a/fs/afs/volume.h b/fs/afs/volume.h deleted file mode 100644 index bfdcf19ba3f3..000000000000 --- a/fs/afs/volume.h +++ /dev/null | |||
@@ -1,140 +0,0 @@ | |||
1 | /* volume.h: AFS volume management | ||
2 | * | ||
3 | * Copyright (C) 2002 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 | #ifndef _LINUX_AFS_VOLUME_H | ||
13 | #define _LINUX_AFS_VOLUME_H | ||
14 | |||
15 | #include "types.h" | ||
16 | #include "fsclient.h" | ||
17 | #include "kafstimod.h" | ||
18 | #include "kafsasyncd.h" | ||
19 | #include "cache.h" | ||
20 | |||
21 | typedef enum { | ||
22 | AFS_VLUPD_SLEEP, /* sleeping waiting for update timer to fire */ | ||
23 | AFS_VLUPD_PENDING, /* on pending queue */ | ||
24 | AFS_VLUPD_INPROGRESS, /* op in progress */ | ||
25 | AFS_VLUPD_BUSYSLEEP, /* sleeping because server returned EBUSY */ | ||
26 | |||
27 | } __attribute__((packed)) afs_vlocation_upd_t; | ||
28 | |||
29 | /*****************************************************************************/ | ||
30 | /* | ||
31 | * entry in the cached volume location catalogue | ||
32 | */ | ||
33 | struct afs_cache_vlocation | ||
34 | { | ||
35 | uint8_t name[64]; /* volume name (lowercase, padded with NULs) */ | ||
36 | uint8_t nservers; /* number of entries used in servers[] */ | ||
37 | uint8_t vidmask; /* voltype mask for vid[] */ | ||
38 | uint8_t srvtmask[8]; /* voltype masks for servers[] */ | ||
39 | #define AFS_VOL_VTM_RW 0x01 /* R/W version of the volume is available (on this server) */ | ||
40 | #define AFS_VOL_VTM_RO 0x02 /* R/O version of the volume is available (on this server) */ | ||
41 | #define AFS_VOL_VTM_BAK 0x04 /* backup version of the volume is available (on this server) */ | ||
42 | |||
43 | afs_volid_t vid[3]; /* volume IDs for R/W, R/O and Bak volumes */ | ||
44 | struct in_addr servers[8]; /* fileserver addresses */ | ||
45 | time_t rtime; /* last retrieval time */ | ||
46 | }; | ||
47 | |||
48 | #ifdef AFS_CACHING_SUPPORT | ||
49 | extern struct cachefs_index_def afs_vlocation_cache_index_def; | ||
50 | #endif | ||
51 | |||
52 | /*****************************************************************************/ | ||
53 | /* | ||
54 | * volume -> vnode hash table entry | ||
55 | */ | ||
56 | struct afs_cache_vhash | ||
57 | { | ||
58 | afs_voltype_t vtype; /* which volume variation */ | ||
59 | uint8_t hash_bucket; /* which hash bucket this represents */ | ||
60 | } __attribute__((packed)); | ||
61 | |||
62 | #ifdef AFS_CACHING_SUPPORT | ||
63 | extern struct cachefs_index_def afs_volume_cache_index_def; | ||
64 | #endif | ||
65 | |||
66 | /*****************************************************************************/ | ||
67 | /* | ||
68 | * AFS volume location record | ||
69 | */ | ||
70 | struct afs_vlocation | ||
71 | { | ||
72 | atomic_t usage; | ||
73 | struct list_head link; /* link in cell volume location list */ | ||
74 | struct afs_timer timeout; /* decaching timer */ | ||
75 | struct afs_cell *cell; /* cell to which volume belongs */ | ||
76 | #ifdef AFS_CACHING_SUPPORT | ||
77 | struct cachefs_cookie *cache; /* caching cookie */ | ||
78 | #endif | ||
79 | struct afs_cache_vlocation vldb; /* volume information DB record */ | ||
80 | struct afs_volume *vols[3]; /* volume access record pointer (index by type) */ | ||
81 | rwlock_t lock; /* access lock */ | ||
82 | unsigned long read_jif; /* time at which last read from vlserver */ | ||
83 | struct afs_timer upd_timer; /* update timer */ | ||
84 | struct afs_async_op upd_op; /* update operation */ | ||
85 | afs_vlocation_upd_t upd_state; /* update state */ | ||
86 | unsigned short upd_first_svix; /* first server index during update */ | ||
87 | unsigned short upd_curr_svix; /* current server index during update */ | ||
88 | unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */ | ||
89 | unsigned short upd_busy_cnt; /* EBUSY count during update */ | ||
90 | unsigned short valid; /* T if valid */ | ||
91 | }; | ||
92 | |||
93 | extern int afs_vlocation_lookup(struct afs_cell *cell, | ||
94 | const char *name, | ||
95 | unsigned namesz, | ||
96 | struct afs_vlocation **_vlocation); | ||
97 | |||
98 | #define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0) | ||
99 | |||
100 | extern void afs_put_vlocation(struct afs_vlocation *vlocation); | ||
101 | extern void afs_vlocation_do_timeout(struct afs_vlocation *vlocation); | ||
102 | |||
103 | /*****************************************************************************/ | ||
104 | /* | ||
105 | * AFS volume access record | ||
106 | */ | ||
107 | struct afs_volume | ||
108 | { | ||
109 | atomic_t usage; | ||
110 | struct afs_cell *cell; /* cell to which belongs (unrefd ptr) */ | ||
111 | struct afs_vlocation *vlocation; /* volume location */ | ||
112 | #ifdef AFS_CACHING_SUPPORT | ||
113 | struct cachefs_cookie *cache; /* caching cookie */ | ||
114 | #endif | ||
115 | afs_volid_t vid; /* volume ID */ | ||
116 | afs_voltype_t type; /* type of volume */ | ||
117 | char type_force; /* force volume type (suppress R/O -> R/W) */ | ||
118 | unsigned short nservers; /* number of server slots filled */ | ||
119 | unsigned short rjservers; /* number of servers discarded due to -ENOMEDIUM */ | ||
120 | struct afs_server *servers[8]; /* servers on which volume resides (ordered) */ | ||
121 | struct rw_semaphore server_sem; /* lock for accessing current server */ | ||
122 | }; | ||
123 | |||
124 | extern int afs_volume_lookup(const char *name, | ||
125 | struct afs_cell *cell, | ||
126 | int rwpath, | ||
127 | struct afs_volume **_volume); | ||
128 | |||
129 | #define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0) | ||
130 | |||
131 | extern void afs_put_volume(struct afs_volume *volume); | ||
132 | |||
133 | extern int afs_volume_pick_fileserver(struct afs_volume *volume, | ||
134 | struct afs_server **_server); | ||
135 | |||
136 | extern int afs_volume_release_fileserver(struct afs_volume *volume, | ||
137 | struct afs_server *server, | ||
138 | int result); | ||
139 | |||
140 | #endif /* _LINUX_AFS_VOLUME_H */ | ||