root/source3/modules/onefs_dir.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rdp_retrieve_dir_state
  2. rdp_init
  3. rdp_fill_cache
  4. onefs_rdp_add_dir_state
  5. onefs_opendir
  6. onefs_readdir
  7. onefs_seekdir
  8. onefs_telldir
  9. onefs_rewinddir
  10. onefs_closedir
  11. onefs_init_search_op

   1 /*
   2  * Unix SMB/CIFS implementation.
   3  *
   4  * Support for OneFS bulk directory enumeration API
   5  *
   6  * Copyright (C) Steven Danneman, 2009
   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 #include "onefs.h"
  24 #include "onefs_config.h"
  25 
  26 #include <ifs/ifs_syscalls.h>
  27 #include <isi_util/isi_dir.h>
  28 
  29 /* The OneFS filesystem provides a readdirplus() syscall, equivalent to the
  30  * NFSv3 PDU, which retrieves bulk directory listings with stat information
  31  * in a single syscall.
  32  *
  33  * This file hides this bulk interface underneath Samba's very POSIX like
  34  * opendir/readdir/telldir VFS interface.  This is done to provide a
  35  * significant performance improvement when listing the contents of large
  36  * directories, which also require file meta information. ie a typical
  37  * Windows Explorer request.
  38  */
  39 
  40 #define RDP_RESUME_KEY_START 0x1
  41 
  42 #define RDP_BATCH_SIZE 128
  43 #define RDP_DIRENTRIES_SIZE ((size_t)(RDP_BATCH_SIZE * sizeof(struct dirent)))
  44 
  45 static char *rdp_direntries = NULL;
  46 static SMB_STRUCT_STAT *rdp_stats = NULL;
  47 static uint64_t *rdp_cookies = NULL;
  48 
  49 struct rdp_dir_state {
  50         struct rdp_dir_state *next, *prev;
  51         SMB_STRUCT_DIR *dirp;
  52         char *direntries_cursor; /* cursor to last returned direntry in cache */
  53         size_t stat_count;       /* number of entries stored in the cache */
  54         size_t stat_cursor;      /* cursor to last returned stat in the cache */
  55         uint64_t resume_cookie;  /* cookie from the last entry returned from the
  56                                     cache */
  57 };
  58 
  59 static struct rdp_dir_state *dirstatelist = NULL;
  60 
  61 SMB_STRUCT_DIR *rdp_last_dirp = NULL;
  62 
  63 /**
  64  * Given a DIR pointer, return our internal state.
  65  *
  66  * This function also tells us whether the given DIR is the same as we saw
  67  * during the last call.  Because we use a single globally allocated buffer
  68  * for readdirplus entries we must check every call into this API to see if
  69  * it's for the same directory listing, or a new one. If it's the same we can
  70  * maintain our current cached entries, otherwise we must go to the kernel.
  71  *
  72  * @return 0 on success, 1 on failure
  73  */
  74 static int
  75 rdp_retrieve_dir_state(SMB_STRUCT_DIR *dirp, struct rdp_dir_state **dir_state,
     /* [<][>][^][v][top][bottom][index][help] */
  76                        bool *same_as_last)
  77 {
  78         struct rdp_dir_state *dsp;
  79 
  80         /* Is this directory the same as the last call */
  81         *same_as_last = (dirp == rdp_last_dirp);
  82 
  83         for(dsp = dirstatelist; dsp; dsp = dsp->next)
  84                 if (dsp->dirp == dirp) {
  85                         *dir_state = dsp;
  86                         return 0;
  87                 }
  88 
  89         /* Couldn't find existing dir_state for the given directory
  90          * pointer. */
  91         return 1;
  92 }
  93 
  94 /**
  95  * Initialize the global readdirplus buffers.
  96  *
  97  * These same buffers are used for all calls into readdirplus.
  98  *
  99  * @return 0 on success, errno value on failure
 100  */
 101 static int
 102 rdp_init(struct rdp_dir_state *dsp)
     /* [<][>][^][v][top][bottom][index][help] */
 103 {
 104         /* Unfortunately, there is no good way to free these buffers.  If we
 105          * allocated and freed for every DIR handle performance would be
 106          * adversely affected.  For now these buffers will be leaked and only
 107          * freed when the smbd process dies. */
 108         if (!rdp_direntries) {
 109                 rdp_direntries = SMB_MALLOC(RDP_DIRENTRIES_SIZE);
 110                 if (!rdp_direntries)
 111                         return ENOMEM;
 112         }
 113 
 114         if (!rdp_stats) {
 115                 rdp_stats =
 116                     SMB_MALLOC(RDP_BATCH_SIZE * sizeof(SMB_STRUCT_STAT));
 117                 if (!rdp_stats)
 118                         return ENOMEM;
 119         }
 120 
 121         if (!rdp_cookies) {
 122                 rdp_cookies = SMB_MALLOC(RDP_BATCH_SIZE * sizeof(uint64_t));
 123                 if (!rdp_cookies)
 124                         return ENOMEM;
 125         }
 126 
 127         dsp->direntries_cursor = rdp_direntries + RDP_DIRENTRIES_SIZE;
 128         dsp->stat_count = RDP_BATCH_SIZE;
 129         dsp->stat_cursor = RDP_BATCH_SIZE;
 130         dsp->resume_cookie = RDP_RESUME_KEY_START;
 131 
 132         return 0;
 133 }
 134 
 135 /**
 136  * Call into readdirplus() to refill our global dirent cache.
 137  *
 138  * This function also resets all cursors back to the beginning of the cache.
 139  * All stat buffers are retrieved by following symlinks.
 140  *
 141  * @return number of entries retrieved, -1 on error
 142  */
 143 static int
 144 rdp_fill_cache(struct rdp_dir_state *dsp)
     /* [<][>][^][v][top][bottom][index][help] */
 145 {
 146         int nread, dirfd;
 147 
 148         dirfd = dirfd(dsp->dirp);
 149         if (dirfd < 0) {
 150                 DEBUG(1, ("Could not retrieve fd for DIR\n"));
 151                 return -1;
 152         }
 153 
 154         /* Resize the stat_count to grab as many entries as possible */
 155         dsp->stat_count = RDP_BATCH_SIZE;
 156 
 157         DEBUG(9, ("Calling readdirplus() with DIR %p, dirfd: %d, "
 158                  "resume_cookie %#llx, size_to_read: %zu, "
 159                  "direntries_size: %zu, stat_count: %u\n",
 160                  dsp->dirp, dirfd, dsp->resume_cookie, RDP_BATCH_SIZE,
 161                  RDP_DIRENTRIES_SIZE, dsp->stat_count));
 162 
 163         nread = readdirplus(dirfd,
 164                             RDP_FOLLOW,
 165                             &dsp->resume_cookie,
 166                             RDP_BATCH_SIZE,
 167                             rdp_direntries,
 168                             RDP_DIRENTRIES_SIZE,
 169                             &dsp->stat_count,
 170                             rdp_stats,
 171                             rdp_cookies);
 172         if (nread < 0) {
 173                 DEBUG(1, ("Error calling readdirplus(): %s\n",
 174                          strerror(errno)));
 175                 return -1;
 176         }
 177 
 178         DEBUG(9, ("readdirplus() returned %u entries from DIR %p\n",
 179                  dsp->stat_count, dsp->dirp));
 180 
 181         dsp->direntries_cursor = rdp_direntries;
 182         dsp->stat_cursor = 0;
 183 
 184         return nread;
 185 }
 186 
 187 /**
 188  * Create a dir_state to track an open directory that we're enumerating.
 189  *
 190  * This utility function is globally accessible for use by other parts of the
 191  * onefs.so module to initialize a dir_state when a directory is opened through
 192  * a path other than the VFS layer.
 193  *
 194  * @return 0 on success and errno on failure
 195  *
 196  * @note: Callers of this function MUST cleanup the dir_state through a proper
 197  * call to VFS_CLOSEDIR().
 198  */
 199 int
 200 onefs_rdp_add_dir_state(connection_struct *conn, SMB_STRUCT_DIR *dirp)
     /* [<][>][^][v][top][bottom][index][help] */
 201 {
 202         int ret = 0;
 203         struct rdp_dir_state *dsp = NULL;
 204 
 205         /* No-op if readdirplus is disabled */
 206         if (!lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE,
 207             PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
 208         {
 209                 return 0;
 210         }
 211 
 212         /* Create a struct dir_state */
 213         dsp = SMB_MALLOC_P(struct rdp_dir_state);
 214         if (!dsp) {
 215                 DEBUG(0, ("Error allocating struct rdp_dir_state.\n"));
 216                 return ENOMEM;
 217         }
 218 
 219         /* Initialize the dir_state structure and add it to the list */
 220         ret = rdp_init(dsp);
 221         if (ret) {
 222                 DEBUG(0, ("Error initializing readdirplus() buffers: %s\n",
 223                          strerror(ret)));
 224                 return ret;
 225         }
 226 
 227         /* Set the SMB_STRUCT_DIR in the dsp */
 228         dsp->dirp = dirp;
 229 
 230         DLIST_ADD(dirstatelist, dsp);
 231 
 232         return 0;
 233 }
 234 
 235 /**
 236  * Open a directory for enumeration.
 237  *
 238  * Create a state struct to track the state of this directory for the life
 239  * of this open.
 240  *
 241  * @param[in] handle vfs handle given in most VFS calls
 242  * @param[in] fname filename of the directory to open
 243  * @param[in] mask unused
 244  * @param[in] attr unused
 245  *
 246  * @return DIR pointer, NULL if directory does not exist, NULL on error
 247  */
 248 SMB_STRUCT_DIR *
 249 onefs_opendir(vfs_handle_struct *handle, const char *fname, const char *mask,
     /* [<][>][^][v][top][bottom][index][help] */
 250               uint32 attr)
 251 {
 252         int ret = 0;
 253         SMB_STRUCT_DIR *ret_dirp;
 254 
 255         /* Fallback to default system routines if readdirplus is disabled */
 256         if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
 257             PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
 258         {
 259                 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
 260         }
 261 
 262         /* Open the directory */
 263         ret_dirp = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
 264         if (!ret_dirp) {
 265                 DEBUG(3, ("Unable to open directory: %s\n", fname));
 266                 return NULL;
 267         }
 268 
 269         /* Create the dir_state struct and add it to the list */
 270         ret = onefs_rdp_add_dir_state(handle->conn, ret_dirp);
 271         if (ret) {
 272                 DEBUG(0, ("Error adding dir_state to the list\n"));
 273                 return NULL;
 274         }
 275 
 276         DEBUG(9, ("Opened handle on directory: \"%s\", DIR %p\n",
 277                  fname, ret_dirp));
 278 
 279         return ret_dirp;
 280 }
 281 
 282 /**
 283  * Retrieve one direntry and optional stat buffer from our readdir cache.
 284  *
 285  * Increment the internal resume cookie, and refresh the cache from the
 286  * kernel if necessary.
 287  *
 288  * The cache cursor tracks the last entry which was successfully returned
 289  * to a caller of onefs_readdir().  When a new entry is requested, this
 290  * function first increments the cursor, then returns that entry.
 291  *
 292  * @param[in] handle vfs handle given in most VFS calls
 293  * @param[in] dirp system DIR handle to retrieve direntries from
 294  * @param[in/out] sbuf optional stat buffer to fill, this can be NULL
 295  *
 296  * @return dirent structure, NULL if at the end of the directory, NULL on error
 297  */
 298 SMB_STRUCT_DIRENT *
 299 onefs_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp,
     /* [<][>][^][v][top][bottom][index][help] */
 300               SMB_STRUCT_STAT *sbuf)
 301 {
 302         struct rdp_dir_state *dsp = NULL;
 303         SMB_STRUCT_DIRENT *ret_direntp;
 304         bool same_as_last, filled_cache = false;
 305         int ret = -1;
 306 
 307         /* Set stat invalid in-case we error out */
 308         if (sbuf)
 309                 SET_STAT_INVALID(*sbuf);
 310 
 311         /* Fallback to default system routines if readdirplus is disabled */
 312         if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
 313             PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
 314         {
 315                 return sys_readdir(dirp);
 316         }
 317 
 318         /* Retrieve state based off DIR handle */
 319         ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last);
 320         if (ret) {
 321                 DEBUG(1, ("Could not retrieve dir_state struct for "
 322                          "SMB_STRUCT_DIR pointer.\n"));
 323                 ret_direntp = NULL;
 324                 goto end;
 325         }
 326 
 327         /* DIR is the same, current buffer and cursors are valid.
 328          * Check if there are any entries left in our current cache. */
 329         if (same_as_last) {
 330                 if (dsp->stat_cursor == dsp->stat_count - 1) {
 331                         /* Cache is empty, refill from kernel */
 332                         ret = rdp_fill_cache(dsp);
 333                         if (ret <= 0) {
 334                                 ret_direntp = NULL;
 335                                 goto end;
 336                         }
 337                         filled_cache = true;
 338                 }
 339         } else {
 340                 /* DIR is different from last call, reset all buffers and
 341                  * cursors, and refill the global cache from the new DIR */
 342                 ret = rdp_fill_cache(dsp);
 343                 if (ret <= 0) {
 344                         ret_direntp = NULL;
 345                         goto end;
 346                 }
 347                 filled_cache = true;
 348                 DEBUG(8, ("Switched global rdp cache to new DIR entry.\n"));
 349         }
 350 
 351         /* If we just filled the cache we treat that action as the cursor
 352          * increment as the resume cookie used belonged to the previous
 353          * directory entry.  If the cache has not changed we first increment
 354          * our cursor, then return the next entry */
 355         if (!filled_cache) {
 356                 dsp->direntries_cursor +=
 357                     ((SMB_STRUCT_DIRENT *)dsp->direntries_cursor)->d_reclen;
 358                 dsp->stat_cursor++;
 359         }
 360 
 361         /* The resume_cookie stored here purposely differs based on whether we
 362          * just filled the cache. The resume cookie stored must always provide
 363          * the next direntry, in case the cache is reloaded on every
 364          * onefs_readdir() */
 365         dsp->resume_cookie = rdp_cookies[dsp->stat_cursor];
 366 
 367         /* Return an entry from cache */
 368         ret_direntp = ((SMB_STRUCT_DIRENT *)dsp->direntries_cursor);
 369         if (sbuf) {
 370                 *sbuf = rdp_stats[dsp->stat_cursor];
 371                 /* readdirplus() sets st_ino field to 0, if it was
 372                  * unable to retrieve stat information for that
 373                  * particular directory entry. */
 374                 if (sbuf->st_ino == 0)
 375                         SET_STAT_INVALID(*sbuf);
 376         }
 377 
 378         DEBUG(9, ("Read from DIR %p, direntry: \"%s\", resume cookie: %#llx, "
 379                  "cache cursor: %zu, cache count: %zu\n",
 380                  dsp->dirp, ret_direntp->d_name, dsp->resume_cookie,
 381                  dsp->stat_cursor, dsp->stat_count));
 382 
 383         /* FALLTHROUGH */
 384 end:
 385         /* Set rdp_last_dirp at the end of every VFS call where the cache was
 386          * reloaded */
 387         rdp_last_dirp = dirp;
 388         return ret_direntp;
 389 }
 390 
 391 /**
 392  * Set the location of the next direntry to be read via onefs_readdir().
 393  *
 394  * This function should only pass in locations retrieved from onefs_telldir().
 395  *
 396  * @param[in] handle vfs handle given in most VFS calls
 397  * @param[in] dirp system DIR handle to set offset on
 398  * @param[in] offset into the directory to resume reading from
 399  *
 400  * @return no return value
 401  */
 402 void
 403 onefs_seekdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, long offset)
     /* [<][>][^][v][top][bottom][index][help] */
 404 {
 405         struct rdp_dir_state *dsp = NULL;
 406         bool same_as_last;
 407         uint64_t resume_cookie = 0;
 408         int ret = -1;
 409 
 410         /* Fallback to default system routines if readdirplus is disabled */
 411         if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
 412             PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
 413         {
 414                 return sys_seekdir(dirp, offset);
 415         }
 416 
 417         /* Validate inputs */
 418         if (offset < 0) {
 419                 DEBUG(1, ("Invalid offset %ld passed.\n", offset));
 420                 return;
 421         }
 422 
 423         /* Retrieve state based off DIR handle */
 424         ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last);
 425         if (ret) {
 426                 DEBUG(1, ("Could not retrieve dir_state struct for "
 427                          "SMB_STRUCT_DIR pointer.\n"));
 428                 /* XXX: we can't return an error, should we ABORT rather than
 429                  * return without actually seeking? */
 430                 return;
 431         }
 432 
 433         /* Convert offset to resume_cookie */
 434         resume_cookie = rdp_offset31_to_cookie63(offset);
 435 
 436         DEBUG(9, ("Seek DIR %p, offset: %ld, resume_cookie: %#llx\n",
 437                  dsp->dirp, offset, resume_cookie));
 438 
 439         /* TODO: We could check if the resume_cookie is already in the cache
 440          * through a linear search.  This would allow us to avoid the cost of
 441          * flushing the cache.  Frequently, the seekdir offset will only be
 442          * one entry before the current cache cursor.  However, usually
 443          * VFS_SEEKDIR() is only called at the end of a TRAND2_FIND read and
 444          * we'll flush the cache at the beginning of the next PDU anyway. Some
 445          * analysis should be done to see if this enhancement would provide
 446          * better performance. */
 447 
 448         /* Set the resume cookie and indicate that the cache should be reloaded
 449          * on next read */
 450         dsp->resume_cookie = resume_cookie;
 451         rdp_last_dirp = NULL;
 452 
 453         return;
 454 }
 455 
 456 /**
 457  * Returns the location of the next direntry to be read via onefs_readdir().
 458  *
 459  * This value can be passed into onefs_seekdir().
 460  *
 461  * @param[in] handle vfs handle given in most VFS calls
 462  * @param[in] dirp system DIR handle to set offset on
 463  *
 464  * @return offset into the directory to resume reading from
 465  */
 466 long
 467 onefs_telldir(vfs_handle_struct *handle,  SMB_STRUCT_DIR *dirp)
     /* [<][>][^][v][top][bottom][index][help] */
 468 {
 469         struct rdp_dir_state *dsp = NULL;
 470         bool same_as_last;
 471         long offset;
 472         int ret = -1;
 473 
 474         /* Fallback to default system routines if readdirplus is disabled */
 475         if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
 476             PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
 477         {
 478                 return sys_telldir(dirp);
 479         }
 480 
 481         /* Retrieve state based off DIR handle */
 482         ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last);
 483         if (ret) {
 484                 DEBUG(1, ("Could not retrieve dir_state struct for "
 485                          "SMB_STRUCT_DIR pointer.\n"));
 486                 return -1;
 487         }
 488 
 489         /* Convert resume_cookie to offset */
 490         offset = rdp_cookie63_to_offset31(dsp->resume_cookie);
 491         if (offset < 0) {
 492                 DEBUG(1, ("Unable to convert resume_cookie: %#llx to a "
 493                          "suitable 32-bit offset value. Error: %s\n",
 494                          dsp->resume_cookie, strerror(errno)));
 495                 return -1;
 496         }
 497 
 498         DEBUG(9, ("Seek DIR %p, offset: %ld, resume_cookie: %#llx\n",
 499                  dsp->dirp, offset, dsp->resume_cookie));
 500 
 501         return offset;
 502 }
 503 
 504 /**
 505  * Set the next direntry to be read via onefs_readdir() to the beginning of the
 506  * directory.
 507  *
 508  * @param[in] handle vfs handle given in most VFS calls
 509  * @param[in] dirp system DIR handle to set offset on
 510  *
 511  * @return no return value
 512  */
 513 void
 514 onefs_rewinddir(vfs_handle_struct *handle,  SMB_STRUCT_DIR *dirp)
     /* [<][>][^][v][top][bottom][index][help] */
 515 {
 516         struct rdp_dir_state *dsp = NULL;
 517         bool same_as_last;
 518         int ret = -1;
 519 
 520         /* Fallback to default system routines if readdirplus is disabled */
 521         if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
 522             PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
 523         {
 524                 return sys_rewinddir(dirp);
 525         }
 526 
 527         /* Retrieve state based off DIR handle */
 528         ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last);
 529         if (ret) {
 530                 DEBUG(1, ("Could not retrieve dir_state struct for "
 531                          "SMB_STRUCT_DIR pointer.\n"));
 532                 return;
 533         }
 534 
 535         /* Reset location and resume key to beginning */
 536         ret = rdp_init(dsp);
 537         if (ret) {
 538                 DEBUG(0, ("Error re-initializing rdp cursors: %s\n",
 539                     strerror(ret)));
 540                 return;
 541         }
 542 
 543         DEBUG(9, ("Rewind DIR: %p, to resume_cookie: %#llx\n", dsp->dirp,
 544                  dsp->resume_cookie));
 545 
 546         return;
 547 }
 548 
 549 /**
 550  * Close DIR pointer and remove all state for that directory open.
 551  *
 552  * @param[in] handle vfs handle given in most VFS calls
 553  * @param[in] dirp system DIR handle to set offset on
 554  *
 555  * @return -1 on failure, setting errno
 556  */
 557 int
 558 onefs_closedir(vfs_handle_struct *handle,  SMB_STRUCT_DIR *dirp)
     /* [<][>][^][v][top][bottom][index][help] */
 559 {
 560         struct rdp_dir_state *dsp = NULL;
 561         bool same_as_last;
 562         int ret_val = -1;
 563         int ret = -1;
 564 
 565         /* Fallback to default system routines if readdirplus is disabled */
 566         if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
 567             PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
 568         {
 569                 return SMB_VFS_NEXT_CLOSEDIR(handle, dirp);
 570         }
 571 
 572         /* Retrieve state based off DIR handle */
 573         ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last);
 574         if (ret) {
 575                 DEBUG(1, ("Could not retrieve dir_state struct for "
 576                          "SMB_STRUCT_DIR pointer.\n"));
 577                 errno = ENOENT;
 578                 return -1;
 579         }
 580 
 581         /* Close DIR pointer */
 582         ret_val = SMB_VFS_NEXT_CLOSEDIR(handle, dsp->dirp);
 583 
 584         DEBUG(9, ("Closed handle on DIR %p\n", dsp->dirp));
 585 
 586         /* Tear down state struct */
 587         DLIST_REMOVE(dirstatelist, dsp);
 588         SAFE_FREE(dsp);
 589 
 590         /* Set lastp to NULL, as cache is no longer valid */
 591         rdp_last_dirp = NULL;
 592 
 593         return ret_val;
 594 }
 595 
 596 /**
 597  * Initialize cache data at the beginning of every SMB search operation
 598  *
 599  * Since filesystem operations, such as delete files or meta data
 600  * updates can occur to files in the directory we're searching
 601  * between FIND_FIRST and FIND_NEXT calls we must refresh the cache
 602  * from the kernel on every new search SMB.
 603  *
 604  * @param[in] handle vfs handle given in most VFS calls
 605  * @param[in] dirp system DIR handle for the current search
 606  *
 607  * @return nothing
 608  */
 609 void
 610 onefs_init_search_op(vfs_handle_struct *handle,  SMB_STRUCT_DIR *dirp)
     /* [<][>][^][v][top][bottom][index][help] */
 611 {
 612         /* Setting the rdp_last_dirp to NULL will cause the next readdir
 613          * operation to refill the cache. */
 614         rdp_last_dirp = NULL;
 615 
 616         return;
 617 }

/* [<][>][^][v][top][bottom][index][help] */