smbd/fileio.c

説明を見る。
00001 /* 
00002    Unix SMB/Netbios implementation.
00003    Version 1.9.
00004    read/write to a files_struct
00005    Copyright (C) Andrew Tridgell 1992-1998
00006    Copyright (C) Jeremy Allison 2000-2002. - write cache.
00007    
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017    
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 
00023 #include "includes.h"
00024 
00025 static BOOL setup_write_cache(files_struct *, SMB_OFF_T);
00026 
00027 /****************************************************************************
00028  Read from write cache if we can.
00029 ****************************************************************************/
00030 
00031 static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
00032 {
00033         write_cache *wcp = fsp->wcp;
00034 
00035         if(!wcp) {
00036                 return False;
00037         }
00038 
00039         if( n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) {
00040                 return False;
00041         }
00042 
00043         memcpy(data, wcp->data + (pos - wcp->offset), n);
00044 
00045         DO_PROFILE_INC(writecache_read_hits);
00046 
00047         return True;
00048 }
00049 
00050 /****************************************************************************
00051  Read from a file.
00052 ****************************************************************************/
00053 
00054 ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
00055 {
00056         ssize_t ret=0,readret;
00057 
00058         /* you can't read from print files */
00059         if (fsp->print_file) {
00060                 return -1;
00061         }
00062 
00063         /*
00064          * Serve from write cache if we can.
00065          */
00066 
00067         if(read_from_write_cache(fsp, data, pos, n)) {
00068                 fsp->fh->pos = pos + n;
00069                 fsp->fh->position_information = fsp->fh->pos;
00070                 return n;
00071         }
00072 
00073         flush_write_cache(fsp, READ_FLUSH);
00074 
00075         fsp->fh->pos = pos;
00076 
00077         if (n > 0) {
00078 #ifdef DMF_FIX
00079                 int numretries = 3;
00080 tryagain:
00081                 readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos);
00082 
00083                 if (readret == -1) {
00084                         if ((errno == EAGAIN) && numretries) {
00085                                 DEBUG(3,("read_file EAGAIN retry in 10 seconds\n"));
00086                                 (void)sleep(10);
00087                                 --numretries;
00088                                 goto tryagain;
00089                         }
00090                         return -1;
00091                 }
00092 #else /* NO DMF fix. */
00093                 readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos);
00094 
00095                 if (readret == -1) {
00096                         return -1;
00097                 }
00098 #endif
00099                 if (readret > 0) {
00100                         ret += readret;
00101                 }
00102         }
00103 
00104         DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n",
00105                 fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
00106 
00107         fsp->fh->pos += ret;
00108         fsp->fh->position_information = fsp->fh->pos;
00109 
00110         return(ret);
00111 }
00112 
00113 /* how many write cache buffers have been allocated */
00114 static unsigned int allocated_write_caches;
00115 
00116 /****************************************************************************
00117  *Really* write to a file.
00118 ****************************************************************************/
00119 
00120 static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos, size_t n)
00121 {
00122         ssize_t ret;
00123 
00124         if (pos == -1) {
00125                 ret = vfs_write_data(fsp, data, n);
00126         } else {
00127                 fsp->fh->pos = pos;
00128                 if (pos && lp_strict_allocate(SNUM(fsp->conn))) {
00129                         if (vfs_fill_sparse(fsp, pos) == -1) {
00130                                 return -1;
00131                         }
00132                 }
00133                 ret = vfs_pwrite_data(fsp, data, n, pos);
00134         }
00135 
00136         DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
00137                 fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));
00138 
00139         if (ret != -1) {
00140                 fsp->fh->pos += ret;
00141 
00142                 /*
00143                  * It turns out that setting the last write time from a Windows
00144                  * client stops any subsequent writes from updating the write time.
00145                  * Doing this after the write gives a race condition here where
00146                  * a stat may see the changed write time before we reset it here,
00147                  * but it's cheaper than having to store the write time in shared
00148                  * memory and look it up using dev/inode across all running smbd's.
00149                  * The 99% solution will hopefully be good enough in this case. JRA.
00150                  */
00151 
00152                 if (!null_timespec(fsp->pending_modtime)) {
00153                         set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime);
00154 
00155                         /* If we didn't get the "set modtime" call ourselves, we must
00156                            store the last write time to restore on close. JRA. */
00157                         if (!fsp->pending_modtime_owner) {
00158                                 fsp->last_write_time = timespec_current();
00159                         }
00160                 }
00161 
00162 /* Yes - this is correct - writes don't update this. JRA. */
00163 /* Found by Samba4 tests. */
00164 #if 0
00165                 fsp->position_information = fsp->pos;
00166 #endif
00167         }
00168 
00169         return ret;
00170 }
00171 
00172 /****************************************************************************
00173  File size cache change.
00174  Updates size on disk but doesn't flush the cache.
00175 ****************************************************************************/
00176 
00177 static int wcp_file_size_change(files_struct *fsp)
00178 {
00179         int ret;
00180         write_cache *wcp = fsp->wcp;
00181 
00182         wcp->file_size = wcp->offset + wcp->data_size;
00183         ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, wcp->file_size);
00184         if (ret == -1) {
00185                 DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f error %s\n",
00186                         fsp->fsp_name, (double)wcp->file_size, strerror(errno) ));
00187         }
00188         return ret;
00189 }
00190 
00191 /****************************************************************************
00192  Write to a file.
00193 ****************************************************************************/
00194 
00195 ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n)
00196 {
00197         write_cache *wcp = fsp->wcp;
00198         ssize_t total_written = 0;
00199         int write_path = -1; 
00200 
00201         if (fsp->print_file) {
00202                 fstring sharename;
00203                 uint32 jobid;
00204 
00205                 if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) {
00206                         DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n",
00207                                                 (unsigned int)fsp->rap_print_jobid ));
00208                         errno = EBADF;
00209                         return -1;
00210                 }
00211 
00212                 return print_job_write(SNUM(fsp->conn), jobid, data, pos, n);
00213         }
00214 
00215         if (!fsp->can_write) {
00216                 errno = EPERM;
00217                 return -1;
00218         }
00219 
00220         if (!fsp->modified) {
00221                 SMB_STRUCT_STAT st;
00222                 fsp->modified = True;
00223 
00224                 if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) {
00225                         int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
00226                         if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) {
00227                                 file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False);
00228                         }
00229 
00230                         /*
00231                          * If this is the first write and we have an exclusive oplock then setup
00232                          * the write cache.
00233                          */
00234 
00235                         if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
00236                                 setup_write_cache(fsp, st.st_size);
00237                                 wcp = fsp->wcp;
00238                         } 
00239                 }  
00240         }
00241 
00242 #ifdef WITH_PROFILE
00243         DO_PROFILE_INC(writecache_total_writes);
00244         if (!fsp->oplock_type) {
00245                 DO_PROFILE_INC(writecache_non_oplock_writes);
00246         }
00247 #endif
00248 
00249         /*
00250          * If this file is level II oplocked then we need
00251          * to grab the shared memory lock and inform all
00252          * other files with a level II lock that they need
00253          * to flush their read caches. We keep the lock over
00254          * the shared memory area whilst doing this.
00255          */
00256 
00257         release_level_2_oplocks_on_change(fsp);
00258 
00259 #ifdef WITH_PROFILE
00260         if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
00261                 DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
00262 nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
00263                         profile_p->writecache_init_writes,
00264                         profile_p->writecache_abutted_writes,
00265                         profile_p->writecache_total_writes,
00266                         profile_p->writecache_non_oplock_writes,
00267                         profile_p->writecache_allocated_write_caches,
00268                         profile_p->writecache_num_write_caches,
00269                         profile_p->writecache_direct_writes,
00270                         profile_p->writecache_num_perfect_writes,
00271                         profile_p->writecache_read_hits ));
00272 
00273                 DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
00274                         profile_p->writecache_flushed_writes[SEEK_FLUSH],
00275                         profile_p->writecache_flushed_writes[READ_FLUSH],
00276                         profile_p->writecache_flushed_writes[WRITE_FLUSH],
00277                         profile_p->writecache_flushed_writes[READRAW_FLUSH],
00278                         profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
00279                         profile_p->writecache_flushed_writes[CLOSE_FLUSH],
00280                         profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
00281         }
00282 #endif
00283 
00284         if(!wcp) {
00285                 DO_PROFILE_INC(writecache_direct_writes);
00286                 total_written = real_write_file(fsp, data, pos, n);
00287                 return total_written;
00288         }
00289 
00290         DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n",
00291                 fsp->fsp_name, fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size));
00292 
00293         fsp->fh->pos = pos + n;
00294 
00295         /* 
00296          * If we have active cache and it isn't contiguous then we flush.
00297          * NOTE: There is a small problem with running out of disk ....
00298          */
00299 
00300         if (wcp->data_size) {
00301                 BOOL cache_flush_needed = False;
00302 
00303                 if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) {
00304       
00305                         /* ASCII art.... JRA.
00306 
00307       +--------------+-----
00308       | Cached data  | Rest of allocated cache buffer....
00309       +--------------+-----
00310 
00311             +-------------------+
00312             | Data to write     |
00313             +-------------------+
00314 
00315                         */
00316 
00317                         /*
00318                          * Start of write overlaps or abutts the existing data.
00319                          */
00320 
00321                         size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n);
00322 
00323                         memcpy(wcp->data + (pos - wcp->offset), data, data_used);
00324 
00325                         /*
00326                          * Update the current buffer size with the new data.
00327                          */
00328 
00329                         if(pos + data_used > wcp->offset + wcp->data_size) {
00330                                 wcp->data_size = pos + data_used - wcp->offset;
00331                         }
00332 
00333                         /*
00334                          * Update the file size if changed.
00335                          */
00336 
00337                         if (wcp->offset + wcp->data_size > wcp->file_size) {
00338                                 if (wcp_file_size_change(fsp) == -1) {
00339                                         return -1;
00340                                 }
00341                         }
00342 
00343                         /*
00344                          * If we used all the data then
00345                          * return here.
00346                          */
00347 
00348                         if(n == data_used) {
00349                                 return n;
00350                         } else {
00351                                 cache_flush_needed = True;
00352                         }
00353                         /*
00354                          * Move the start of data forward by the amount used,
00355                          * cut down the amount left by the same amount.
00356                          */
00357 
00358                         data += data_used;
00359                         pos += data_used;
00360                         n -= data_used;
00361 
00362                         DO_PROFILE_INC(writecache_abutted_writes);
00363                         total_written = data_used;
00364 
00365                         write_path = 1;
00366 
00367                 } else if ((pos < wcp->offset) && (pos + n > wcp->offset) && 
00368                                         (pos + n <= wcp->offset + wcp->alloc_size)) {
00369 
00370                         /* ASCII art.... JRA.
00371 
00372                         +---------------+
00373                         | Cache buffer  |
00374                         +---------------+
00375 
00376             +-------------------+
00377             | Data to write     |
00378             +-------------------+
00379 
00380                         */
00381 
00382                         /*
00383                          * End of write overlaps the existing data.
00384                          */
00385 
00386                         size_t data_used = pos + n - wcp->offset;
00387 
00388                         memcpy(wcp->data, data + n - data_used, data_used);
00389 
00390                         /*
00391                          * Update the current buffer size with the new data.
00392                          */
00393 
00394                         if(pos + n > wcp->offset + wcp->data_size) {
00395                                 wcp->data_size = pos + n - wcp->offset;
00396                         }
00397 
00398                         /*
00399                          * Update the file size if changed.
00400                          */
00401 
00402                         if (wcp->offset + wcp->data_size > wcp->file_size) {
00403                                 if (wcp_file_size_change(fsp) == -1) {
00404                                         return -1;
00405                                 }
00406                         }
00407 
00408                         /*
00409                          * We don't need to move the start of data, but we
00410                          * cut down the amount left by the amount used.
00411                          */
00412 
00413                         n -= data_used;
00414 
00415                         /*
00416                          * We cannot have used all the data here.
00417                          */
00418 
00419                         cache_flush_needed = True;
00420 
00421                         DO_PROFILE_INC(writecache_abutted_writes);
00422                         total_written = data_used;
00423 
00424                         write_path = 2;
00425 
00426                 } else if ( (pos >= wcp->file_size) && 
00427                                         (wcp->offset + wcp->data_size == wcp->file_size) &&
00428                                         (pos > wcp->offset + wcp->data_size) && 
00429                                         (pos < wcp->offset + wcp->alloc_size) ) {
00430 
00431                         /* ASCII art.... JRA.
00432 
00433                        End of file ---->|
00434 
00435                         +---------------+---------------+
00436                         | Cached data   | Cache buffer  |
00437                         +---------------+---------------+
00438 
00439                                               +-------------------+
00440                                               | Data to write     |
00441                                               +-------------------+
00442 
00443                         */
00444 
00445                         /*
00446                          * Non-contiguous write part of which fits within
00447                          * the cache buffer and is extending the file
00448                          * and the cache contents reflect the current
00449                          * data up to the current end of the file.
00450                          */
00451 
00452                         size_t data_used;
00453 
00454                         if(pos + n <= wcp->offset + wcp->alloc_size) {
00455                                 data_used = n;
00456                         } else {
00457                                 data_used = wcp->offset + wcp->alloc_size - pos;
00458                         }
00459 
00460                         /*
00461                          * Fill in the non-continuous area with zeros.
00462                          */
00463 
00464                         memset(wcp->data + wcp->data_size, '\0',
00465                                 pos - (wcp->offset + wcp->data_size) );
00466 
00467                         memcpy(wcp->data + (pos - wcp->offset), data, data_used);
00468 
00469                         /*
00470                          * Update the current buffer size with the new data.
00471                          */
00472 
00473                         if(pos + data_used > wcp->offset + wcp->data_size) {
00474                                 wcp->data_size = pos + data_used - wcp->offset;
00475                         }
00476 
00477                         /*
00478                          * Update the file size if changed.
00479                          */
00480 
00481                         if (wcp->offset + wcp->data_size > wcp->file_size) {
00482                                 if (wcp_file_size_change(fsp) == -1) {
00483                                         return -1;
00484                                 }
00485                         }
00486 
00487                         /*
00488                          * If we used all the data then
00489                          * return here.
00490                          */
00491 
00492                         if(n == data_used) {
00493                                 return n;
00494                         } else {
00495                                 cache_flush_needed = True;
00496                         }
00497 
00498                         /*
00499                          * Move the start of data forward by the amount used,
00500                          * cut down the amount left by the same amount.
00501                          */
00502 
00503                         data += data_used;
00504                         pos += data_used;
00505                         n -= data_used;
00506 
00507                         DO_PROFILE_INC(writecache_abutted_writes);
00508                         total_written = data_used;
00509 
00510                         write_path = 3;
00511 
00512                 } else if ( (pos >= wcp->file_size) &&
00513                             (n == 1) &&
00514                             (wcp->file_size == wcp->offset + wcp->data_size) &&
00515                             (pos < wcp->file_size + wcp->alloc_size)) {
00516 
00517                         /*
00518 
00519                 End of file ---->|
00520 
00521                  +---------------+---------------+
00522                  | Cached data   | Cache buffer  |
00523                  +---------------+---------------+
00524 
00525                                  |<------- allocated size ---------------->|
00526 
00527                                                          +--------+
00528                                                          | 1 Byte |
00529                                                          +--------+
00530 
00531                         MS-Office seems to do this a lot to determine if there's enough
00532                         space on the filesystem to write a new file.
00533 
00534                         Change to :
00535 
00536                 End of file ---->|
00537                                  +-----------------------+--------+
00538                                  | Zeroed Cached data    | 1 Byte |
00539                                  +-----------------------+--------+
00540                         */
00541 
00542                         flush_write_cache(fsp, WRITE_FLUSH);
00543                         wcp->offset = wcp->file_size;
00544                         wcp->data_size = pos - wcp->file_size + 1;
00545                         memset(wcp->data, '\0', wcp->data_size);
00546                         memcpy(wcp->data + wcp->data_size-1, data, 1);
00547 
00548                         /*
00549                          * Update the file size if changed.
00550                          */
00551 
00552                         if (wcp->offset + wcp->data_size > wcp->file_size) {
00553                                 if (wcp_file_size_change(fsp) == -1) {
00554                                         return -1;
00555                                 }
00556                         }
00557 
00558                         return n;
00559 
00560                 } else {
00561 
00562                         /* ASCII art..... JRA.
00563 
00564    Case 1).
00565 
00566                         +---------------+---------------+
00567                         | Cached data   | Cache buffer  |
00568                         +---------------+---------------+
00569 
00570                                                               +-------------------+
00571                                                               | Data to write     |
00572                                                               +-------------------+
00573 
00574    Case 2).
00575 
00576                            +---------------+---------------+
00577                            | Cached data   | Cache buffer  |
00578                            +---------------+---------------+
00579 
00580    +-------------------+
00581    | Data to write     |
00582    +-------------------+
00583 
00584     Case 3).
00585 
00586                            +---------------+---------------+
00587                            | Cached data   | Cache buffer  |
00588                            +---------------+---------------+
00589 
00590                   +-----------------------------------------------------+
00591                   | Data to write                                       |
00592                   +-----------------------------------------------------+
00593 
00594                   */
00595 
00596                         /*
00597                          * Write is bigger than buffer, or there is no overlap on the
00598                          * low or high ends.
00599                          */
00600 
00601                         DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \
00602 len = %u\n",fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size ));
00603 
00604                         /*
00605                          * If write would fit in the cache, and is larger than
00606                          * the data already in the cache, flush the cache and
00607                          * preferentially copy the data new data into it. Otherwise
00608                          * just write the data directly.
00609                          */
00610 
00611                         if ( n <= wcp->alloc_size && n > wcp->data_size) {
00612                                 cache_flush_needed = True;
00613                         } else {
00614                                 ssize_t ret = real_write_file(fsp, data, pos, n);
00615 
00616                                 /*
00617                                  * If the write overlaps the entire cache, then
00618                                  * discard the current contents of the cache.
00619                                  * Fix from Rasmus Borup Hansen rbh@math.ku.dk.
00620                                  */
00621 
00622                                 if ((pos <= wcp->offset) &&
00623                                                 (pos + n >= wcp->offset + wcp->data_size) ) {
00624                                         DEBUG(9,("write_file: discarding overwritten write \
00625 cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size ));
00626                                         wcp->data_size = 0;
00627                                 }
00628 
00629                                 DO_PROFILE_INC(writecache_direct_writes);
00630                                 if (ret == -1) {
00631                                         return ret;
00632                                 }
00633 
00634                                 if (pos + ret > wcp->file_size) {
00635                                         wcp->file_size = pos + ret;
00636                                 }
00637 
00638                                 return ret;
00639                         }
00640 
00641                         write_path = 4;
00642 
00643                 }
00644 
00645                 if (cache_flush_needed) {
00646                         DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \
00647 n = %u, wcp->offset=%.0f, wcp->data_size=%u\n",
00648                                 write_path, fsp->fh->fd, (double)wcp->file_size, (double)pos, (unsigned int)n,
00649                                 (double)wcp->offset, (unsigned int)wcp->data_size ));
00650 
00651                         flush_write_cache(fsp, WRITE_FLUSH);
00652                 }
00653         }
00654 
00655         /*
00656          * If the write request is bigger than the cache
00657          * size, write it all out.
00658          */
00659 
00660         if (n > wcp->alloc_size ) {
00661                 ssize_t ret = real_write_file(fsp, data, pos, n);
00662                 if (ret == -1) {
00663                         return -1;
00664                 }
00665 
00666                 if (pos + ret > wcp->file_size) {
00667                         wcp->file_size = pos + n;
00668                 }
00669 
00670                 DO_PROFILE_INC(writecache_direct_writes);
00671                 return total_written + n;
00672         }
00673 
00674         /*
00675          * If there's any data left, cache it.
00676          */
00677 
00678         if (n) {
00679 #ifdef WITH_PROFILE
00680                 if (wcp->data_size) {
00681                         DO_PROFILE_INC(writecache_abutted_writes);
00682                 } else {
00683                         DO_PROFILE_INC(writecache_init_writes);
00684                 }
00685 #endif
00686                 memcpy(wcp->data+wcp->data_size, data, n);
00687                 if (wcp->data_size == 0) {
00688                         wcp->offset = pos;
00689                         DO_PROFILE_INC(writecache_num_write_caches);
00690                 }
00691                 wcp->data_size += n;
00692 
00693                 /*
00694                  * Update the file size if changed.
00695                  */
00696 
00697                 if (wcp->offset + wcp->data_size > wcp->file_size) {
00698                         if (wcp_file_size_change(fsp) == -1) {
00699                                 return -1;
00700                         }
00701                 }
00702                 DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n",
00703                         (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n));
00704 
00705                 total_written += n;
00706                 return total_written; /* .... that's a write :) */
00707         }
00708   
00709         return total_written;
00710 }
00711 
00712 /****************************************************************************
00713  Delete the write cache structure.
00714 ****************************************************************************/
00715 
00716 void delete_write_cache(files_struct *fsp)
00717 {
00718         write_cache *wcp;
00719 
00720         if(!fsp) {
00721                 return;
00722         }
00723 
00724         if(!(wcp = fsp->wcp)) {
00725                 return;
00726         }
00727 
00728         DO_PROFILE_DEC(writecache_allocated_write_caches);
00729         allocated_write_caches--;
00730 
00731         SMB_ASSERT(wcp->data_size == 0);
00732 
00733         SAFE_FREE(wcp->data);
00734         SAFE_FREE(fsp->wcp);
00735 
00736         DEBUG(10,("delete_write_cache: File %s deleted write cache\n", fsp->fsp_name ));
00737 }
00738 
00739 /****************************************************************************
00740  Setup the write cache structure.
00741 ****************************************************************************/
00742 
00743 static BOOL setup_write_cache(files_struct *fsp, SMB_OFF_T file_size)
00744 {
00745         ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
00746         write_cache *wcp;
00747 
00748         if (allocated_write_caches >= MAX_WRITE_CACHES) {
00749                 return False;
00750         }
00751 
00752         if(alloc_size == 0 || fsp->wcp) {
00753                 return False;
00754         }
00755 
00756         if((wcp = SMB_MALLOC_P(write_cache)) == NULL) {
00757                 DEBUG(0,("setup_write_cache: malloc fail.\n"));
00758                 return False;
00759         }
00760 
00761         wcp->file_size = file_size;
00762         wcp->offset = 0;
00763         wcp->alloc_size = alloc_size;
00764         wcp->data_size = 0;
00765         if((wcp->data = (char *)SMB_MALLOC(wcp->alloc_size)) == NULL) {
00766                 DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
00767                         (unsigned int)wcp->alloc_size ));
00768                 SAFE_FREE(wcp);
00769                 return False;
00770         }
00771 
00772         memset(wcp->data, '\0', wcp->alloc_size );
00773 
00774         fsp->wcp = wcp;
00775         DO_PROFILE_INC(writecache_allocated_write_caches);
00776         allocated_write_caches++;
00777 
00778         DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n",
00779                 fsp->fsp_name, (unsigned long)wcp->alloc_size ));
00780 
00781         return True;
00782 }
00783 
00784 /****************************************************************************
00785  Cope with a size change.
00786 ****************************************************************************/
00787 
00788 void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size)
00789 {
00790         if(fsp->wcp) {
00791                 /* The cache *must* have been flushed before we do this. */
00792                 if (fsp->wcp->data_size != 0) {
00793                         pstring msg;
00794                         slprintf(msg, sizeof(msg)-1, "set_filelen_write_cache: size change \
00795 on file %s with write cache size = %lu\n", fsp->fsp_name, (unsigned long)fsp->wcp->data_size );
00796                         smb_panic(msg);
00797                 }
00798                 fsp->wcp->file_size = file_size;
00799         }
00800 }
00801 
00802 /*******************************************************************
00803  Flush a write cache struct to disk.
00804 ********************************************************************/
00805 
00806 ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
00807 {
00808         write_cache *wcp = fsp->wcp;
00809         size_t data_size;
00810         ssize_t ret;
00811 
00812         if(!wcp || !wcp->data_size) {
00813                 return 0;
00814         }
00815 
00816         data_size = wcp->data_size;
00817         wcp->data_size = 0;
00818 
00819         DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]);
00820 
00821         DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
00822                 fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size));
00823 
00824 #ifdef WITH_PROFILE
00825         if(data_size == wcp->alloc_size) {
00826                 DO_PROFILE_INC(writecache_num_perfect_writes);
00827         }
00828 #endif
00829 
00830         ret = real_write_file(fsp, wcp->data, wcp->offset, data_size);
00831 
00832         /*
00833          * Ensure file size if kept up to date if write extends file.
00834          */
00835 
00836         if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) {
00837                 wcp->file_size = wcp->offset + ret;
00838         }
00839 
00840         return ret;
00841 }
00842 
00843 /*******************************************************************
00844 sync a file
00845 ********************************************************************/
00846 
00847 NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, BOOL write_through)
00848 {
00849         if (fsp->fh->fd == -1)
00850                 return NT_STATUS_INVALID_HANDLE;
00851 
00852         if (lp_strict_sync(SNUM(conn)) &&
00853             (lp_syncalways(SNUM(conn)) || write_through)) {
00854                 int ret = flush_write_cache(fsp, SYNC_FLUSH);
00855                 if (ret == -1) {
00856                         return map_nt_error_from_unix(errno);
00857                 }
00858                 ret = SMB_VFS_FSYNC(fsp,fsp->fh->fd);
00859                 if (ret == -1) {
00860                         return map_nt_error_from_unix(errno);
00861                 }
00862         }
00863         return NT_STATUS_OK;
00864 }
00865 
00866 /************************************************************
00867  Perform a stat whether a valid fd or not.
00868 ************************************************************/
00869 
00870 int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst)
00871 {
00872         if (fsp->fh->fd == -1) {
00873                 return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst);
00874         } else {
00875                 return SMB_VFS_FSTAT(fsp,fsp->fh->fd, pst);
00876         }
00877 }

Sambaに対してSat Aug 29 21:23:23 2009に生成されました。  doxygen 1.4.7