~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/modules/vfs_fileid.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * VFS module to alter the algorithm to calculate
 
3
 * the struct file_id used as key for the share mode
 
4
 * and byte range locking db's.
 
5
 *
 
6
 * Copyright (C) 2007, Stefan Metzmacher
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 3 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
 
 
22
#include "includes.h"
 
23
 
 
24
static int vfs_fileid_debug_level = DBGC_VFS;
 
25
 
 
26
#undef DBGC_CLASS
 
27
#define DBGC_CLASS vfs_fileid_debug_level
 
28
 
 
29
struct fileid_mount_entry {
 
30
        SMB_DEV_T device;
 
31
        const char *mnt_fsname;
 
32
        fsid_t fsid;
 
33
        uint64_t devid;
 
34
};
 
35
 
 
36
struct fileid_handle_data {
 
37
        uint64_t (*device_mapping_fn)(struct fileid_handle_data *data,
 
38
                                      SMB_DEV_T dev);
 
39
        unsigned num_mount_entries;
 
40
        struct fileid_mount_entry *mount_entries;
 
41
};
 
42
 
 
43
/* load all the mount entries from the mtab */
 
44
static void fileid_load_mount_entries(struct fileid_handle_data *data)
 
45
{
 
46
        FILE *f;
 
47
        struct mntent *m;
 
48
 
 
49
        data->num_mount_entries = 0;
 
50
        TALLOC_FREE(data->mount_entries);
 
51
 
 
52
        f = setmntent("/etc/mtab", "r");
 
53
        if (!f) return;
 
54
 
 
55
        while ((m = getmntent(f))) {
 
56
                struct stat st;
 
57
                struct statfs sfs;
 
58
                struct fileid_mount_entry *cur;
 
59
 
 
60
                if (stat(m->mnt_dir, &st) != 0) continue;
 
61
                if (statfs(m->mnt_dir, &sfs) != 0) continue;
 
62
 
 
63
                if (strncmp(m->mnt_fsname, "/dev/", 5) == 0) {
 
64
                        m->mnt_fsname += 5;
 
65
                }
 
66
 
 
67
                data->mount_entries = TALLOC_REALLOC_ARRAY(data,
 
68
                                                           data->mount_entries,
 
69
                                                           struct fileid_mount_entry,
 
70
                                                           data->num_mount_entries+1);
 
71
                if (data->mount_entries == NULL) {
 
72
                        goto nomem;
 
73
                }
 
74
 
 
75
                cur = &data->mount_entries[data->num_mount_entries];
 
76
                cur->device     = st.st_dev;
 
77
                cur->mnt_fsname = talloc_strdup(data->mount_entries,
 
78
                                                m->mnt_fsname);
 
79
                if (!cur->mnt_fsname) goto nomem;
 
80
                cur->fsid       = sfs.f_fsid;
 
81
                cur->devid      = (uint64_t)-1;
 
82
 
 
83
                data->num_mount_entries++;
 
84
        }
 
85
        endmntent(f);
 
86
        return;
 
87
        
 
88
nomem:
 
89
        if (f) endmntent(f);
 
90
 
 
91
        data->num_mount_entries = 0;
 
92
        TALLOC_FREE(data->mount_entries);
 
93
 
 
94
        return;
 
95
}
 
96
 
 
97
/* find a mount entry given a dev_t */
 
98
static struct fileid_mount_entry *fileid_find_mount_entry(struct fileid_handle_data *data,
 
99
                                                          SMB_DEV_T dev)
 
100
{
 
101
        int i;
 
102
 
 
103
        if (data->num_mount_entries == 0) {
 
104
                fileid_load_mount_entries(data);
 
105
        }
 
106
        for (i=0;i<data->num_mount_entries;i++) {
 
107
                if (data->mount_entries[i].device == dev) {
 
108
                        return &data->mount_entries[i];
 
109
                }
 
110
        }
 
111
        /* 2nd pass after reloading */
 
112
        fileid_load_mount_entries(data);
 
113
        for (i=0;i<data->num_mount_entries;i++) {
 
114
                if (data->mount_entries[i].device == dev) {
 
115
                        return &data->mount_entries[i];
 
116
                }
 
117
        }       
 
118
        return NULL;
 
119
}
 
120
 
 
121
 
 
122
/* a 64 bit hash, based on the one in tdb */
 
123
static uint64_t fileid_uint64_hash(const uint8_t *s, size_t len)
 
124
{
 
125
        uint64_t value; /* Used to compute the hash value.  */
 
126
        uint32_t i;     /* Used to cycle through random values. */
 
127
 
 
128
        /* Set the initial value from the key size. */
 
129
        for (value = 0x238F13AFLL * len, i=0; i < len; i++)
 
130
                value = (value + (s[i] << (i*5 % 24)));
 
131
 
 
132
        return (1103515243LL * value + 12345LL);
 
133
}
 
134
 
 
135
/* a device mapping using a fsname */
 
136
static uint64_t fileid_device_mapping_fsname(struct fileid_handle_data *data,
 
137
                                             SMB_DEV_T dev)
 
138
{
 
139
        struct fileid_mount_entry *m;
 
140
 
 
141
        m = fileid_find_mount_entry(data, dev);
 
142
        if (!m) return dev;
 
143
 
 
144
        if (m->devid == (uint64_t)-1) {
 
145
                m->devid = fileid_uint64_hash((uint8_t *)m->mnt_fsname,
 
146
                                              strlen(m->mnt_fsname));
 
147
        }
 
148
 
 
149
        return m->devid;
 
150
}
 
151
 
 
152
/* device mapping functions using a fsid */
 
153
static uint64_t fileid_device_mapping_fsid(struct fileid_handle_data *data,
 
154
                                           SMB_DEV_T dev)
 
