2015-09-08 6 views
1

Я реализую драйвер устройства в пользовательском пространстве в python с помощью ctypes и CUSE часть FUSE. Это не мой первый драйвер CUSE, и в прошлом я смог сделать следующее, чтобы вернуть структуру.CUSE IOCTL Ответ с конструкцией, содержащей указатель на массив символов

class tvStruct(Structure): 
    _fields_ = [("tv_sec",c_long), 
       ("tv_usec",c_long)] 

Структуру timeval можно передать обратно в приложение, использующее вызов IOCTL с соответствующим номером. Ниже приведена операция файла IOCTL для драйвера CUSE.

def ioctl(self, req, cmd, arg_p, file_info, uflags, in_buff_p, in_bufsz, out_bufsz): 
    ioctl = DECODE_IOC(cmd) 
    if ioctl == IOC_READ_TIMEVAL: 
     if not in_buff_p: 
      PyCuse.fuse_reply_ioctl_retry(req, 
              pointer(PyCuse.iovec(cast(arg_p,c_void_p), 
              sizeof(tvStruct))),1, 
              pointer(PyCuse.iovec(cast(arg_p,c_void_p), 
              sizeof(tvStruct))),1) 
     else: 
      tvPtr = cast(in_buff_p,POINTER(tvStruct)) 
      PyCuse.fuse_reply_ioctl(req, 0, tvPtr, sizeof(tvStruct)) 
    else: 
     print("%s Unrecognized IOCTL #...\n",self.devname) 
     PyCuse.fuse_reply_err(req,1) 

Текущий драйвер, который я разрабатываю, должен возвращать структуру, содержащую указатель на массив символов.

# C++ Struct 
typedef struct { 
    __u16 addr; 
    __u16 length; 
    __u8* pBuf; 
} EEPromData; 

# Python Class 
class EEPromDataStruct(Structure): 
    _fields_ = [("addr",c_ushort), 
       ("length",c_ushort), 
       ("pBuf",POINTER(c_char))] # I have tried several other ctypes types 
              # for `pBuf`, but to no avail yet 

Я понимаю, что я не могу присвоить указатель из Python в pBuf, потому что это не тот же контекст памяти. Я также понимаю, что это довольно просто из пространства ядра с использованием copy_to_user. Я связан требованиями, что это приложение python, потому что оно привязано к графическому интерфейсу python. Я ценю любую помощь.

Update 1

Я знаю, что это может быть решена с помощью метода fuse_reply_ioctl_retry. Этот метод позволяет мне копировать данные из приложения и в приложение. Проблема в том, что при втором вызове fuse_reply_ioctl_retry, FUSE возвращает код ошибки в приложение. Я буду продолжать пытаться исправить это, но буду благодарен за любую помощь. Благодарю.

ответ

1

Я понял. Хитрость заключается в вызове fuse_reply_ioctl_retry для каждого указателя в структуре, к которой вы хотите получить доступ к содержимому, независимо от того, нужно ли их модифицировать или просто читать с них. Это оказалось довольно неприятным, используя python и ctypes, а также FUSE/CUSE, и если кто-то еще это сделает, я настоятельно рекомендую переключиться на прямой C для этого приложения, потому что ctypes может быть довольно сложным, но поверх CUSE/FUSE систем, это довольно ужасающий. Я бы это сделал, но я был связан с python, потому что это было дополнение к другому приложению. Мини-напыщенный.

Вот урезанная версия решения.

# ctypes Structure for driver 
class EEPromDataStruct(Structure): 
    _fields_ = [("addr",c_ushort), 
       ("length",c_ushort), 
       ("pBuf",c_ulong)] #u8* 
       # Note that this is a long instead of some pointer. 
       # This is so I can easily know the application address 
       # the pointer holds. 
... 

# The IOCTL file operation for this driver 
def ioctl(self, req, cmd, arg_p, file_info, uflags, in_buff_p, 
          in_bufsz, out_bufsz): 
    ioctl = DECODE_IOC(cmd) 
    if ioctl == IOC_READ_EEPROM: 
     if not in_buff_p: 
      PyCuse.fuse_reply_ioctl_retry(req,pointer(PyCuse.iovec(
              cast(arg_p,c_void_p),sizeof(
              EEPromDataStruct))),1,None,0) 
     else: 
      if out_bufsz == 0: 
       eepromDataPtr = cast(in_buff_p,POINTER(EEPromDataStruct)) 
       addr = eepromDataPtr.contents.addr 
       length = eepromDataPtr.contents.length 
       pBuf = eepromDataPtr.contents.pBuf 
       # Load from pBuf 
       out_iovecs = pointer(PyCuse.iovec(cast(pBuf,c_void_p),length)) 
       in_iovecs = pointer(PyCuse.iovec(cast(pBuf,c_void_p),length)) 
       PyCuse.fuse_reply_ioctl_retry(req,in_iovecs,1,out_iovecs,1) 
      else: 
       eepromBuff.value = "Some String Here" 
       PyCuse.fuse_reply_ioctl(req, 0, eepromBuff, out_bufsz) 
     else: 
      print("%s Unrecognized IOCTL #...\n",self.devname) 
      PyCuse.fuse_reply_err(req,1) 

if not in_buff_p будет проверять, если память приложение было загружено в водителя, а если нет, то он будет вызывать fuse_reply_ioctl_retry, чтобы сделать это. Обратите внимание, что в настоящее время основное различие состоит в том, что вектор выходных данных, указанный для этой попытки, был None. Это важно, потому что я затем проверяю, что такое размер вывода. Если это 0, то я знаю, что это мой основной EEPromDataStruct, и я продолжаю этот путь. Я готовлю несколько векторов данных и снова повторю попытку. Наконец, я беру указатель и назначаю некоторую строку его содержимому.

Его длительный процесс. Но это работает. Надеюсь, это поможет всем, кто в этом нуждается.