Port-amd64 archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: fcntl64 in linux32 emul



In article <47A0B793.1060308%pp2.inet.fi@localhost>,
Arto Huusko  <arto.huusko%pp2.inet.fi@localhost> wrote:
>-=-=-=-=-=-
>
>This post is about fcntl64 in linux32 emul, but the same issues may
>affect other system calls that have 64 bit variants as well.
>
>The first problem is that fcntl64 emul in compat/linux/common/linux_file64.c
>handles only F_GETLK64, F_SETLK64 and F_SETLKW64, and for other fcntl commands
>it calls linux_sys_fcntl(). But linux_sys_fcntl() is part of the *64-bit*
>linux emulation. This means that F_SETLK request from 32-bit linux binary
>is handled as if it came from 64-bit binary, and this means that the
>struct flock userland gave (32-bit off_t fields) and the struct flock the
>kernel expects (64-bit off_t fields) do not match at all.
>
>Looking at ktrace, you'll see something like this:
>
>    153      1 skype    CALL  fcntl64(3,6,0xfddfe7e4)
>    153      1 skype    RET   fcntl64 -1 errno -22 Invalid argument
>
>
>I did not check for sure, but I guess that even {G,S}ETLK64 variant
>is handled wrong, because struct flock64 looks like this:
>
>struct linux_flock64 {
>     short       l_type;
>     short       l_whence;
>     off_t       l_start;
>     off_t       l_len;
>     linux_pid_t l_pid;
>};
>
>When kernel is compiled on amd64, fields are aligned accodring to
>amd64 rules. What I did not check, but do suspect is that when
>compiled on 32 bit linux (with off_t fields loff_t in linux, which
>is long long), l_start and l_len are aligned on 4 byte boundary,
>not 8 as on amd64. Based on printfs I added to kernel, SETLK64
>requests look more sane when linux_flock64 structure is packed
>in NetBSD kernel (i.e. align l_start on 4 byte boundary).
>
>
>This all is from trying to get skype running on NetBSD/amd64 under
>linux32 emul. The program starts, but when trying to log in, it
>keeps on spinning and spinning, and does not log in.
>
>With the attached diff, I got skype started. The diff handles only
>SETLK and GETLK calls, but I suspect other commands and syscalls
>may need some treatment as well.
>
>-=-=-=-=-=-
>
>Index: linux_fcntl.h
>===================================================================
>RCS file: /cvsroot/src/sys/compat/linux/common/linux_fcntl.h,v
>retrieving revision 1.11
>diff -r1.11 linux_fcntl.h
>55a56,59
>> #ifdef       COMPAT_LINUX32
>>      linux32_off_t l_start;
>>      linux32_off_t l_len;
>> #else
>57a62
>> #endif
>61c66
>< struct linux_flock64 {
>---
>> struct __attribute__ ((__packed__)) linux_flock64 {
>Index: linux_file64.c
>===================================================================
>RCS file: /cvsroot/src/sys/compat/linux/common/linux_file64.c,v
>retrieving revision 1.44
>diff -r1.44 linux_file64.c
>264a265,306
>> static void
>> bsd_to_linux_flock(struct flock *bfp, struct linux_flock *lfp)
>> {
>> 
>>      lfp->l_start = bfp->l_start;
>>      lfp->l_len = bfp->l_len;
>>      lfp->l_pid = bfp->l_pid;
>>      lfp->l_whence = bfp->l_whence;
>>      switch (bfp->l_type) {
>>      case F_RDLCK:
>>              lfp->l_type = LINUX_F_RDLCK;
>>              break;
>>      case F_UNLCK:
>>              lfp->l_type = LINUX_F_UNLCK;
>>              break;
>>      case F_WRLCK:
>>              lfp->l_type = LINUX_F_WRLCK;
>>              break;
>>      }
>> }
>> 
>> static void
>> linux_to_bsd_flock(struct linux_flock *lfp, struct flock *bfp)
>> {
>> 
>>      bfp->l_start = lfp->l_start;
>>      bfp->l_len = lfp->l_len;
>>      bfp->l_pid = lfp->l_pid;
>>      bfp->l_whence = lfp->l_whence;
>>      switch (lfp->l_type) {
>>      case LINUX_F_RDLCK:
>>              bfp->l_type = F_RDLCK;
>>              break;
>>      case LINUX_F_UNLCK:
>>              bfp->l_type = F_UNLCK;
>>              break;
>>      case LINUX_F_WRLCK:
>>              bfp->l_type = F_WRLCK;
>>              break;
>>      }
>> }
>> 
>273a316
>>      struct linux_flock lfl32;
>296a340,357
>>      case LINUX_F_GETLK:
>>              if ((error = copyin(arg, &lfl32, sizeof lfl32)))
>>                      return error;
>>              linux_to_bsd_flock(&lfl32, &bfl);
>>              error = do_fcntl_lock(l, fd, F_GETLK, &bfl);
>>              if (error)
>>                      return error;
>>              bsd_to_linux_flock(&bfl, &lfl32);
>>              return copyout(&lfl32, arg, sizeof lfl32);
>> 
>>      case LINUX_F_SETLK:
>>      case LINUX_F_SETLKW:
>>              cmd = (cmd == LINUX_F_SETLK ? F_SETLK : F_SETLKW);
>>              if ((error = copyin(arg, &lfl32, sizeof lfl32))) {
>>                      return error;
>>              }
>>              linux_to_bsd_flock(&lfl32, &bfl);
>>              return do_fcntl_lock(l, fd, cmd, &bfl);

Can you send-pr this with diff -u?

christos




Home | Main Index | Thread Index | Old Index