155
{
 
156
        struct fileid_mount_entry *m;
 
157
 
 
158
        m = fileid_find_mount_entry(data, dev);
 
159
        if (!m) return dev;
 
160
 
 
161
        if (m->devid == (uint64_t)-1) {
 
162
                if (sizeof(fsid_t) > sizeof(uint64_t)) {
 
163
                        m->devid = fileid_uint64_hash((uint8_t *)&m->fsid,
 
164
                                                      sizeof(m->fsid));
 
165
                } else {
 
166
                        union {
 
167
                                uint64_t ret;
 
168
                                fsid_t fsid;
 
169
                        } u;
 
170
                        ZERO_STRUCT(u);
 
171
                        u.fsid = m->fsid;
 
172
                        m->devid = u.ret;
 
173
                }
 
174
        }
 
175
 
 
176
        return m->devid;
 
177
}
 
178
 
 
179
static int fileid_connect(struct vfs_handle_struct *handle,
 
180
                          const char *service, const char *user)
 
181
{
 
182
        struct fileid_handle_data *data;
 
183
        const char *algorithm;
 
184
 
 
185
        data = talloc_zero(handle->conn, struct fileid_handle_data);
 
186
        if (!data) {
 
187
                DEBUG(0, ("talloc_zero() failed\n"));
 
188
                return -1;
 
189
        }
 
190
 
 
191
        /*
 
192
         * "fileid:mapping" is only here as fallback for old setups
 
193
         * "fileid:algorithm" is the option new setups should use
 
194
         */
 
195
        algorithm = lp_parm_const_string(SNUM(handle->conn),
 
196
                                         "fileid", "mapping",
 
197
                                         "fsname");
 
198
        algorithm = lp_parm_const_string(SNUM(handle->conn),
 
199
                                         "fileid", "algorithm",
 
200
                                         algorithm);
 
201
        if (strcmp("fsname", algorithm) == 0) {
 
202
                data->device_mapping_fn = fileid_device_mapping_fsname;
 
203
        } else if (strcmp("fsid", algorithm) == 0) {
 
204
                data->device_mapping_fn = fileid_device_mapping_fsid;
 
205
        } else {
 
206
                DEBUG(0,("fileid_connect(): unknown algorithm[%s]\n", algorithm));
 
207
                return -1;
 
208
        }
 
209
 
 
210
        SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
 
211
                                struct fileid_handle_data,
 
212
                                return -1);
 
213
 
 
214
        DEBUG(10, ("fileid_connect(): connect to service[%s] with algorithm[%s]\n",
 
215
                service, algorithm));
 
216
 
 
217
        return SMB_VFS_NEXT_CONNECT(handle, service, user);
 
218
}
 
219
 
 
220
static void fileid_disconnect(struct vfs_handle_struct *handle)
 
221
{
 
222
        DEBUG(10,("fileid_disconnect() connect to service[%s].\n",
 
223
                lp_servicename(SNUM(handle->conn))));
 
224
 
 
225
        SMB_VFS_NEXT_DISCONNECT(handle);
 
226
}
 
227
 
 
228
static struct file_id fileid_file_id_create(struct vfs_handle_struct *handle,
 
229
                                            const SMB_STRUCT_STAT *sbuf)
 
230
{
 
231
        struct fileid_handle_data *data;
 
232
        struct file_id id;
 
233
 
 
234
        ZERO_STRUCT(id);
 
235
 
 
236
        SMB_VFS_HANDLE_GET_DATA(handle, data,
 
237
                                struct fileid_handle_data,
 
238
                                return id);
 
239
 
 
240
        id.devid        = data->device_mapping_fn(data, sbuf->st_dev);
 
241
        id.inode        = sbuf->st_ino;
 
242
 
 
243
        return id;
 
244
}
 
245
 
 
246
static vfs_op_tuple fileid_ops[] = {
 
247
 
 
248
        /* Disk operations */
 
249
        {
 
250
                SMB_VFS_OP(fileid_connect),
 
251
                SMB_VFS_OP_CONNECT,
 
252
                SMB_VFS_LAYER_TRANSPARENT
 
253
        },
 
254
        {
 
255
                SMB_VFS_OP(fileid_disconnect),
 
256
                SMB_VFS_OP_DISCONNECT,
 
257
                SMB_VFS_LAYER_TRANSPARENT
 
258
        },
 
259
 
 
260
        /* File operations */
 
261
        {
 
262
                SMB_VFS_OP(fileid_file_id_create),
 
263
                SMB_VFS_OP_FILE_ID_CREATE,
 
264
                SMB_VFS_LAYER_OPAQUE
 
265
        },
 
266
 
 
267
        /* End marker */
 
268
        {
 
269
                SMB_VFS_OP(NULL),
 
270
                SMB_VFS_OP_NOOP,
 
271
                SMB_VFS_LAYER_NOOP
 
272
        }
 
273
};
 
274
 
 
275
NTSTATUS vfs_fileid_init(void);
 
276
NTSTATUS vfs_fileid_init(void)
 
277
{
 
278
        NTSTATUS ret;
 
279
 
 
280
        ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fileid", fileid_ops);
 
281
        if (!NT_STATUS_IS_OK(ret)) {
 
282
                return ret;
 
283
        }
 
284
 
 
285
        vfs_fileid_debug_level = debug_add_class("fileid");
 
286
        if (vfs_fileid_debug_level == -1) {
 
287
                vfs_fileid_debug_level = DBGC_VFS;
 
288
                DEBUG(0, ("vfs_fileid: Couldn't register custom debugging class!\n"));
 
289
        } else {
 
290
                DEBUG(10, ("vfs_fileid: Debug class number of 'fileid': %d\n", vfs_fileid_debug_level));
 
291
        }
 
292
 
 
293
        return ret;
 
294
}