Fixed the (incorrect) paranioa fix I put in for the fcntl lock spin.
authorJeremy Allison <jra@samba.org>
Wed, 22 Aug 2001 00:29:40 +0000 (00:29 +0000)
committerJeremy Allison <jra@samba.org>
Wed, 22 Aug 2001 00:29:40 +0000 (00:29 +0000)
Don't delete a share mode that failed to remove the oplock (doh!),
just set the oplock entry to zero....
Jeremy.

source/locking/locking.c
source/smbd/close.c
source/smbd/open.c
source/smbd/oplock.c

index a9bcada02678654ef5c8df93a7581cca3cd54a57..fea821baa17b442c2fb8d6726994b55af3d58327 100644 (file)
@@ -451,7 +451,7 @@ static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_t
  and port info. 
 ********************************************************************/
 
-static BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2)
+BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2)
 {
        return (e1->pid == e2->pid &&
          e1->share_mode == e2->share_mode &&
@@ -465,7 +465,7 @@ static BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2)
  Ignore if no entry deleted.
 ********************************************************************/
 
-ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
+static ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
                        share_mode_entry *entry, share_mode_entry **ppse)
 {
        TDB_DATA dbuf;
@@ -491,6 +491,8 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
         * from the record.
         */
 
+       DEBUG(10,("del_share_mode: num_share_modes = %d\n", data->num_share_mode_entries ));
+
        for (i=0;i<data->num_share_mode_entries;) {
                if (share_modes_identical(&shares[i], entry)) {
                        if (ppse)
@@ -499,6 +501,9 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode,
                        memmove(&shares[i], &shares[i+1], 
                                dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
                        del_count++;
+
+                       DEBUG(10,("del_share_mode: deleting entry %d\n", i ));
+
                } else {
                        i++;
                }
@@ -603,34 +608,28 @@ BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type)
  A generic in-place modification call for share mode entries.
 ********************************************************************/
 
-static BOOL mod_share_mode(files_struct *fsp,
+static BOOL mod_share_mode( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry,
                           void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
                           void *param)
 {
        TDB_DATA dbuf;
        struct locking_data *data;
        int i;
-       share_mode_entry *shares, entry;
+       share_mode_entry *shares;
        BOOL need_store=False;
 
        /* read in the existing share modes */
-       dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
+       dbuf = tdb_fetch(tdb, locking_key(dev, inode));
        if (!dbuf.dptr)
                return False;
 
        data = (struct locking_data *)dbuf.dptr;
        shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
 
-       /*
-        * Fake up a share_mode_entry for comparisons.
-        */
-
-       fill_share_mode((char *)&entry, fsp, 0, 0);
-       
        /* find any with our pid and call the supplied function */
        for (i=0;i<data->num_share_mode_entries;i++) {
-               if (share_modes_identical(&entry, &shares[i])) {
-                       mod_fn(&shares[i], fsp->dev, fsp->inode, param);
+               if (share_modes_identical(entry, &shares[i])) {
+                       mod_fn(&shares[i], dev, inode, param);
                        need_store=True;
                }
        }
@@ -638,10 +637,10 @@ static BOOL mod_share_mode(files_struct *fsp,
        /* if the mod fn was called then store it back */
        if (need_store) {
                if (data->num_share_mode_entries == 0) {
-                       if (tdb_delete(tdb, locking_key_fsp(fsp)) == -1)
+                       if (tdb_delete(tdb, locking_key(dev, inode)) == -1)
                                need_store = False;
                } else {
-                       if (tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE) == -1)
+                       if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1)
                                need_store = False;
                }
        }
@@ -671,7 +670,12 @@ static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_I
 
 BOOL remove_share_oplock(files_struct *fsp)
 {
-       return mod_share_mode(fsp, remove_share_oplock_fn, NULL);
+       share_mode_entry entry;
+       /*
+        * Fake up an entry for comparisons...
+        */
+       fill_share_mode((char *)&entry, fsp, 0, 0);
+       return mod_share_mode(fsp->dev, fsp->inode, &entry, remove_share_oplock_fn, NULL);
 }
 
 /*******************************************************************
@@ -693,7 +697,21 @@ static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SM
 
 BOOL downgrade_share_oplock(files_struct *fsp)
 {
-       return mod_share_mode(fsp, downgrade_share_oplock_fn, NULL);
+       share_mode_entry entry;
+       /*
+        * Fake up an entry for comparisons...
+        */
+       fill_share_mode((char *)&entry, fsp, 0, 0);
+       return mod_share_mode(fsp->dev, fsp->inode, &entry, downgrade_share_oplock_fn, NULL);
+}
+
+/*******************************************************************
+ Delete an exclusive share oplock owned by a defunct smbd..
+********************************************************************/
+
+BOOL clear_share_entry(SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry)
+{
+       return mod_share_mode(dev, inode, entry, remove_share_oplock_fn, NULL);
 }
 
 /*******************************************************************
index 6b72a8563a40675f898f8755e197d50a6bf65aa1..dd1a25293d849b4113d3e91709dcaa4f1957c321 100644 (file)
@@ -153,6 +153,9 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
        lock_share_entry_fsp(fsp);
        share_entry_count = del_share_mode(fsp, &share_entry);
 
+       DEBUG(10,("close_normal_file: share_entry_count = %d for file %s\n",
+               share_entry_count, fsp->fsp_name ));
+
        /*
         * We delete on close if it's the last open, and the
         * delete on close flag was set in the entry we just deleted.
index 143aa934a683e1298ceda56a629a9b8e53b70bef..633cf718179f76890595e02b8db34181804c1b70 100644 (file)
@@ -527,17 +527,42 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
 
     if(broke_oplock) {
       free((char *)old_shares);
-      if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) {
-        DEBUG(0,("open_mode_check: cannot delete entry when breaking oplock (%x) on file %s, \
-dev = %x, inode = %.0f\n", broken_entry.op_type, fname, (unsigned int)dev, (double)inode));
-        errno = EACCES;
-        unix_ERR_class = ERRDOS;
-        unix_ERR_code = ERRbadshare;
-        return -1;
-      }
       num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
       oplock_contention_count++;
-    }
+
+      /* Paranoia check that this is no longer an exlusive entry. */
+      for(i = 0; i < num_share_modes; i++) {
+        share_mode_entry *share_entry = &old_shares[i];
+
+        if (share_modes_identical(&broken_entry, share_entry) && 
+               EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) {
+
+          /*
+           * This should not happen. The target left this oplock
+           * as exlusive.... The process *must* be dead.... 
+           */
+
+          DEBUG(0,("open_mode_check: exlusive oplock left after break ! For file %s,
+dev = %x, inode = %.0f\n", fname, (unsigned int)dev, (double)inode));
+
+          if (process_exists(broken_entry.pid)) {
+            pstring errmsg;
+            slprintf(errmsg, sizeof(errmsg)-1, 
+                 "open_mode_check: Existant process %d left active oplock.\n",
+                 broken_entry.pid );
+            smb_panic(errmsg);
+          }
+
+          if (!clear_share_entry(dev, inode, &broken_entry)) {
+            errno = EACCES;
+            unix_ERR_class = ERRDOS;
+            unix_ERR_code = ERRbadshare;
+            return -1;
+          }
+        }
+      } /* end for paranoia... */
+    } /* end if broke_oplock */
+
   } while(broke_oplock);
 
   if(old_shares != 0)
@@ -570,6 +595,7 @@ static void kernel_flock(files_struct *fsp, int deny_mode)
        else if (deny_mode == DENY_ALL) kernel_mode = LOCK_MAND;
        if (kernel_mode) flock(fsp->fd, kernel_mode);
 #endif
+       ;;
 }
 
 
index 4bc8fce69804b4adbf28006dffc19159ad370426..f841432960b3cfab7eb3359933a9e9e91f263112 100644 (file)
@@ -1141,6 +1141,9 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
 
        num_share_modes = get_share_modes(fsp->conn, fsp->dev, fsp->inode, &share_list);
 
+       DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n", 
+                       num_share_modes ));
+
        for(i = 0; i < num_share_modes; i++) {
                share_mode_entry *share_entry = &share_list[i];
 
@@ -1153,6 +1156,9 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
                 * also no harm to ignore existing NO_OPLOCK states. JRA.
                 */
 
+               DEBUG(10,("release_level_2_oplocks_on_change: share_entry[%i]->op_type == %d\n",
+                               i, share_entry->op_type ));
+
                if (share_entry->op_type == NO_OPLOCK)
                        continue;
 
@@ -1179,6 +1185,8 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
                                abort();
                        }
 
+                       DEBUG(10,("release_level_2_oplocks_on_change: breaking our own oplock.\n"));
+
                        oplock_break_level2(new_fsp, True, token);
 
                } else {
@@ -1188,17 +1196,19 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
                         * message.
                         */
 
+                       DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock.\n"));
                        request_oplock_break(share_entry, fsp->dev, fsp->inode);
                }
        }
 
-       free((char *)share_list);
+       if (share_list)
+               free((char *)share_list);
        unlock_share_entry_fsp(fsp);
 
        /* Paranoia check... */
        if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
                DEBUG(0,("release_level_2_oplocks_on_change: PANIC. File %s still has a level II oplock.\n", fsp->fsp_name));
-               abort();
+               smb_panic("release_level_2_oplocks_on_change");
        }
 }