Merge branch '3.2-without-smb2' of git://git.samba.org/sfrench/cifs-2.6
[pandora-kernel.git] / fs / cifs / connect.c
index 0f69b31..d545a95 100644 (file)
@@ -320,27 +320,24 @@ requeue_echo:
 }
 
 static bool
-allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size,
-                bool is_large_buf)
+allocate_buffers(struct TCP_Server_Info *server)
 {
-       char *bbuf = *bigbuf, *sbuf = *smallbuf;
-
-       if (bbuf == NULL) {
-               bbuf = (char *)cifs_buf_get();
-               if (!bbuf) {
+       if (!server->bigbuf) {
+               server->bigbuf = (char *)cifs_buf_get();
+               if (!server->bigbuf) {
                        cERROR(1, "No memory for large SMB response");
                        msleep(3000);
                        /* retry will check if exiting */
                        return false;
                }
-       } else if (is_large_buf) {
+       } else if (server->large_buf) {
                /* we are reusing a dirty large buf, clear its start */
-               memset(bbuf, 0, size);
+               memset(server->bigbuf, 0, sizeof(struct smb_hdr));
        }
 
-       if (sbuf == NULL) {
-               sbuf = (char *)cifs_small_buf_get();
-               if (!sbuf) {
+       if (!server->smallbuf) {
+               server->smallbuf = (char *)cifs_small_buf_get();
+               if (!server->smallbuf) {
                        cERROR(1, "No memory for SMB response");
                        msleep(1000);
                        /* retry will check if exiting */
@@ -349,12 +346,9 @@ allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size,
                /* beginning of smb buffer is cleared in our buf_get */
        } else {
                /* if existing small buf clear beginning */
-               memset(sbuf, 0, size);
+               memset(server->smallbuf, 0, sizeof(struct smb_hdr));
        }
 
-       *bigbuf = bbuf;
-       *smallbuf = sbuf;
-
        return true;
 }
 
@@ -428,9 +422,9 @@ get_server_iovec(struct TCP_Server_Info *server, unsigned int nr_segs)
        return new_iov;
 }
 
-static int
-readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
-                 unsigned int nr_segs, unsigned int to_read)
+int
+cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
+                      unsigned int nr_segs, unsigned int to_read)
 {
        int length = 0;
        int total_read;
@@ -485,16 +479,16 @@ readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
        return total_read;
 }
 
-static int
-read_from_socket(struct TCP_Server_Info *server, char *buf,
-                unsigned int to_read)
+int
+cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
+                     unsigned int to_read)
 {
        struct kvec iov;
 
        iov.iov_base = buf;
        iov.iov_len = to_read;
 
-       return readv_from_socket(server, &iov, 1, to_read);
+       return cifs_readv_from_socket(server, &iov, 1, to_read);
 }
 
 static bool
@@ -559,8 +553,8 @@ find_mid(struct TCP_Server_Info *server, struct smb_hdr *buf)
        return NULL;
 }
 
-static void
-dequeue_mid(struct mid_q_entry *mid, int malformed)
+void
+dequeue_mid(struct mid_q_entry *mid, bool malformed)
 {
 #ifdef CONFIG_CIFS_STATS2
        mid->when_received = jiffies;
@@ -574,48 +568,44 @@ dequeue_mid(struct mid_q_entry *mid, int malformed)
        spin_unlock(&GlobalMid_Lock);
 }
 
