Commit b14ebcfc authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://thebsh.namesys.com/bk/reiser3-linux-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents cb7ada82 16b39f5f
......@@ -247,6 +247,17 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.0.24:
- Small internal cleanups.
- Support for sendfile system call. (Christoph Hellwig)
2.0.23:
- Massive internal locking changes to mft record locking. Fixes
various race conditions and deadlocks.
- Fix ntfs over loopback for compressed files by adding an
optimization barrier. (gcc was screwing up otherwise ?)
Thanks go to Christoph Hellwig for pointing these two out:
- Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
- Fix ntfs_free() for ia64 and parisc.
2.0.22:
- Small internal cleanups.
2.0.21:
......
......@@ -138,7 +138,7 @@ typedef struct actcapi_ncpd {
typedef struct actcapi_msg {
actcapi_msghdr hdr;
union msg {
union {
__u16 manuf_msg;
struct manufacturer_req_net {
__u16 manuf_msg;
......
......@@ -564,8 +564,8 @@ isdn_audio_eval_dtmf(modem_info * info)
ISDN_AUDIO_SKB_LOCK(skb) = 0;
save_flags(flags);
cli();
di = info->isdn_driver;
ch = info->isdn_channel;
di = isdn_slot_driver(info->isdn_slot);
ch = isdn_slot_channel(info->isdn_slot);
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
dev->drv[di]->rcvcount[ch] += 2;
restore_flags(flags);
......@@ -685,8 +685,8 @@ isdn_audio_put_dle_code(modem_info * info, u_char code)
ISDN_AUDIO_SKB_LOCK(skb) = 0;
save_flags(flags);
cli();
di = info->isdn_driver;
ch = info->isdn_channel;
di = isdn_slot_driver(info->isdn_slot);
ch = isdn_slot_channel(info->isdn_slot);
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
dev->drv[di]->rcvcount[ch] += 2;
restore_flags(flags);
......
This diff is collapsed.
......@@ -23,6 +23,32 @@
#undef ISDN_DEBUG_NET_DUMP
#undef ISDN_DEBUG_NET_DIAL
#undef ISDN_DEBUG_NET_ICALL
#undef ISDN_DEBUG_STATCALLB
#undef ISDN_DEBUG_COMMAND
#ifdef ISDN_DEBUG_NET_DIAL
#define dbg_net_dial(arg...) printk(KERN_DEBUG arg)
#else
#define dbg_net_dial(arg...) do {} while (0)
#endif
#ifdef ISDN_DEBUG_NET_ICALL
#define dbg_net_icall(arg...) printk(KERN_DEBUG arg)
#else
#define dbg_net_icall(arg...) do {} while (0)
#endif
#ifdef ISDN_DEBUG_STATCALLB
#define dbg_statcallb(arg...) printk(KERN_DEBUG arg)
#else
#define dbg_statcallb(arg...) do {} while (0)
#endif
#define isdn_BUG() \
do { printk(KERN_WARNING "ISDN Bug at %s:%d\n", __FILE__, __LINE__); \
} while(0)
#define HERE printk("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__)
/* Prototypes */
extern void isdn_MOD_INC_USE_COUNT(void);
......@@ -30,20 +56,50 @@ extern void isdn_MOD_DEC_USE_COUNT(void);
extern void isdn_lock_drivers(void);
extern void isdn_unlock_drivers(void);
extern void isdn_free_channel(int di, int ch, int usage);
extern void isdn_all_eaz(int di, int ch);
extern int isdn_command(isdn_ctrl *);
extern int isdn_dc2minor(int di, int ch);
extern void isdn_info_update(void);
extern char *isdn_map_eaz2msn(char *msn, int di);
extern void isdn_timer_ctrl(int tf, int onoff);
extern void isdn_unexclusive_channel(int di, int ch);
extern int isdn_getnum(char **);
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
extern int isdn_get_free_channel(int, int, int, int, int, char *);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if * i);
extern int isdn_msncmp( const char *, const char *);
extern int isdn_add_channels(driver *, int, int, int);
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
extern void isdn_dumppkt(char *, u_char *, int, int);
#else
static inline void isdn_dumppkt(char *s, u_char *d, int l, int m) { }
#endif
struct dial_info {
int l2_proto;
int l3_proto;
struct T30_s *fax;
unsigned char si1;
unsigned char si2;
unsigned char *msn;
unsigned char *phone;
};
extern struct list_head isdn_net_devs;
extern int isdn_get_free_slot(int, int, int, int, int, char *);
extern void isdn_slot_free(int slot, int usage);
extern void isdn_slot_all_eaz(int slot);
extern int isdn_slot_command(int slot, int cmd, isdn_ctrl *);
extern int isdn_slot_dial(int slot, struct dial_info *dial);
extern char *isdn_slot_map_eaz2msn(int slot, char *msn);
extern int isdn_slot_write(int slot, struct sk_buff *);
extern int isdn_slot_readbchan(int slot, u_char *, u_char *, int);
extern int isdn_slot_hdrlen(int slot);
extern int isdn_slot_driver(int slot);
extern int isdn_slot_channel(int slot);
extern int isdn_slot_usage(int slot);
extern void isdn_slot_set_usage(int slot, int usage);
extern char *isdn_slot_num(int slot);
extern int isdn_slot_m_idx(int slot);
extern void isdn_slot_set_m_idx(int slot, int midx);
extern void isdn_slot_set_rx_netdev(int sl, isdn_net_dev *nd);
extern void isdn_slot_set_st_netdev(int sl, isdn_net_dev *nd);
extern isdn_net_dev *isdn_slot_rx_netdev(int sl);
extern isdn_net_dev *isdn_slot_st_netdev(int sl);
This diff is collapsed.
......@@ -31,8 +31,8 @@
#define CISCO_SLARP_REPLY 1
#define CISCO_SLARP_KEEPALIVE 2
extern char *isdn_net_new(char *, struct net_device *);
extern char *isdn_net_newslave(char *);
extern int isdn_net_new(char *, struct net_device *);
extern int isdn_net_newslave(char *);
extern int isdn_net_rm(char *);
extern int isdn_net_rmall(void);
extern int isdn_net_stat_callback(int, isdn_ctrl *);
......@@ -44,7 +44,6 @@ extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *);
extern int isdn_net_delphone(isdn_net_ioctl_phone *);
extern int isdn_net_find_icall(int, int, int, setup_parm *);
extern void isdn_net_hangup(struct net_device *);
extern void isdn_net_dial(void);
extern void isdn_net_autohup(void);
extern int isdn_net_force_hangup(char *);
extern int isdn_net_force_dial(char *);
......@@ -131,7 +130,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
if (master_lp->netdev->queue == lp) {
master_lp->netdev->queue = lp->next;
if (lp->next == lp) { /* last in queue */
master_lp->netdev->queue = master_lp->netdev->local;
master_lp->netdev->queue = &master_lp->netdev->local;
}
}
lp->next = lp->last = lp; /* (re)set own pointers */
......
......@@ -165,14 +165,15 @@ isdn_ppp_bind(isdn_net_local * lp)
save_flags(flags);
cli();
if (lp->pppbind < 0) { /* device bounded to ippp device ? */
isdn_net_dev *net_dev = dev->netdev;
struct list_head *l;
char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
memset(exclusive, 0, ISDN_MAX_CHANNELS);
while (net_dev) { /* step through net devices to find exclusive minors */
isdn_net_local *lp = net_dev->local;
/* step through net devices to find exclusive minors */
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
isdn_net_local *lp = &p->local;
if (lp->pppbind >= 0)
exclusive[lp->pppbind] = 1;
net_dev = net_dev->next;
}
/*
* search a free device / slot
......@@ -804,11 +805,11 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
if (proto != PPP_LCP)
lp->huptimer = 0;
if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
if (lp->isdn_slot < 0) {
retval = 0;
goto out;
}
if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
if ((dev->drv[isdn_slot_driver(lp->isdn_slot)]->flags & DRV_FLAG_RUNNING) &&
lp->dialstate == 0 &&
(lp->flags & ISDN_NET_CONNECTED)) {
unsigned short hl;
......@@ -818,7 +819,7 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
* sk_buff. old call to dev_alloc_skb only reserved
* 16 bytes, now we are looking what the driver want
*/
hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
hl = isdn_slot_hdrlen(lp->isdn_slot);
skb = alloc_skb(hl+count, GFP_ATOMIC);
if (!skb) {
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
......@@ -974,7 +975,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
int slot;
int proto;
if (net_dev->local->master)
if (net_dev->local.master)
BUG(); // we're called with the master device always
slot = lp->ppp_slot;
......@@ -1077,12 +1078,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
case PPP_VJC_UNCOMP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
if (net_dev->local->ppp_slot < 0) {
if (net_dev->local.ppp_slot < 0) {
printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
net_dev->local->ppp_slot);
net_dev->local.ppp_slot);
goto drop_packet;
}
if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
goto drop_packet;
}
......@@ -1103,12 +1104,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
skb_put(skb, skb_old->len + 128);
memcpy(skb->data, skb_old->data, skb_old->len);
if (net_dev->local->ppp_slot < 0) {
if (net_dev->local.ppp_slot < 0) {
printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
net_dev->local->ppp_slot);
net_dev->local.ppp_slot);
goto drop_packet;
}
pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
skb->data, skb_old->len);
kfree_skb(skb_old);
if (pkt_len < 0)
......@@ -1144,7 +1145,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
return;
drop_packet:
net_dev->local->stats.rx_dropped++;
net_dev->local.stats.rx_dropped++;
kfree_skb(skb);
}
......@@ -1263,7 +1264,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
* sk_buff. old call to dev_alloc_skb only reserved
* 16 bytes, now we are looking what the driver want.
*/
hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
hl = isdn_slot_hdrlen(lp->isdn_slot) + IPPP_MAX_HEADER;;
/*
* Note: hl might still be insufficient because the method
* above does not account for a possibible MPPP slave channel
......@@ -1976,7 +1977,7 @@ isdn_ppp_dial_slave(char *name)
if (!(ndev = isdn_net_findif(name)))
return 1;
lp = ndev->local;
lp = &ndev->local;
if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
......@@ -2007,7 +2008,7 @@ isdn_ppp_hangup_slave(char *name)
if (!(ndev = isdn_net_findif(name)))
return 1;
lp = ndev->local;
lp = &ndev->local;
if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
......@@ -2094,7 +2095,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
isdn_net_local *lp = is->lp;
/* Alloc large enough skb */
hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
hl = isdn_slot_hdrlen(lp->isdn_slot);
skb = alloc_skb(len + hl + 16,GFP_ATOMIC);
if(!skb) {
printk(KERN_WARNING
......
This diff is collapsed.
......@@ -105,7 +105,7 @@ extern void isdn_tty_modem_escape(void);
extern void isdn_tty_modem_ring(void);
extern void isdn_tty_carrier_timeout(void);
extern void isdn_tty_modem_xmit(void);
extern int isdn_tty_modem_init(void);
extern int isdn_tty_init(void);
extern void isdn_tty_readmodem(void);
extern int isdn_tty_find_icall(int, int, setup_parm *);
extern void isdn_tty_cleanup_xmit(modem_info *);
......@@ -119,3 +119,6 @@ extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *);
extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *);
extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
#endif
extern int isdn_tty_init(void);
extern void isdn_tty_exit(void);
......@@ -74,7 +74,7 @@ isdn_tty_fax_modem_result(int code, modem_info * info)
case 2: /* +FCON */
/* Append CPN, if enabled */
if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
(!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
(!(isdn_slot_usage(info->isdn_slot) & ISDN_USAGE_OUTGOING))) {
sprintf(rs, "/%s", m->cpn);
isdn_tty_at_cout(rs, info);
}
......@@ -360,12 +360,11 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
default:
PARSE_ERROR1;
}
c.command = ISDN_CMD_FAXCMD;
#ifdef ISDN_TTY_FAX_CMD_DEBUG
printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
#endif
if (info->isdn_driver < 0) {
if (info->isdn_slot < 0) {
save_flags(flags);
cli();
if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
......@@ -374,32 +373,21 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
PARSE_ERROR1;
}
/* get a temporary connection to the first free fax driver */
i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
i = isdn_get_free_slot(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
if (i < 0) {
restore_flags(flags);
PARSE_ERROR1;
}
info->isdn_driver = dev->drvmap[i];
info->isdn_channel = dev->chanmap[i];
info->drv_index = i;
dev->m_idx[i] = info->line;
c.driver = info->isdn_driver;
c.arg = info->isdn_channel;
isdn_command(&c);
isdn_free_channel(info->isdn_driver, info->isdn_channel,
ISDN_USAGE_FAX);
info->isdn_driver = -1;
info->isdn_channel = -1;
if (info->drv_index >= 0) {
dev->m_idx[info->drv_index] = -1;
info->drv_index = -1;
}
info->isdn_slot = i;
isdn_slot_set_m_idx(i, info->line);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
isdn_slot_free(info->isdn_slot, ISDN_USAGE_FAX);
isdn_slot_set_m_idx(i, -1);
info->isdn_slot = -1;
restore_flags(flags);
} else {
c.driver = info->isdn_driver;
c.arg = info->isdn_channel;
isdn_command(&c);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
}
return 1;
}
......@@ -800,10 +788,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
#endif
f->code = ISDN_TTY_FAX_DR;
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_FAXCMD;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
if (f->phase == ISDN_FAX_PHASE_B) {
f->phase = ISDN_FAX_PHASE_C;
} else if (f->phase == ISDN_FAX_PHASE_D) {
......@@ -855,10 +840,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
#endif
if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
f->code = ISDN_TTY_FAX_DT;
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_FAXCMD;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
if (f->phase == ISDN_FAX_PHASE_D) {
f->phase = ISDN_FAX_PHASE_C;
isdn_tty_fax_modem_result(7, info); /* CONNECT */
......@@ -913,10 +895,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
PARSE_ERROR1;
f->fet = par;
f->code = ISDN_TTY_FAX_ET;
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_FAXCMD;
isdn_command(&cmd);
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &cmd);
#ifdef ISDN_TTY_FAX_STAT_DEBUG
printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
#endif
......
......@@ -515,14 +515,12 @@ isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
}
int
isdn_v110_stat_callback(int idx, isdn_ctrl * c)
isdn_v110_stat_callback(struct isdn_v110 *iv110, isdn_ctrl *c)
{
isdn_v110_stream *v = NULL;
int i;
int ret;
if (idx < 0)
return 0;
switch (c->command) {
case ISDN_STAT_BSENT:
/* Keep the send-queue of the driver filled
......@@ -531,9 +529,9 @@ isdn_v110_stat_callback(int idx, isdn_ctrl * c)
* send down an Idle-Frame (or an Sync-Frame, if
* v->SyncInit != 0).
*/
if (!(v = dev->v110[idx]))
if (!(v = iv110->v110))
return 0;
atomic_inc(&dev->v110use[idx]);
atomic_inc(&iv110->v110use);
if (v->skbidle > 0) {
v->skbidle--;
ret = 1;
......@@ -560,38 +558,38 @@ isdn_v110_stat_callback(int idx, isdn_ctrl * c)
} else
break;
}
atomic_dec(&dev->v110use[idx]);
atomic_dec(&iv110->v110use);
return ret;
case ISDN_STAT_DHUP:
case ISDN_STAT_BHUP:
while (1) {
atomic_inc(&dev->v110use[idx]);
if (atomic_dec_and_test(&dev->v110use[idx])) {
isdn_v110_close(dev->v110[idx]);
dev->v110[idx] = NULL;
atomic_inc(&iv110->v110use);
if (atomic_dec_and_test(&iv110->v110use)) {
isdn_v110_close(iv110->v110);
iv110->v110 = NULL;
break;
}
sti();
}
break;
case ISDN_STAT_BCONN:
if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) {
if (iv110->v110emu && (iv110->v110 == NULL)) {
int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
int maxsize = dev->drv[c->driver]->interface->maxbufsize;
atomic_inc(&dev->v110use[idx]);
switch (dev->v110emu[idx]) {
atomic_inc(&iv110->v110use);
switch (iv110->v110emu) {
case ISDN_PROTO_L2_V11096:
dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize);
iv110->v110 = isdn_v110_open(V110_9600, hdrlen, maxsize);
break;
case ISDN_PROTO_L2_V11019:
dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize);
iv110->v110 = isdn_v110_open(V110_19200, hdrlen, maxsize);
break;
case ISDN_PROTO_L2_V11038:
dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
iv110->v110 = isdn_v110_open(V110_38400, hdrlen, maxsize);
break;
default:;
}
if ((v = dev->v110[idx])) {
if ((v = iv110->v110)) {
while (v->SyncInit) {
struct sk_buff *skb = isdn_v110_sync(v);
if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
......@@ -603,8 +601,8 @@ isdn_v110_stat_callback(int idx, isdn_ctrl * c)
v->skbidle++;
}
} else
printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
atomic_dec(&dev->v110use[idx]);
printk(KERN_WARNING "isdn_v110: Couldn't open stream\n");
atomic_dec(&iv110->v110use);
}
break;
default:
......
......@@ -9,8 +9,14 @@
*
*/
#ifndef _isdn_v110_h_
#define _isdn_v110_h_
#ifndef ISDN_V110_H
#define ISDN_V110_H
struct isdn_v110 {
int v110emu; /* V.110 emulator-mode 0=none */
atomic_t v110use; /* Usage-Semaphore for stream */
isdn_v110_stream *v110; /* V.110 private data */
};
/*
* isdn_v110_encode will take raw data and encode it using V.110
......@@ -23,7 +29,7 @@ extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
*/
extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
extern int isdn_v110_stat_callback(int, isdn_ctrl *);
extern int isdn_v110_stat_callback(struct isdn_v110 *v110, isdn_ctrl *);
extern void isdn_v110_close(isdn_v110_stream * v);
#endif
......@@ -757,6 +757,10 @@ isdnloop_vstphone(isdnloop_card * card, char *phone, int caller)
int i;
static char nphone[30];
if (!card) {
printk("BUG!!!\n");
return "";
}
switch (card->ptype) {
case ISDN_PTYPE_EURO:
if (caller) {
......@@ -775,7 +779,7 @@ isdnloop_vstphone(isdnloop_card * card, char *phone, int caller)
return (&phone[strlen(phone) - 1]);
break;
}
return ("\0");
return "";
}
/*
......@@ -882,7 +886,7 @@ isdnloop_parse_cmd(isdnloop_card * card)
isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
cmd.parm.setup.si1,
cmd.parm.setup.si2,
isdnloop_vstphone(card->rcard[ch],
isdnloop_vstphone(card->rcard[ch - 1],
cmd.parm.setup.phone, 0));
isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
/* Fall through */
......
......@@ -2,6 +2,36 @@ ToDo:
- Find and fix bugs.
- Enable NFS exporting of NTFS.
2.0.24 - Cleanups.
- Treat BUG_ON() as ASSERT() not VERIFY(), i.e. do not use side effects
inside BUG_ON(). (Adam J. Richter)
- Split logical OR expressions inside BUG_ON() into individual BUG_ON()
calls for improved debugging. (Adam J. Richter)
- Add errors flag to the ntfs volume state, accessed via
NVol{,Set,Clear}Errors(vol).
- Do not allow read-write remounts of read-only volumes with errors.
- Clarify comment for ntfs file operation sendfile which was added by
Christoph Hellwig a while ago (just using generic_file_sendfile())
to say that ntfs ->sendfile is only used for the case where the
source data is on the ntfs partition and the destination is
somewhere else, i.e. nothing we need to concern ourselves with.
- Add generic_file_write() as our ntfs file write operation.
2.0.23 - Major bug fixes (races, deadlocks, non-i386 architectures).
- Massive internal locking changes to mft record locking. Fixes lock
recursion and replaces the mrec_lock read/write semaphore with a
mutex. Also removes the now superfluous mft_count. This fixes several
race conditions and deadlocks, especially in the future write code.
- Fix ntfs over loopback for compressed files by adding an
optimization barrier. (gcc was screwing up otherwise ?)
- Miscellaneous cleanups all over the code and a fix or two in error
handling code paths.
Thanks go to Christoph Hellwig for pointing out the following two:
- Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs().
- Fix ntfs_free() for ia64 and parisc by checking for VMALLOC_END, too.
2.0.22 - Cleanups, mainly to ntfs_readdir(), and use C99 initializers.
- Change fs/ntfs/dir.c::ntfs_reddir() to only read/write ->f_pos once
......
......@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.22\"
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.24\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......
......@@ -106,8 +106,6 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
if (!NInoMstProtected(ni)) {
if (likely(page_uptodate && !PageError(page)))
SetPageUptodate(page);
unlock_page(page);
return;
} else {
char *addr;
unsigned int i, recs, nr_err;
......@@ -332,6 +330,8 @@ static int ntfs_read_block(struct page *page)
* for it to be read in before we can do the copy.
*
* Return 0 on success and -errno on error.
*
* WARNING: Do not make this function static! It is used by mft.c!
*/
int ntfs_readpage(struct file *file, struct page *page)
{
......@@ -372,8 +372,8 @@ int ntfs_readpage(struct file *file, struct page *page)
else
base_ni = ni->_INE(base_ntfs_ino);
/* Map, pin and lock the mft record for reading. */
mrec = map_mft_record(READ, base_ni);
/* Map, pin and lock the mft record. */
mrec = map_mft_record(base_ni);
if (unlikely(IS_ERR(mrec))) {
err = PTR_ERR(mrec);
goto err_out;
......@@ -416,7 +416,7 @@ int ntfs_readpage(struct file *file, struct page *page)
put_unm_err_out:
put_attr_search_ctx(ctx);
unm_err_out:
unmap_mft_record(READ, base_ni);
unmap_mft_record(base_ni);
err_out:
unlock_page(page);
return err;
......
......@@ -110,7 +110,8 @@ static inline run_list_element *ntfs_rl_realloc(run_list_element *rl,
static inline BOOL ntfs_are_rl_mergeable(run_list_element *dst,
run_list_element *src)
{
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
if ((dst->lcn < 0) || (src->lcn < 0)) /* Are we merging holes? */
return FALSE;
......@@ -192,7 +193,8 @@ static inline run_list_element *ntfs_rl_append(run_list_element *dst,
BOOL right;
int magic;
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
/* First, check if the right hand end needs merging. */
right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
......@@ -258,7 +260,8 @@ static inline run_list_element *ntfs_rl_insert(run_list_element *dst,
BOOL hole = FALSE; /* Following a hole */
int magic;
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
/* disc => Discontinuity between the end of @dst and the start of @src.
* This means we might need to insert a hole.
......@@ -362,7 +365,8 @@ static inline run_list_element *ntfs_rl_replace(run_list_element *dst,
BOOL right;
int magic;
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
/* First, merge the left and right ends, if necessary. */
right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
......@@ -423,7 +427,8 @@ static inline run_list_element *ntfs_rl_replace(run_list_element *dst,
static inline run_list_element *ntfs_rl_split(run_list_element *dst, int dsize,
run_list_element *src, int ssize, int loc)
{
BUG_ON(!dst || !src);
BUG_ON(!dst);
BUG_ON(!src);
/* Space required: @dst size + @src size + one new hole. */
dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1);
......@@ -948,7 +953,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn)
else
base_ni = ni->_INE(base_ntfs_ino);
mrec = map_mft_record(READ, base_ni);
mrec = map_mft_record(base_ni);
if (IS_ERR(mrec))
return PTR_ERR(mrec);
ctx = get_attr_search_ctx(base_ni, mrec);
......@@ -979,7 +984,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn)
put_attr_search_ctx(ctx);
err_out:
unmap_mft_record(READ, base_ni);
unmap_mft_record(base_ni);
return err;
}
......@@ -1671,7 +1676,7 @@ void reinit_attr_search_ctx(attr_search_context *ctx)
return;
} /* Attribute list. */
if (ctx->ntfs_ino != ctx->base_ntfs_ino)
unmap_mft_record(READ, ctx->ntfs_ino);
unmap_mft_record(ctx->ntfs_ino);
init_attr_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
return;
}
......@@ -1704,7 +1709,7 @@ attr_search_context *get_attr_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
void put_attr_search_ctx(attr_search_context *ctx)
{
if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino)
unmap_mft_record(READ, ctx->ntfs_ino);
unmap_mft_record(ctx->ntfs_ino);
kmem_cache_free(ntfs_attr_ctx_cache, ctx);
return;
}
......
......@@ -467,7 +467,8 @@ int ntfs_read_compressed_block(struct page *page)
* Bad things happen if we get here for anything that is not an
* unnamed $DATA attribute.
*/
BUG_ON(ni->type != AT_DATA || ni->name_len);
BUG_ON(ni->type != AT_DATA);
BUG_ON(ni->name_len);
pages = kmalloc(nr_pages * sizeof(struct page *), GFP_NOFS);
......@@ -608,8 +609,27 @@ int ntfs_read_compressed_block(struct page *page)
if (buffer_uptodate(tbh))
continue;
wait_on_buffer(tbh);
/*
* We need an optimization barrier here, otherwise we start
* hitting the below fixup code when accessing a loopback
* mounted ntfs partition. This indicates either there is a
* race condition in the loop driver or, more likely, gcc
* overoptimises the code without the barrier and it doesn't
* do the Right Thing(TM).
*/
barrier();
if (unlikely(!buffer_uptodate(tbh))) {
ntfs_warning(vol->sb, "Buffer is unlocked but not "
"uptodate! Unplugging the disk queue "
"and rescheduling.");
get_bh(tbh);
blk_run_queues();
schedule();
put_bh(tbh);
if (unlikely(!buffer_uptodate(tbh)))
goto read_err;
ntfs_warning(vol->sb, "Buffer is now uptodate. Good.");
}
}
/*
......
This diff is collapsed.
......@@ -51,8 +51,15 @@ static int ntfs_file_open(struct inode *vi, struct file *filp)
struct file_operations ntfs_file_ops = {
.llseek = generic_file_llseek, /* Seek inside file. */
.read = generic_file_read, /* Read from file. */
#ifdef NTFS_RW
.write = generic_file_write, /* Write to a file. */
#endif
.mmap = generic_file_mmap, /* Mmap file. */
.sendfile = generic_file_sendfile,/* Zero-copy data send. */
.sendfile = generic_file_sendfile,/* Zero-copy data send with the
data source being on the
ntfs partition. We don't
need to care about the data
destination. */
.open = ntfs_file_open, /* Open file. */
};
......
......@@ -278,7 +278,9 @@ void ntfs_destroy_big_inode(struct inode *inode)
ntfs_inode *ni = NTFS_I(inode);
ntfs_debug("Entering.");
BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
BUG_ON(ni->page);
if (!atomic_dec_and_test(&ni->count))
BUG();
kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode));
}
......@@ -299,7 +301,9 @@ static inline ntfs_inode *ntfs_alloc_extent_inode(void)
void ntfs_destroy_extent_inode(ntfs_inode *ni)
{
ntfs_debug("Entering.");
BUG_ON(atomic_read(&ni->mft_count) || !atomic_dec_and_test(&ni->count));
BUG_ON(ni->page);
if (!atomic_dec_and_test(&ni->count))
BUG();
kmem_cache_free(ntfs_inode_cache, ni);
}
......@@ -323,8 +327,7 @@ static void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
atomic_set(&ni->count, 1);
ni->vol = NTFS_SB(sb);
init_run_list(&ni->run_list);
init_rwsem(&ni->mrec_lock);
atomic_set(&ni->mft_count, 0);
init_MUTEX(&ni->mrec_lock);
ni->page = NULL;
ni->page_ofs = 0;
ni->attr_list_size = 0;
......@@ -504,7 +507,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
ntfs_init_big_inode(vi);
ni = NTFS_I(vi);
m = map_mft_record(READ, ni);
m = map_mft_record(ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
goto err_out;
......@@ -790,6 +793,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
/* No index allocation. */
vi->i_size = ni->initialized_size =
ni->allocated_size = 0;
/* We are done with the mft record, so we release it. */
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
m = NULL;
ctx = NULL;
goto skip_large_dir_stuff;
} /* LARGE_INDEX: Index allocation present. Setup state. */
NInoSetIndexAllocPresent(ni);
......@@ -834,7 +842,14 @@ static int ntfs_read_locked_inode(struct inode *vi)
ctx->attr->_ANR(initialized_size));
ni->allocated_size = sle64_to_cpu(
ctx->attr->_ANR(allocated_size));
/*
* We are done with the mft record, so we release it. Otherwise
*
*/
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
m = NULL;
ctx = NULL;
/* Get the index bitmap attribute inode. */
bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
if (unlikely(IS_ERR(bvi))) {
......@@ -858,7 +873,6 @@ static int ntfs_read_locked_inode(struct inode *vi)
bvi->i_size << 3, vi->i_size);
goto unm_err_out;
}
skip_large_dir_stuff:
/* Everyone gets read and scan permissions. */
vi->i_mode |= S_IRUGO | S_IXUGO;
......@@ -998,6 +1012,11 @@ static int ntfs_read_locked_inode(struct inode *vi)
le32_to_cpu(ctx->attr->_ARA(value_length));
}
no_data_attr_special_case:
/* We are done with the mft record, so we release it. */
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
m = NULL;
ctx = NULL;
/* Everyone gets all permissions. */
vi->i_mode |= S_IRWXUGO;
/* If read-only, noone gets write permissions. */
......@@ -1026,9 +1045,6 @@ static int ntfs_read_locked_inode(struct inode *vi)
else
vi->i_blocks = ni->_ICF(compressed_size) >> 9;
put_attr_search_ctx(ctx);
unmap_mft_record(READ, ni);
ntfs_debug("Done.");
return 0;
......@@ -1037,7 +1053,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
err = -EIO;
if (ctx)
put_attr_search_ctx(ctx);
unmap_mft_record(READ, ni);
if (m)
unmap_mft_record(ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i. Marking inode 0x%lx "
"as bad.", -err, vi->i_ino);
......@@ -1091,7 +1108,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
/* Set inode type to zero but preserve permissions. */
vi->i_mode = base_vi->i_mode & ~S_IFMT;
m = map_mft_record(READ, base_ni);
m = map_mft_record(base_ni);
if (IS_ERR(m)) {
err = PTR_ERR(m);
goto err_out;
......@@ -1265,7 +1282,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
ni->nr_extents = -1;
put_attr_search_ctx(ctx);
unmap_mft_record(READ, base_ni);
unmap_mft_record(base_ni);
ntfs_debug("Done.");
return 0;
......@@ -1275,7 +1292,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
err = -EIO;
if (ctx)
put_attr_search_ctx(ctx);
unmap_mft_record(READ, base_ni);
unmap_mft_record(base_ni);
err_out:
ntfs_error(vi->i_sb, "Failed with error code %i while reading "
"attribute inode (mft_no 0x%lx, type 0x%x, name_len "
......@@ -1398,7 +1415,7 @@ void ntfs_read_inode_mount(struct inode *vi)
/* Need this to sanity check attribute list references to $MFT. */
ni->seq_no = le16_to_cpu(m->sequence_number);
/* Provides readpage() and sync_page() for map_mft_record(READ). */
/* Provides readpage() and sync_page() for map_mft_record(). */
vi->i_mapping->a_ops = &ntfs_mft_aops;
ctx = get_attr_search_ctx(ni, m);
......@@ -1795,8 +1812,8 @@ void __ntfs_clear_inode(ntfs_inode *ni)
}
}
/* Synchronize with ntfs_commit_inode(). */
down_write(&ni->mrec_lock);
up_write(&ni->mrec_lock);
down(&ni->mrec_lock);
up(&ni->mrec_lock);
if (NInoDirty(ni)) {
ntfs_error(ni->vol->sb, "Failed to commit dirty inode "
"asynchronously.");
......
......@@ -72,9 +72,8 @@ struct _ntfs_inode {
* The following fields are only valid for real inodes and extent
* inodes.
*/
struct rw_semaphore mrec_lock; /* Lock for serializing access to the
struct semaphore mrec_lock; /* Lock for serializing access to the
mft record belonging to this inode. */
atomic_t mft_count; /* Mapping reference count for book keeping. */
struct page *page; /* The page containing the mft record of the
inode. This should only be touched by the
(un)map_mft_record*() functions. */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment