2 Unix SMB/CIFS implementation.
3 Make use of gpfs prefetch functionality
5 Copyright (C) Volker Lendecke 2008
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #define DBGC_CLASS DBGC_VFS
28 #include <gpfs_fcntl.h>
30 static int (*gpfs_fcntl_fn
)(int fd
, void *arg
);
32 static int smbd_gpfs_fcntl(int fd
, void *arg
)
34 static void *libgpfs_handle
= NULL
;
36 DEBUG(10, ("smbd_gpfs_fcntl called for %d\n", fd
));
38 if (gpfs_fcntl_fn
== NULL
) {
39 libgpfs_handle
= sys_dlopen("libgpfs.so", RTLD_LAZY
);
41 if (libgpfs_handle
== NULL
) {
42 DEBUG(10, ("sys_dlopen for libgpfs failed: %s\n",
47 gpfs_fcntl_fn
= sys_dlsym(libgpfs_handle
, "gpfs_fcntl");
48 if (gpfs_fcntl_fn
== NULL
) {
49 DEBUG(3, ("libgpfs.so does not contain the symbol "
56 return gpfs_fcntl_fn(fd
, arg
);
59 struct gpfs_prefetch_config
{
60 name_compare_entry
*namelist
;
64 struct gpfs_prefetch_hints
{
67 * The current center around which config->size bytes are
73 static void gpfs_prefetch_recenter(vfs_handle_struct
*handle
,
75 SMB_OFF_T offset
, size_t size
,
76 struct gpfs_prefetch_hints
*hints
)
82 gpfsFcntlHeader_t hdr
;
83 gpfsMultipleAccessRange_t acc
;
87 if (hints
->st_blksize
== 0) {
90 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
93 DEBUG(10, ("gpfs_prefetch_recenter: st_blksize = %d\n",
94 (int)sbuf
.st_blksize
));
95 hints
->st_blksize
= sbuf
.st_blksize
;
98 new_center
= (offset
> size
) ? offset
: 0;
100 DEBUG(10, ("gpfs_prefetch_recenter: size=%d, offset=%d, "
101 "old_center=%d, new_center=%d\n", (int)size
, (int)offset
,
102 (int)hints
->center
, (int)new_center
));
106 arg
.hdr
.totalLength
= sizeof(arg
);
107 arg
.hdr
.fcntlVersion
= GPFS_FCNTL_CURRENT_VERSION
;
108 arg
.hdr
.fcntlReserved
= 0;
109 arg
.acc
.structLen
= sizeof(arg
.acc
);
110 arg
.acc
.structType
= GPFS_MULTIPLE_ACCESS_RANGE
;
111 arg
.acc
.accRangeCnt
= 1;
112 arg
.acc
.relRangeCnt
= 1;
114 arg
.acc
.accRangeArray
[0].blockNumber
= new_center
/hints
->st_blksize
;
115 arg
.acc
.accRangeArray
[0].start
= 0;
116 arg
.acc
.accRangeArray
[0].length
= size
;
117 arg
.acc
.accRangeArray
[0].isWrite
= 0;
119 arg
.acc
.relRangeArray
[0].blockNumber
= hints
->center
/hints
->st_blksize
;
120 arg
.acc
.relRangeArray
[0].start
= 0;
121 arg
.acc
.relRangeArray
[0].length
= size
;
122 arg
.acc
.relRangeArray
[0].isWrite
= 0;
124 ret
= smbd_gpfs_fcntl(fsp
->fh
->fd
, &arg
);
126 DEBUG(5, ("gpfs_fcntl returned %s\n", strerror(errno
)));
129 hints
->center
= new_center
;
132 static ssize_t
gpfs_prefetch_pread(vfs_handle_struct
*handle
,
133 files_struct
*fsp
, void *data
,
134 size_t n
, SMB_OFF_T offset
)
136 struct gpfs_prefetch_config
*config
=
137 (struct gpfs_prefetch_config
*)handle
->data
;
138 struct gpfs_prefetch_hints
*hints
= (struct gpfs_prefetch_hints
*)
139 VFS_FETCH_FSP_EXTENSION(handle
, fsp
);
140 SMB_OFF_T out_of_center
;
143 * How far away from the center of the prefetch region is the
147 out_of_center
= (offset
> hints
->center
)
148 ? (offset
- hints
->center
) : (hints
->center
- offset
);
150 DEBUG(10, ("gpfs_prefetch_pread: n=%d, offset=%d, center=%d, "
151 "out_of_center=%d, size=%d\n", (int)n
, (int)offset
,
152 (int)hints
->center
, (int)out_of_center
,
155 * Are we completely out of the prefetch range or less than
156 * 10% at its borders?
159 if ((out_of_center
> config
->size
)
160 || ((config
->size
- out_of_center
) * 10 < config
->size
)) {
162 * Re-center the prefetch area
164 gpfs_prefetch_recenter(handle
, fsp
, offset
, config
->size
,
168 return SMB_VFS_NEXT_PREAD(handle
, fsp
, data
, n
, offset
);
171 static int gpfs_prefetch_open(vfs_handle_struct
*handle
, const char *fname
,
172 files_struct
*fsp
, int flags
, mode_t mode
)
175 struct gpfs_prefetch_hints
*hints
;
176 struct gpfs_prefetch_config
*config
=
177 (struct gpfs_prefetch_config
*)handle
->data
;
180 gpfsFcntlHeader_t hdr
;
181 gpfsAccessRange_t acc
;
184 DEBUG(10, ("gpfs_prefetch_open called for %s, config=%p, "
185 "config->namelist = %p, config->size=%d\n", fname
,
186 config
, config
->namelist
, (int)config
->size
));
188 if (!is_in_path(fname
, config
->namelist
,
189 handle
->conn
->case_sensitive
)) {
190 DEBUG(10, ("gpfs_prefetch_open not in list: %s\n", fname
));
191 return SMB_VFS_NEXT_OPEN(handle
, fname
, fsp
, flags
, mode
);
194 hints
= (struct gpfs_prefetch_hints
*)VFS_ADD_FSP_EXTENSION(
195 handle
, fsp
, struct gpfs_prefetch_hints
);
201 fd
= SMB_VFS_NEXT_OPEN(handle
, fname
, fsp
, flags
, mode
);
203 VFS_REMOVE_FSP_EXTENSION(handle
, fsp
);
207 arg
.hdr
.totalLength
= sizeof(arg
);
208 arg
.hdr
.fcntlVersion
= GPFS_FCNTL_CURRENT_VERSION
;
209 arg
.hdr
.fcntlReserved
= 0;
210 arg
.acc
.structLen
= sizeof(arg
.acc
);
211 arg
.acc
.structType
= GPFS_ACCESS_RANGE
;
216 ret
= smbd_gpfs_fcntl(fd
, &arg
);
218 DEBUG(5, ("gpfs_fcntl returned %s\n", strerror(errno
)));
221 hints
->st_blksize
= 0;
227 static void gpfs_prefetch_config_free(void **data
)
229 struct gpfs_prefetch_config
**config
=
230 (struct gpfs_prefetch_config
**)data
;
232 free_namearray((*config
)->namelist
);
233 TALLOC_FREE(*config
);
236 static int gpfs_prefetch_connect(struct vfs_handle_struct
*handle
,
240 struct gpfs_prefetch_config
*config
;
243 config
= talloc(handle
, struct gpfs_prefetch_config
);
244 if (config
== NULL
) {
245 DEBUG(0, ("talloc failed\n"));
250 mask
= lp_parm_const_string(SNUM(handle
->conn
), "gpfs_prefetch",
253 set_namearray(&config
->namelist
, mask
);
254 config
->size
= lp_parm_int(SNUM(handle
->conn
), "gpfs_prefetch",
258 * The size calculations in the core routines assume that
259 * config->size is the size from the center to the border of
260 * the prefetched area. So we need to multiply by 1024/2 here
261 * to get the whole prefetch area in kilobytes.
263 config
->size
*= 1024/2;
265 SMB_VFS_HANDLE_SET_DATA(handle
, config
, gpfs_prefetch_config_free
,
266 struct gpfs_prefetch_config
, goto fail
);
268 return SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
271 free_namearray(config
->namelist
);
276 /* VFS operations structure */
278 static vfs_op_tuple gpfs_prefetch_op_tuples
[] = {
280 {SMB_VFS_OP(gpfs_prefetch_open
), SMB_VFS_OP_OPEN
,
281 SMB_VFS_LAYER_TRANSPARENT
},
282 {SMB_VFS_OP(gpfs_prefetch_pread
), SMB_VFS_OP_PREAD
,
283 SMB_VFS_LAYER_TRANSPARENT
},
284 {SMB_VFS_OP(gpfs_prefetch_connect
), SMB_VFS_OP_CONNECT
,
285 SMB_VFS_LAYER_TRANSPARENT
},
287 { SMB_VFS_OP(NULL
), SMB_VFS_OP_NOOP
, SMB_VFS_LAYER_NOOP
}
291 * When done properly upstream (GPL issue resolved), change this
292 * routine name to vfs_gpfs_prefetch_init!!
295 NTSTATUS
init_samba_module(void);
296 NTSTATUS
init_samba_module(void)
300 DEBUG(10, ("vfs_gpfs_prefetch_init called\n"));
302 status
= smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "gpfs_prefetch",
303 gpfs_prefetch_op_tuples
);
304 DEBUG(10, ("smb_register_vfs returned %s\n",