-static struct mid_q_entry *
-find_cifs_mid(struct TCP_Server_Info *server, struct smb_hdr *buf,
-             int *malformed, bool is_large_buf, bool *is_multi_rsp,
-             char **bigbuf)
+static void
+handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
+          struct smb_hdr *buf, int malformed)
 {
-       struct mid_q_entry *mid = NULL;
-
-       mid = find_mid(server, buf);
-       if (!mid)
-               return mid;
-
-       if (*malformed == 0 && check2ndT2(buf) > 0) {
-               /* We have a multipart transact2 resp */
-               *is_multi_rsp = true;
+       if (malformed == 0 && check2ndT2(buf) > 0) {
+               mid->multiRsp = true;
                if (mid->resp_buf) {
                        /* merge response - fix up 1st*/
-                       *malformed = coalesce_t2(buf, mid->resp_buf);
-                       if (*malformed > 0) {
-                               *malformed = 0;
-                               mid->multiRsp = true;
-                               return NULL;
-                       }
+                       malformed = coalesce_t2(buf, mid->resp_buf);
+                       if (malformed > 0)
+                               return;
+
                        /* All parts received or packet is malformed. */
                        mid->multiEnd = true;
-                       goto multi_t2_fnd;
+                       return dequeue_mid(mid, malformed);
                }
-               if (!is_large_buf) {
+               if (!server->large_buf) {
                        /*FIXME: switch to already allocated largebuf?*/
                        cERROR(1, "1st trans2 resp needs bigbuf");
                } else {
                        /* Have first buffer */
                        mid->resp_buf = buf;
                        mid->largeBuf = true;
-                       *bigbuf = NULL;
+                       server->bigbuf = NULL;
                }
-               return mid;
+               return;
        }
        mid->resp_buf = buf;
-       mid->largeBuf = is_large_buf;
-multi_t2_fnd:
-       dequeue_mid(mid, *malformed);
-       return mid;
+       mid->largeBuf = server->large_buf;
+       /* Was previous buf put in mpx struct for multi-rsp? */
+       if (!mid->multiRsp) {
+               /* smb buffer will be freed by user thread */
+               if (server->large_buf)
+                       server->bigbuf = NULL;
+               else
+                       server->smallbuf = NULL;
+       }
+       dequeue_mid(mid, malformed);
 }
 
 static void clean_demultiplex_info(struct TCP_Server_Info *server)
@@ -714,18 +704,71 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
                                GFP_KERNEL);
 }
 
+static int
+standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+{
+       int length;
+       char *buf = server->smallbuf;
+       struct smb_hdr *smb_buffer = (struct smb_hdr *)buf;
+       unsigned int pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
+
+       /* make sure this will fit in a large buffer */
+       if (pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+               cERROR(1, "SMB response too long (%u bytes)",
+                       pdu_length);
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return -EAGAIN;
+       }
+
+       /* switch to large buffer if too big for a small one */
+       if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
+               server->large_buf = true;
+               memcpy(server->bigbuf, server->smallbuf, server->total_read);
+               buf = server->bigbuf;
+               smb_buffer = (struct smb_hdr *)buf;
+       }
+
+       /* now read the rest */
+       length = cifs_read_from_socket(server,
+                         buf + sizeof(struct smb_hdr) - 1,
+                         pdu_length - sizeof(struct smb_hdr) + 1 + 4);
+       if (length < 0)
+               return length;
+       server->total_read += length;
+
+       dump_smb(smb_buffer, server->total_read);
+
+       /*
+        * We know that we received enough to get to the MID as we
+        * checked the pdu_length earlier. Now check to see
+        * if the rest of the header is OK. We borrow the length
+        * var for the rest of the loop to avoid a new stack var.
+        *
+        * 48 bytes is enough to display the header and a little bit
+        * into the payload for debugging purposes.
+        */
+       length = checkSMB(smb_buffer, smb_buffer->Mid, server->total_read);
+       if (length != 0)
+               cifs_dump_mem("Bad SMB: ", buf,
+                       min_t(unsigned int, server->total_read, 48));
+
+       if (mid)
+               handle_mid(mid, server, smb_buffer, length);
+
+       return length;
+}
+
 static int
 cifs_demultiplex_thread(void *p)
 {
        int length;
        struct TCP_Server_Info *server = p;
-       unsigned int pdu_length, total_read;
-       char *buf = NULL, *bigbuf = NULL, *smallbuf = NULL;
+       unsigned int pdu_length;
+       char *buf = NULL;
        struct smb_hdr *smb_buffer = NULL;
        struct task_struct *task_to_wake = NULL;
        struct mid_q_entry *mid_entry;
-       bool isLargeBuf = false;
-       bool isMultiRsp = false;
 
        current->flags |= PF_MEMALLOC;
        cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
@@ -740,20 +783,18 @@ cifs_demultiplex_thread(void *p)
                if (try_to_freeze())
                        continue;
 
-               if (!allocate_buffers(&bigbuf, &smallbuf,
-                                     sizeof(struct smb_hdr), isLargeBuf))
+               if (!allocate_buffers(server))
                        continue;
 
-               isLargeBuf = false;
-               isMultiRsp = false;
-               smb_buffer = (struct smb_hdr *)smallbuf;
-               buf = smallbuf;
+               server->large_buf = false;
+               smb_buffer = (struct smb_hdr *)server->smallbuf;
+               buf = server->smallbuf;
                pdu_length = 4; /* enough to get RFC1001 header */
 
-               length = read_from_socket(server, buf, pdu_length);
+               length = cifs_read_from_socket(server, buf, pdu_length);
                if (length < 0)
                        continue;
-               total_read = length;
+               server->total_read = length;
 
                /*
                 * The right amount was read from socket - 4 bytes,
@@ -775,71 +816,32 @@ cifs_demultiplex_thread(void *p)
                }
 
                /* read down to the MID */
-               length = read_from_socket(server, buf + 4,
-                                         sizeof(struct smb_hdr) - 1 - 4);
+               length = cifs_read_from_socket(server, buf + 4,
+                                       sizeof(struct smb_hdr) - 1 - 4);
                if (length < 0)
                        continue;
-               total_read += length;
+               server->total_read += length;
 
-               if (pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
-                       cERROR(1, "SMB response too long (%u bytes)",
-                               pdu_length);
-                       cifs_reconnect(server);
-                       wake_up(&server->response_q);
-                       continue;
-               }
+               mid_entry = find_mid(server, smb_buffer);
 
-               /* else length ok */
-               if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
-                       isLargeBuf = true;
-                       memcpy(bigbuf, smallbuf, total_read);
-                       smb_buffer = (struct smb_hdr *)bigbuf;
-                       buf = bigbuf;
-               }
+               if (!mid_entry || !mid_entry->receive)
+                       length = standard_receive3(server, mid_entry);
+               else
+                       length = mid_entry->receive(server, mid_entry);
 
-               /* now read the rest */
-               length = read_from_socket(server,
-                                 buf + sizeof(struct smb_hdr) - 1,
-                                 pdu_length - sizeof(struct smb_hdr) + 1 + 4);
                if (length < 0)
                        continue;
-               total_read += length;
 
-               dump_smb(smb_buffer, total_read);
-
-               /*
-                * We know that we received enough to get to the MID as we
-                * checked the pdu_length earlier. Now check to see
-                * if the rest of the header is OK. We borrow the length
-                * var for the rest of the loop to avoid a new stack var.
-                *
-                * 48 bytes is enough to display the header and a little bit
-                * into the payload for debugging purposes.
-                */
-               length = checkSMB(smb_buffer, smb_buffer->Mid, total_read);
-               if (length != 0)
-                       cifs_dump_mem("Bad SMB: ", buf,
-                                     min_t(unsigned int, total_read, 48));
+               if (server->large_buf) {
+                       buf = server->bigbuf;
+                       smb_buffer = (struct smb_hdr *)buf;
+               }
 
                server->lstrp = jiffies;
-
-               mid_entry = find_cifs_mid(server, smb_buffer, &length,
-                                         isLargeBuf, &isMultiRsp, &bigbuf);
                if (mid_entry != NULL) {
-                       mid_entry->callback(mid_entry);
-                       /* Was previous buf put in mpx struct for multi-rsp? */
-                       if (!isMultiRsp) {
-                               /* smb buffer will be freed by user thread */
-                               if (isLargeBuf)
-                                       bigbuf = NULL;
-                               else
-                                       smallbuf = NULL;
-                       }
-               } else if (length != 0) {
-                       /* response sanity checks failed */
-                       continue;
-               } else if (!is_valid_oplock_break(smb_buffer, server) &&
-                          !isMultiRsp) {
+                       if (!mid_entry->multiRsp || mid_entry->multiEnd)
+                               mid_entry->callback(mid_entry);
+               } else if (!is_valid_oplock_break(smb_buffer, server)) {
                        cERROR(1, "No task to wake, unknown frame received! "
                                   "NumMids %d", atomic_read(&midCount));
                        cifs_dump_mem("Received Data is: ", buf,
@@ -853,9 +855,9 @@ cifs_demultiplex_thread(void *p)
        } /* end while !EXITING */
 
        /* buffer usually freed in free_mid - need to free it here on exit */
-       cifs_buf_release(bigbuf);
-       if (smallbuf) /* no sense logging a debug message if NULL */
-               cifs_small_buf_release(smallbuf);
+       cifs_buf_release(server->bigbuf);
+       if (server->smallbuf) /* no sense logging a debug message if NULL */
+               cifs_small_buf_release(server->smallbuf);
 
        task_to_wake = xchg(&server->tsk, NULL);
        clean_demultiplex_info(server);
@@ -2308,16 +2310,16 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
            (new->mnt_cifs_flags & CIFS_MOUNT_MASK))
                return 0;
 
-       if (old->rsize != new->rsize)
-               return 0;
-
        /*
-        * We want to share sb only if we don't specify wsize or specified wsize
-        * is greater or equal than existing one.
+        * We want to share sb only if we don't specify an r/wsize or
+        * specified r/wsize is greater than or equal to existing one.
         */
        if (new->wsize && new->wsize < old->wsize)
                return 0;
 
+       if (new->rsize && new->rsize < old->rsize)
+               return 0;
+
        if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid)
                return 0;
 
@@ -2755,14 +2757,6 @@ void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon,
                                        CIFS_MOUNT_POSIX_PATHS;
                }
 
-               if (cifs_sb && (cifs_sb->rsize > 127 * 1024)) {
-                       if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
-                               cifs_sb->rsize = 127 * 1024;
-                               cFYI(DBG2, "larger reads not supported by srv");
-                       }
-               }
-
-
                cFYI(1, "Negotiate caps 0x%x", (int)cap);
 #ifdef CONFIG_CIFS_DEBUG2
                if (cap & CIFS_UNIX_FCNTL_CAP)
@@ -2807,27 +2801,11 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
        spin_lock_init(&cifs_sb->tlink_tree_lock);
        cifs_sb->tlink_tree = RB_ROOT;
 
-       if (pvolume_info->rsize > CIFSMaxBufSize) {
-               cERROR(1, "rsize %d too large, using MaxBufSize",
-                       pvolume_info->rsize);
-               cifs_sb->rsize = CIFSMaxBufSize;
-       } else if ((pvolume_info->rsize) &&
-                       (pvolume_info->rsize <= CIFSMaxBufSize))
-               cifs_sb->rsize = pvolume_info->rsize;
-       else /* default */
-               cifs_sb->rsize = CIFSMaxBufSize;
-
-       if (cifs_sb->rsize < 2048) {
-               cifs_sb->rsize = 2048;
-               /* Windows ME may prefer this */
-               cFYI(1, "readsize set to minimum: 2048");
-       }
-
        /*
-        * Temporarily set wsize for matching superblock. If we end up using
-        * new sb then cifs_negotiate_wsize will later negotiate it downward
-        * if needed.
+        * Temporarily set r/wsize for matching superblock. If we end up using
+        * new sb then client will later negotiate it downward if needed.
         */
+       cifs_sb->rsize = pvolume_info->rsize;
        cifs_sb->wsize = pvolume_info->wsize;
 
        cifs_sb->mnt_uid = pvolume_info->linux_uid;
@@ -2902,29 +2880,41 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
 }
 
 /*
- * When the server supports very large writes via POSIX extensions, we can
- * allow up to 2^24-1, minus the size of a WRITE_AND_X header, not including
- * the RFC1001 length.
+ * When the server supports very large reads and writes via POSIX extensions,
+ * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
+ * including the RFC1001 length.
  *
  * Note that this might make for "interesting" allocation problems during
  * writeback however as we have to allocate an array of pointers for the
  * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+ *
+ * For reads, there is a similar problem as we need to allocate an array
+ * of kvecs to handle the receive, though that should only need to be done
+ * once.
  */
 #define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
 
 /*
- * When the server doesn't allow large posix writes, only allow a wsize of
- * 2^17-1 minus the size of the WRITE_AND_X header. That allows for a write up
- * to the maximum size described by RFC1002.
+ * When the server doesn't allow large posix writes, only allow a rsize/wsize
+ * of 2^17-1 minus the size of the call header. That allows for a read or
+ * write up to the maximum size described by RFC1002.
  */
 #define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
 
 /*
  * The default wsize is 1M. find_get_pages seems to return a maximum of 256
  * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
  * a single wsize request with a single call.
  */
-#define CIFS_DEFAULT_WSIZE (1024 * 1024)
+#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
+
+/*
+ * Windows only supports a max of 60k reads. Default to that when posix
+ * extensions aren't in force.
+ */
+#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
 
 static unsigned int
 cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
@@ -2932,7 +2922,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
        __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
        struct TCP_Server_Info *server = tcon->ses->server;
        unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize :
-                               CIFS_DEFAULT_WSIZE;
+                               CIFS_DEFAULT_IOSIZE;
 
        /* can server support 24-bit write sizes? (via UNIX extensions) */
        if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
@@ -2955,6 +2945,50 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
        return wsize;
 }
 
+static unsigned int
+cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
+{
+       __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+       struct TCP_Server_Info *server = tcon->ses->server;
+       unsigned int rsize, defsize;
+
+       /*
+        * Set default value...
+        *
+        * HACK alert! Ancient servers have very small buffers. Even though
+        * MS-CIFS indicates that servers are only limited by the client's
+        * bufsize for reads, testing against win98se shows that it throws
+        * INVALID_PARAMETER errors if you try to request too large a read.
+        *
+        * If the server advertises a MaxBufferSize of less than one page,
+        * assume that it also can't satisfy reads larger than that either.
+        *
+        * FIXME: Is there a better heuristic for this?
+        */
+       if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
+               defsize = CIFS_DEFAULT_IOSIZE;
+       else if (server->capabilities & CAP_LARGE_READ_X)
+               defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
+       else if (server->maxBuf >= PAGE_CACHE_SIZE)
+               defsize = CIFSMaxBufSize;
+       else
+               defsize = server->maxBuf - sizeof(READ_RSP);
+
+       rsize = pvolume_info->rsize ? pvolume_info->rsize : defsize;
+
+       /*
+        * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
+        * the client's MaxBufferSize.
+        */
+       if (!(server->capabilities & CAP_LARGE_READ_X))
+               rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
+
+       /* hard limit of CIFS_MAX_RSIZE */
+       rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
+
+       return rsize;
+}
+
 static int
 is_path_accessible(int xid, struct cifs_tcon *tcon,
                   struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -2984,9 +3018,9 @@ cleanup_volume_info_contents(struct smb_vol *volume_info)
 {
        kfree(volume_info->username);
        kzfree(volume_info->password);
-       kfree(volume_info->UNC);
        if (volume_info->UNCip != volume_info->UNC + 2)
                kfree(volume_info->UNCip);
+       kfree(volume_info->UNC);
        kfree(volume_info->domainname);
        kfree(volume_info->iocharset);
        kfree(volume_info->prepath);
@@ -3148,6 +3182,22 @@ cifs_get_volume_info(char *mount_data, const char *devname)
        return volume_info;
 }
 
+/* make sure ra_pages is a multiple of rsize */
+static inline unsigned int
+cifs_ra_pages(struct cifs_sb_info *cifs_sb)
+{
+       unsigned int reads;
+       unsigned int rsize_pages = cifs_sb->rsize / PAGE_CACHE_SIZE;
+
+       if (rsize_pages >= default_backing_dev_info.ra_pages)
+               return default_backing_dev_info.ra_pages;
+       else if (rsize_pages == 0)
+               return rsize_pages;
+
+       reads = default_backing_dev_info.ra_pages / rsize_pages;
+       return reads * rsize_pages;
+}
+
 int
 cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
 {
@@ -3166,8 +3216,6 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
        if (rc)
                return rc;
 
-       cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;
-
 #ifdef CONFIG_CIFS_DFS_UPCALL
 try_mount_again:
        /* cleanup activities if we're chasing a referral */
@@ -3232,14 +3280,11 @@ try_mount_again:
                CIFSSMBQFSAttributeInfo(xid, tcon);
        }
 
-       if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
-               cifs_sb->rsize = 1024 * 127;
-               cFYI(DBG2, "no very large read support, rsize now 127K");
-       }
-       if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
-               cifs_sb->rsize = min(cifs_sb->rsize, CIFSMaxBufSize);
-
        cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
+       cifs_sb->rsize = cifs_negotiate_rsize(tcon, volume_info);
+
+       /* tune readahead according to rsize */
+       cifs_sb->bdi.ra_pages = cifs_ra_pages(cifs_sb);
 
 remote_path_check:
 #ifdef CONFIG_CIFS_DFS_UPCALL